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