From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_query_system/src/ich/hcx.rs | 223 +++++++++++++++++++++ compiler/rustc_query_system/src/ich/impls_hir.rs | 42 ++++ .../rustc_query_system/src/ich/impls_syntax.rs | 150 ++++++++++++++ compiler/rustc_query_system/src/ich/mod.rs | 19 ++ 4 files changed, 434 insertions(+) create mode 100644 compiler/rustc_query_system/src/ich/hcx.rs create mode 100644 compiler/rustc_query_system/src/ich/impls_hir.rs create mode 100644 compiler/rustc_query_system/src/ich/impls_syntax.rs create mode 100644 compiler/rustc_query_system/src/ich/mod.rs (limited to 'compiler/rustc_query_system/src/ich') diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs new file mode 100644 index 000000000..217fac341 --- /dev/null +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -0,0 +1,223 @@ +use crate::ich; + +use rustc_ast as ast; +use rustc_data_structures::sorted_map::SortedMap; +use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; +use rustc_data_structures::sync::Lrc; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_index::vec::IndexVec; +use rustc_session::cstore::CrateStore; +use rustc_session::Session; +use rustc_span::source_map::SourceMap; +use rustc_span::symbol::Symbol; +use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData}; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., +/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various +/// things (e.g., each `DefId`/`DefPath` is only hashed once). +#[derive(Clone)] +pub struct StableHashingContext<'a> { + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + source_span: &'a IndexVec, + // The value of `-Z incremental-ignore-spans`. + // This field should only be used by `unstable_opts_incremental_ignore_span` + incremental_ignore_spans: bool, + pub(super) body_resolver: BodyResolver<'a>, + // Very often, we are hashing something that does not need the + // `CachingSourceMapView`, so we initialize it lazily. + raw_source_map: &'a SourceMap, + caching_source_map: Option>, + pub(super) hashing_controls: HashingControls, +} + +/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. +/// We could also just store a plain reference to the `hir::Crate` but we want +/// to avoid that the crate is used to get untracked access to all of the HIR. +#[derive(Clone, Copy)] +pub(super) enum BodyResolver<'tcx> { + Forbidden, + Traverse { + hash_bodies: bool, + owner: LocalDefId, + bodies: &'tcx SortedMap>, + }, +} + +impl<'a> StableHashingContext<'a> { + #[inline] + fn new_with_or_without_spans( + sess: &'a Session, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + source_span: &'a IndexVec, + always_ignore_spans: bool, + ) -> Self { + let hash_spans_initial = + !always_ignore_spans && !sess.opts.unstable_opts.incremental_ignore_spans; + + StableHashingContext { + body_resolver: BodyResolver::Forbidden, + definitions, + cstore, + source_span, + incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans, + caching_source_map: None, + raw_source_map: sess.source_map(), + hashing_controls: HashingControls { hash_spans: hash_spans_initial }, + } + } + + #[inline] + pub fn new( + sess: &'a Session, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + source_span: &'a IndexVec, + ) -> Self { + Self::new_with_or_without_spans( + sess, + definitions, + cstore, + source_span, + /*always_ignore_spans=*/ false, + ) + } + + #[inline] + pub fn ignore_spans( + sess: &'a Session, + definitions: &'a Definitions, + cstore: &'a dyn CrateStore, + source_span: &'a IndexVec, + ) -> Self { + let always_ignore_spans = true; + Self::new_with_or_without_spans(sess, definitions, cstore, source_span, always_ignore_spans) + } + + /// Allow hashing + #[inline] + pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) { + let prev = match &mut self.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { ref mut hash_bodies, .. } => { + std::mem::replace(hash_bodies, hb) + } + }; + f(self); + match &mut self.body_resolver { + BodyResolver::Forbidden => unreachable!(), + BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev, + } + } + + #[inline] + pub fn with_hir_bodies( + &mut self, + hash_bodies: bool, + owner: LocalDefId, + bodies: &SortedMap>, + f: impl FnOnce(&mut StableHashingContext<'_>), + ) { + f(&mut StableHashingContext { + body_resolver: BodyResolver::Traverse { hash_bodies, owner, bodies }, + ..self.clone() + }); + } + + #[inline] + pub fn while_hashing_spans(&mut self, hash_spans: bool, f: F) { + let prev_hash_spans = self.hashing_controls.hash_spans; + self.hashing_controls.hash_spans = hash_spans; + f(self); + self.hashing_controls.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + if let Some(def_id) = def_id.as_local() { + self.local_def_path_hash(def_id) + } else { + self.cstore.def_path_hash(def_id) + } + } + + #[inline] + pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash { + self.definitions.def_path_hash(def_id) + } + + #[inline] + pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { + match self.caching_source_map { + Some(ref mut sm) => sm, + ref mut none => { + *none = Some(CachingSourceMapView::new(self.raw_source_map)); + none.as_mut().unwrap() + } + } + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + ich::IGNORED_ATTRIBUTES.contains(&name) + } + + #[inline] + pub fn hashing_controls(&self) -> HashingControls { + self.hashing_controls.clone() + } +} + +impl<'a> HashStable> for ast::NodeId { + #[inline] + fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { + panic!("Node IDs should not appear in incremental state"); + } +} + +impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { + #[inline] + fn hash_spans(&self) -> bool { + self.hashing_controls.hash_spans + } + + #[inline] + fn unstable_opts_incremental_ignore_spans(&self) -> bool { + self.incremental_ignore_spans + } + + #[inline] + fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + self.def_path_hash(def_id) + } + + #[inline] + fn def_span(&self, def_id: LocalDefId) -> Span { + self.source_span[def_id] + } + + #[inline] + fn span_data_to_lines_and_cols( + &mut self, + span: &SpanData, + ) -> Option<(Lrc, usize, BytePos, usize, BytePos)> { + self.source_map().span_data_to_lines_and_cols(span) + } + + #[inline] + fn hashing_controls(&self) -> HashingControls { + self.hashing_controls.clone() + } +} + +impl<'a> rustc_data_structures::intern::InternedHashingContext for StableHashingContext<'a> { + fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)) { + self.while_hashing_spans(false, f); + } +} + +impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs new file mode 100644 index 000000000..3390ed9eb --- /dev/null +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -0,0 +1,42 @@ +//! This module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use crate::ich::hcx::BodyResolver; +use crate::ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir as hir; + +impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { + #[inline] + fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { + let hcx = self; + match hcx.body_resolver { + BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."), + BodyResolver::Traverse { hash_bodies: false, .. } => {} + BodyResolver::Traverse { hash_bodies: true, owner, bodies } => { + assert_eq!(id.hir_id.owner, owner); + bodies[&id.hir_id.local_id].hash_stable(hcx, hasher); + } + } + } + + fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { + self.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { hir_id, ref span, ref kind } = *expr; + + hir_id.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + }) + } + + fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) { + self.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { hir_id, ref kind, ref span } = *ty; + + hir_id.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs new file mode 100644 index 000000000..1fa085926 --- /dev/null +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -0,0 +1,150 @@ +//! This module contains `HashStable` implementations for various data types +//! from `rustc_ast` in no particular order. + +use crate::ich::StableHashingContext; + +use rustc_ast as ast; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_span::{BytePos, NormalizedPos, SourceFile}; +use std::assert_matches::assert_matches; + +use smallvec::SmallVec; + +impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} + +impl<'a> HashStable> for [ast::Attribute] { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + if self.is_empty() { + self.len().hash_stable(hcx, hasher); + return; + } + + // Some attributes are always ignored during hashing. + let filtered: SmallVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_doc_comment() + && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> { + fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name))); + debug_assert!(!attr.is_doc_comment()); + + let ast::Attribute { kind, id: _, style, span } = attr; + if let ast::AttrKind::Normal(item, tokens) = kind { + item.hash_stable(self, hasher); + style.hash_stable(self, hasher); + span.hash_stable(self, hasher); + assert_matches!( + tokens.as_ref(), + None, + "Tokens should have been removed during lowering!" + ); + } else { + unreachable!(); + } + } +} + +impl<'a> HashStable> for SourceFile { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let SourceFile { + name: _, // We hash the smaller name_hash instead of this + name_hash, + cnum, + // Do not hash the source as it is not encoded + src: _, + ref src_hash, + external_src: _, + start_pos, + end_pos: _, + lines: _, + ref multibyte_chars, + ref non_narrow_chars, + ref normalized_pos, + } = *self; + + (name_hash as u64).hash_stable(hcx, hasher); + + src_hash.hash_stable(hcx, hasher); + + // We are always in `Lines` form by the time we reach here. + assert!(self.lines.borrow().is_lines()); + self.lines(|lines| { + // We only hash the relative position within this source_file + lines.len().hash_stable(hcx, hasher); + for &line in lines.iter() { + stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); + } + }); + + // We only hash the relative position within this source_file + multibyte_chars.len().hash_stable(hcx, hasher); + for &char_pos in multibyte_chars.iter() { + stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); + } + + non_narrow_chars.len().hash_stable(hcx, hasher); + for &char_pos in non_narrow_chars.iter() { + stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + } + + normalized_pos.len().hash_stable(hcx, hasher); + for &char_pos in normalized_pos.iter() { + stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher); + } + + cnum.hash_stable(hcx, hasher); + } +} + +fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { + pos.0 - source_file_start.0 +} + +fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { + let rustc_span::MultiByteChar { pos, bytes } = mbc; + + (pos.0 - source_file_start.0, bytes as u32) +} + +fn stable_non_narrow_char( + swc: rustc_span::NonNarrowChar, + source_file_start: BytePos, +) -> (u32, u32) { + let pos = swc.pos(); + let width = swc.width(); + + (pos.0 - source_file_start.0, width as u32) +} + +fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { + let NormalizedPos { pos, diff } = np; + + (pos.0 - source_file_start.0, diff) +} + +impl<'tcx> HashStable> for rustc_feature::Features { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs new file mode 100644 index 000000000..0a1c350b2 --- /dev/null +++ b/compiler/rustc_query_system/src/ich/mod.rs @@ -0,0 +1,19 @@ +//! ICH - Incremental Compilation Hash + +pub use self::hcx::StableHashingContext; +use rustc_span::symbol::{sym, Symbol}; + +mod hcx; +mod impls_hir; +mod impls_syntax; + +pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ + sym::cfg, + sym::rustc_if_this_changed, + sym::rustc_then_this_would_need, + sym::rustc_dirty, + sym::rustc_clean, + sym::rustc_partition_reused, + sym::rustc_partition_codegened, + sym::rustc_expected_cgu_reuse, +]; -- cgit v1.2.3