rustc_span/
hygiene.rs

1//! Machinery for hygienic macros.
2//!
3//! Inspired by Matthew Flatt et al., “Macros That Work Together: Compile-Time Bindings, Partial
4//! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
5//! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
6
7// Hygiene data is stored in a global variable and accessed via TLS, which
8// means that accesses are somewhat expensive. (`HygieneData::with`
9// encapsulates a single access.) Therefore, on hot code paths it is worth
10// ensuring that multiple HygieneData accesses are combined into a single
11// `HygieneData::with`.
12//
13// This explains why `HygieneData`, `SyntaxContext` and `ExpnId` have interfaces
14// with a certain amount of redundancy in them. For example,
15// `SyntaxContext::outer_expn_data` combines `SyntaxContext::outer` and
16// `ExpnId::expn_data` so that two `HygieneData` accesses can be performed within
17// a single `HygieneData::with` call.
18//
19// It also explains why many functions appear in `HygieneData` and again in
20// `SyntaxContext` or `ExpnId`. For example, `HygieneData::outer` and
21// `SyntaxContext::outer` do the same thing, but the former is for use within a
22// `HygieneData::with` call while the latter is for use outside such a call.
23// When modifying this file it is important to understand this distinction,
24// because getting it wrong can lead to nested `HygieneData::with` calls that
25// trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
26
27use std::cell::RefCell;
28use std::collections::hash_map::Entry;
29use std::collections::hash_set::Entry as SetEntry;
30use std::fmt;
31use std::hash::Hash;
32use std::sync::Arc;
33
34use rustc_data_structures::fingerprint::Fingerprint;
35use rustc_data_structures::fx::{FxHashMap, FxHashSet};
36use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher};
37use rustc_data_structures::sync::{Lock, WorkerLocal};
38use rustc_data_structures::unhash::UnhashMap;
39use rustc_index::IndexVec;
40use rustc_macros::{Decodable, Encodable, HashStable_Generic};
41use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
42use tracing::{debug, trace};
43
44use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId};
45use crate::edition::Edition;
46use crate::symbol::{Symbol, kw, sym};
47use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
48
49/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
50#[derive(Clone, Copy, PartialEq, Eq, Hash)]
51pub struct SyntaxContext(u32);
52
53// To ensure correctness of incremental compilation,
54// `SyntaxContext` must not implement `Ord` or `PartialOrd`.
55// See https://github.com/rust-lang/rust/issues/90317.
56impl !Ord for SyntaxContext {}
57impl !PartialOrd for SyntaxContext {}
58
59#[derive(Debug, Encodable, Decodable, Clone)]
60pub struct SyntaxContextData {
61    outer_expn: ExpnId,
62    outer_transparency: Transparency,
63    parent: SyntaxContext,
64    /// This context, but with all transparent and semi-transparent expansions filtered away.
65    opaque: SyntaxContext,
66    /// This context, but with all transparent expansions filtered away.
67    opaque_and_semitransparent: SyntaxContext,
68    /// Name of the crate to which `$crate` with this context would resolve.
69    dollar_crate_name: Symbol,
70}
71
72rustc_index::newtype_index! {
73    /// A unique ID associated with a macro invocation and expansion.
74    #[orderable]
75    pub struct ExpnIndex {}
76}
77
78/// A unique ID associated with a macro invocation and expansion.
79#[derive(Clone, Copy, PartialEq, Eq, Hash)]
80pub struct ExpnId {
81    pub krate: CrateNum,
82    pub local_id: ExpnIndex,
83}
84
85impl fmt::Debug for ExpnId {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        // Generate crate_::{{expn_}}.
88        write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
89    }
90}
91
92rustc_index::newtype_index! {
93    /// A unique ID associated with a macro invocation and expansion.
94    #[debug_format = "expn{}"]
95    pub struct LocalExpnId {}
96}
97
98// To ensure correctness of incremental compilation,
99// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
100// See https://github.com/rust-lang/rust/issues/90317.
101impl !Ord for LocalExpnId {}
102impl !PartialOrd for LocalExpnId {}
103
104/// Assert that the provided `HashStableContext` is configured with the 'default'
105/// `HashingControls`. We should always have bailed out before getting to here
106/// with a non-default mode. With this check in place, we can avoid the need
107/// to maintain separate versions of `ExpnData` hashes for each permutation
108/// of `HashingControls` settings.
109fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
110    match ctx.hashing_controls() {
111        // Note that we require that `hash_spans` be set according to the global
112        // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
113        // which will cause us to require that this method always be called with `Span` hashing
114        // enabled.
115        //
116        // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
117        // This is the case for instance when building a hash for name mangling.
118        // Such configuration must not be used for metadata.
119        HashingControls { hash_spans }
120            if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
121        other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
122    }
123}
124
125/// A unique hash value associated to an expansion.
126#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
127pub struct ExpnHash(Fingerprint);
128
129impl ExpnHash {
130    /// Returns the [StableCrateId] identifying the crate this [ExpnHash]
131    /// originates from.
132    #[inline]
133    pub fn stable_crate_id(self) -> StableCrateId {
134        StableCrateId(self.0.split().0)
135    }
136
137    /// Returns the crate-local part of the [ExpnHash].
138    ///
139    /// Used for assertions.
140    #[inline]
141    pub fn local_hash(self) -> Hash64 {
142        self.0.split().1
143    }
144
145    #[inline]
146    pub fn is_root(self) -> bool {
147        self.0 == Fingerprint::ZERO
148    }
149
150    /// Builds a new [ExpnHash] with the given [StableCrateId] and
151    /// `local_hash`, where `local_hash` must be unique within its crate.
152    fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
153        ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
154    }
155}
156
157/// A property of a macro expansion that determines how identifiers
158/// produced by that expansion are resolved.
159#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
160#[derive(HashStable_Generic)]
161pub enum Transparency {
162    /// Identifier produced by a transparent expansion is always resolved at call-site.
163    /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
164    Transparent,
165    /// Identifier produced by a semi-transparent expansion may be resolved
166    /// either at call-site or at definition-site.
167    /// If it's a local variable, label or `$crate` then it's resolved at def-site.
168    /// Otherwise it's resolved at call-site.
169    /// `macro_rules` macros behave like this, built-in macros currently behave like this too,
170    /// but that's an implementation detail.
171    SemiTransparent,
172    /// Identifier produced by an opaque expansion is always resolved at definition-site.
173    /// Def-site spans in procedural macros, identifiers from `macro` by default use this.
174    Opaque,
175}
176
177impl LocalExpnId {
178    /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
179    pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
180
181    #[inline]
182    fn from_raw(idx: ExpnIndex) -> LocalExpnId {
183        LocalExpnId::from_u32(idx.as_u32())
184    }
185
186    #[inline]
187    pub fn as_raw(self) -> ExpnIndex {
188        ExpnIndex::from_u32(self.as_u32())
189    }
190
191    pub fn fresh_empty() -> LocalExpnId {
192        HygieneData::with(|data| {
193            let expn_id = data.local_expn_data.push(None);
194            let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
195            debug_assert_eq!(expn_id, _eid);
196            expn_id
197        })
198    }
199
200    pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
201        debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
202        let expn_hash = update_disambiguator(&mut expn_data, ctx);
203        HygieneData::with(|data| {
204            let expn_id = data.local_expn_data.push(Some(expn_data));
205            let _eid = data.local_expn_hashes.push(expn_hash);
206            debug_assert_eq!(expn_id, _eid);
207            let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
208            debug_assert!(_old_id.is_none());
209            expn_id
210        })
211    }
212
213    #[inline]
214    pub fn expn_data(self) -> ExpnData {
215        HygieneData::with(|data| data.local_expn_data(self).clone())
216    }
217
218    #[inline]
219    pub fn to_expn_id(self) -> ExpnId {
220        ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
221    }
222
223    #[inline]
224    pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
225        debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
226        let expn_hash = update_disambiguator(&mut expn_data, ctx);
227        HygieneData::with(|data| {
228            let old_expn_data = &mut data.local_expn_data[self];
229            assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
230            *old_expn_data = Some(expn_data);
231            debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
232            data.local_expn_hashes[self] = expn_hash;
233            let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
234            debug_assert!(_old_id.is_none());
235        });
236    }
237
238    #[inline]
239    pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
240        self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
241    }
242
243    /// Returns span for the macro which originally caused this expansion to happen.
244    ///
245    /// Stops backtracing at include! boundary.
246    #[inline]
247    pub fn expansion_cause(self) -> Option<Span> {
248        self.to_expn_id().expansion_cause()
249    }
250}
251
252impl ExpnId {
253    /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
254    /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0.
255    pub const fn root() -> ExpnId {
256        ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
257    }
258
259    #[inline]
260    pub fn expn_hash(self) -> ExpnHash {
261        HygieneData::with(|data| data.expn_hash(self))
262    }
263
264    #[inline]
265    pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
266        HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
267    }
268
269    #[inline]
270    pub fn as_local(self) -> Option<LocalExpnId> {
271        if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
272    }
273
274    #[inline]
275    #[track_caller]
276    pub fn expect_local(self) -> LocalExpnId {
277        self.as_local().unwrap()
278    }
279
280    #[inline]
281    pub fn expn_data(self) -> ExpnData {
282        HygieneData::with(|data| data.expn_data(self).clone())
283    }
284
285    #[inline]
286    pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
287        // a few "fast path" cases to avoid locking HygieneData
288        if ancestor == ExpnId::root() || ancestor == self {
289            return true;
290        }
291        if ancestor.krate != self.krate {
292            return false;
293        }
294        HygieneData::with(|data| data.is_descendant_of(self, ancestor))
295    }
296
297    /// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
298    /// `expn_id.is_descendant_of(ctxt.outer_expn())`.
299    pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
300        HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
301    }
302
303    /// Returns span for the macro which originally caused this expansion to happen.
304    ///
305    /// Stops backtracing at include! boundary.
306    pub fn expansion_cause(mut self) -> Option<Span> {
307        let mut last_macro = None;
308        loop {
309            // Fast path to avoid locking.
310            if self == ExpnId::root() {
311                break;
312            }
313            let expn_data = self.expn_data();
314            // Stop going up the backtrace once include! is encountered
315            if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
316                break;
317            }
318            self = expn_data.call_site.ctxt().outer_expn();
319            last_macro = Some(expn_data.call_site);
320        }
321        last_macro
322    }
323}
324
325#[derive(Debug)]
326pub(crate) struct HygieneData {
327    /// Each expansion should have an associated expansion data, but sometimes there's a delay
328    /// between creation of an expansion ID and obtaining its data (e.g. macros are collected
329    /// first and then resolved later), so we use an `Option` here.
330    local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
331    local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
332    /// Data and hash information from external crates. We may eventually want to remove these
333    /// maps, and fetch the information directly from the other crate's metadata like DefIds do.
334    foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
335    foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
336    expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
337    syntax_context_data: Vec<SyntaxContextData>,
338    syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
339    /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value.
340    /// This is used by `update_disambiguator` to keep track of which `ExpnData`s
341    /// would have collisions without a disambiguator.
342    /// The keys of this map are always computed with `ExpnData.disambiguator`
343    /// set to 0.
344    expn_data_disambiguators: UnhashMap<Hash64, u32>,
345}
346
347impl HygieneData {
348    pub(crate) fn new(edition: Edition) -> Self {
349        let root_data = ExpnData::default(
350            ExpnKind::Root,
351            DUMMY_SP,
352            edition,
353            Some(CRATE_DEF_ID.to_def_id()),
354            None,
355        );
356
357        HygieneData {
358            local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
359            local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
360            foreign_expn_data: FxHashMap::default(),
361            foreign_expn_hashes: FxHashMap::default(),
362            expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
363                .collect(),
364            syntax_context_data: vec![SyntaxContextData {
365                outer_expn: ExpnId::root(),
366                outer_transparency: Transparency::Opaque,
367                parent: SyntaxContext(0),
368                opaque: SyntaxContext(0),
369                opaque_and_semitransparent: SyntaxContext(0),
370                dollar_crate_name: kw::DollarCrate,
371            }],
372            syntax_context_map: FxHashMap::default(),
373            expn_data_disambiguators: UnhashMap::default(),
374        }
375    }
376
377    fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
378        with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
379    }
380
381    #[inline]
382    fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
383        match expn_id.as_local() {
384            Some(expn_id) => self.local_expn_hashes[expn_id],
385            None => self.foreign_expn_hashes[&expn_id],
386        }
387    }
388
389    fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
390        self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
391    }
392
393    fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
394        if let Some(expn_id) = expn_id.as_local() {
395            self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
396        } else {
397            &self.foreign_expn_data[&expn_id]
398        }
399    }
400
401    fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
402        // a couple "fast path" cases to avoid traversing parents in the loop below
403        if ancestor == ExpnId::root() {
404            return true;
405        }
406        if expn_id.krate != ancestor.krate {
407            return false;
408        }
409        loop {
410            if expn_id == ancestor {
411                return true;
412            }
413            if expn_id == ExpnId::root() {
414                return false;
415            }
416            expn_id = self.expn_data(expn_id).parent;
417        }
418    }
419
420    fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
421        self.syntax_context_data[ctxt.0 as usize].opaque
422    }
423
424    fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
425        self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
426    }
427
428    fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
429        self.syntax_context_data[ctxt.0 as usize].outer_expn
430    }
431
432    fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
433        let data = &self.syntax_context_data[ctxt.0 as usize];
434        (data.outer_expn, data.outer_transparency)
435    }
436
437    fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
438        self.syntax_context_data[ctxt.0 as usize].parent
439    }
440
441    fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) {
442        let outer_mark = self.outer_mark(*ctxt);
443        *ctxt = self.parent_ctxt(*ctxt);
444        outer_mark
445    }
446
447    fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
448        let mut marks = Vec::new();
449        while !ctxt.is_root() {
450            debug!("marks: getting parent of {:?}", ctxt);
451            marks.push(self.outer_mark(ctxt));
452            ctxt = self.parent_ctxt(ctxt);
453        }
454        marks.reverse();
455        marks
456    }
457
458    fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
459        let orig_span = span;
460        debug!("walk_chain({:?}, {:?})", span, to);
461        debug!("walk_chain: span ctxt = {:?}", span.ctxt());
462        while span.ctxt() != to && span.from_expansion() {
463            let outer_expn = self.outer_expn(span.ctxt());
464            debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
465            let expn_data = self.expn_data(outer_expn);
466            debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
467            span = expn_data.call_site;
468        }
469        debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
470        span
471    }
472
473    fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
474        let orig_span = span;
475        let mut ret_span = span;
476        debug!("walk_chain_collapsed({:?}, {:?})", span, to);
477        debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
478        while let ctxt = span.ctxt()
479            && !ctxt.is_root()
480            && ctxt != to.ctxt()
481        {
482            let outer_expn = self.outer_expn(ctxt);
483            debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
484            let expn_data = self.expn_data(outer_expn);
485            debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
486            span = expn_data.call_site;
487            if expn_data.collapse_debuginfo {
488                ret_span = span;
489            }
490        }
491        debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
492        ret_span
493    }
494
495    fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
496        let mut scope = None;
497        while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
498            scope = Some(self.remove_mark(ctxt).0);
499        }
500        scope
501    }
502
503    fn apply_mark(
504        &mut self,
505        ctxt: SyntaxContext,
506        expn_id: ExpnId,
507        transparency: Transparency,
508    ) -> SyntaxContext {
509        assert_ne!(expn_id, ExpnId::root());
510        if transparency == Transparency::Opaque {
511            return self.apply_mark_internal(ctxt, expn_id, transparency);
512        }
513
514        let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
515        let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
516            self.normalize_to_macros_2_0(call_site_ctxt)
517        } else {
518            self.normalize_to_macro_rules(call_site_ctxt)
519        };
520
521        if call_site_ctxt.is_root() {
522            return self.apply_mark_internal(ctxt, expn_id, transparency);
523        }
524
525        // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
526        // macros 2.0 expansion, i.e., a macros 1.0 invocation is in a macros 2.0 definition.
527        //
528        // In this case, the tokens from the macros 1.0 definition inherit the hygiene
529        // at their invocation. That is, we pretend that the macros 1.0 definition
530        // was defined at its invocation (i.e., inside the macros 2.0 definition)
531        // so that the macros 2.0 definition remains hygienic.
532        //
533        // See the example at `test/ui/hygiene/legacy_interaction.rs`.
534        for (expn_id, transparency) in self.marks(ctxt) {
535            call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency);
536        }
537        self.apply_mark_internal(call_site_ctxt, expn_id, transparency)
538    }
539
540    fn apply_mark_internal(
541        &mut self,
542        ctxt: SyntaxContext,
543        expn_id: ExpnId,
544        transparency: Transparency,
545    ) -> SyntaxContext {
546        let syntax_context_data = &mut self.syntax_context_data;
547        let mut opaque = syntax_context_data[ctxt.0 as usize].opaque;
548        let mut opaque_and_semitransparent =
549            syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent;
550
551        if transparency >= Transparency::Opaque {
552            let parent = opaque;
553            opaque = *self
554                .syntax_context_map
555                .entry((parent, expn_id, transparency))
556                .or_insert_with(|| {
557                    let new_opaque = SyntaxContext(syntax_context_data.len() as u32);
558                    syntax_context_data.push(SyntaxContextData {
559                        outer_expn: expn_id,
560                        outer_transparency: transparency,
561                        parent,
562                        opaque: new_opaque,
563                        opaque_and_semitransparent: new_opaque,
564                        dollar_crate_name: kw::DollarCrate,
565                    });
566                    new_opaque
567                });
568        }
569
570        if transparency >= Transparency::SemiTransparent {
571            let parent = opaque_and_semitransparent;
572            opaque_and_semitransparent = *self
573                .syntax_context_map
574                .entry((parent, expn_id, transparency))
575                .or_insert_with(|| {
576                    let new_opaque_and_semitransparent =
577                        SyntaxContext(syntax_context_data.len() as u32);
578                    syntax_context_data.push(SyntaxContextData {
579                        outer_expn: expn_id,
580                        outer_transparency: transparency,
581                        parent,
582                        opaque,
583                        opaque_and_semitransparent: new_opaque_and_semitransparent,
584                        dollar_crate_name: kw::DollarCrate,
585                    });
586                    new_opaque_and_semitransparent
587                });
588        }
589
590        let parent = ctxt;
591        *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| {
592            let new_opaque_and_semitransparent_and_transparent =
593                SyntaxContext(syntax_context_data.len() as u32);
594            syntax_context_data.push(SyntaxContextData {
595                outer_expn: expn_id,
596                outer_transparency: transparency,
597                parent,
598                opaque,
599                opaque_and_semitransparent,
600                dollar_crate_name: kw::DollarCrate,
601            });
602            new_opaque_and_semitransparent_and_transparent
603        })
604    }
605}
606
607pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
608    HygieneData::with(|data| data.walk_chain(span, to))
609}
610
611/// In order to have good line stepping behavior in debugger, for the given span we return its
612/// outermost macro call site that still has a `#[collapse_debuginfo(yes)]` property on it.
613/// We also stop walking call sites at the function body level because no line stepping can occur
614/// at the level above that.
615/// The returned span can then be used in emitted debuginfo.
616pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
617    HygieneData::with(|data| data.walk_chain_collapsed(span, to))
618}
619
620pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
621    // The new contexts that need updating are at the end of the list and have `$crate` as a name.
622    let (len, to_update) = HygieneData::with(|data| {
623        (
624            data.syntax_context_data.len(),
625            data.syntax_context_data
626                .iter()
627                .rev()
628                .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate)
629                .count(),
630        )
631    });
632    // The callback must be called from outside of the `HygieneData` lock,
633    // since it will try to acquire it too.
634    let range_to_update = len - to_update..len;
635    let names: Vec<_> =
636        range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
637    HygieneData::with(|data| {
638        range_to_update.zip(names).for_each(|(idx, name)| {
639            data.syntax_context_data[idx].dollar_crate_name = name;
640        })
641    })
642}
643
644pub fn debug_hygiene_data(verbose: bool) -> String {
645    HygieneData::with(|data| {
646        if verbose {
647            format!("{data:#?}")
648        } else {
649            let mut s = String::from("Expansions:");
650            let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
651                s.push_str(&format!(
652                    "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
653                    id,
654                    expn_data.parent,
655                    expn_data.call_site.ctxt(),
656                    expn_data.def_site.ctxt(),
657                    expn_data.kind,
658                ))
659            };
660            data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
661                let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
662                debug_expn_data((&id.to_expn_id(), expn_data))
663            });
664
665            // Sort the hash map for more reproducible output.
666            // Because of this, it is fine to rely on the unstable iteration order of the map.
667            #[allow(rustc::potential_query_instability)]
668            let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
669            foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
670            foreign_expn_data.into_iter().for_each(debug_expn_data);
671            s.push_str("\n\nSyntaxContexts:");
672            data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
673                s.push_str(&format!(
674                    "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
675                    id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
676                ));
677            });
678            s
679        }
680    })
681}
682
683impl SyntaxContext {
684    #[inline]
685    pub const fn root() -> Self {
686        SyntaxContext(0)
687    }
688
689    #[inline]
690    pub const fn is_root(self) -> bool {
691        self.0 == SyntaxContext::root().as_u32()
692    }
693
694    #[inline]
695    pub(crate) const fn as_u32(self) -> u32 {
696        self.0
697    }
698
699    #[inline]
700    pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
701        SyntaxContext(raw)
702    }
703
704    #[inline]
705    pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
706        SyntaxContext(raw as u32)
707    }
708
709    /// Extend a syntax context with a given expansion and transparency.
710    pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
711        HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
712    }
713
714    /// Pulls a single mark off of the syntax context. This effectively moves the
715    /// context up one macro definition level. That is, if we have a nested macro
716    /// definition as follows:
717    ///
718    /// ```ignore (illustrative)
719    /// macro_rules! f {
720    ///    macro_rules! g {
721    ///        ...
722    ///    }
723    /// }
724    /// ```
725    ///
726    /// and we have a SyntaxContext that is referring to something declared by an invocation
727    /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
728    /// invocation of f that created g1.
729    /// Returns the mark that was removed.
730    pub fn remove_mark(&mut self) -> ExpnId {
731        HygieneData::with(|data| data.remove_mark(self).0)
732    }
733
734    pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
735        HygieneData::with(|data| data.marks(self))
736    }
737
738    /// Adjust this context for resolution in a scope created by the given expansion.
739    /// For example, consider the following three resolutions of `f`:
740    ///
741    /// ```rust
742    /// #![feature(decl_macro)]
743    /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty.
744    /// m!(f);
745    /// macro m($f:ident) {
746    ///     mod bar {
747    ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
748    ///         pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
749    ///     }
750    ///     foo::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m`
751    ///     //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
752    ///     //| and it resolves to `::foo::f`.
753    ///     bar::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m`
754    ///     //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
755    ///     //| and it resolves to `::bar::f`.
756    ///     bar::$f(); // `f`'s `SyntaxContext` is empty.
757    ///     //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
758    ///     //| and it resolves to `::bar::$f`.
759    /// }
760    /// ```
761    /// This returns the expansion whose definition scope we use to privacy check the resolution,
762    /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
763    pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
764        HygieneData::with(|data| data.adjust(self, expn_id))
765    }
766
767    /// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
768    pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
769        HygieneData::with(|data| {
770            *self = data.normalize_to_macros_2_0(*self);
771            data.adjust(self, expn_id)
772        })
773    }
774
775    /// Adjust this context for resolution in a scope created by the given expansion
776    /// via a glob import with the given `SyntaxContext`.
777    /// For example:
778    ///
779    /// ```compile_fail,E0425
780    /// #![feature(decl_macro)]
781    /// m!(f);
782    /// macro m($i:ident) {
783    ///     mod foo {
784    ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
785    ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
786    ///     }
787    ///     n!(f);
788    ///     macro n($j:ident) {
789    ///         use foo::*;
790    ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
791    ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
792    ///         $i(); // `$i`'s `SyntaxContext` has a mark from `n`
793    ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
794    ///         $j(); // `$j`'s `SyntaxContext` has a mark from `m`
795    ///         //^ This cannot be glob-adjusted, so this is a resolution error.
796    ///     }
797    /// }
798    /// ```
799    /// This returns `None` if the context cannot be glob-adjusted.
800    /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details).
801    pub(crate) fn glob_adjust(
802        &mut self,
803        expn_id: ExpnId,
804        glob_span: Span,
805    ) -> Option<Option<ExpnId>> {
806        HygieneData::with(|data| {
807            let mut scope = None;
808            let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
809            while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
810                scope = Some(data.remove_mark(&mut glob_ctxt).0);
811                if data.remove_mark(self).0 != scope.unwrap() {
812                    return None;
813                }
814            }
815            if data.adjust(self, expn_id).is_some() {
816                return None;
817            }
818            Some(scope)
819        })
820    }
821
822    /// Undo `glob_adjust` if possible:
823    ///
824    /// ```ignore (illustrative)
825    /// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
826    ///     assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
827    /// }
828    /// ```
829    pub(crate) fn reverse_glob_adjust(
830        &mut self,
831        expn_id: ExpnId,
832        glob_span: Span,
833    ) -> Option<Option<ExpnId>> {
834        HygieneData::with(|data| {
835            if data.adjust(self, expn_id).is_some() {
836                return None;
837            }
838
839            let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
840            let mut marks = Vec::new();
841            while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
842                marks.push(data.remove_mark(&mut glob_ctxt));
843            }
844
845            let scope = marks.last().map(|mark| mark.0);
846            while let Some((expn_id, transparency)) = marks.pop() {
847                *self = data.apply_mark(*self, expn_id, transparency);
848            }
849            Some(scope)
850        })
851    }
852
853    pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool {
854        HygieneData::with(|data| {
855            let mut self_normalized = data.normalize_to_macros_2_0(self);
856            data.adjust(&mut self_normalized, expn_id);
857            self_normalized == data.normalize_to_macros_2_0(other)
858        })
859    }
860
861    #[inline]
862    pub fn normalize_to_macros_2_0(self) -> SyntaxContext {
863        HygieneData::with(|data| data.normalize_to_macros_2_0(self))
864    }
865
866    #[inline]
867    pub fn normalize_to_macro_rules(self) -> SyntaxContext {
868        HygieneData::with(|data| data.normalize_to_macro_rules(self))
869    }
870
871    #[inline]
872    pub fn outer_expn(self) -> ExpnId {
873        HygieneData::with(|data| data.outer_expn(self))
874    }
875
876    /// `ctxt.outer_expn_data()` is equivalent to but faster than
877    /// `ctxt.outer_expn().expn_data()`.
878    #[inline]
879    pub fn outer_expn_data(self) -> ExpnData {
880        HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
881    }
882
883    #[inline]
884    fn outer_mark(self) -> (ExpnId, Transparency) {
885        HygieneData::with(|data| data.outer_mark(self))
886    }
887
888    pub(crate) fn dollar_crate_name(self) -> Symbol {
889        HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
890    }
891
892    pub fn edition(self) -> Edition {
893        HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
894    }
895}
896
897impl fmt::Debug for SyntaxContext {
898    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
899        write!(f, "#{}", self.0)
900    }
901}
902
903impl Span {
904    /// Reuses the span but adds information like the kind of the desugaring and features that are
905    /// allowed inside this span.
906    pub fn mark_with_reason(
907        self,
908        allow_internal_unstable: Option<Arc<[Symbol]>>,
909        reason: DesugaringKind,
910        edition: Edition,
911        ctx: impl HashStableContext,
912    ) -> Span {
913        let expn_data = ExpnData {
914            allow_internal_unstable,
915            ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
916        };
917        let expn_id = LocalExpnId::fresh(expn_data, ctx);
918        self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
919    }
920}
921
922/// A subset of properties from both macro definition and macro call available through global data.
923/// Avoid using this if you have access to the original definition or call structures.
924#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
925pub struct ExpnData {
926    // --- The part unique to each expansion.
927    /// The kind of this expansion - macro or compiler desugaring.
928    pub kind: ExpnKind,
929    /// The expansion that produced this expansion.
930    pub parent: ExpnId,
931    /// The location of the actual macro invocation or syntax sugar , e.g.
932    /// `let x = foo!();` or `if let Some(y) = x {}`
933    ///
934    /// This may recursively refer to other macro invocations, e.g., if
935    /// `foo!()` invoked `bar!()` internally, and there was an
936    /// expression inside `bar!`; the call_site of the expression in
937    /// the expansion would point to the `bar!` invocation; that
938    /// call_site span would have its own ExpnData, with the call_site
939    /// pointing to the `foo!` invocation.
940    pub call_site: Span,
941    /// Used to force two `ExpnData`s to have different `Fingerprint`s.
942    /// Due to macro expansion, it's possible to end up with two `ExpnId`s
943    /// that have identical `ExpnData`s. This violates the contract of `HashStable`
944    /// - the two `ExpnId`s are not equal, but their `Fingerprint`s are equal
945    /// (since the numerical `ExpnId` value is not considered by the `HashStable`
946    /// implementation).
947    ///
948    /// The `disambiguator` field is set by `update_disambiguator` when two distinct
949    /// `ExpnId`s would end up with the same `Fingerprint`. Since `ExpnData` includes
950    /// a `krate` field, this value only needs to be unique within a single crate.
951    disambiguator: u32,
952
953    // --- The part specific to the macro/desugaring definition.
954    // --- It may be reasonable to share this part between expansions with the same definition,
955    // --- but such sharing is known to bring some minor inconveniences without also bringing
956    // --- noticeable perf improvements (PR #62898).
957    /// The span of the macro definition (possibly dummy).
958    /// This span serves only informational purpose and is not used for resolution.
959    pub def_site: Span,
960    /// List of `#[unstable]`/feature-gated features that the macro is allowed to use
961    /// internally without forcing the whole crate to opt-in
962    /// to them.
963    pub allow_internal_unstable: Option<Arc<[Symbol]>>,
964    /// Edition of the crate in which the macro is defined.
965    pub edition: Edition,
966    /// The `DefId` of the macro being invoked,
967    /// if this `ExpnData` corresponds to a macro invocation
968    pub macro_def_id: Option<DefId>,
969    /// The normal module (`mod`) in which the expanded macro was defined.
970    pub parent_module: Option<DefId>,
971    /// Suppresses the `unsafe_code` lint for code produced by this macro.
972    pub(crate) allow_internal_unsafe: bool,
973    /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
974    pub local_inner_macros: bool,
975    /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
976    /// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
977    pub(crate) collapse_debuginfo: bool,
978}
979
980impl !PartialEq for ExpnData {}
981impl !Hash for ExpnData {}
982
983impl ExpnData {
984    pub fn new(
985        kind: ExpnKind,
986        parent: ExpnId,
987        call_site: Span,
988        def_site: Span,
989        allow_internal_unstable: Option<Arc<[Symbol]>>,
990        edition: Edition,
991        macro_def_id: Option<DefId>,
992        parent_module: Option<DefId>,
993        allow_internal_unsafe: bool,
994        local_inner_macros: bool,
995        collapse_debuginfo: bool,
996    ) -> ExpnData {
997        ExpnData {
998            kind,
999            parent,
1000            call_site,
1001            def_site,
1002            allow_internal_unstable,
1003            edition,
1004            macro_def_id,
1005            parent_module,
1006            disambiguator: 0,
1007            allow_internal_unsafe,
1008            local_inner_macros,
1009            collapse_debuginfo,
1010        }
1011    }
1012
1013    /// Constructs expansion data with default properties.
1014    pub fn default(
1015        kind: ExpnKind,
1016        call_site: Span,
1017        edition: Edition,
1018        macro_def_id: Option<DefId>,
1019        parent_module: Option<DefId>,
1020    ) -> ExpnData {
1021        ExpnData {
1022            kind,
1023            parent: ExpnId::root(),
1024            call_site,
1025            def_site: DUMMY_SP,
1026            allow_internal_unstable: None,
1027            edition,
1028            macro_def_id,
1029            parent_module,
1030            disambiguator: 0,
1031            allow_internal_unsafe: false,
1032            local_inner_macros: false,
1033            collapse_debuginfo: false,
1034        }
1035    }
1036
1037    pub fn allow_unstable(
1038        kind: ExpnKind,
1039        call_site: Span,
1040        edition: Edition,
1041        allow_internal_unstable: Arc<[Symbol]>,
1042        macro_def_id: Option<DefId>,
1043        parent_module: Option<DefId>,
1044    ) -> ExpnData {
1045        ExpnData {
1046            allow_internal_unstable: Some(allow_internal_unstable),
1047            ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1048        }
1049    }
1050
1051    #[inline]
1052    pub fn is_root(&self) -> bool {
1053        matches!(self.kind, ExpnKind::Root)
1054    }
1055
1056    #[inline]
1057    fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1058        let mut hasher = StableHasher::new();
1059        self.hash_stable(ctx, &mut hasher);
1060        hasher.finish()
1061    }
1062}
1063
1064/// Expansion kind.
1065#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1066pub enum ExpnKind {
1067    /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
1068    Root,
1069    /// Expansion produced by a macro.
1070    Macro(MacroKind, Symbol),
1071    /// Transform done by the compiler on the AST.
1072    AstPass(AstPass),
1073    /// Desugaring done by the compiler during AST lowering.
1074    Desugaring(DesugaringKind),
1075}
1076
1077impl ExpnKind {
1078    pub fn descr(&self) -> String {
1079        match *self {
1080            ExpnKind::Root => kw::PathRoot.to_string(),
1081            ExpnKind::Macro(macro_kind, name) => match macro_kind {
1082                MacroKind::Bang => format!("{name}!"),
1083                MacroKind::Attr => format!("#[{name}]"),
1084                MacroKind::Derive => format!("#[derive({name})]"),
1085            },
1086            ExpnKind::AstPass(kind) => kind.descr().to_string(),
1087            ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1088        }
1089    }
1090}
1091
1092/// The kind of macro invocation or definition.
1093#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
1094#[derive(HashStable_Generic)]
1095pub enum MacroKind {
1096    /// A bang macro `foo!()`.
1097    Bang,
1098    /// An attribute macro `#[foo]`.
1099    Attr,
1100    /// A derive macro `#[derive(Foo)]`
1101    Derive,
1102}
1103
1104impl MacroKind {
1105    pub fn descr(self) -> &'static str {
1106        match self {
1107            MacroKind::Bang => "macro",
1108            MacroKind::Attr => "attribute macro",
1109            MacroKind::Derive => "derive macro",
1110        }
1111    }
1112
1113    pub fn descr_expected(self) -> &'static str {
1114        match self {
1115            MacroKind::Attr => "attribute",
1116            _ => self.descr(),
1117        }
1118    }
1119
1120    pub fn article(self) -> &'static str {
1121        match self {
1122            MacroKind::Attr => "an",
1123            _ => "a",
1124        }
1125    }
1126}
1127
1128/// The kind of AST transform.
1129#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1130pub enum AstPass {
1131    StdImports,
1132    TestHarness,
1133    ProcMacroHarness,
1134}
1135
1136impl AstPass {
1137    pub fn descr(self) -> &'static str {
1138        match self {
1139            AstPass::StdImports => "standard library imports",
1140            AstPass::TestHarness => "test harness",
1141            AstPass::ProcMacroHarness => "proc macro harness",
1142        }
1143    }
1144}
1145
1146/// The kind of compiler desugaring.
1147#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1148pub enum DesugaringKind {
1149    /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
1150    /// However, we do not want to blame `c` for unreachability but rather say that `i`
1151    /// is unreachable. This desugaring kind allows us to avoid blaming `c`.
1152    /// This also applies to `while` loops.
1153    CondTemporary,
1154    QuestionMark,
1155    TryBlock,
1156    YeetExpr,
1157    /// Desugaring of an `impl Trait` in return type position
1158    /// to an `type Foo = impl Trait;` and replacing the
1159    /// `impl Trait` with `Foo`.
1160    OpaqueTy,
1161    Async,
1162    Await,
1163    ForLoop,
1164    WhileLoop,
1165    /// `async Fn()` bound modifier
1166    BoundModifier,
1167    /// Calls to contract checks (`#[requires]` to precond, `#[ensures]` to postcond)
1168    Contract,
1169}
1170
1171impl DesugaringKind {
1172    /// The description wording should combine well with "desugaring of {}".
1173    pub fn descr(self) -> &'static str {
1174        match self {
1175            DesugaringKind::CondTemporary => "`if` or `while` condition",
1176            DesugaringKind::Async => "`async` block or function",
1177            DesugaringKind::Await => "`await` expression",
1178            DesugaringKind::QuestionMark => "operator `?`",
1179            DesugaringKind::TryBlock => "`try` block",
1180            DesugaringKind::YeetExpr => "`do yeet` expression",
1181            DesugaringKind::OpaqueTy => "`impl Trait`",
1182            DesugaringKind::ForLoop => "`for` loop",
1183            DesugaringKind::WhileLoop => "`while` loop",
1184            DesugaringKind::BoundModifier => "trait bound modifier",
1185            DesugaringKind::Contract => "contract check",
1186        }
1187    }
1188}
1189
1190#[derive(Default)]
1191pub struct HygieneEncodeContext {
1192    /// All `SyntaxContexts` for which we have written `SyntaxContextData` into crate metadata.
1193    /// This is `None` after we finish encoding `SyntaxContexts`, to ensure
1194    /// that we don't accidentally try to encode any more `SyntaxContexts`
1195    serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1196    /// The `SyntaxContexts` that we have serialized (e.g. as a result of encoding `Spans`)
1197    /// in the most recent 'round' of serializing. Serializing `SyntaxContextData`
1198    /// may cause us to serialize more `SyntaxContext`s, so serialize in a loop
1199    /// until we reach a fixed point.
1200    latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1201
1202    serialized_expns: Lock<FxHashSet<ExpnId>>,
1203
1204    latest_expns: Lock<FxHashSet<ExpnId>>,
1205}
1206
1207impl HygieneEncodeContext {
1208    /// Record the fact that we need to serialize the corresponding `ExpnData`.
1209    pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1210        if !self.serialized_expns.lock().contains(&expn) {
1211            self.latest_expns.lock().insert(expn);
1212        }
1213    }
1214
1215    pub fn encode<T>(
1216        &self,
1217        encoder: &mut T,
1218        mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData),
1219        mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1220    ) {
1221        // When we serialize a `SyntaxContextData`, we may end up serializing
1222        // a `SyntaxContext` that we haven't seen before
1223        while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1224            debug!(
1225                "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1226                self.latest_ctxts.lock().len(),
1227                self.latest_ctxts
1228            );
1229
1230            // Consume the current round of SyntaxContexts.
1231            // Drop the lock() temporary early
1232            let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) };
1233
1234            // It's fine to iterate over a HashMap, because the serialization
1235            // of the table that we insert data into doesn't depend on insertion
1236            // order
1237            #[allow(rustc::potential_query_instability)]
1238            for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
1239                if self.serialized_ctxts.lock().insert(ctxt) {
1240                    encode_ctxt(encoder, index, data);
1241                }
1242            });
1243
1244            let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
1245
1246            // Same as above, this is fine as we are inserting into a order-independent hashset
1247            #[allow(rustc::potential_query_instability)]
1248            for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
1249                if self.serialized_expns.lock().insert(expn) {
1250                    encode_expn(encoder, expn, data, hash);
1251                }
1252            });
1253        }
1254        debug!("encode_hygiene: Done serializing SyntaxContextData");
1255    }
1256}
1257
1258#[derive(Default)]
1259/// Additional information used to assist in decoding hygiene data
1260struct HygieneDecodeContextInner {
1261    // Maps serialized `SyntaxContext` ids to a `SyntaxContext` in the current
1262    // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create
1263    // a new id in the global `HygieneData`. This map tracks the ID we end up picking,
1264    // so that multiple occurrences of the same serialized id are decoded to the same
1265    // `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded.
1266    remapped_ctxts: Vec<Option<SyntaxContext>>,
1267
1268    /// Maps serialized `SyntaxContext` ids that are currently being decoded to a `SyntaxContext`.
1269    decoding: FxHashMap<u32, SyntaxContext>,
1270}
1271
1272#[derive(Default)]
1273/// Additional information used to assist in decoding hygiene data
1274pub struct HygieneDecodeContext {
1275    inner: Lock<HygieneDecodeContextInner>,
1276
1277    /// A set of serialized `SyntaxContext` ids that are currently being decoded on each thread.
1278    local_in_progress: WorkerLocal<RefCell<FxHashSet<u32>>>,
1279}
1280
1281/// Register an expansion which has been decoded from the on-disk-cache for the local crate.
1282pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1283    HygieneData::with(|hygiene_data| {
1284        let expn_id = hygiene_data.local_expn_data.next_index();
1285        hygiene_data.local_expn_data.push(Some(data));
1286        let _eid = hygiene_data.local_expn_hashes.push(hash);
1287        debug_assert_eq!(expn_id, _eid);
1288
1289        let expn_id = expn_id.to_expn_id();
1290
1291        let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1292        debug_assert!(_old_id.is_none());
1293        expn_id
1294    })
1295}
1296
1297/// Register an expansion which has been decoded from the metadata of a foreign crate.
1298pub fn register_expn_id(
1299    krate: CrateNum,
1300    local_id: ExpnIndex,
1301    data: ExpnData,
1302    hash: ExpnHash,
1303) -> ExpnId {
1304    debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1305    let expn_id = ExpnId { krate, local_id };
1306    HygieneData::with(|hygiene_data| {
1307        let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1308        let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1309        debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1310        let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1311        debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1312    });
1313    expn_id
1314}
1315
1316/// Decode an expansion from the metadata of a foreign crate.
1317pub fn decode_expn_id(
1318    krate: CrateNum,
1319    index: u32,
1320    decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1321) -> ExpnId {
1322    if index == 0 {
1323        trace!("decode_expn_id: deserialized root");
1324        return ExpnId::root();
1325    }
1326
1327    let index = ExpnIndex::from_u32(index);
1328
1329    // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE.
1330    debug_assert_ne!(krate, LOCAL_CRATE);
1331    let expn_id = ExpnId { krate, local_id: index };
1332
1333    // Fast path if the expansion has already been decoded.
1334    if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1335        return expn_id;
1336    }
1337
1338    // Don't decode the data inside `HygieneData::with`, since we need to recursively decode
1339    // other ExpnIds
1340    let (expn_data, hash) = decode_data(expn_id);
1341
1342    register_expn_id(krate, index, expn_data, hash)
1343}
1344
1345// Decodes `SyntaxContext`, using the provided `HygieneDecodeContext`
1346// to track which `SyntaxContext`s we have already decoded.
1347// The provided closure will be invoked to deserialize a `SyntaxContextData`
1348// if we haven't already seen the id of the `SyntaxContext` we are deserializing.
1349pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
1350    d: &mut D,
1351    context: &HygieneDecodeContext,
1352    decode_data: F,
1353) -> SyntaxContext {
1354    let raw_id: u32 = Decodable::decode(d);
1355    if raw_id == 0 {
1356        trace!("decode_syntax_context: deserialized root");
1357        // The root is special
1358        return SyntaxContext::root();
1359    }
1360
1361    let ctxt = {
1362        let mut inner = context.inner.lock();
1363
1364        if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() {
1365            // This has already been decoded.
1366            return ctxt;
1367        }
1368
1369        match inner.decoding.entry(raw_id) {
1370            Entry::Occupied(ctxt_entry) => {
1371                match context.local_in_progress.borrow_mut().entry(raw_id) {
1372                    SetEntry::Occupied(..) => {
1373                        // We're decoding this already on the current thread. Return here
1374                        // and let the function higher up the stack finish decoding to handle
1375                        // recursive cases.
1376                        return *ctxt_entry.get();
1377                    }
1378                    SetEntry::Vacant(entry) => {
1379                        entry.insert();
1380
1381                        // Some other thread is current decoding this. Race with it.
1382                        *ctxt_entry.get()
1383                    }
1384                }
1385            }
1386            Entry::Vacant(entry) => {
1387                // We are the first thread to start decoding. Mark the current thread as being progress.
1388                context.local_in_progress.borrow_mut().insert(raw_id);
1389
1390                // Allocate and store SyntaxContext id *before* calling the decoder function,
1391                // as the SyntaxContextData may reference itself.
1392                let new_ctxt = HygieneData::with(|hygiene_data| {
1393                    let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32);
1394                    // Push a dummy SyntaxContextData to ensure that nobody else can get the
1395                    // same ID as us. This will be overwritten after call `decode_Data`
1396                    hygiene_data.syntax_context_data.push(SyntaxContextData {
1397                        outer_expn: ExpnId::root(),
1398                        outer_transparency: Transparency::Transparent,
1399                        parent: SyntaxContext::root(),
1400                        opaque: SyntaxContext::root(),
1401                        opaque_and_semitransparent: SyntaxContext::root(),
1402                        dollar_crate_name: kw::Empty,
1403                    });
1404                    new_ctxt
1405                });
1406                entry.insert(new_ctxt);
1407                new_ctxt
1408            }
1409        }
1410    };
1411
1412    // Don't try to decode data while holding the lock, since we need to
1413    // be able to recursively decode a SyntaxContext
1414    let mut ctxt_data = decode_data(d, raw_id);
1415    // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`
1416    // We don't care what the encoding crate set this to - we want to resolve it
1417    // from the perspective of the current compilation session
1418    ctxt_data.dollar_crate_name = kw::DollarCrate;
1419
1420    // Overwrite the dummy data with our decoded SyntaxContextData
1421    HygieneData::with(|hygiene_data| {
1422        if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
1423            && old.outer_expn == ctxt_data.outer_expn
1424            && old.outer_transparency == ctxt_data.outer_transparency
1425            && old.parent == ctxt_data.parent
1426        {
1427            ctxt_data = old.clone();
1428        }
1429
1430        hygiene_data.syntax_context_data[ctxt.as_u32() as usize] = ctxt_data;
1431    });
1432
1433    // Mark the context as completed
1434
1435    context.local_in_progress.borrow_mut().remove(&raw_id);
1436
1437    let mut inner = context.inner.lock();
1438    let new_len = raw_id as usize + 1;
1439    if inner.remapped_ctxts.len() < new_len {
1440        inner.remapped_ctxts.resize(new_len, None);
1441    }
1442    inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
1443    inner.decoding.remove(&raw_id);
1444
1445    ctxt
1446}
1447
1448fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextData)>(
1449    ctxts: impl Iterator<Item = SyntaxContext>,
1450    mut f: F,
1451) {
1452    let all_data: Vec<_> = HygieneData::with(|data| {
1453        ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
1454    });
1455    for (ctxt, data) in all_data.into_iter() {
1456        f(ctxt.0, ctxt, &data);
1457    }
1458}
1459
1460fn for_all_expns_in(
1461    expns: impl Iterator<Item = ExpnId>,
1462    mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
1463) {
1464    let all_data: Vec<_> = HygieneData::with(|data| {
1465        expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
1466    });
1467    for (expn, data, hash) in all_data.into_iter() {
1468        f(expn, &data, hash);
1469    }
1470}
1471
1472impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1473    fn encode(&self, e: &mut E) {
1474        self.to_expn_id().encode(e);
1475    }
1476}
1477
1478impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1479    fn decode(d: &mut D) -> Self {
1480        ExpnId::expect_local(ExpnId::decode(d))
1481    }
1482}
1483
1484pub fn raw_encode_syntax_context<E: Encoder>(
1485    ctxt: SyntaxContext,
1486    context: &HygieneEncodeContext,
1487    e: &mut E,
1488) {
1489    if !context.serialized_ctxts.lock().contains(&ctxt) {
1490        context.latest_ctxts.lock().insert(ctxt);
1491    }
1492    ctxt.0.encode(e);
1493}
1494
1495/// Updates the `disambiguator` field of the corresponding `ExpnData`
1496/// such that the `Fingerprint` of the `ExpnData` does not collide with
1497/// any other `ExpnIds`.
1498///
1499/// This method is called only when an `ExpnData` is first associated
1500/// with an `ExpnId` (when the `ExpnId` is initially constructed, or via
1501/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized
1502/// from another crate's metadata - since `ExpnHash` includes the stable crate id,
1503/// collisions are only possible between `ExpnId`s within the same crate.
1504fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1505    // This disambiguator should not have been set yet.
1506    assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1507    assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1508    let mut expn_hash = expn_data.hash_expn(&mut ctx);
1509
1510    let disambiguator = HygieneData::with(|data| {
1511        // If this is the first ExpnData with a given hash, then keep our
1512        // disambiguator at 0 (the default u32 value)
1513        let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1514        let disambiguator = *disambig;
1515        *disambig += 1;
1516        disambiguator
1517    });
1518
1519    if disambiguator != 0 {
1520        debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1521
1522        expn_data.disambiguator = disambiguator;
1523        expn_hash = expn_data.hash_expn(&mut ctx);
1524
1525        // Verify that the new disambiguator makes the hash unique
1526        #[cfg(debug_assertions)]
1527        HygieneData::with(|data| {
1528            assert_eq!(
1529                data.expn_data_disambiguators.get(&expn_hash),
1530                None,
1531                "Hash collision after disambiguator update!",
1532            );
1533        });
1534    }
1535
1536    ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1537}
1538
1539impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1540    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1541        const TAG_EXPANSION: u8 = 0;
1542        const TAG_NO_EXPANSION: u8 = 1;
1543
1544        if self.is_root() {
1545            TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1546        } else {
1547            TAG_EXPANSION.hash_stable(ctx, hasher);
1548            let (expn_id, transparency) = self.outer_mark();
1549            expn_id.hash_stable(ctx, hasher);
1550            transparency.hash_stable(ctx, hasher);
1551        }
1552    }
1553}
1554
1555impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1556    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1557        assert_default_hashing_controls(ctx, "ExpnId");
1558        let hash = if *self == ExpnId::root() {
1559            // Avoid fetching TLS storage for a trivial often-used value.
1560            Fingerprint::ZERO
1561        } else {
1562            self.expn_hash().0
1563        };
1564
1565        hash.hash_stable(ctx, hasher);
1566    }
1567}