|  | //! Machinery for hygienic macros. | 
|  | //! | 
|  | //! Inspired by Matthew Flatt et al., “Macros That Work Together: Compile-Time Bindings, Partial | 
|  | //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2 | 
|  | //! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>. | 
|  |  | 
|  | // Hygiene data is stored in a global variable and accessed via TLS, which | 
|  | // means that accesses are somewhat expensive. (`HygieneData::with` | 
|  | // encapsulates a single access.) Therefore, on hot code paths it is worth | 
|  | // ensuring that multiple HygieneData accesses are combined into a single | 
|  | // `HygieneData::with`. | 
|  | // | 
|  | // This explains why `HygieneData`, `SyntaxContext` and `ExpnId` have interfaces | 
|  | // with a certain amount of redundancy in them. For example, | 
|  | // `SyntaxContext::outer_expn_data` combines `SyntaxContext::outer` and | 
|  | // `ExpnId::expn_data` so that two `HygieneData` accesses can be performed within | 
|  | // a single `HygieneData::with` call. | 
|  | // | 
|  | // It also explains why many functions appear in `HygieneData` and again in | 
|  | // `SyntaxContext` or `ExpnId`. For example, `HygieneData::outer` and | 
|  | // `SyntaxContext::outer` do the same thing, but the former is for use within a | 
|  | // `HygieneData::with` call while the latter is for use outside such a call. | 
|  | // When modifying this file it is important to understand this distinction, | 
|  | // because getting it wrong can lead to nested `HygieneData::with` calls that | 
|  | // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) | 
|  |  | 
|  | use std::hash::Hash; | 
|  | use std::sync::Arc; | 
|  | use std::{fmt, iter, mem}; | 
|  |  | 
|  | use rustc_data_structures::fingerprint::Fingerprint; | 
|  | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | 
|  | use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; | 
|  | use rustc_data_structures::sync::Lock; | 
|  | use rustc_data_structures::unhash::UnhashMap; | 
|  | use rustc_hashes::Hash64; | 
|  | use rustc_index::IndexVec; | 
|  | use rustc_macros::{Decodable, Encodable, HashStable_Generic}; | 
|  | use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; | 
|  | use tracing::{debug, trace}; | 
|  |  | 
|  | use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId}; | 
|  | use crate::edition::Edition; | 
|  | use crate::source_map::SourceMap; | 
|  | use crate::symbol::{Symbol, kw, sym}; | 
|  | use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals}; | 
|  |  | 
|  | /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". | 
|  | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | 
|  | pub struct SyntaxContext(u32); | 
|  |  | 
|  | // To ensure correctness of incremental compilation, | 
|  | // `SyntaxContext` must not implement `Ord` or `PartialOrd`. | 
|  | // See https://github.com/rust-lang/rust/issues/90317. | 
|  | impl !Ord for SyntaxContext {} | 
|  | impl !PartialOrd for SyntaxContext {} | 
|  |  | 
|  | /// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal. | 
|  | /// The other fields are only for caching. | 
|  | pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); | 
|  |  | 
|  | #[derive(Clone, Copy, Debug)] | 
|  | struct SyntaxContextData { | 
|  | outer_expn: ExpnId, | 
|  | outer_transparency: Transparency, | 
|  | parent: SyntaxContext, | 
|  | /// This context, but with all transparent and semi-opaque expansions filtered away. | 
|  | opaque: SyntaxContext, | 
|  | /// This context, but with all transparent expansions filtered away. | 
|  | opaque_and_semiopaque: SyntaxContext, | 
|  | /// Name of the crate to which `$crate` with this context would resolve. | 
|  | dollar_crate_name: Symbol, | 
|  | } | 
|  |  | 
|  | impl SyntaxContextData { | 
|  | fn root() -> SyntaxContextData { | 
|  | SyntaxContextData { | 
|  | outer_expn: ExpnId::root(), | 
|  | outer_transparency: Transparency::Opaque, | 
|  | parent: SyntaxContext::root(), | 
|  | opaque: SyntaxContext::root(), | 
|  | opaque_and_semiopaque: SyntaxContext::root(), | 
|  | dollar_crate_name: kw::DollarCrate, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn key(&self) -> SyntaxContextKey { | 
|  | (self.parent, self.outer_expn, self.outer_transparency) | 
|  | } | 
|  | } | 
|  |  | 
|  | rustc_index::newtype_index! { | 
|  | /// A unique ID associated with a macro invocation and expansion. | 
|  | #[orderable] | 
|  | pub struct ExpnIndex {} | 
|  | } | 
|  |  | 
|  | /// A unique ID associated with a macro invocation and expansion. | 
|  | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | 
|  | pub struct ExpnId { | 
|  | pub krate: CrateNum, | 
|  | pub local_id: ExpnIndex, | 
|  | } | 
|  |  | 
|  | impl fmt::Debug for ExpnId { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | // Generate crate_::{{expn_}}. | 
|  | write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32()) | 
|  | } | 
|  | } | 
|  |  | 
|  | rustc_index::newtype_index! { | 
|  | /// A unique ID associated with a macro invocation and expansion. | 
|  | #[debug_format = "expn{}"] | 
|  | pub struct LocalExpnId {} | 
|  | } | 
|  |  | 
|  | // To ensure correctness of incremental compilation, | 
|  | // `LocalExpnId` must not implement `Ord` or `PartialOrd`. | 
|  | // See https://github.com/rust-lang/rust/issues/90317. | 
|  | impl !Ord for LocalExpnId {} | 
|  | impl !PartialOrd for LocalExpnId {} | 
|  |  | 
|  | /// Assert that the provided `HashStableContext` is configured with the 'default' | 
|  | /// `HashingControls`. We should always have bailed out before getting to here | 
|  | /// with a non-default mode. With this check in place, we can avoid the need | 
|  | /// to maintain separate versions of `ExpnData` hashes for each permutation | 
|  | /// of `HashingControls` settings. | 
|  | fn assert_default_hashing_controls(ctx: &impl HashStableContext, msg: &str) { | 
|  | match ctx.hashing_controls() { | 
|  | // Note that we require that `hash_spans` be set according to the global | 
|  | // `-Z incremental-ignore-spans` option. Normally, this option is disabled, | 
|  | // which will cause us to require that this method always be called with `Span` hashing | 
|  | // enabled. | 
|  | // | 
|  | // Span hashing can also be disabled without `-Z incremental-ignore-spans`. | 
|  | // This is the case for instance when building a hash for name mangling. | 
|  | // Such configuration must not be used for metadata. | 
|  | HashingControls { hash_spans } | 
|  | if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {} | 
|  | other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A unique hash value associated to an expansion. | 
|  | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] | 
|  | pub struct ExpnHash(Fingerprint); | 
|  |  | 
|  | impl ExpnHash { | 
|  | /// Returns the [StableCrateId] identifying the crate this [ExpnHash] | 
|  | /// originates from. | 
|  | #[inline] | 
|  | pub fn stable_crate_id(self) -> StableCrateId { | 
|  | StableCrateId(self.0.split().0) | 
|  | } | 
|  |  | 
|  | /// Returns the crate-local part of the [ExpnHash]. | 
|  | /// | 
|  | /// Used for assertions. | 
|  | #[inline] | 
|  | pub fn local_hash(self) -> Hash64 { | 
|  | self.0.split().1 | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn is_root(self) -> bool { | 
|  | self.0 == Fingerprint::ZERO | 
|  | } | 
|  |  | 
|  | /// Builds a new [ExpnHash] with the given [StableCrateId] and | 
|  | /// `local_hash`, where `local_hash` must be unique within its crate. | 
|  | fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash { | 
|  | ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash)) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A property of a macro expansion that determines how identifiers | 
|  | /// produced by that expansion are resolved. | 
|  | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)] | 
|  | #[derive(HashStable_Generic)] | 
|  | pub enum Transparency { | 
|  | /// Identifier produced by a transparent expansion is always resolved at call-site. | 
|  | /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. | 
|  | Transparent, | 
|  | /// Identifier produced by a semi-opaque expansion may be resolved | 
|  | /// either at call-site or at definition-site. | 
|  | /// If it's a local variable, label or `$crate` then it's resolved at def-site. | 
|  | /// Otherwise it's resolved at call-site. | 
|  | /// `macro_rules` macros behave like this, built-in macros currently behave like this too, | 
|  | /// but that's an implementation detail. | 
|  | SemiOpaque, | 
|  | /// Identifier produced by an opaque expansion is always resolved at definition-site. | 
|  | /// Def-site spans in procedural macros, identifiers from `macro` by default use this. | 
|  | Opaque, | 
|  | } | 
|  |  | 
|  | impl Transparency { | 
|  | pub fn fallback(macro_rules: bool) -> Self { | 
|  | if macro_rules { Transparency::SemiOpaque } else { Transparency::Opaque } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl LocalExpnId { | 
|  | /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. | 
|  | pub const ROOT: LocalExpnId = LocalExpnId::ZERO; | 
|  |  | 
|  | #[inline] | 
|  | fn from_raw(idx: ExpnIndex) -> LocalExpnId { | 
|  | LocalExpnId::from_u32(idx.as_u32()) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn as_raw(self) -> ExpnIndex { | 
|  | ExpnIndex::from_u32(self.as_u32()) | 
|  | } | 
|  |  | 
|  | pub fn fresh_empty() -> LocalExpnId { | 
|  | HygieneData::with(|data| { | 
|  | let expn_id = data.local_expn_data.push(None); | 
|  | let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO)); | 
|  | debug_assert_eq!(expn_id, _eid); | 
|  | expn_id | 
|  | }) | 
|  | } | 
|  |  | 
|  | pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId { | 
|  | debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); | 
|  | let expn_hash = update_disambiguator(&mut expn_data, ctx); | 
|  | HygieneData::with(|data| { | 
|  | let expn_id = data.local_expn_data.push(Some(expn_data)); | 
|  | let _eid = data.local_expn_hashes.push(expn_hash); | 
|  | debug_assert_eq!(expn_id, _eid); | 
|  | let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id()); | 
|  | debug_assert!(_old_id.is_none()); | 
|  | expn_id | 
|  | }) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn expn_data(self) -> ExpnData { | 
|  | HygieneData::with(|data| data.local_expn_data(self).clone()) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn to_expn_id(self) -> ExpnId { | 
|  | ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() } | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { | 
|  | debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE); | 
|  | let expn_hash = update_disambiguator(&mut expn_data, ctx); | 
|  | HygieneData::with(|data| { | 
|  | let old_expn_data = &mut data.local_expn_data[self]; | 
|  | assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); | 
|  | *old_expn_data = Some(expn_data); | 
|  | debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO); | 
|  | data.local_expn_hashes[self] = expn_hash; | 
|  | let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id()); | 
|  | debug_assert!(_old_id.is_none()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool { | 
|  | self.to_expn_id().is_descendant_of(ancestor.to_expn_id()) | 
|  | } | 
|  |  | 
|  | /// Returns span for the macro which originally caused this expansion to happen. | 
|  | /// | 
|  | /// Stops backtracing at include! boundary. | 
|  | #[inline] | 
|  | pub fn expansion_cause(self) -> Option<Span> { | 
|  | self.to_expn_id().expansion_cause() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl ExpnId { | 
|  | /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. | 
|  | /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0. | 
|  | pub const fn root() -> ExpnId { | 
|  | ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO } | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn expn_hash(self) -> ExpnHash { | 
|  | HygieneData::with(|data| data.expn_hash(self)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> { | 
|  | HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied()) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn as_local(self) -> Option<LocalExpnId> { | 
|  | if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None } | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | #[track_caller] | 
|  | pub fn expect_local(self) -> LocalExpnId { | 
|  | self.as_local().unwrap() | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn expn_data(self) -> ExpnData { | 
|  | HygieneData::with(|data| data.expn_data(self).clone()) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn is_descendant_of(self, ancestor: ExpnId) -> bool { | 
|  | // a few "fast path" cases to avoid locking HygieneData | 
|  | if ancestor == ExpnId::root() || ancestor == self { | 
|  | return true; | 
|  | } | 
|  | if ancestor.krate != self.krate { | 
|  | return false; | 
|  | } | 
|  | HygieneData::with(|data| data.is_descendant_of(self, ancestor)) | 
|  | } | 
|  |  | 
|  | /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than | 
|  | /// `expn_id.is_descendant_of(ctxt.outer_expn())`. | 
|  | pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { | 
|  | HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt))) | 
|  | } | 
|  |  | 
|  | /// Returns span for the macro which originally caused this expansion to happen. | 
|  | /// | 
|  | /// Stops backtracing at include! boundary. | 
|  | pub fn expansion_cause(mut self) -> Option<Span> { | 
|  | let mut last_macro = None; | 
|  | loop { | 
|  | // Fast path to avoid locking. | 
|  | if self == ExpnId::root() { | 
|  | break; | 
|  | } | 
|  | let expn_data = self.expn_data(); | 
|  | // Stop going up the backtrace once include! is encountered | 
|  | if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) { | 
|  | break; | 
|  | } | 
|  | self = expn_data.call_site.ctxt().outer_expn(); | 
|  | last_macro = Some(expn_data.call_site); | 
|  | } | 
|  | last_macro | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | pub(crate) struct HygieneData { | 
|  | /// Each expansion should have an associated expansion data, but sometimes there's a delay | 
|  | /// between creation of an expansion ID and obtaining its data (e.g. macros are collected | 
|  | /// first and then resolved later), so we use an `Option` here. | 
|  | local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>, | 
|  | local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>, | 
|  | /// Data and hash information from external crates. We may eventually want to remove these | 
|  | /// maps, and fetch the information directly from the other crate's metadata like DefIds do. | 
|  | foreign_expn_data: FxHashMap<ExpnId, ExpnData>, | 
|  | foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>, | 
|  | expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>, | 
|  | syntax_context_data: Vec<SyntaxContextData>, | 
|  | syntax_context_map: FxHashMap<SyntaxContextKey, SyntaxContext>, | 
|  | /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value. | 
|  | /// This is used by `update_disambiguator` to keep track of which `ExpnData`s | 
|  | /// would have collisions without a disambiguator. | 
|  | /// The keys of this map are always computed with `ExpnData.disambiguator` | 
|  | /// set to 0. | 
|  | expn_data_disambiguators: UnhashMap<Hash64, u32>, | 
|  | } | 
|  |  | 
|  | impl HygieneData { | 
|  | pub(crate) fn new(edition: Edition) -> Self { | 
|  | let root_data = ExpnData::default( | 
|  | ExpnKind::Root, | 
|  | DUMMY_SP, | 
|  | edition, | 
|  | Some(CRATE_DEF_ID.to_def_id()), | 
|  | None, | 
|  | ); | 
|  |  | 
|  | let root_ctxt_data = SyntaxContextData::root(); | 
|  | HygieneData { | 
|  | local_expn_data: IndexVec::from_elem_n(Some(root_data), 1), | 
|  | local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1), | 
|  | foreign_expn_data: FxHashMap::default(), | 
|  | foreign_expn_hashes: FxHashMap::default(), | 
|  | expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) | 
|  | .collect(), | 
|  | syntax_context_data: vec![root_ctxt_data], | 
|  | syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(), | 
|  | expn_data_disambiguators: UnhashMap::default(), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn with<R>(f: impl FnOnce(&mut HygieneData) -> R) -> R { | 
|  | with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut())) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash { | 
|  | match expn_id.as_local() { | 
|  | Some(expn_id) => self.local_expn_hashes[expn_id], | 
|  | None => self.foreign_expn_hashes[&expn_id], | 
|  | } | 
|  | } | 
|  |  | 
|  | fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData { | 
|  | self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") | 
|  | } | 
|  |  | 
|  | fn expn_data(&self, expn_id: ExpnId) -> &ExpnData { | 
|  | if let Some(expn_id) = expn_id.as_local() { | 
|  | self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID") | 
|  | } else { | 
|  | &self.foreign_expn_data[&expn_id] | 
|  | } | 
|  | } | 
|  |  | 
|  | fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool { | 
|  | // a couple "fast path" cases to avoid traversing parents in the loop below | 
|  | if ancestor == ExpnId::root() { | 
|  | return true; | 
|  | } | 
|  | if expn_id.krate != ancestor.krate { | 
|  | return false; | 
|  | } | 
|  | loop { | 
|  | if expn_id == ancestor { | 
|  | return true; | 
|  | } | 
|  | if expn_id == ExpnId::root() { | 
|  | return false; | 
|  | } | 
|  | expn_id = self.expn_data(expn_id).parent; | 
|  | } | 
|  | } | 
|  |  | 
|  | fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { | 
|  | self.syntax_context_data[ctxt.0 as usize].opaque | 
|  | } | 
|  |  | 
|  | fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { | 
|  | self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque | 
|  | } | 
|  |  | 
|  | fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { | 
|  | self.syntax_context_data[ctxt.0 as usize].outer_expn | 
|  | } | 
|  |  | 
|  | fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { | 
|  | let data = &self.syntax_context_data[ctxt.0 as usize]; | 
|  | (data.outer_expn, data.outer_transparency) | 
|  | } | 
|  |  | 
|  | fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { | 
|  | self.syntax_context_data[ctxt.0 as usize].parent | 
|  | } | 
|  |  | 
|  | fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { | 
|  | let outer_mark = self.outer_mark(*ctxt); | 
|  | *ctxt = self.parent_ctxt(*ctxt); | 
|  | outer_mark | 
|  | } | 
|  |  | 
|  | fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { | 
|  | let mut marks = Vec::new(); | 
|  | while !ctxt.is_root() { | 
|  | debug!("marks: getting parent of {:?}", ctxt); | 
|  | marks.push(self.outer_mark(ctxt)); | 
|  | ctxt = self.parent_ctxt(ctxt); | 
|  | } | 
|  | marks.reverse(); | 
|  | marks | 
|  | } | 
|  |  | 
|  | fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span { | 
|  | let orig_span = span; | 
|  | debug!("walk_chain({:?}, {:?})", span, to); | 
|  | debug!("walk_chain: span ctxt = {:?}", span.ctxt()); | 
|  | while span.ctxt() != to && span.from_expansion() { | 
|  | let outer_expn = self.outer_expn(span.ctxt()); | 
|  | debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn); | 
|  | let expn_data = self.expn_data(outer_expn); | 
|  | debug!("walk_chain({:?}): expn_data={:?}", span, expn_data); | 
|  | span = expn_data.call_site; | 
|  | } | 
|  | debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span); | 
|  | span | 
|  | } | 
|  |  | 
|  | fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span { | 
|  | let orig_span = span; | 
|  | let mut ret_span = span; | 
|  | debug!("walk_chain_collapsed({:?}, {:?})", span, to); | 
|  | debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt()); | 
|  | while let ctxt = span.ctxt() | 
|  | && !ctxt.is_root() | 
|  | && ctxt != to.ctxt() | 
|  | { | 
|  | let outer_expn = self.outer_expn(ctxt); | 
|  | debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn); | 
|  | let expn_data = self.expn_data(outer_expn); | 
|  | debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data); | 
|  | span = expn_data.call_site; | 
|  | if expn_data.collapse_debuginfo { | 
|  | ret_span = span; | 
|  | } | 
|  | } | 
|  | debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span); | 
|  | ret_span | 
|  | } | 
|  |  | 
|  | fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> { | 
|  | let mut scope = None; | 
|  | while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { | 
|  | scope = Some(self.remove_mark(ctxt).0); | 
|  | } | 
|  | scope | 
|  | } | 
|  |  | 
|  | fn apply_mark( | 
|  | &mut self, | 
|  | ctxt: SyntaxContext, | 
|  | expn_id: ExpnId, | 
|  | transparency: Transparency, | 
|  | ) -> SyntaxContext { | 
|  | assert_ne!(expn_id, ExpnId::root()); | 
|  | if transparency == Transparency::Opaque { | 
|  | return self.alloc_ctxt(ctxt, expn_id, transparency); | 
|  | } | 
|  |  | 
|  | let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); | 
|  | let mut call_site_ctxt = if transparency == Transparency::SemiOpaque { | 
|  | self.normalize_to_macros_2_0(call_site_ctxt) | 
|  | } else { | 
|  | self.normalize_to_macro_rules(call_site_ctxt) | 
|  | }; | 
|  |  | 
|  | if call_site_ctxt.is_root() { | 
|  | return self.alloc_ctxt(ctxt, expn_id, transparency); | 
|  | } | 
|  |  | 
|  | // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a | 
|  | // macros 2.0 expansion, i.e., a macros 1.0 invocation is in a macros 2.0 definition. | 
|  | // | 
|  | // In this case, the tokens from the macros 1.0 definition inherit the hygiene | 
|  | // at their invocation. That is, we pretend that the macros 1.0 definition | 
|  | // was defined at its invocation (i.e., inside the macros 2.0 definition) | 
|  | // so that the macros 2.0 definition remains hygienic. | 
|  | // | 
|  | // See the example at `test/ui/hygiene/legacy_interaction.rs`. | 
|  | for (expn_id, transparency) in self.marks(ctxt) { | 
|  | call_site_ctxt = self.alloc_ctxt(call_site_ctxt, expn_id, transparency); | 
|  | } | 
|  | self.alloc_ctxt(call_site_ctxt, expn_id, transparency) | 
|  | } | 
|  |  | 
|  | /// Allocate a new context with the given key, or retrieve it from cache if the given key | 
|  | /// already exists. The auxiliary fields are calculated from the key. | 
|  | fn alloc_ctxt( | 
|  | &mut self, | 
|  | parent: SyntaxContext, | 
|  | expn_id: ExpnId, | 
|  | transparency: Transparency, | 
|  | ) -> SyntaxContext { | 
|  | // Look into the cache first. | 
|  | let key = (parent, expn_id, transparency); | 
|  | if let Some(ctxt) = self.syntax_context_map.get(&key) { | 
|  | return *ctxt; | 
|  | } | 
|  |  | 
|  | // Reserve a new syntax context. | 
|  | // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls, | 
|  | // the assert below ensures that it doesn't happen. | 
|  | let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); | 
|  | self.syntax_context_data | 
|  | .push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() }); | 
|  | self.syntax_context_map.insert(key, ctxt); | 
|  |  | 
|  | // Opaque and semi-opaque versions of the parent. Note that they may be equal to the | 
|  | // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, | 
|  | // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques. | 
|  | let parent_data = &self.syntax_context_data[parent.0 as usize]; | 
|  | assert_ne!(parent_data.dollar_crate_name, sym::dummy); | 
|  | let parent_opaque = parent_data.opaque; | 
|  | let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque; | 
|  |  | 
|  | // Evaluate opaque and semi-opaque versions of the new syntax context. | 
|  | let (opaque, opaque_and_semiopaque) = match transparency { | 
|  | Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque), | 
|  | Transparency::SemiOpaque => ( | 
|  | parent_opaque, | 
|  | // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. | 
|  | self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), | 
|  | ), | 
|  | Transparency::Opaque => ( | 
|  | // Will be the same as `ctxt` if the expn chain contains only opaques. | 
|  | self.alloc_ctxt(parent_opaque, expn_id, transparency), | 
|  | // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques. | 
|  | self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency), | 
|  | ), | 
|  | }; | 
|  |  | 
|  | // Fill the full data, now that we have it. | 
|  | self.syntax_context_data[ctxt.as_u32() as usize] = SyntaxContextData { | 
|  | outer_expn: expn_id, | 
|  | outer_transparency: transparency, | 
|  | parent, | 
|  | opaque, | 
|  | opaque_and_semiopaque, | 
|  | dollar_crate_name: kw::DollarCrate, | 
|  | }; | 
|  | ctxt | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn walk_chain(span: Span, to: SyntaxContext) -> Span { | 
|  | HygieneData::with(|data| data.walk_chain(span, to)) | 
|  | } | 
|  |  | 
|  | /// In order to have good line stepping behavior in debugger, for the given span we return its | 
|  | /// outermost macro call site that still has a `#[collapse_debuginfo(yes)]` property on it. | 
|  | /// We also stop walking call sites at the function body level because no line stepping can occur | 
|  | /// at the level above that. | 
|  | /// The returned span can then be used in emitted debuginfo. | 
|  | pub fn walk_chain_collapsed(span: Span, to: Span) -> Span { | 
|  | HygieneData::with(|data| data.walk_chain_collapsed(span, to)) | 
|  | } | 
|  |  | 
|  | pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) { | 
|  | // The new contexts that need updating are at the end of the list and have `$crate` as a name. | 
|  | let mut to_update = vec![]; | 
|  | HygieneData::with(|data| { | 
|  | for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() { | 
|  | if scdata.dollar_crate_name == kw::DollarCrate { | 
|  | to_update.push((idx, kw::DollarCrate)); | 
|  | } else { | 
|  | break; | 
|  | } | 
|  | } | 
|  | }); | 
|  | // The callback must be called from outside of the `HygieneData` lock, | 
|  | // since it will try to acquire it too. | 
|  | for (idx, name) in &mut to_update { | 
|  | *name = get_name(SyntaxContext::from_usize(*idx)); | 
|  | } | 
|  | HygieneData::with(|data| { | 
|  | for (idx, name) in to_update { | 
|  | data.syntax_context_data[idx].dollar_crate_name = name; | 
|  | } | 
|  | }) | 
|  | } | 
|  |  | 
|  | pub fn debug_hygiene_data(verbose: bool) -> String { | 
|  | HygieneData::with(|data| { | 
|  | if verbose { | 
|  | format!("{data:#?}") | 
|  | } else { | 
|  | let mut s = String::from("Expansions:"); | 
|  | let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| { | 
|  | s.push_str(&format!( | 
|  | "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", | 
|  | id, | 
|  | expn_data.parent, | 
|  | expn_data.call_site.ctxt(), | 
|  | expn_data.def_site.ctxt(), | 
|  | expn_data.kind, | 
|  | )) | 
|  | }; | 
|  | data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| { | 
|  | let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); | 
|  | debug_expn_data((&id.to_expn_id(), expn_data)) | 
|  | }); | 
|  |  | 
|  | // Sort the hash map for more reproducible output. | 
|  | // Because of this, it is fine to rely on the unstable iteration order of the map. | 
|  | #[allow(rustc::potential_query_instability)] | 
|  | let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect(); | 
|  | foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id)); | 
|  | foreign_expn_data.into_iter().for_each(debug_expn_data); | 
|  | s.push_str("\n\nSyntaxContexts:"); | 
|  | data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { | 
|  | s.push_str(&format!( | 
|  | "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})", | 
|  | id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency, | 
|  | )); | 
|  | }); | 
|  | s | 
|  | } | 
|  | }) | 
|  | } | 
|  |  | 
|  | impl SyntaxContext { | 
|  | #[inline] | 
|  | pub const fn root() -> Self { | 
|  | SyntaxContext(0) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub const fn is_root(self) -> bool { | 
|  | self.0 == SyntaxContext::root().as_u32() | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub(crate) const fn as_u32(self) -> u32 { | 
|  | self.0 | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub(crate) const fn from_u32(raw: u32) -> SyntaxContext { | 
|  | SyntaxContext(raw) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub(crate) const fn from_u16(raw: u16) -> SyntaxContext { | 
|  | SyntaxContext(raw as u32) | 
|  | } | 
|  |  | 
|  | fn from_usize(raw: usize) -> SyntaxContext { | 
|  | SyntaxContext(u32::try_from(raw).unwrap()) | 
|  | } | 
|  |  | 
|  | /// Extend a syntax context with a given expansion and transparency. | 
|  | pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { | 
|  | HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) | 
|  | } | 
|  |  | 
|  | /// Pulls a single mark off of the syntax context. This effectively moves the | 
|  | /// context up one macro definition level. That is, if we have a nested macro | 
|  | /// definition as follows: | 
|  | /// | 
|  | /// ```ignore (illustrative) | 
|  | /// macro_rules! f { | 
|  | ///    macro_rules! g { | 
|  | ///        ... | 
|  | ///    } | 
|  | /// } | 
|  | /// ``` | 
|  | /// | 
|  | /// and we have a SyntaxContext that is referring to something declared by an invocation | 
|  | /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the | 
|  | /// invocation of f that created g1. | 
|  | /// Returns the mark that was removed. | 
|  | pub fn remove_mark(&mut self) -> ExpnId { | 
|  | HygieneData::with(|data| data.remove_mark(self).0) | 
|  | } | 
|  |  | 
|  | pub fn marks(self) -> Vec<(ExpnId, Transparency)> { | 
|  | HygieneData::with(|data| data.marks(self)) | 
|  | } | 
|  |  | 
|  | /// Adjust this context for resolution in a scope created by the given expansion. | 
|  | /// For example, consider the following three resolutions of `f`: | 
|  | /// | 
|  | /// ```rust | 
|  | /// #![feature(decl_macro)] | 
|  | /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty. | 
|  | /// m!(f); | 
|  | /// macro m($f:ident) { | 
|  | ///     mod bar { | 
|  | ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`. | 
|  | ///         pub fn $f() {} // `$f`'s `SyntaxContext` is empty. | 
|  | ///     } | 
|  | ///     foo::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m` | 
|  | ///     //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`, | 
|  | ///     //| and it resolves to `::foo::f`. | 
|  | ///     bar::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m` | 
|  | ///     //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`, | 
|  | ///     //| and it resolves to `::bar::f`. | 
|  | ///     bar::$f(); // `f`'s `SyntaxContext` is empty. | 
|  | ///     //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`, | 
|  | ///     //| and it resolves to `::bar::$f`. | 
|  | /// } | 
|  | /// ``` | 
|  | /// This returns the expansion whose definition scope we use to privacy check the resolution, | 
|  | /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope). | 
|  | pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { | 
|  | HygieneData::with(|data| data.adjust(self, expn_id)) | 
|  | } | 
|  |  | 
|  | /// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0. | 
|  | pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> { | 
|  | HygieneData::with(|data| { | 
|  | *self = data.normalize_to_macros_2_0(*self); | 
|  | data.adjust(self, expn_id) | 
|  | }) | 
|  | } | 
|  |  | 
|  | /// Adjust this context for resolution in a scope created by the given expansion | 
|  | /// via a glob import with the given `SyntaxContext`. | 
|  | /// For example: | 
|  | /// | 
|  | /// ```compile_fail,E0425 | 
|  | /// #![feature(decl_macro)] | 
|  | /// m!(f); | 
|  | /// macro m($i:ident) { | 
|  | ///     mod foo { | 
|  | ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`. | 
|  | ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty. | 
|  | ///     } | 
|  | ///     n!(f); | 
|  | ///     macro n($j:ident) { | 
|  | ///         use foo::*; | 
|  | ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n` | 
|  | ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`. | 
|  | ///         $i(); // `$i`'s `SyntaxContext` has a mark from `n` | 
|  | ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`. | 
|  | ///         $j(); // `$j`'s `SyntaxContext` has a mark from `m` | 
|  | ///         //^ This cannot be glob-adjusted, so this is a resolution error. | 
|  | ///     } | 
|  | /// } | 
|  | /// ``` | 
|  | /// This returns `None` if the context cannot be glob-adjusted. | 
|  | /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details). | 
|  | pub(crate) fn glob_adjust( | 
|  | &mut self, | 
|  | expn_id: ExpnId, | 
|  | glob_span: Span, | 
|  | ) -> Option<Option<ExpnId>> { | 
|  | HygieneData::with(|data| { | 
|  | let mut scope = None; | 
|  | let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt()); | 
|  | while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) { | 
|  | scope = Some(data.remove_mark(&mut glob_ctxt).0); | 
|  | if data.remove_mark(self).0 != scope.unwrap() { | 
|  | return None; | 
|  | } | 
|  | } | 
|  | if data.adjust(self, expn_id).is_some() { | 
|  | return None; | 
|  | } | 
|  | Some(scope) | 
|  | }) | 
|  | } | 
|  |  | 
|  | /// Undo `glob_adjust` if possible: | 
|  | /// | 
|  | /// ```ignore (illustrative) | 
|  | /// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) { | 
|  | ///     assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope)); | 
|  | /// } | 
|  | /// ``` | 
|  | pub(crate) fn reverse_glob_adjust( | 
|  | &mut self, | 
|  | expn_id: ExpnId, | 
|  | glob_span: Span, | 
|  | ) -> Option<Option<ExpnId>> { | 
|  | HygieneData::with(|data| { | 
|  | if data.adjust(self, expn_id).is_some() { | 
|  | return None; | 
|  | } | 
|  |  | 
|  | let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt()); | 
|  | let mut marks = Vec::new(); | 
|  | while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) { | 
|  | marks.push(data.remove_mark(&mut glob_ctxt)); | 
|  | } | 
|  |  | 
|  | let scope = marks.last().map(|mark| mark.0); | 
|  | while let Some((expn_id, transparency)) = marks.pop() { | 
|  | *self = data.apply_mark(*self, expn_id, transparency); | 
|  | } | 
|  | Some(scope) | 
|  | }) | 
|  | } | 
|  |  | 
|  | pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool { | 
|  | HygieneData::with(|data| { | 
|  | let mut self_normalized = data.normalize_to_macros_2_0(self); | 
|  | data.adjust(&mut self_normalized, expn_id); | 
|  | self_normalized == data.normalize_to_macros_2_0(other) | 
|  | }) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn normalize_to_macros_2_0(self) -> SyntaxContext { | 
|  | HygieneData::with(|data| data.normalize_to_macros_2_0(self)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn normalize_to_macro_rules(self) -> SyntaxContext { | 
|  | HygieneData::with(|data| data.normalize_to_macro_rules(self)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn outer_expn(self) -> ExpnId { | 
|  | HygieneData::with(|data| data.outer_expn(self)) | 
|  | } | 
|  |  | 
|  | /// `ctxt.outer_expn_data()` is equivalent to but faster than | 
|  | /// `ctxt.outer_expn().expn_data()`. | 
|  | #[inline] | 
|  | pub fn outer_expn_data(self) -> ExpnData { | 
|  | HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone()) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn outer_mark(self) -> (ExpnId, Transparency) { | 
|  | HygieneData::with(|data| data.outer_mark(self)) | 
|  | } | 
|  |  | 
|  | pub(crate) fn dollar_crate_name(self) -> Symbol { | 
|  | HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) | 
|  | } | 
|  |  | 
|  | pub fn edition(self) -> Edition { | 
|  | HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition) | 
|  | } | 
|  |  | 
|  | /// Returns whether this context originates in a foreign crate's external macro. | 
|  | /// | 
|  | /// This is used to test whether a lint should not even begin to figure out whether it should | 
|  | /// be reported on the current node. | 
|  | pub fn in_external_macro(self, sm: &SourceMap) -> bool { | 
|  | let expn_data = self.outer_expn_data(); | 
|  | match expn_data.kind { | 
|  | ExpnKind::Root | 
|  | | ExpnKind::Desugaring( | 
|  | DesugaringKind::ForLoop | 
|  | | DesugaringKind::WhileLoop | 
|  | | DesugaringKind::OpaqueTy | 
|  | | DesugaringKind::Async | 
|  | | DesugaringKind::Await, | 
|  | ) => false, | 
|  | ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" | 
|  | ExpnKind::Macro(MacroKind::Bang, _) => { | 
|  | // Dummy span for the `def_site` means it's an external macro. | 
|  | expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) | 
|  | } | 
|  | ExpnKind::Macro { .. } => true, // definitely a plugin | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl fmt::Debug for SyntaxContext { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "#{}", self.0) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Span { | 
|  | /// Reuses the span but adds information like the kind of the desugaring and features that are | 
|  | /// allowed inside this span. | 
|  | pub fn mark_with_reason( | 
|  | self, | 
|  | allow_internal_unstable: Option<Arc<[Symbol]>>, | 
|  | reason: DesugaringKind, | 
|  | edition: Edition, | 
|  | ctx: impl HashStableContext, | 
|  | ) -> Span { | 
|  | let expn_data = ExpnData { | 
|  | allow_internal_unstable, | 
|  | ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None) | 
|  | }; | 
|  | let expn_id = LocalExpnId::fresh(expn_data, ctx); | 
|  | self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A subset of properties from both macro definition and macro call available through global data. | 
|  | /// Avoid using this if you have access to the original definition or call structures. | 
|  | #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] | 
|  | pub struct ExpnData { | 
|  | // --- The part unique to each expansion. | 
|  | /// The kind of this expansion - macro or compiler desugaring. | 
|  | pub kind: ExpnKind, | 
|  | /// The expansion that produced this expansion. | 
|  | pub parent: ExpnId, | 
|  | /// The location of the actual macro invocation or syntax sugar , e.g. | 
|  | /// `let x = foo!();` or `if let Some(y) = x {}` | 
|  | /// | 
|  | /// This may recursively refer to other macro invocations, e.g., if | 
|  | /// `foo!()` invoked `bar!()` internally, and there was an | 
|  | /// expression inside `bar!`; the call_site of the expression in | 
|  | /// the expansion would point to the `bar!` invocation; that | 
|  | /// call_site span would have its own ExpnData, with the call_site | 
|  | /// pointing to the `foo!` invocation. | 
|  | pub call_site: Span, | 
|  | /// Used to force two `ExpnData`s to have different `Fingerprint`s. | 
|  | /// Due to macro expansion, it's possible to end up with two `ExpnId`s | 
|  | /// that have identical `ExpnData`s. This violates the contract of `HashStable` | 
|  | /// - the two `ExpnId`s are not equal, but their `Fingerprint`s are equal | 
|  | /// (since the numerical `ExpnId` value is not considered by the `HashStable` | 
|  | /// implementation). | 
|  | /// | 
|  | /// The `disambiguator` field is set by `update_disambiguator` when two distinct | 
|  | /// `ExpnId`s would end up with the same `Fingerprint`. Since `ExpnData` includes | 
|  | /// a `krate` field, this value only needs to be unique within a single crate. | 
|  | disambiguator: u32, | 
|  |  | 
|  | // --- The part specific to the macro/desugaring definition. | 
|  | // --- It may be reasonable to share this part between expansions with the same definition, | 
|  | // --- but such sharing is known to bring some minor inconveniences without also bringing | 
|  | // --- noticeable perf improvements (PR #62898). | 
|  | /// The span of the macro definition (possibly dummy). | 
|  | /// This span serves only informational purpose and is not used for resolution. | 
|  | pub def_site: Span, | 
|  | /// List of `#[unstable]`/feature-gated features that the macro is allowed to use | 
|  | /// internally without forcing the whole crate to opt-in | 
|  | /// to them. | 
|  | pub allow_internal_unstable: Option<Arc<[Symbol]>>, | 
|  | /// Edition of the crate in which the macro is defined. | 
|  | pub edition: Edition, | 
|  | /// The `DefId` of the macro being invoked, | 
|  | /// if this `ExpnData` corresponds to a macro invocation | 
|  | pub macro_def_id: Option<DefId>, | 
|  | /// The normal module (`mod`) in which the expanded macro was defined. | 
|  | pub parent_module: Option<DefId>, | 
|  | /// Suppresses the `unsafe_code` lint for code produced by this macro. | 
|  | pub(crate) allow_internal_unsafe: bool, | 
|  | /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. | 
|  | pub local_inner_macros: bool, | 
|  | /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other | 
|  | /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? | 
|  | pub(crate) collapse_debuginfo: bool, | 
|  | /// When true, we do not display the note telling people to use the `-Zmacro-backtrace` flag. | 
|  | pub hide_backtrace: bool, | 
|  | } | 
|  |  | 
|  | impl !PartialEq for ExpnData {} | 
|  | impl !Hash for ExpnData {} | 
|  |  | 
|  | impl ExpnData { | 
|  | pub fn new( | 
|  | kind: ExpnKind, | 
|  | parent: ExpnId, | 
|  | call_site: Span, | 
|  | def_site: Span, | 
|  | allow_internal_unstable: Option<Arc<[Symbol]>>, | 
|  | edition: Edition, | 
|  | macro_def_id: Option<DefId>, | 
|  | parent_module: Option<DefId>, | 
|  | allow_internal_unsafe: bool, | 
|  | local_inner_macros: bool, | 
|  | collapse_debuginfo: bool, | 
|  | hide_backtrace: bool, | 
|  | ) -> ExpnData { | 
|  | ExpnData { | 
|  | kind, | 
|  | parent, | 
|  | call_site, | 
|  | def_site, | 
|  | allow_internal_unstable, | 
|  | edition, | 
|  | macro_def_id, | 
|  | parent_module, | 
|  | disambiguator: 0, | 
|  | allow_internal_unsafe, | 
|  | local_inner_macros, | 
|  | collapse_debuginfo, | 
|  | hide_backtrace, | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Constructs expansion data with default properties. | 
|  | pub fn default( | 
|  | kind: ExpnKind, | 
|  | call_site: Span, | 
|  | edition: Edition, | 
|  | macro_def_id: Option<DefId>, | 
|  | parent_module: Option<DefId>, | 
|  | ) -> ExpnData { | 
|  | ExpnData { | 
|  | kind, | 
|  | parent: ExpnId::root(), | 
|  | call_site, | 
|  | def_site: DUMMY_SP, | 
|  | allow_internal_unstable: None, | 
|  | edition, | 
|  | macro_def_id, | 
|  | parent_module, | 
|  | disambiguator: 0, | 
|  | allow_internal_unsafe: false, | 
|  | local_inner_macros: false, | 
|  | collapse_debuginfo: false, | 
|  | hide_backtrace: false, | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn allow_unstable( | 
|  | kind: ExpnKind, | 
|  | call_site: Span, | 
|  | edition: Edition, | 
|  | allow_internal_unstable: Arc<[Symbol]>, | 
|  | macro_def_id: Option<DefId>, | 
|  | parent_module: Option<DefId>, | 
|  | ) -> ExpnData { | 
|  | ExpnData { | 
|  | allow_internal_unstable: Some(allow_internal_unstable), | 
|  | ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub fn is_root(&self) -> bool { | 
|  | matches!(self.kind, ExpnKind::Root) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 { | 
|  | let mut hasher = StableHasher::new(); | 
|  | self.hash_stable(ctx, &mut hasher); | 
|  | hasher.finish() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Expansion kind. | 
|  | #[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] | 
|  | pub enum ExpnKind { | 
|  | /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind. | 
|  | Root, | 
|  | /// Expansion produced by a macro. | 
|  | Macro(MacroKind, Symbol), | 
|  | /// Transform done by the compiler on the AST. | 
|  | AstPass(AstPass), | 
|  | /// Desugaring done by the compiler during AST lowering. | 
|  | Desugaring(DesugaringKind), | 
|  | } | 
|  |  | 
|  | impl ExpnKind { | 
|  | pub fn descr(&self) -> String { | 
|  | match *self { | 
|  | ExpnKind::Root => kw::PathRoot.to_string(), | 
|  | ExpnKind::Macro(macro_kind, name) => match macro_kind { | 
|  | MacroKind::Bang => format!("{name}!"), | 
|  | MacroKind::Attr => format!("#[{name}]"), | 
|  | MacroKind::Derive => format!("#[derive({name})]"), | 
|  | }, | 
|  | ExpnKind::AstPass(kind) => kind.descr().to_string(), | 
|  | ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The kind of macro invocation or definition. | 
|  | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)] | 
|  | #[derive(HashStable_Generic)] | 
|  | pub enum MacroKind { | 
|  | /// A bang macro `foo!()`. | 
|  | Bang, | 
|  | /// An attribute macro `#[foo]`. | 
|  | Attr, | 
|  | /// A derive macro `#[derive(Foo)]` | 
|  | Derive, | 
|  | } | 
|  |  | 
|  | impl MacroKind { | 
|  | pub fn descr(self) -> &'static str { | 
|  | match self { | 
|  | MacroKind::Bang => "macro", | 
|  | MacroKind::Attr => "attribute macro", | 
|  | MacroKind::Derive => "derive macro", | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn descr_expected(self) -> &'static str { | 
|  | match self { | 
|  | MacroKind::Attr => "attribute", | 
|  | _ => self.descr(), | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn article(self) -> &'static str { | 
|  | match self { | 
|  | MacroKind::Attr => "an", | 
|  | _ => "a", | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The kind of AST transform. | 
|  | #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] | 
|  | pub enum AstPass { | 
|  | StdImports, | 
|  | TestHarness, | 
|  | ProcMacroHarness, | 
|  | } | 
|  |  | 
|  | impl AstPass { | 
|  | pub fn descr(self) -> &'static str { | 
|  | match self { | 
|  | AstPass::StdImports => "standard library imports", | 
|  | AstPass::TestHarness => "test harness", | 
|  | AstPass::ProcMacroHarness => "proc macro harness", | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The kind of compiler desugaring. | 
|  | #[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] | 
|  | pub enum DesugaringKind { | 
|  | QuestionMark, | 
|  | TryBlock, | 
|  | YeetExpr, | 
|  | /// Desugaring of an `impl Trait` in return type position | 
|  | /// to an `type Foo = impl Trait;` and replacing the | 
|  | /// `impl Trait` with `Foo`. | 
|  | OpaqueTy, | 
|  | Async, | 
|  | Await, | 
|  | ForLoop, | 
|  | WhileLoop, | 
|  | /// `async Fn()` bound modifier | 
|  | BoundModifier, | 
|  | /// Calls to contract checks (`#[requires]` to precond, `#[ensures]` to postcond) | 
|  | Contract, | 
|  | /// A pattern type range start/end | 
|  | PatTyRange, | 
|  | /// A format literal. | 
|  | FormatLiteral { | 
|  | /// Was this format literal written in the source? | 
|  | /// - `format!("boo")` => Yes, | 
|  | /// - `format!(concat!("b", "o", "o"))` => No, | 
|  | /// - `format!(include_str!("boo.txt"))` => No, | 
|  | /// | 
|  | /// If it wasn't written in the source then we have to be careful with suggestions about | 
|  | /// rewriting it. | 
|  | source: bool, | 
|  | }, | 
|  | } | 
|  |  | 
|  | impl DesugaringKind { | 
|  | /// The description wording should combine well with "desugaring of {}". | 
|  | pub fn descr(self) -> &'static str { | 
|  | match self { | 
|  | DesugaringKind::Async => "`async` block or function", | 
|  | DesugaringKind::Await => "`await` expression", | 
|  | DesugaringKind::QuestionMark => "operator `?`", | 
|  | DesugaringKind::TryBlock => "`try` block", | 
|  | DesugaringKind::YeetExpr => "`do yeet` expression", | 
|  | DesugaringKind::OpaqueTy => "`impl Trait`", | 
|  | DesugaringKind::ForLoop => "`for` loop", | 
|  | DesugaringKind::WhileLoop => "`while` loop", | 
|  | DesugaringKind::BoundModifier => "trait bound modifier", | 
|  | DesugaringKind::Contract => "contract check", | 
|  | DesugaringKind::PatTyRange => "pattern type", | 
|  | DesugaringKind::FormatLiteral { source: true } => "format string literal", | 
|  | DesugaringKind::FormatLiteral { source: false } => { | 
|  | "expression that expanded into a format string literal" | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// For use with `rustc_unimplemented` to support conditions | 
|  | /// like `from_desugaring = "QuestionMark"` | 
|  | pub fn matches(&self, value: &str) -> bool { | 
|  | match self { | 
|  | DesugaringKind::Async => value == "Async", | 
|  | DesugaringKind::Await => value == "Await", | 
|  | DesugaringKind::QuestionMark => value == "QuestionMark", | 
|  | DesugaringKind::TryBlock => value == "TryBlock", | 
|  | DesugaringKind::YeetExpr => value == "YeetExpr", | 
|  | DesugaringKind::OpaqueTy => value == "OpaqueTy", | 
|  | DesugaringKind::ForLoop => value == "ForLoop", | 
|  | DesugaringKind::WhileLoop => value == "WhileLoop", | 
|  | DesugaringKind::BoundModifier => value == "BoundModifier", | 
|  | DesugaringKind::Contract => value == "Contract", | 
|  | DesugaringKind::PatTyRange => value == "PatTyRange", | 
|  | DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral", | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Default)] | 
|  | pub struct HygieneEncodeContext { | 
|  | /// All `SyntaxContexts` for which we have written `SyntaxContextData` into crate metadata. | 
|  | /// This is `None` after we finish encoding `SyntaxContexts`, to ensure | 
|  | /// that we don't accidentally try to encode any more `SyntaxContexts` | 
|  | serialized_ctxts: Lock<FxHashSet<SyntaxContext>>, | 
|  | /// The `SyntaxContexts` that we have serialized (e.g. as a result of encoding `Spans`) | 
|  | /// in the most recent 'round' of serializing. Serializing `SyntaxContextData` | 
|  | /// may cause us to serialize more `SyntaxContext`s, so serialize in a loop | 
|  | /// until we reach a fixed point. | 
|  | latest_ctxts: Lock<FxHashSet<SyntaxContext>>, | 
|  |  | 
|  | serialized_expns: Lock<FxHashSet<ExpnId>>, | 
|  |  | 
|  | latest_expns: Lock<FxHashSet<ExpnId>>, | 
|  | } | 
|  |  | 
|  | impl HygieneEncodeContext { | 
|  | /// Record the fact that we need to serialize the corresponding `ExpnData`. | 
|  | pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) { | 
|  | if !self.serialized_expns.lock().contains(&expn) { | 
|  | self.latest_expns.lock().insert(expn); | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn encode<T>( | 
|  | &self, | 
|  | encoder: &mut T, | 
|  | mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), | 
|  | mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), | 
|  | ) { | 
|  | // When we serialize a `SyntaxContextData`, we may end up serializing | 
|  | // a `SyntaxContext` that we haven't seen before | 
|  | while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() { | 
|  | debug!( | 
|  | "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}", | 
|  | self.latest_ctxts.lock().len(), | 
|  | self.latest_ctxts | 
|  | ); | 
|  |  | 
|  | // Consume the current round of syntax contexts. | 
|  | // Drop the lock() temporary early. | 
|  | // It's fine to iterate over a HashMap, because the serialization of the table | 
|  | // that we insert data into doesn't depend on insertion order. | 
|  | #[allow(rustc::potential_query_instability)] | 
|  | let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter(); | 
|  | let all_ctxt_data: Vec<_> = HygieneData::with(|data| { | 
|  | latest_ctxts | 
|  | .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key())) | 
|  | .collect() | 
|  | }); | 
|  | for (ctxt, ctxt_key) in all_ctxt_data { | 
|  | if self.serialized_ctxts.lock().insert(ctxt) { | 
|  | encode_ctxt(encoder, ctxt.0, &ctxt_key); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Same as above, but for expansions instead of syntax contexts. | 
|  | #[allow(rustc::potential_query_instability)] | 
|  | let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter(); | 
|  | let all_expn_data: Vec<_> = HygieneData::with(|data| { | 
|  | latest_expns | 
|  | .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))) | 
|  | .collect() | 
|  | }); | 
|  | for (expn, expn_data, expn_hash) in all_expn_data { | 
|  | if self.serialized_expns.lock().insert(expn) { | 
|  | encode_expn(encoder, expn, &expn_data, expn_hash); | 
|  | } | 
|  | } | 
|  | } | 
|  | debug!("encode_hygiene: Done serializing SyntaxContextData"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Additional information used to assist in decoding hygiene data | 
|  | #[derive(Default)] | 
|  | pub struct HygieneDecodeContext { | 
|  | // A cache mapping raw serialized per-crate syntax context ids to corresponding decoded | 
|  | // `SyntaxContext`s in the current global `HygieneData`. | 
|  | remapped_ctxts: Lock<IndexVec<u32, Option<SyntaxContext>>>, | 
|  | } | 
|  |  | 
|  | /// Register an expansion which has been decoded from the on-disk-cache for the local crate. | 
|  | pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId { | 
|  | HygieneData::with(|hygiene_data| { | 
|  | let expn_id = hygiene_data.local_expn_data.next_index(); | 
|  | hygiene_data.local_expn_data.push(Some(data)); | 
|  | let _eid = hygiene_data.local_expn_hashes.push(hash); | 
|  | debug_assert_eq!(expn_id, _eid); | 
|  |  | 
|  | let expn_id = expn_id.to_expn_id(); | 
|  |  | 
|  | let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); | 
|  | debug_assert!(_old_id.is_none()); | 
|  | expn_id | 
|  | }) | 
|  | } | 
|  |  | 
|  | /// Register an expansion which has been decoded from the metadata of a foreign crate. | 
|  | pub fn register_expn_id( | 
|  | krate: CrateNum, | 
|  | local_id: ExpnIndex, | 
|  | data: ExpnData, | 
|  | hash: ExpnHash, | 
|  | ) -> ExpnId { | 
|  | debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate); | 
|  | let expn_id = ExpnId { krate, local_id }; | 
|  | HygieneData::with(|hygiene_data| { | 
|  | let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data); | 
|  | let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash); | 
|  | debug_assert!(_old_hash.is_none() || _old_hash == Some(hash)); | 
|  | let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); | 
|  | debug_assert!(_old_id.is_none() || _old_id == Some(expn_id)); | 
|  | }); | 
|  | expn_id | 
|  | } | 
|  |  | 
|  | /// Decode an expansion from the metadata of a foreign crate. | 
|  | pub fn decode_expn_id( | 
|  | krate: CrateNum, | 
|  | index: u32, | 
|  | decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash), | 
|  | ) -> ExpnId { | 
|  | if index == 0 { | 
|  | trace!("decode_expn_id: deserialized root"); | 
|  | return ExpnId::root(); | 
|  | } | 
|  |  | 
|  | let index = ExpnIndex::from_u32(index); | 
|  |  | 
|  | // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE. | 
|  | debug_assert_ne!(krate, LOCAL_CRATE); | 
|  | let expn_id = ExpnId { krate, local_id: index }; | 
|  |  | 
|  | // Fast path if the expansion has already been decoded. | 
|  | if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) { | 
|  | return expn_id; | 
|  | } | 
|  |  | 
|  | // Don't decode the data inside `HygieneData::with`, since we need to recursively decode | 
|  | // other ExpnIds | 
|  | let (expn_data, hash) = decode_data(expn_id); | 
|  |  | 
|  | register_expn_id(krate, index, expn_data, hash) | 
|  | } | 
|  |  | 
|  | // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` | 
|  | // to track which `SyntaxContext`s we have already decoded. | 
|  | // The provided closure will be invoked to deserialize a `SyntaxContextData` | 
|  | // if we haven't already seen the id of the `SyntaxContext` we are deserializing. | 
|  | pub fn decode_syntax_context<D: Decoder>( | 
|  | d: &mut D, | 
|  | context: &HygieneDecodeContext, | 
|  | decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey, | 
|  | ) -> SyntaxContext { | 
|  | let raw_id: u32 = Decodable::decode(d); | 
|  | if raw_id == 0 { | 
|  | trace!("decode_syntax_context: deserialized root"); | 
|  | // The root is special | 
|  | return SyntaxContext::root(); | 
|  | } | 
|  |  | 
|  | // Look into the cache first. | 
|  | // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between | 
|  | // raw ids from different crate metadatas. | 
|  | if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) { | 
|  | return *ctxt; | 
|  | } | 
|  |  | 
|  | // Don't try to decode data while holding the lock, since we need to | 
|  | // be able to recursively decode a SyntaxContext | 
|  | let (parent, expn_id, transparency) = decode_data(d, raw_id); | 
|  | let ctxt = | 
|  | HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency)); | 
|  |  | 
|  | context.remapped_ctxts.lock().insert(raw_id, ctxt); | 
|  |  | 
|  | ctxt | 
|  | } | 
|  |  | 
|  | impl<E: SpanEncoder> Encodable<E> for LocalExpnId { | 
|  | fn encode(&self, e: &mut E) { | 
|  | self.to_expn_id().encode(e); | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<D: SpanDecoder> Decodable<D> for LocalExpnId { | 
|  | fn decode(d: &mut D) -> Self { | 
|  | ExpnId::expect_local(ExpnId::decode(d)) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn raw_encode_syntax_context( | 
|  | ctxt: SyntaxContext, | 
|  | context: &HygieneEncodeContext, | 
|  | e: &mut impl Encoder, | 
|  | ) { | 
|  | if !context.serialized_ctxts.lock().contains(&ctxt) { | 
|  | context.latest_ctxts.lock().insert(ctxt); | 
|  | } | 
|  | ctxt.0.encode(e); | 
|  | } | 
|  |  | 
|  | /// Updates the `disambiguator` field of the corresponding `ExpnData` | 
|  | /// such that the `Fingerprint` of the `ExpnData` does not collide with | 
|  | /// any other `ExpnIds`. | 
|  | /// | 
|  | /// This method is called only when an `ExpnData` is first associated | 
|  | /// with an `ExpnId` (when the `ExpnId` is initially constructed, or via | 
|  | /// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized | 
|  | /// from another crate's metadata - since `ExpnHash` includes the stable crate id, | 
|  | /// collisions are only possible between `ExpnId`s within the same crate. | 
|  | fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash { | 
|  | // This disambiguator should not have been set yet. | 
|  | assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}"); | 
|  | assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)"); | 
|  | let mut expn_hash = expn_data.hash_expn(&mut ctx); | 
|  |  | 
|  | let disambiguator = HygieneData::with(|data| { | 
|  | // If this is the first ExpnData with a given hash, then keep our | 
|  | // disambiguator at 0 (the default u32 value) | 
|  | let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default(); | 
|  | let disambiguator = *disambig; | 
|  | *disambig += 1; | 
|  | disambiguator | 
|  | }); | 
|  |  | 
|  | if disambiguator != 0 { | 
|  | debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash); | 
|  |  | 
|  | expn_data.disambiguator = disambiguator; | 
|  | expn_hash = expn_data.hash_expn(&mut ctx); | 
|  |  | 
|  | // Verify that the new disambiguator makes the hash unique | 
|  | #[cfg(debug_assertions)] | 
|  | HygieneData::with(|data| { | 
|  | assert_eq!( | 
|  | data.expn_data_disambiguators.get(&expn_hash), | 
|  | None, | 
|  | "Hash collision after disambiguator update!", | 
|  | ); | 
|  | }); | 
|  | } | 
|  |  | 
|  | ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash) | 
|  | } | 
|  |  | 
|  | impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext { | 
|  | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | 
|  | const TAG_EXPANSION: u8 = 0; | 
|  | const TAG_NO_EXPANSION: u8 = 1; | 
|  |  | 
|  | if self.is_root() { | 
|  | TAG_NO_EXPANSION.hash_stable(ctx, hasher); | 
|  | } else { | 
|  | TAG_EXPANSION.hash_stable(ctx, hasher); | 
|  | let (expn_id, transparency) = self.outer_mark(); | 
|  | expn_id.hash_stable(ctx, hasher); | 
|  | transparency.hash_stable(ctx, hasher); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<CTX: HashStableContext> HashStable<CTX> for ExpnId { | 
|  | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | 
|  | assert_default_hashing_controls(ctx, "ExpnId"); | 
|  | let hash = if *self == ExpnId::root() { | 
|  | // Avoid fetching TLS storage for a trivial often-used value. | 
|  | Fingerprint::ZERO | 
|  | } else { | 
|  | self.expn_hash().0 | 
|  | }; | 
|  |  | 
|  | hash.hash_stable(ctx, hasher); | 
|  | } | 
|  | } |