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