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::{HashStable, HashingControls, StableHasher};
37use rustc_data_structures::sync::{Lock, WorkerLocal};
38use rustc_data_structures::unhash::UnhashMap;
39use rustc_hashes::Hash64;
40use rustc_index::IndexVec;
41use rustc_macros::{Decodable, Encodable, HashStable_Generic};
42use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
43use tracing::{debug, trace};
44
45use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId};
46use crate::edition::Edition;
47use crate::symbol::{Symbol, kw, sym};
48use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
49
50#[derive(Clone, Copy, PartialEq, Eq, Hash)]
52pub struct SyntaxContext(u32);
53
54impl !Ord for SyntaxContext {}
58impl !PartialOrd for SyntaxContext {}
59
60#[derive(Debug, Encodable, Decodable, Clone)]
61pub struct SyntaxContextData {
62 outer_expn: ExpnId,
63 outer_transparency: Transparency,
64 parent: SyntaxContext,
65 opaque: SyntaxContext,
67 opaque_and_semitransparent: SyntaxContext,
69 dollar_crate_name: Symbol,
71}
72
73rustc_index::newtype_index! {
74 #[orderable]
76 pub struct ExpnIndex {}
77}
78
79#[derive(Clone, Copy, PartialEq, Eq, Hash)]
81pub struct ExpnId {
82 pub krate: CrateNum,
83 pub local_id: ExpnIndex,
84}
85
86impl fmt::Debug for ExpnId {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
90 }
91}
92
93rustc_index::newtype_index! {
94 #[debug_format = "expn{}"]
96 pub struct LocalExpnId {}
97}
98
99impl !Ord for LocalExpnId {}
103impl !PartialOrd for LocalExpnId {}
104
105fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
111 match ctx.hashing_controls() {
112 HashingControls { hash_spans }
121 if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
122 other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
123 }
124}
125
126#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
128pub struct ExpnHash(Fingerprint);
129
130impl ExpnHash {
131 #[inline]
134 pub fn stable_crate_id(self) -> StableCrateId {
135 StableCrateId(self.0.split().0)
136 }
137
138 #[inline]
142 pub fn local_hash(self) -> Hash64 {
143 self.0.split().1
144 }
145
146 #[inline]
147 pub fn is_root(self) -> bool {
148 self.0 == Fingerprint::ZERO
149 }
150
151 fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
154 ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
155 }
156}
157
158#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
161#[derive(HashStable_Generic)]
162pub enum Transparency {
163 Transparent,
166 SemiTransparent,
173 Opaque,
176}
177
178impl Transparency {
179 pub fn fallback(macro_rules: bool) -> Self {
180 if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }
181 }
182}
183
184impl LocalExpnId {
185 pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
187
188 #[inline]
189 fn from_raw(idx: ExpnIndex) -> LocalExpnId {
190 LocalExpnId::from_u32(idx.as_u32())
191 }
192
193 #[inline]
194 pub fn as_raw(self) -> ExpnIndex {
195 ExpnIndex::from_u32(self.as_u32())
196 }
197
198 pub fn fresh_empty() -> LocalExpnId {
199 HygieneData::with(|data| {
200 let expn_id = data.local_expn_data.push(None);
201 let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
202 debug_assert_eq!(expn_id, _eid);
203 expn_id
204 })
205 }
206
207 pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
208 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
209 let expn_hash = update_disambiguator(&mut expn_data, ctx);
210 HygieneData::with(|data| {
211 let expn_id = data.local_expn_data.push(Some(expn_data));
212 let _eid = data.local_expn_hashes.push(expn_hash);
213 debug_assert_eq!(expn_id, _eid);
214 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
215 debug_assert!(_old_id.is_none());
216 expn_id
217 })
218 }
219
220 #[inline]
221 pub fn expn_data(self) -> ExpnData {
222 HygieneData::with(|data| data.local_expn_data(self).clone())
223 }
224
225 #[inline]
226 pub fn to_expn_id(self) -> ExpnId {
227 ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
228 }
229
230 #[inline]
231 pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
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 old_expn_data = &mut data.local_expn_data[self];
236 assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
237 *old_expn_data = Some(expn_data);
238 debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
239 data.local_expn_hashes[self] = expn_hash;
240 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
241 debug_assert!(_old_id.is_none());
242 });
243 }
244
245 #[inline]
246 pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
247 self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
248 }
249
250 #[inline]
254 pub fn expansion_cause(self) -> Option<Span> {
255 self.to_expn_id().expansion_cause()
256 }
257}
258
259impl ExpnId {
260 pub const fn root() -> ExpnId {
263 ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
264 }
265
266 #[inline]
267 pub fn expn_hash(self) -> ExpnHash {
268 HygieneData::with(|data| data.expn_hash(self))
269 }
270
271 #[inline]
272 pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
273 HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
274 }
275
276 #[inline]
277 pub fn as_local(self) -> Option<LocalExpnId> {
278 if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
279 }
280
281 #[inline]
282 #[track_caller]
283 pub fn expect_local(self) -> LocalExpnId {
284 self.as_local().unwrap()
285 }
286
287 #[inline]
288 pub fn expn_data(self) -> ExpnData {
289 HygieneData::with(|data| data.expn_data(self).clone())
290 }
291
292 #[inline]
293 pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
294 if ancestor == ExpnId::root() || ancestor == self {
296 return true;
297 }
298 if ancestor.krate != self.krate {
299 return false;
300 }
301 HygieneData::with(|data| data.is_descendant_of(self, ancestor))
302 }
303
304 pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
307 HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
308 }
309
310 pub fn expansion_cause(mut self) -> Option<Span> {
314 let mut last_macro = None;
315 loop {
316 if self == ExpnId::root() {
318 break;
319 }
320 let expn_data = self.expn_data();
321 if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
323 break;
324 }
325 self = expn_data.call_site.ctxt().outer_expn();
326 last_macro = Some(expn_data.call_site);
327 }
328 last_macro
329 }
330}
331
332#[derive(Debug)]
333pub(crate) struct HygieneData {
334 local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
338 local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
339 foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
342 foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
343 expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
344 syntax_context_data: Vec<SyntaxContextData>,
345 syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
346 expn_data_disambiguators: UnhashMap<Hash64, u32>,
352}
353
354impl HygieneData {
355 pub(crate) fn new(edition: Edition) -> Self {
356 let root_data = ExpnData::default(
357 ExpnKind::Root,
358 DUMMY_SP,
359 edition,
360 Some(CRATE_DEF_ID.to_def_id()),
361 None,
362 );
363
364 HygieneData {
365 local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
366 local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
367 foreign_expn_data: FxHashMap::default(),
368 foreign_expn_hashes: FxHashMap::default(),
369 expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
370 .collect(),
371 syntax_context_data: vec![SyntaxContextData {
372 outer_expn: ExpnId::root(),
373 outer_transparency: Transparency::Opaque,
374 parent: SyntaxContext(0),
375 opaque: SyntaxContext(0),
376 opaque_and_semitransparent: SyntaxContext(0),
377 dollar_crate_name: kw::DollarCrate,
378 }],
379 syntax_context_map: FxHashMap::default(),
380 expn_data_disambiguators: UnhashMap::default(),
381 }
382 }
383
384 fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
385 with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
386 }
387
388 #[inline]
389 fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
390 match expn_id.as_local() {
391 Some(expn_id) => self.local_expn_hashes[expn_id],
392 None => self.foreign_expn_hashes[&expn_id],
393 }
394 }
395
396 fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
397 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
398 }
399
400 fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
401 if let Some(expn_id) = expn_id.as_local() {
402 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
403 } else {
404 &self.foreign_expn_data[&expn_id]
405 }
406 }
407
408 fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
409 if ancestor == ExpnId::root() {
411 return true;
412 }
413 if expn_id.krate != ancestor.krate {
414 return false;
415 }
416 loop {
417 if expn_id == ancestor {
418 return true;
419 }
420 if expn_id == ExpnId::root() {
421 return false;
422 }
423 expn_id = self.expn_data(expn_id).parent;
424 }
425 }
426
427 fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
428 self.syntax_context_data[ctxt.0 as usize].opaque
429 }
430
431 fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
432 self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
433 }
434
435 fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
436 self.syntax_context_data[ctxt.0 as usize].outer_expn
437 }
438
439 fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
440 let data = &self.syntax_context_data[ctxt.0 as usize];
441 (data.outer_expn, data.outer_transparency)
442 }
443
444 fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
445 self.syntax_context_data[ctxt.0 as usize].parent
446 }
447
448 fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) {
449 let outer_mark = self.outer_mark(*ctxt);
450 *ctxt = self.parent_ctxt(*ctxt);
451 outer_mark
452 }
453
454 fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
455 let mut marks = Vec::new();
456 while !ctxt.is_root() {
457 debug!("marks: getting parent of {:?}", ctxt);
458 marks.push(self.outer_mark(ctxt));
459 ctxt = self.parent_ctxt(ctxt);
460 }
461 marks.reverse();
462 marks
463 }
464
465 fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
466 let orig_span = span;
467 debug!("walk_chain({:?}, {:?})", span, to);
468 debug!("walk_chain: span ctxt = {:?}", span.ctxt());
469 while span.ctxt() != to && span.from_expansion() {
470 let outer_expn = self.outer_expn(span.ctxt());
471 debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
472 let expn_data = self.expn_data(outer_expn);
473 debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
474 span = expn_data.call_site;
475 }
476 debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
477 span
478 }
479
480 fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
481 let orig_span = span;
482 let mut ret_span = span;
483 debug!("walk_chain_collapsed({:?}, {:?})", span, to);
484 debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
485 while let ctxt = span.ctxt()
486 && !ctxt.is_root()
487 && ctxt != to.ctxt()
488 {
489 let outer_expn = self.outer_expn(ctxt);
490 debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
491 let expn_data = self.expn_data(outer_expn);
492 debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
493 span = expn_data.call_site;
494 if expn_data.collapse_debuginfo {
495 ret_span = span;
496 }
497 }
498 debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
499 ret_span
500 }
501
502 fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
503 let mut scope = None;
504 while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
505 scope = Some(self.remove_mark(ctxt).0);
506 }
507 scope
508 }
509
510 fn apply_mark(
511 &mut self,
512 ctxt: SyntaxContext,
513 expn_id: ExpnId,
514 transparency: Transparency,
515 ) -> SyntaxContext {
516 assert_ne!(expn_id, ExpnId::root());
517 if transparency == Transparency::Opaque {
518 return self.apply_mark_internal(ctxt, expn_id, transparency);
519 }
520
521 let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
522 let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
523 self.normalize_to_macros_2_0(call_site_ctxt)
524 } else {
525 self.normalize_to_macro_rules(call_site_ctxt)
526 };
527
528 if call_site_ctxt.is_root() {
529 return self.apply_mark_internal(ctxt, expn_id, transparency);
530 }
531
532 for (expn_id, transparency) in self.marks(ctxt) {
542 call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency);
543 }
544 self.apply_mark_internal(call_site_ctxt, expn_id, transparency)
545 }
546
547 fn apply_mark_internal(
548 &mut self,
549 ctxt: SyntaxContext,
550 expn_id: ExpnId,
551 transparency: Transparency,
552 ) -> SyntaxContext {
553 let syntax_context_data = &mut self.syntax_context_data;
554 let mut opaque = syntax_context_data[ctxt.0 as usize].opaque;
555 let mut opaque_and_semitransparent =
556 syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent;
557
558 if transparency >= Transparency::Opaque {
559 let parent = opaque;
560 opaque = *self
561 .syntax_context_map
562 .entry((parent, expn_id, transparency))
563 .or_insert_with(|| {
564 let new_opaque = SyntaxContext(syntax_context_data.len() as u32);
565 syntax_context_data.push(SyntaxContextData {
566 outer_expn: expn_id,
567 outer_transparency: transparency,
568 parent,
569 opaque: new_opaque,
570 opaque_and_semitransparent: new_opaque,
571 dollar_crate_name: kw::DollarCrate,
572 });
573 new_opaque
574 });
575 }
576
577 if transparency >= Transparency::SemiTransparent {
578 let parent = opaque_and_semitransparent;
579 opaque_and_semitransparent = *self
580 .syntax_context_map
581 .entry((parent, expn_id, transparency))
582 .or_insert_with(|| {
583 let new_opaque_and_semitransparent =
584 SyntaxContext(syntax_context_data.len() as u32);
585 syntax_context_data.push(SyntaxContextData {
586 outer_expn: expn_id,
587 outer_transparency: transparency,
588 parent,
589 opaque,
590 opaque_and_semitransparent: new_opaque_and_semitransparent,
591 dollar_crate_name: kw::DollarCrate,
592 });
593 new_opaque_and_semitransparent
594 });
595 }
596
597 let parent = ctxt;
598 *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| {
599 let new_opaque_and_semitransparent_and_transparent =
600 SyntaxContext(syntax_context_data.len() as u32);
601 syntax_context_data.push(SyntaxContextData {
602 outer_expn: expn_id,
603 outer_transparency: transparency,
604 parent,
605 opaque,
606 opaque_and_semitransparent,
607 dollar_crate_name: kw::DollarCrate,
608 });
609 new_opaque_and_semitransparent_and_transparent
610 })
611 }
612}
613
614pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
615 HygieneData::with(|data| data.walk_chain(span, to))
616}
617
618pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
624 HygieneData::with(|data| data.walk_chain_collapsed(span, to))
625}
626
627pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
628 let (len, to_update) = HygieneData::with(|data| {
630 (
631 data.syntax_context_data.len(),
632 data.syntax_context_data
633 .iter()
634 .rev()
635 .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate)
636 .count(),
637 )
638 });
639 let range_to_update = len - to_update..len;
642 let names: Vec<_> =
643 range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
644 HygieneData::with(|data| {
645 range_to_update.zip(names).for_each(|(idx, name)| {
646 data.syntax_context_data[idx].dollar_crate_name = name;
647 })
648 })
649}
650
651pub fn debug_hygiene_data(verbose: bool) -> String {
652 HygieneData::with(|data| {
653 if verbose {
654 format!("{data:#?}")
655 } else {
656 let mut s = String::from("Expansions:");
657 let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
658 s.push_str(&format!(
659 "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
660 id,
661 expn_data.parent,
662 expn_data.call_site.ctxt(),
663 expn_data.def_site.ctxt(),
664 expn_data.kind,
665 ))
666 };
667 data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
668 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
669 debug_expn_data((&id.to_expn_id(), expn_data))
670 });
671
672 #[allow(rustc::potential_query_instability)]
675 let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
676 foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
677 foreign_expn_data.into_iter().for_each(debug_expn_data);
678 s.push_str("\n\nSyntaxContexts:");
679 data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
680 s.push_str(&format!(
681 "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
682 id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
683 ));
684 });
685 s
686 }
687 })
688}
689
690impl SyntaxContext {
691 #[inline]
692 pub const fn root() -> Self {
693 SyntaxContext(0)
694 }
695
696 #[inline]
697 pub const fn is_root(self) -> bool {
698 self.0 == SyntaxContext::root().as_u32()
699 }
700
701 #[inline]
702 pub(crate) const fn as_u32(self) -> u32 {
703 self.0
704 }
705
706 #[inline]
707 pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
708 SyntaxContext(raw)
709 }
710
711 #[inline]
712 pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
713 SyntaxContext(raw as u32)
714 }
715
716 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
718 HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
719 }
720
721 pub fn remove_mark(&mut self) -> ExpnId {
738 HygieneData::with(|data| data.remove_mark(self).0)
739 }
740
741 pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
742 HygieneData::with(|data| data.marks(self))
743 }
744
745 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
771 HygieneData::with(|data| data.adjust(self, expn_id))
772 }
773
774 pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
776 HygieneData::with(|data| {
777 *self = data.normalize_to_macros_2_0(*self);
778 data.adjust(self, expn_id)
779 })
780 }
781
782 pub(crate) fn glob_adjust(
809 &mut self,
810 expn_id: ExpnId,
811 glob_span: Span,
812 ) -> Option<Option<ExpnId>> {
813 HygieneData::with(|data| {
814 let mut scope = None;
815 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
816 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
817 scope = Some(data.remove_mark(&mut glob_ctxt).0);
818 if data.remove_mark(self).0 != scope.unwrap() {
819 return None;
820 }
821 }
822 if data.adjust(self, expn_id).is_some() {
823 return None;
824 }
825 Some(scope)
826 })
827 }
828
829 pub(crate) fn reverse_glob_adjust(
837 &mut self,
838 expn_id: ExpnId,
839 glob_span: Span,
840 ) -> Option<Option<ExpnId>> {
841 HygieneData::with(|data| {
842 if data.adjust(self, expn_id).is_some() {
843 return None;
844 }
845
846 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
847 let mut marks = Vec::new();
848 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
849 marks.push(data.remove_mark(&mut glob_ctxt));
850 }
851
852 let scope = marks.last().map(|mark| mark.0);
853 while let Some((expn_id, transparency)) = marks.pop() {
854 *self = data.apply_mark(*self, expn_id, transparency);
855 }
856 Some(scope)
857 })
858 }
859
860 pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool {
861 HygieneData::with(|data| {
862 let mut self_normalized = data.normalize_to_macros_2_0(self);
863 data.adjust(&mut self_normalized, expn_id);
864 self_normalized == data.normalize_to_macros_2_0(other)
865 })
866 }
867
868 #[inline]
869 pub fn normalize_to_macros_2_0(self) -> SyntaxContext {
870 HygieneData::with(|data| data.normalize_to_macros_2_0(self))
871 }
872
873 #[inline]
874 pub fn normalize_to_macro_rules(self) -> SyntaxContext {
875 HygieneData::with(|data| data.normalize_to_macro_rules(self))
876 }
877
878 #[inline]
879 pub fn outer_expn(self) -> ExpnId {
880 HygieneData::with(|data| data.outer_expn(self))
881 }
882
883 #[inline]
886 pub fn outer_expn_data(self) -> ExpnData {
887 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
888 }
889
890 #[inline]
891 fn outer_mark(self) -> (ExpnId, Transparency) {
892 HygieneData::with(|data| data.outer_mark(self))
893 }
894
895 pub(crate) fn dollar_crate_name(self) -> Symbol {
896 HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
897 }
898
899 pub fn edition(self) -> Edition {
900 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
901 }
902}
903
904impl fmt::Debug for SyntaxContext {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 write!(f, "#{}", self.0)
907 }
908}
909
910impl Span {
911 pub fn mark_with_reason(
914 self,
915 allow_internal_unstable: Option<Arc<[Symbol]>>,
916 reason: DesugaringKind,
917 edition: Edition,
918 ctx: impl HashStableContext,
919 ) -> Span {
920 let expn_data = ExpnData {
921 allow_internal_unstable,
922 ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
923 };
924 let expn_id = LocalExpnId::fresh(expn_data, ctx);
925 self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
926 }
927}
928
929#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
932pub struct ExpnData {
933 pub kind: ExpnKind,
936 pub parent: ExpnId,
938 pub call_site: Span,
948 disambiguator: u32,
959
960 pub def_site: Span,
967 pub allow_internal_unstable: Option<Arc<[Symbol]>>,
971 pub edition: Edition,
973 pub macro_def_id: Option<DefId>,
976 pub parent_module: Option<DefId>,
978 pub(crate) allow_internal_unsafe: bool,
980 pub local_inner_macros: bool,
982 pub(crate) collapse_debuginfo: bool,
985 pub hide_backtrace: bool,
987}
988
989impl !PartialEq for ExpnData {}
990impl !Hash for ExpnData {}
991
992impl ExpnData {
993 pub fn new(
994 kind: ExpnKind,
995 parent: ExpnId,
996 call_site: Span,
997 def_site: Span,
998 allow_internal_unstable: Option<Arc<[Symbol]>>,
999 edition: Edition,
1000 macro_def_id: Option<DefId>,
1001 parent_module: Option<DefId>,
1002 allow_internal_unsafe: bool,
1003 local_inner_macros: bool,
1004 collapse_debuginfo: bool,
1005 hide_backtrace: bool,
1006 ) -> ExpnData {
1007 ExpnData {
1008 kind,
1009 parent,
1010 call_site,
1011 def_site,
1012 allow_internal_unstable,
1013 edition,
1014 macro_def_id,
1015 parent_module,
1016 disambiguator: 0,
1017 allow_internal_unsafe,
1018 local_inner_macros,
1019 collapse_debuginfo,
1020 hide_backtrace,
1021 }
1022 }
1023
1024 pub fn default(
1026 kind: ExpnKind,
1027 call_site: Span,
1028 edition: Edition,
1029 macro_def_id: Option<DefId>,
1030 parent_module: Option<DefId>,
1031 ) -> ExpnData {
1032 ExpnData {
1033 kind,
1034 parent: ExpnId::root(),
1035 call_site,
1036 def_site: DUMMY_SP,
1037 allow_internal_unstable: None,
1038 edition,
1039 macro_def_id,
1040 parent_module,
1041 disambiguator: 0,
1042 allow_internal_unsafe: false,
1043 local_inner_macros: false,
1044 collapse_debuginfo: false,
1045 hide_backtrace: false,
1046 }
1047 }
1048
1049 pub fn allow_unstable(
1050 kind: ExpnKind,
1051 call_site: Span,
1052 edition: Edition,
1053 allow_internal_unstable: Arc<[Symbol]>,
1054 macro_def_id: Option<DefId>,
1055 parent_module: Option<DefId>,
1056 ) -> ExpnData {
1057 ExpnData {
1058 allow_internal_unstable: Some(allow_internal_unstable),
1059 ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1060 }
1061 }
1062
1063 #[inline]
1064 pub fn is_root(&self) -> bool {
1065 matches!(self.kind, ExpnKind::Root)
1066 }
1067
1068 #[inline]
1069 fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1070 let mut hasher = StableHasher::new();
1071 self.hash_stable(ctx, &mut hasher);
1072 hasher.finish()
1073 }
1074}
1075
1076#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1078pub enum ExpnKind {
1079 Root,
1081 Macro(MacroKind, Symbol),
1083 AstPass(AstPass),
1085 Desugaring(DesugaringKind),
1087}
1088
1089impl ExpnKind {
1090 pub fn descr(&self) -> String {
1091 match *self {
1092 ExpnKind::Root => kw::PathRoot.to_string(),
1093 ExpnKind::Macro(macro_kind, name) => match macro_kind {
1094 MacroKind::Bang => format!("{name}!"),
1095 MacroKind::Attr => format!("#[{name}]"),
1096 MacroKind::Derive => format!("#[derive({name})]"),
1097 },
1098 ExpnKind::AstPass(kind) => kind.descr().to_string(),
1099 ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1100 }
1101 }
1102}
1103
1104#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
1106#[derive(HashStable_Generic)]
1107pub enum MacroKind {
1108 Bang,
1110 Attr,
1112 Derive,
1114}
1115
1116impl MacroKind {
1117 pub fn descr(self) -> &'static str {
1118 match self {
1119 MacroKind::Bang => "macro",
1120 MacroKind::Attr => "attribute macro",
1121 MacroKind::Derive => "derive macro",
1122 }
1123 }
1124
1125 pub fn descr_expected(self) -> &'static str {
1126 match self {
1127 MacroKind::Attr => "attribute",
1128 _ => self.descr(),
1129 }
1130 }
1131
1132 pub fn article(self) -> &'static str {
1133 match self {
1134 MacroKind::Attr => "an",
1135 _ => "a",
1136 }
1137 }
1138}
1139
1140#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1142pub enum AstPass {
1143 StdImports,
1144 TestHarness,
1145 ProcMacroHarness,
1146}
1147
1148impl AstPass {
1149 pub fn descr(self) -> &'static str {
1150 match self {
1151 AstPass::StdImports => "standard library imports",
1152 AstPass::TestHarness => "test harness",
1153 AstPass::ProcMacroHarness => "proc macro harness",
1154 }
1155 }
1156}
1157
1158#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1160pub enum DesugaringKind {
1161 CondTemporary,
1166 QuestionMark,
1167 TryBlock,
1168 YeetExpr,
1169 OpaqueTy,
1173 Async,
1174 Await,
1175 ForLoop,
1176 WhileLoop,
1177 BoundModifier,
1179 Contract,
1181 PatTyRange,
1183}
1184
1185impl DesugaringKind {
1186 pub fn descr(self) -> &'static str {
1188 match self {
1189 DesugaringKind::CondTemporary => "`if` or `while` condition",
1190 DesugaringKind::Async => "`async` block or function",
1191 DesugaringKind::Await => "`await` expression",
1192 DesugaringKind::QuestionMark => "operator `?`",
1193 DesugaringKind::TryBlock => "`try` block",
1194 DesugaringKind::YeetExpr => "`do yeet` expression",
1195 DesugaringKind::OpaqueTy => "`impl Trait`",
1196 DesugaringKind::ForLoop => "`for` loop",
1197 DesugaringKind::WhileLoop => "`while` loop",
1198 DesugaringKind::BoundModifier => "trait bound modifier",
1199 DesugaringKind::Contract => "contract check",
1200 DesugaringKind::PatTyRange => "pattern type",
1201 }
1202 }
1203}
1204
1205#[derive(Default)]
1206pub struct HygieneEncodeContext {
1207 serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1211 latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1216
1217 serialized_expns: Lock<FxHashSet<ExpnId>>,
1218
1219 latest_expns: Lock<FxHashSet<ExpnId>>,
1220}
1221
1222impl HygieneEncodeContext {
1223 pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1225 if !self.serialized_expns.lock().contains(&expn) {
1226 self.latest_expns.lock().insert(expn);
1227 }
1228 }
1229
1230 pub fn encode<T>(
1231 &self,
1232 encoder: &mut T,
1233 mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData),
1234 mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1235 ) {
1236 while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1239 debug!(
1240 "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1241 self.latest_ctxts.lock().len(),
1242 self.latest_ctxts
1243 );
1244
1245 let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) };
1248
1249 #[allow(rustc::potential_query_instability)]
1253 for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
1254 if self.serialized_ctxts.lock().insert(ctxt) {
1255 encode_ctxt(encoder, index, data);
1256 }
1257 });
1258
1259 let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
1260
1261 #[allow(rustc::potential_query_instability)]
1263 for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
1264 if self.serialized_expns.lock().insert(expn) {
1265 encode_expn(encoder, expn, data, hash);
1266 }
1267 });
1268 }
1269 debug!("encode_hygiene: Done serializing SyntaxContextData");
1270 }
1271}
1272
1273#[derive(Default)]
1274struct HygieneDecodeContextInner {
1276 remapped_ctxts: Vec<Option<SyntaxContext>>,
1282
1283 decoding: FxHashMap<u32, SyntaxContext>,
1285}
1286
1287#[derive(Default)]
1288pub struct HygieneDecodeContext {
1290 inner: Lock<HygieneDecodeContextInner>,
1291
1292 local_in_progress: WorkerLocal<RefCell<FxHashSet<u32>>>,
1294}
1295
1296pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1298 HygieneData::with(|hygiene_data| {
1299 let expn_id = hygiene_data.local_expn_data.next_index();
1300 hygiene_data.local_expn_data.push(Some(data));
1301 let _eid = hygiene_data.local_expn_hashes.push(hash);
1302 debug_assert_eq!(expn_id, _eid);
1303
1304 let expn_id = expn_id.to_expn_id();
1305
1306 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1307 debug_assert!(_old_id.is_none());
1308 expn_id
1309 })
1310}
1311
1312pub fn register_expn_id(
1314 krate: CrateNum,
1315 local_id: ExpnIndex,
1316 data: ExpnData,
1317 hash: ExpnHash,
1318) -> ExpnId {
1319 debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1320 let expn_id = ExpnId { krate, local_id };
1321 HygieneData::with(|hygiene_data| {
1322 let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1323 let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1324 debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1325 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1326 debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1327 });
1328 expn_id
1329}
1330
1331pub fn decode_expn_id(
1333 krate: CrateNum,
1334 index: u32,
1335 decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1336) -> ExpnId {
1337 if index == 0 {
1338 trace!("decode_expn_id: deserialized root");
1339 return ExpnId::root();
1340 }
1341
1342 let index = ExpnIndex::from_u32(index);
1343
1344 debug_assert_ne!(krate, LOCAL_CRATE);
1346 let expn_id = ExpnId { krate, local_id: index };
1347
1348 if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1350 return expn_id;
1351 }
1352
1353 let (expn_data, hash) = decode_data(expn_id);
1356
1357 register_expn_id(krate, index, expn_data, hash)
1358}
1359
1360pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
1365 d: &mut D,
1366 context: &HygieneDecodeContext,
1367 decode_data: F,
1368) -> SyntaxContext {
1369 let raw_id: u32 = Decodable::decode(d);
1370 if raw_id == 0 {
1371 trace!("decode_syntax_context: deserialized root");
1372 return SyntaxContext::root();
1374 }
1375
1376 let ctxt = {
1377 let mut inner = context.inner.lock();
1378
1379 if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() {
1380 return ctxt;
1382 }
1383
1384 match inner.decoding.entry(raw_id) {
1385 Entry::Occupied(ctxt_entry) => {
1386 match context.local_in_progress.borrow_mut().entry(raw_id) {
1387 SetEntry::Occupied(..) => {
1388 return *ctxt_entry.get();
1392 }
1393 SetEntry::Vacant(entry) => {
1394 entry.insert();
1395
1396 *ctxt_entry.get()
1398 }
1399 }
1400 }
1401 Entry::Vacant(entry) => {
1402 context.local_in_progress.borrow_mut().insert(raw_id);
1404
1405 let new_ctxt = HygieneData::with(|hygiene_data| {
1408 let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32);
1409 hygiene_data.syntax_context_data.push(SyntaxContextData {
1412 outer_expn: ExpnId::root(),
1413 outer_transparency: Transparency::Transparent,
1414 parent: SyntaxContext::root(),
1415 opaque: SyntaxContext::root(),
1416 opaque_and_semitransparent: SyntaxContext::root(),
1417 dollar_crate_name: kw::Empty,
1418 });
1419 new_ctxt
1420 });
1421 entry.insert(new_ctxt);
1422 new_ctxt
1423 }
1424 }
1425 };
1426
1427 let mut ctxt_data = decode_data(d, raw_id);
1430 ctxt_data.dollar_crate_name = kw::DollarCrate;
1434
1435 HygieneData::with(|hygiene_data| {
1437 if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize)
1438 && old.outer_expn == ctxt_data.outer_expn
1439 && old.outer_transparency == ctxt_data.outer_transparency
1440 && old.parent == ctxt_data.parent
1441 {
1442 ctxt_data = old.clone();
1443 }
1444
1445 hygiene_data.syntax_context_data[ctxt.as_u32() as usize] = ctxt_data;
1446 });
1447
1448 context.local_in_progress.borrow_mut().remove(&raw_id);
1451
1452 let mut inner = context.inner.lock();
1453 let new_len = raw_id as usize + 1;
1454 if inner.remapped_ctxts.len() < new_len {
1455 inner.remapped_ctxts.resize(new_len, None);
1456 }
1457 inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
1458 inner.decoding.remove(&raw_id);
1459
1460 ctxt
1461}
1462
1463fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextData)>(
1464 ctxts: impl Iterator<Item = SyntaxContext>,
1465 mut f: F,
1466) {
1467 let all_data: Vec<_> = HygieneData::with(|data| {
1468 ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
1469 });
1470 for (ctxt, data) in all_data.into_iter() {
1471 f(ctxt.0, ctxt, &data);
1472 }
1473}
1474
1475fn for_all_expns_in(
1476 expns: impl Iterator<Item = ExpnId>,
1477 mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
1478) {
1479 let all_data: Vec<_> = HygieneData::with(|data| {
1480 expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
1481 });
1482 for (expn, data, hash) in all_data.into_iter() {
1483 f(expn, &data, hash);
1484 }
1485}
1486
1487impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1488 fn encode(&self, e: &mut E) {
1489 self.to_expn_id().encode(e);
1490 }
1491}
1492
1493impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1494 fn decode(d: &mut D) -> Self {
1495 ExpnId::expect_local(ExpnId::decode(d))
1496 }
1497}
1498
1499pub fn raw_encode_syntax_context<E: Encoder>(
1500 ctxt: SyntaxContext,
1501 context: &HygieneEncodeContext,
1502 e: &mut E,
1503) {
1504 if !context.serialized_ctxts.lock().contains(&ctxt) {
1505 context.latest_ctxts.lock().insert(ctxt);
1506 }
1507 ctxt.0.encode(e);
1508}
1509
1510fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1520 assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1522 assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1523 let mut expn_hash = expn_data.hash_expn(&mut ctx);
1524
1525 let disambiguator = HygieneData::with(|data| {
1526 let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1529 let disambiguator = *disambig;
1530 *disambig += 1;
1531 disambiguator
1532 });
1533
1534 if disambiguator != 0 {
1535 debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1536
1537 expn_data.disambiguator = disambiguator;
1538 expn_hash = expn_data.hash_expn(&mut ctx);
1539
1540 #[cfg(debug_assertions)]
1542 HygieneData::with(|data| {
1543 assert_eq!(
1544 data.expn_data_disambiguators.get(&expn_hash),
1545 None,
1546 "Hash collision after disambiguator update!",
1547 );
1548 });
1549 }
1550
1551 ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1552}
1553
1554impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1555 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1556 const TAG_EXPANSION: u8 = 0;
1557 const TAG_NO_EXPANSION: u8 = 1;
1558
1559 if self.is_root() {
1560 TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1561 } else {
1562 TAG_EXPANSION.hash_stable(ctx, hasher);
1563 let (expn_id, transparency) = self.outer_mark();
1564 expn_id.hash_stable(ctx, hasher);
1565 transparency.hash_stable(ctx, hasher);
1566 }
1567 }
1568}
1569
1570impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1571 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1572 assert_default_hashing_controls(ctx, "ExpnId");
1573 let hash = if *self == ExpnId::root() {
1574 Fingerprint::ZERO
1576 } else {
1577 self.expn_hash().0
1578 };
1579
1580 hash.hash_stable(ctx, hasher);
1581 }
1582}