1use std::cell::RefCell;
28use std::collections::hash_map::Entry;
29use std::collections::hash_set::Entry as SetEntry;
30use std::fmt;
31use std::hash::Hash;
32use std::sync::Arc;
33
34use rustc_data_structures::fingerprint::Fingerprint;
35use rustc_data_structures::fx::{FxHashMap, FxHashSet};
36use rustc_data_structures::stable_hasher::{Hash64, HashStable, HashingControls, StableHasher};
37use rustc_data_structures::sync::{Lock, WorkerLocal};
38use rustc_data_structures::unhash::UnhashMap;
39use rustc_index::IndexVec;
40use rustc_macros::{Decodable, Encodable, HashStable_Generic};
41use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
42use tracing::{debug, trace};
43
44use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId};
45use crate::edition::Edition;
46use crate::symbol::{Symbol, kw, sym};
47use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
48
49#[derive(Clone, Copy, PartialEq, Eq, Hash)]
51pub struct SyntaxContext(u32);
52
53impl !Ord for SyntaxContext {}
57impl !PartialOrd for SyntaxContext {}
58
59#[derive(Debug, Encodable, Decodable, Clone)]
60pub struct SyntaxContextData {
61 outer_expn: ExpnId,
62 outer_transparency: Transparency,
63 parent: SyntaxContext,
64 opaque: SyntaxContext,
66 opaque_and_semitransparent: SyntaxContext,
68 dollar_crate_name: Symbol,
70}
71
72rustc_index::newtype_index! {
73 #[orderable]
75 pub struct ExpnIndex {}
76}
77
78#[derive(Clone, Copy, PartialEq, Eq, Hash)]
80pub struct ExpnId {
81 pub krate: CrateNum,
82 pub local_id: ExpnIndex,
83}
84
85impl fmt::Debug for ExpnId {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
89 }
90}
91
92rustc_index::newtype_index! {
93 #[debug_format = "expn{}"]
95 pub struct LocalExpnId {}
96}
97
98impl !Ord for LocalExpnId {}
102impl !PartialOrd for LocalExpnId {}
103
104fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
110 match ctx.hashing_controls() {
111 HashingControls { hash_spans }
120 if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
121 other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
122 }
123}
124
125#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
127pub struct ExpnHash(Fingerprint);
128
129impl ExpnHash {
130 #[inline]
133 pub fn stable_crate_id(self) -> StableCrateId {
134 StableCrateId(self.0.split().0)
135 }
136
137 #[inline]
141 pub fn local_hash(self) -> Hash64 {
142 self.0.split().1
143 }
144
145 #[inline]
146 pub fn is_root(self) -> bool {
147 self.0 == Fingerprint::ZERO
148 }
149
150 fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
153 ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
154 }
155}
156
157#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
160#[derive(HashStable_Generic)]
161pub enum Transparency {
162 Transparent,
165 SemiTransparent,
172 Opaque,
175}
176
177impl LocalExpnId {
178 pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
180
181 #[inline]
182 fn from_raw(idx: ExpnIndex) -> LocalExpnId {
183 LocalExpnId::from_u32(idx.as_u32())
184 }
185
186 #[inline]
187 pub fn as_raw(self) -> ExpnIndex {
188 ExpnIndex::from_u32(self.as_u32())
189 }
190
191 pub fn fresh_empty() -> LocalExpnId {
192 HygieneData::with(|data| {
193 let expn_id = data.local_expn_data.push(None);
194 let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
195 debug_assert_eq!(expn_id, _eid);
196 expn_id
197 })
198 }
199
200 pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
201 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
202 let expn_hash = update_disambiguator(&mut expn_data, ctx);
203 HygieneData::with(|data| {
204 let expn_id = data.local_expn_data.push(Some(expn_data));
205 let _eid = data.local_expn_hashes.push(expn_hash);
206 debug_assert_eq!(expn_id, _eid);
207 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
208 debug_assert!(_old_id.is_none());
209 expn_id
210 })
211 }
212
213 #[inline]
214 pub fn expn_data(self) -> ExpnData {
215 HygieneData::with(|data| data.local_expn_data(self).clone())
216 }
217
218 #[inline]
219 pub fn to_expn_id(self) -> ExpnId {
220 ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
221 }
222
223 #[inline]
224 pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
225 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
226 let expn_hash = update_disambiguator(&mut expn_data, ctx);
227 HygieneData::with(|data| {
228 let old_expn_data = &mut data.local_expn_data[self];
229 assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
230 *old_expn_data = Some(expn_data);
231 debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
232 data.local_expn_hashes[self] = expn_hash;
233 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
234 debug_assert!(_old_id.is_none());
235 });
236 }
237
238 #[inline]
239 pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
240 self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
241 }
242
243 #[inline]
247 pub fn expansion_cause(self) -> Option<Span> {
248 self.to_expn_id().expansion_cause()
249 }
250}
251
252impl ExpnId {
253 pub const fn root() -> ExpnId {
256 ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
257 }
258
259 #[inline]
260 pub fn expn_hash(self) -> ExpnHash {
261 HygieneData::with(|data| data.expn_hash(self))
262 }
263
264 #[inline]
265 pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
266 HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
267 }
268
269 #[inline]
270 pub fn as_local(self) -> Option<LocalExpnId> {
271 if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
272 }
273
274 #[inline]
275 #[track_caller]
276 pub fn expect_local(self) -> LocalExpnId {
277 self.as_local().unwrap()
278 }
279
280 #[inline]
281 pub fn expn_data(self) -> ExpnData {
282 HygieneData::with(|data| data.expn_data(self).clone())
283 }
284
285 #[inline]
286 pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
287 if ancestor == ExpnId::root() || ancestor == self {
289 return true;
290 }
291 if ancestor.krate != self.krate {
292 return false;
293 }
294 HygieneData::with(|data| data.is_descendant_of(self, ancestor))
295 }
296
297 pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
300 HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
301 }
302
303 pub fn expansion_cause(mut self) -> Option<Span> {
307 let mut last_macro = None;
308 loop {
309 if self == ExpnId::root() {
311 break;
312 }
313 let expn_data = self.expn_data();
314 if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
316 break;
317 }
318 self = expn_data.call_site.ctxt().outer_expn();
319 last_macro = Some(expn_data.call_site);
320 }
321 last_macro
322 }
323}
324
325#[derive(Debug)]
326pub(crate) struct HygieneData {
327 local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
331 local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
332 foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
335 foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
336 expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
337 syntax_context_data: Vec<SyntaxContextData>,
338 syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
339 expn_data_disambiguators: UnhashMap<Hash64, u32>,
345}
346
347impl HygieneData {
348 pub(crate) fn new(edition: Edition) -> Self {
349 let root_data = ExpnData::default(
350 ExpnKind::Root,
351 DUMMY_SP,
352 edition,
353 Some(CRATE_DEF_ID.to_def_id()),
354 None,
355 );
356
357 HygieneData {
358 local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
359 local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
360 foreign_expn_data: FxHashMap::default(),
361 foreign_expn_hashes: FxHashMap::default(),
362 expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
363 .collect(),
364 syntax_context_data: vec![SyntaxContextData {
365 outer_expn: ExpnId::root(),
366 outer_transparency: Transparency::Opaque,
367 parent: SyntaxContext(0),
368 opaque: SyntaxContext(0),
369 opaque_and_semitransparent: SyntaxContext(0),
370 dollar_crate_name: kw::DollarCrate,
371 }],
372 syntax_context_map: FxHashMap::default(),
373 expn_data_disambiguators: UnhashMap::default(),
374 }
375 }
376
377 fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
378 with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
379 }
380
381 #[inline]
382 fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
383 match expn_id.as_local() {
384 Some(expn_id) => self.local_expn_hashes[expn_id],
385 None => self.foreign_expn_hashes[&expn_id],
386 }
387 }
388
389 fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
390 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
391 }
392
393 fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
394 if let Some(expn_id) = expn_id.as_local() {
395 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
396 } else {
397 &self.foreign_expn_data[&expn_id]
398 }
399 }
400
401 fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
402 if ancestor == ExpnId::root() {
404 return true;
405 }
406 if expn_id.krate != ancestor.krate {
407 return false;
408 }
409 loop {
410 if expn_id == ancestor {
411 return true;
412 }
413 if expn_id == ExpnId::root() {
414 return false;
415 }
416 expn_id = self.expn_data(expn_id).parent;
417 }
418 }
419
420 fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
421 self.syntax_context_data[ctxt.0 as usize].opaque
422 }
423
424 fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
425 self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
426 }
427
428 fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
429 self.syntax_context_data[ctxt.0 as usize].outer_expn
430 }
431
432 fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
433 let data = &self.syntax_context_data[ctxt.0 as usize];
434 (data.outer_expn, data.outer_transparency)
435 }
436
437 fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
438 self.syntax_context_data[ctxt.0 as usize].parent
439 }
440
441 fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) {
442 let outer_mark = self.outer_mark(*ctxt);
443 *ctxt = self.parent_ctxt(*ctxt);
444 outer_mark
445 }
446
447 fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
448 let mut marks = Vec::new();
449 while !ctxt.is_root() {
450 debug!("marks: getting parent of {:?}", ctxt);
451 marks.push(self.outer_mark(ctxt));
452 ctxt = self.parent_ctxt(ctxt);
453 }
454 marks.reverse();
455 marks
456 }
457
458 fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
459 let orig_span = span;
460 debug!("walk_chain({:?}, {:?})", span, to);
461 debug!("walk_chain: span ctxt = {:?}", span.ctxt());
462 while span.ctxt() != to && span.from_expansion() {
463 let outer_expn = self.outer_expn(span.ctxt());
464 debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
465 let expn_data = self.expn_data(outer_expn);
466 debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
467 span = expn_data.call_site;
468 }
469 debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
470 span
471 }
472
473 fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
474 let orig_span = span;
475 let mut ret_span = span;
476 debug!("walk_chain_collapsed({:?}, {:?})", span, to);
477 debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
478 while let ctxt = span.ctxt()
479 && !ctxt.is_root()
480 && ctxt != to.ctxt()
481 {
482 let outer_expn = self.outer_expn(ctxt);
483 debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
484 let expn_data = self.expn_data(outer_expn);
485 debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
486 span = expn_data.call_site;
487 if expn_data.collapse_debuginfo {
488 ret_span = span;
489 }
490 }
491 debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
492 ret_span
493 }
494
495 fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
496 let mut scope = None;
497 while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
498 scope = Some(self.remove_mark(ctxt).0);
499 }
500 scope
501 }
502
503 fn apply_mark(
504 &mut self,
505 ctxt: SyntaxContext,
506 expn_id: ExpnId,
507 transparency: Transparency,
508 ) -> SyntaxContext {
509 assert_ne!(expn_id, ExpnId::root());
510 if transparency == Transparency::Opaque {
511 return self.apply_mark_internal(ctxt, expn_id, transparency);
512 }
513
514 let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
515 let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
516 self.normalize_to_macros_2_0(call_site_ctxt)
517 } else {
518 self.normalize_to_macro_rules(call_site_ctxt)
519 };
520
521 if call_site_ctxt.is_root() {
522 return self.apply_mark_internal(ctxt, expn_id, transparency);
523 }
524
525 for (expn_id, transparency) in self.marks(ctxt) {
535 call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency);
536 }
537 self.apply_mark_internal(call_site_ctxt, expn_id, transparency)
538 }
539
540 fn apply_mark_internal(
541 &mut self,
542 ctxt: SyntaxContext,
543 expn_id: ExpnId,
544 transparency: Transparency,
545 ) -> SyntaxContext {
546 let syntax_context_data = &mut self.syntax_context_data;
547 let mut opaque = syntax_context_data[ctxt.0 as usize].opaque;
548 let mut opaque_and_semitransparent =
549 syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent;
550
551 if transparency >= Transparency::Opaque {
552 let parent = opaque;
553 opaque = *self
554 .syntax_context_map
555 .entry((parent, expn_id, transparency))
556 .or_insert_with(|| {
557 let new_opaque = SyntaxContext(syntax_context_data.len() as u32);
558 syntax_context_data.push(SyntaxContextData {
559 outer_expn: expn_id,
560 outer_transparency: transparency,
561 parent,
562 opaque: new_opaque,
563 opaque_and_semitransparent: new_opaque,
564 dollar_crate_name: kw::DollarCrate,
565 });
566 new_opaque
567 });
568 }
569
570 if transparency >= Transparency::SemiTransparent {
571 let parent = opaque_and_semitransparent;
572 opaque_and_semitransparent = *self
573 .syntax_context_map
574 .entry((parent, expn_id, transparency))
575 .or_insert_with(|| {
576 let new_opaque_and_semitransparent =
577 SyntaxContext(syntax_context_data.len() as u32);
578 syntax_context_data.push(SyntaxContextData {
579 outer_expn: expn_id,
580 outer_transparency: transparency,
581 parent,
582 opaque,
583 opaque_and_semitransparent: new_opaque_and_semitransparent,
584 dollar_crate_name: kw::DollarCrate,
585 });
586 new_opaque_and_semitransparent
587 });
588 }
589
590 let parent = ctxt;
591 *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| {
592 let new_opaque_and_semitransparent_and_transparent =
593 SyntaxContext(syntax_context_data.len() as u32);
594 syntax_context_data.push(SyntaxContextData {
595 outer_expn: expn_id,
596 outer_transparency: transparency,
597 parent,
598 opaque,
599 opaque_and_semitransparent,
600 dollar_crate_name: kw::DollarCrate,
601 });
602 new_opaque_and_semitransparent_and_transparent
603 })
604 }
605}
606
607pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
608 HygieneData::with(|data| data.walk_chain(span, to))
609}
610
611pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
617 HygieneData::with(|data| data.walk_chain_collapsed(span, to))
618}
619
620pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
621 let (len, to_update) = HygieneData::with(|data| {
623 (
624 data.syntax_context_data.len(),
625 data.syntax_context_data
626 .iter()
627 .rev()
628 .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate)
629 .count(),
630 )
631 });
632 let range_to_update = len - to_update..len;
635 let names: Vec<_> =
636 range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
637 HygieneData::with(|data| {
638 range_to_update.zip(names).for_each(|(idx, name)| {
639 data.syntax_context_data[idx].dollar_crate_name = name;
640 })
641 })
642}
643
644pub fn debug_hygiene_data(verbose: bool) -> String {
645 HygieneData::with(|data| {
646 if verbose {
647 format!("{data:#?}")
648 } else {
649 let mut s = String::from("Expansions:");
650 let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
651 s.push_str(&format!(
652 "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
653 id,
654 expn_data.parent,
655 expn_data.call_site.ctxt(),
656 expn_data.def_site.ctxt(),
657 expn_data.kind,
658 ))
659 };
660 data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
661 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
662 debug_expn_data((&id.to_expn_id(), expn_data))
663 });
664
665 #[allow(rustc::potential_query_instability)]
668 let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
669 foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
670 foreign_expn_data.into_iter().for_each(debug_expn_data);
671 s.push_str("\n\nSyntaxContexts:");
672 data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
673 s.push_str(&format!(
674 "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
675 id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
676 ));
677 });
678 s
679 }
680 })
681}
682
683impl SyntaxContext {
684 #[inline]
685 pub const fn root() -> Self {
686 SyntaxContext(0)
687 }
688
689 #[inline]
690 pub const fn is_root(self) -> bool {
691 self.0 == SyntaxContext::root().as_u32()
692 }
693
694 #[inline]
695 pub(crate) const fn as_u32(self) -> u32 {
696 self.0
697 }
698
699 #[inline]
700 pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
701 SyntaxContext(raw)
702 }
703
704 #[inline]
705 pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
706 SyntaxContext(raw as u32)
707 }
708
709 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
711 HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
712 }
713
714 pub fn remove_mark(&mut self) -> ExpnId {
731 HygieneData::with(|data| data.remove_mark(self).0)
732 }
733
734 pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
735 HygieneData::with(|data| data.marks(self))
736 }
737
738 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
764 HygieneData::with(|data| data.adjust(self, expn_id))
765 }
766
767 pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
769 HygieneData::with(|data| {
770 *self = data.normalize_to_macros_2_0(*self);
771 data.adjust(self, expn_id)
772 })
773 }
774
775 pub(crate) fn glob_adjust(
802 &mut self,
803 expn_id: ExpnId,
804 glob_span: Span,
805 ) -> Option<Option<ExpnId>> {
806 HygieneData::with(|data| {
807 let mut scope = None;
808 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
809 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
810 scope = Some(data.remove_mark(&mut glob_ctxt).0);
811 if data.remove_mark(self).0 != scope.unwrap() {
812 return None;
813 }
814 }
815 if data.adjust(self, expn_id).is_some() {
816 return None;
817 }
818 Some(scope)
819 })
820 }
821
822 pub(crate) fn reverse_glob_adjust(
830 &mut self,
831 expn_id: ExpnId,
832 glob_span: Span,
833 ) -> Option<Option<ExpnId>> {
834 HygieneData::with(|data| {
835 if data.adjust(self, expn_id).is_some() {
836 return None;
837 }
838
839 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
840 let mut marks = Vec::new();
841 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
842 marks.push(data.remove_mark(&mut glob_ctxt));
843 }
844
845 let scope = marks.last().map(|mark| mark.0);
846 while let Some((expn_id, transparency)) = marks.pop() {
847 *self = data.apply_mark(*self, expn_id, transparency);
848 }
849 Some(scope)
850 })
851 }
852
853 pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool {
854 HygieneData::with(|data| {
855 let mut self_normalized = data.normalize_to_macros_2_0(self);
856 data.adjust(&mut self_normalized, expn_id);
857 self_normalized == data.normalize_to_macros_2_0(other)
858 })
859 }
860
861 #[inline]
862 pub fn normalize_to_macros_2_0(self) -> SyntaxContext {
863 HygieneData::with(|data| data.normalize_to_macros_2_0(self))
864 }
865
866 #[inline]
867 pub fn normalize_to_macro_rules(self) -> SyntaxContext {
868 HygieneData::with(|data| data.normalize_to_macro_rules(self))
869 }
870
871 #[inline]
872 pub fn outer_expn(self) -> ExpnId {
873 HygieneData::with(|data| data.outer_expn(self))
874 }
875
876 #[inline]
879 pub fn outer_expn_data(self) -> ExpnData {
880 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
881 }
882
883 #[inline]
884 fn outer_mark(self) -> (ExpnId, Transparency) {
885 HygieneData::with(|data| data.outer_mark(self))
886 }
887
888 pub(crate) fn dollar_crate_name(self) -> Symbol {
889 HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
890 }
891
892 pub fn edition(self) -> Edition {
893 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
894 }
895}
896
897impl fmt::Debug for SyntaxContext {
898 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
899 write!(f, "#{}", self.0)
900 }
901}
902
903impl Span {
904 pub fn mark_with_reason(
907 self,
908 allow_internal_unstable: Option<Arc<[Symbol]>>,
909 reason: DesugaringKind,
910 edition: Edition,
911 ctx: impl HashStableContext,
912 ) -> Span {
913 let expn_data = ExpnData {
914 allow_internal_unstable,
915 ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
916 };
917 let expn_id = LocalExpnId::fresh(expn_data, ctx);
918 self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
919 }
920}
921
922#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
925pub struct ExpnData {
926 pub kind: ExpnKind,
929 pub parent: ExpnId,
931 pub call_site: Span,
941 disambiguator: u32,
952
953 pub def_site: Span,
960 pub allow_internal_unstable: Option<Arc<[Symbol]>>,
964 pub edition: Edition,
966 pub macro_def_id: Option<DefId>,
969 pub parent_module: Option<DefId>,
971 pub(crate) allow_internal_unsafe: bool,
973 pub local_inner_macros: bool,
975 pub(crate) collapse_debuginfo: bool,
978}
979
980impl !PartialEq for ExpnData {}
981impl !Hash for ExpnData {}
982
983impl ExpnData {
984 pub fn new(
985 kind: ExpnKind,
986 parent: ExpnId,
987 call_site: Span,
988 def_site: Span,
989 allow_internal_unstable: Option<Arc<[Symbol]>>,
990 edition: Edition,
991 macro_def_id: Option<DefId>,
992 parent_module: Option<DefId>,
993 allow_internal_unsafe: bool,
994 local_inner_macros: bool,
995 collapse_debuginfo: bool,
996 ) -> ExpnData {
997 ExpnData {
998 kind,
999 parent,
1000 call_site,
1001 def_site,
1002 allow_internal_unstable,
1003 edition,
1004 macro_def_id,
1005 parent_module,
1006 disambiguator: 0,
1007 allow_internal_unsafe,
1008 local_inner_macros,
1009 collapse_debuginfo,
1010 }
1011 }
1012
1013 pub fn default(
1015 kind: ExpnKind,
1016 call_site: Span,
1017 edition: Edition,
1018 macro_def_id: Option<DefId>,
1019 parent_module: Option<DefId>,
1020 ) -> ExpnData {
1021 ExpnData {
1022 kind,
1023 parent: ExpnId::root(),
1024 call_site,
1025 def_site: DUMMY_SP,
1026 allow_internal_unstable: None,
1027 edition,
1028 macro_def_id,
1029 parent_module,
1030 disambiguator: 0,
1031 allow_internal_unsafe: false,
1032 local_inner_macros: false,
1033 collapse_debuginfo: false,
1034 }
1035 }
1036
1037 pub fn allow_unstable(
1038 kind: ExpnKind,
1039 call_site: Span,
1040 edition: Edition,
1041 allow_internal_unstable: Arc<[Symbol]>,
1042 macro_def_id: Option<DefId>,
1043 parent_module: Option<DefId>,
1044 ) -> ExpnData {
1045 ExpnData {
1046 allow_internal_unstable: Some(allow_internal_unstable),
1047 ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1048 }
1049 }
1050
1051 #[inline]
1052 pub fn is_root(&self) -> bool {
1053 matches!(self.kind, ExpnKind::Root)
1054 }
1055
1056 #[inline]
1057 fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1058 let mut hasher = StableHasher::new();
1059 self.hash_stable(ctx, &mut hasher);
1060 hasher.finish()
1061 }
1062}
1063
1064#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1066pub enum ExpnKind {
1067 Root,
1069 Macro(MacroKind, Symbol),
1071 AstPass(AstPass),
1073 Desugaring(DesugaringKind),
1075}
1076
1077impl ExpnKind {
1078 pub fn descr(&self) -> String {
1079 match *self {
1080 ExpnKind::Root => kw::PathRoot.to_string(),
1081 ExpnKind::Macro(macro_kind, name) => match macro_kind {
1082 MacroKind::Bang => format!("{name}!"),
1083 MacroKind::Attr => format!("#[{name}]"),
1084 MacroKind::Derive => format!("#[derive({name})]"),
1085 },
1086 ExpnKind::AstPass(kind) => kind.descr().to_string(),
1087 ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1088 }
1089 }
1090}
1091
1092#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
1094#[derive(HashStable_Generic)]
1095pub enum MacroKind {
1096 Bang,
1098 Attr,
1100 Derive,
1102}
1103
1104impl MacroKind {
1105 pub fn descr(self) -> &'static str {
1106 match self {
1107 MacroKind::Bang => "macro",
1108 MacroKind::Attr => "attribute macro",
1109 MacroKind::Derive => "derive macro",
1110 }
1111 }
1112
1113 pub fn descr_expected(self) -> &'static str {
1114 match self {
1115 MacroKind::Attr => "attribute",
1116 _ => self.descr(),
1117 }
1118 }
1119
1120 pub fn article(self) -> &'static str {
1121 match self {
1122 MacroKind::Attr => "an",
1123 _ => "a",
1124 }
1125 }
1126}
1127
1128#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1130pub enum AstPass {
1131 StdImports,
1132 TestHarness,
1133 ProcMacroHarness,
1134}
1135
1136impl AstPass {
1137 pub fn descr(self) -> &'static str {
1138 match self {
1139 AstPass::StdImports => "standard library imports",
1140 AstPass::TestHarness => "test harness",
1141 AstPass::ProcMacroHarness => "proc macro harness",
1142 }
1143 }
1144}
1145
1146#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1148pub enum DesugaringKind {
1149 CondTemporary,
1154 QuestionMark,
1155 TryBlock,
1156 YeetExpr,
1157 OpaqueTy,
1161 Async,
1162 Await,
1163 ForLoop,
1164 WhileLoop,
1165 BoundModifier,
1167 Contract,
1169}
1170
1171impl DesugaringKind {
1172 pub fn descr(self) -> &'static str {
1174 match self {
1175 DesugaringKind::CondTemporary => "`if` or `while` condition",
1176 DesugaringKind::Async => "`async` block or function",
1177 DesugaringKind::Await => "`await` expression",
1178 DesugaringKind::QuestionMark => "operator `?`",
1179 DesugaringKind::TryBlock => "`try` block",
1180 DesugaringKind::YeetExpr => "`do yeet` expression",
1181 DesugaringKind::OpaqueTy => "`impl Trait`",
1182 DesugaringKind::ForLoop => "`for` loop",
1183 DesugaringKind::WhileLoop => "`while` loop",
1184 DesugaringKind::BoundModifier => "trait bound modifier",
1185 DesugaringKind::Contract => "contract check",
1186 }
1187 }
1188}
1189
1190#[derive(Default)]
1191pub struct HygieneEncodeContext {
1192 serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1196 latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1201
1202 serialized_expns: Lock<FxHashSet<ExpnId>>,
1203
1204 latest_expns: Lock<FxHashSet<ExpnId>>,
1205}
1206
1207impl HygieneEncodeContext {
1208 pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1210 if !self.serialized_expns.lock().contains(&expn) {
1211 self.latest_expns.lock().insert(expn);
1212 }
1213 }
1214
1215 pub fn encode<T>(
1216 &self,
1217 encoder: &mut T,
1218 mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData),
1219 mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1220 ) {
1221 while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1224 debug!(
1225 "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1226 self.latest_ctxts.lock().len(),
1227 self.latest_ctxts
1228 );
1229
1230 let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) };
1233
1234 #[allow(rustc::potential_query_instability)]
1238 for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
1239 if self.serialized_ctxts.lock().insert(ctxt) {
1240 encode_ctxt(encoder, index, data);
1241 }
1242 });
1243
1244 let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
1245
1246 #[allow(rustc::potential_query_instability)]
1248 for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
1249 if self.serialized_expns.lock().insert(expn) {
1250 encode_expn(encoder, expn, data, hash);
1251 }
1252 });
1253 }
1254 debug!("encode_hygiene: Done serializing SyntaxContextData");
1255 }
1256}
1257
1258#[derive(Default)]
1259struct HygieneDecodeContextInner {
1261 remapped_ctxts: Vec<Option<SyntaxContext>>,
1267
1268 decoding: FxHashMap<u32, SyntaxContext>,
1270}
1271
1272#[derive(Default)]
1273pub struct HygieneDecodeContext {
1275 inner: Lock<HygieneDecodeContextInner>,
1276
1277 local_in_progress: WorkerLocal<RefCell<FxHashSet<u32>>>,
1279}
1280
1281pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1283 HygieneData::with(|hygiene_data| {
1284 let expn_id = hygiene_data.local_expn_data.next_index();
1285 hygiene_data.local_expn_data.push(Some(data));
1286 let _eid = hygiene_data.local_expn_hashes.push(hash);
1287 debug_assert_eq!(expn_id, _eid);
1288
1289 let expn_id = expn_id.to_expn_id();
1290
1291 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1292 debug_assert!(_old_id.is_none());
1293 expn_id
1294 })
1295}
1296
1297pub fn register_expn_id(
1299 krate: CrateNum,
1300 local_id: ExpnIndex,
1301 data: ExpnData,
1302 hash: ExpnHash,
1303) -> ExpnId {
1304 debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1305 let expn_id = ExpnId { krate, local_id };
1306 HygieneData::with(|hygiene_data| {
1307 let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1308 let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1309 debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1310 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1311 debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1312 });
1313 expn_id
1314}
1315
1316pub fn decode_expn_id(
1318 krate: CrateNum,
1319 index: u32,
1320 decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1321) -> ExpnId {
1322 if index == 0 {
1323 trace!("decode_expn_id: deserialized root");
1324 return ExpnId::root();
1325 }
1326
1327 let index = ExpnIndex::from_u32(index);
1328
1329 debug_assert_ne!(krate, LOCAL_CRATE);
1331 let expn_id = ExpnId { krate, local_id: index };
1332
1333 if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1335 return expn_id;
1336 }
1337
1338 let (expn_data, hash) = decode_data(expn_id);
1341
1342 register_expn_id(krate, index, expn_data, hash)
1343}
1344
1345pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
1350 d: &mut D,
1351 context: &HygieneDecodeContext,
1352 decode_data: F,
1353) -> SyntaxContext {
1354 let raw_id: u32 = Decodable::decode(d);
1355 if raw_id == 0 {
1356 trace!("decode_syntax_context: deserialized root");
1357 return SyntaxContext::root();
1359 }
1360
1361 let ctxt = {
1362 let mut inner = context.inner.lock();
1363
1364 if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() {
1365 return ctxt;
1367 }
1368
1369 match inner.decoding.entry(raw_id) {
1370 Entry::Occupied(ctxt_entry) => {
1371 match context.local_in_progress.borrow_mut().entry(raw_id) {
1372 SetEntry::Occupied(..) => {
1373 return *ctxt_entry.get();
1377 }
1378 SetEntry::Vacant(entry) => {
1379 entry.insert();
1380
1381 *ctxt_entry.get()
1383 }
1384 }
1385 }
1386 Entry::Vacant(entry) => {
1387 context.local_in_progress.borrow_mut().insert(raw_id);
1389
1390 let new_ctxt = HygieneData::with(|hygiene_data| {
1393 let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32);
1394 hygiene_data.syntax_context_data.push(SyntaxContextData {
1397 outer_expn: ExpnId::root(),
1398 outer_transparency: Transparency::Transparent,
1399 parent: SyntaxContext::root(),
1400 opaque: SyntaxContext::root(),
1401 opaque_and_semitransparent: SyntaxContext::root(),
1402 dollar_crate_name: kw::Empty,
1403 });
1404 new_ctxt
1405 });
1406 entry.insert(new_ctxt);
1407 new_ctxt
1408 }
1409 }
1410 };
1411
1412 let mut ctxt_data = decode_data(d, raw_id);
1415 ctxt_data.dollar_crate_name = kw::DollarCrate;
1419
1420 HygieneData::with(|hygiene_data| {
1422 if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
1423 && old.outer_expn == ctxt_data.outer_expn
1424 && old.outer_transparency == ctxt_data.outer_transparency
1425 && old.parent == ctxt_data.parent
1426 {
1427 ctxt_data = old.clone();
1428 }
1429
1430 hygiene_data.syntax_context_data[ctxt.as_u32() as usize] = ctxt_data;
1431 });
1432
1433 context.local_in_progress.borrow_mut().remove(&raw_id);
1436
1437 let mut inner = context.inner.lock();
1438 let new_len = raw_id as usize + 1;
1439 if inner.remapped_ctxts.len() < new_len {
1440 inner.remapped_ctxts.resize(new_len, None);
1441 }
1442 inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
1443 inner.decoding.remove(&raw_id);
1444
1445 ctxt
1446}
1447
1448fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextData)>(
1449 ctxts: impl Iterator<Item = SyntaxContext>,
1450 mut f: F,
1451) {
1452 let all_data: Vec<_> = HygieneData::with(|data| {
1453 ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
1454 });
1455 for (ctxt, data) in all_data.into_iter() {
1456 f(ctxt.0, ctxt, &data);
1457 }
1458}
1459
1460fn for_all_expns_in(
1461 expns: impl Iterator<Item = ExpnId>,
1462 mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
1463) {
1464 let all_data: Vec<_> = HygieneData::with(|data| {
1465 expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
1466 });
1467 for (expn, data, hash) in all_data.into_iter() {
1468 f(expn, &data, hash);
1469 }
1470}
1471
1472impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1473 fn encode(&self, e: &mut E) {
1474 self.to_expn_id().encode(e);
1475 }
1476}
1477
1478impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1479 fn decode(d: &mut D) -> Self {
1480 ExpnId::expect_local(ExpnId::decode(d))
1481 }
1482}
1483
1484pub fn raw_encode_syntax_context<E: Encoder>(
1485 ctxt: SyntaxContext,
1486 context: &HygieneEncodeContext,
1487 e: &mut E,
1488) {
1489 if !context.serialized_ctxts.lock().contains(&ctxt) {
1490 context.latest_ctxts.lock().insert(ctxt);
1491 }
1492 ctxt.0.encode(e);
1493}
1494
1495fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1505 assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1507 assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1508 let mut expn_hash = expn_data.hash_expn(&mut ctx);
1509
1510 let disambiguator = HygieneData::with(|data| {
1511 let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1514 let disambiguator = *disambig;
1515 *disambig += 1;
1516 disambiguator
1517 });
1518
1519 if disambiguator != 0 {
1520 debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1521
1522 expn_data.disambiguator = disambiguator;
1523 expn_hash = expn_data.hash_expn(&mut ctx);
1524
1525 #[cfg(debug_assertions)]
1527 HygieneData::with(|data| {
1528 assert_eq!(
1529 data.expn_data_disambiguators.get(&expn_hash),
1530 None,
1531 "Hash collision after disambiguator update!",
1532 );
1533 });
1534 }
1535
1536 ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1537}
1538
1539impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1540 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1541 const TAG_EXPANSION: u8 = 0;
1542 const TAG_NO_EXPANSION: u8 = 1;
1543
1544 if self.is_root() {
1545 TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1546 } else {
1547 TAG_EXPANSION.hash_stable(ctx, hasher);
1548 let (expn_id, transparency) = self.outer_mark();
1549 expn_id.hash_stable(ctx, hasher);
1550 transparency.hash_stable(ctx, hasher);
1551 }
1552 }
1553}
1554
1555impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1556 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1557 assert_default_hashing_controls(ctx, "ExpnId");
1558 let hash = if *self == ExpnId::root() {
1559 Fingerprint::ZERO
1561 } else {
1562 self.expn_hash().0
1563 };
1564
1565 hash.hash_stable(ctx, hasher);
1566 }
1567}