1use std::cell::RefCell;
28use std::collections::hash_map::Entry;
29use std::collections::hash_set::Entry as SetEntry;
30use std::hash::Hash;
31use std::sync::Arc;
32use std::{fmt, iter, mem};
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
60type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
63
64#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)]
65pub struct SyntaxContextData {
66 outer_expn: ExpnId,
67 outer_transparency: Transparency,
68 parent: SyntaxContext,
69 opaque: SyntaxContext,
71 opaque_and_semitransparent: SyntaxContext,
73 dollar_crate_name: Symbol,
75}
76
77impl SyntaxContextData {
78 fn root() -> SyntaxContextData {
79 SyntaxContextData {
80 outer_expn: ExpnId::root(),
81 outer_transparency: Transparency::Opaque,
82 parent: SyntaxContext::root(),
83 opaque: SyntaxContext::root(),
84 opaque_and_semitransparent: SyntaxContext::root(),
85 dollar_crate_name: kw::DollarCrate,
86 }
87 }
88
89 fn decode_placeholder() -> SyntaxContextData {
90 SyntaxContextData { dollar_crate_name: kw::Empty, ..SyntaxContextData::root() }
91 }
92
93 fn is_decode_placeholder(&self) -> bool {
94 self.dollar_crate_name == kw::Empty
95 }
96
97 fn key(&self) -> SyntaxContextKey {
98 (self.parent, self.outer_expn, self.outer_transparency)
99 }
100}
101
102rustc_index::newtype_index! {
103 #[orderable]
105 pub struct ExpnIndex {}
106}
107
108#[derive(Clone, Copy, PartialEq, Eq, Hash)]
110pub struct ExpnId {
111 pub krate: CrateNum,
112 pub local_id: ExpnIndex,
113}
114
115impl fmt::Debug for ExpnId {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
119 }
120}
121
122rustc_index::newtype_index! {
123 #[debug_format = "expn{}"]
125 pub struct LocalExpnId {}
126}
127
128impl !Ord for LocalExpnId {}
132impl !PartialOrd for LocalExpnId {}
133
134fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
140 match ctx.hashing_controls() {
141 HashingControls { hash_spans }
150 if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
151 other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
152 }
153}
154
155#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
157pub struct ExpnHash(Fingerprint);
158
159impl ExpnHash {
160 #[inline]
163 pub fn stable_crate_id(self) -> StableCrateId {
164 StableCrateId(self.0.split().0)
165 }
166
167 #[inline]
171 pub fn local_hash(self) -> Hash64 {
172 self.0.split().1
173 }
174
175 #[inline]
176 pub fn is_root(self) -> bool {
177 self.0 == Fingerprint::ZERO
178 }
179
180 fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
183 ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
184 }
185}
186
187#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
190#[derive(HashStable_Generic)]
191pub enum Transparency {
192 Transparent,
195 SemiTransparent,
202 Opaque,
205}
206
207impl Transparency {
208 pub fn fallback(macro_rules: bool) -> Self {
209 if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }
210 }
211}
212
213impl LocalExpnId {
214 pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
216
217 #[inline]
218 fn from_raw(idx: ExpnIndex) -> LocalExpnId {
219 LocalExpnId::from_u32(idx.as_u32())
220 }
221
222 #[inline]
223 pub fn as_raw(self) -> ExpnIndex {
224 ExpnIndex::from_u32(self.as_u32())
225 }
226
227 pub fn fresh_empty() -> LocalExpnId {
228 HygieneData::with(|data| {
229 let expn_id = data.local_expn_data.push(None);
230 let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
231 debug_assert_eq!(expn_id, _eid);
232 expn_id
233 })
234 }
235
236 pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
237 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
238 let expn_hash = update_disambiguator(&mut expn_data, ctx);
239 HygieneData::with(|data| {
240 let expn_id = data.local_expn_data.push(Some(expn_data));
241 let _eid = data.local_expn_hashes.push(expn_hash);
242 debug_assert_eq!(expn_id, _eid);
243 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
244 debug_assert!(_old_id.is_none());
245 expn_id
246 })
247 }
248
249 #[inline]
250 pub fn expn_data(self) -> ExpnData {
251 HygieneData::with(|data| data.local_expn_data(self).clone())
252 }
253
254 #[inline]
255 pub fn to_expn_id(self) -> ExpnId {
256 ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
257 }
258
259 #[inline]
260 pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
261 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
262 let expn_hash = update_disambiguator(&mut expn_data, ctx);
263 HygieneData::with(|data| {
264 let old_expn_data = &mut data.local_expn_data[self];
265 assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
266 *old_expn_data = Some(expn_data);
267 debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
268 data.local_expn_hashes[self] = expn_hash;
269 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
270 debug_assert!(_old_id.is_none());
271 });
272 }
273
274 #[inline]
275 pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
276 self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
277 }
278
279 #[inline]
283 pub fn expansion_cause(self) -> Option<Span> {
284 self.to_expn_id().expansion_cause()
285 }
286}
287
288impl ExpnId {
289 pub const fn root() -> ExpnId {
292 ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
293 }
294
295 #[inline]
296 pub fn expn_hash(self) -> ExpnHash {
297 HygieneData::with(|data| data.expn_hash(self))
298 }
299
300 #[inline]
301 pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
302 HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
303 }
304
305 #[inline]
306 pub fn as_local(self) -> Option<LocalExpnId> {
307 if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
308 }
309
310 #[inline]
311 #[track_caller]
312 pub fn expect_local(self) -> LocalExpnId {
313 self.as_local().unwrap()
314 }
315
316 #[inline]
317 pub fn expn_data(self) -> ExpnData {
318 HygieneData::with(|data| data.expn_data(self).clone())
319 }
320
321 #[inline]
322 pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
323 if ancestor == ExpnId::root() || ancestor == self {
325 return true;
326 }
327 if ancestor.krate != self.krate {
328 return false;
329 }
330 HygieneData::with(|data| data.is_descendant_of(self, ancestor))
331 }
332
333 pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
336 HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
337 }
338
339 pub fn expansion_cause(mut self) -> Option<Span> {
343 let mut last_macro = None;
344 loop {
345 if self == ExpnId::root() {
347 break;
348 }
349 let expn_data = self.expn_data();
350 if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
352 break;
353 }
354 self = expn_data.call_site.ctxt().outer_expn();
355 last_macro = Some(expn_data.call_site);
356 }
357 last_macro
358 }
359}
360
361#[derive(Debug)]
362pub(crate) struct HygieneData {
363 local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
367 local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
368 foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
371 foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
372 expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
373 syntax_context_data: Vec<SyntaxContextData>,
374 syntax_context_map: FxHashMap<SyntaxContextKey, SyntaxContext>,
375 expn_data_disambiguators: UnhashMap<Hash64, u32>,
381}
382
383impl HygieneData {
384 pub(crate) fn new(edition: Edition) -> Self {
385 let root_data = ExpnData::default(
386 ExpnKind::Root,
387 DUMMY_SP,
388 edition,
389 Some(CRATE_DEF_ID.to_def_id()),
390 None,
391 );
392
393 let root_ctxt_data = SyntaxContextData::root();
394 HygieneData {
395 local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
396 local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
397 foreign_expn_data: FxHashMap::default(),
398 foreign_expn_hashes: FxHashMap::default(),
399 expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
400 .collect(),
401 syntax_context_data: vec![root_ctxt_data],
402 syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(),
403 expn_data_disambiguators: UnhashMap::default(),
404 }
405 }
406
407 fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
408 with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
409 }
410
411 #[inline]
412 fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
413 match expn_id.as_local() {
414 Some(expn_id) => self.local_expn_hashes[expn_id],
415 None => self.foreign_expn_hashes[&expn_id],
416 }
417 }
418
419 fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
420 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
421 }
422
423 fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
424 if let Some(expn_id) = expn_id.as_local() {
425 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
426 } else {
427 &self.foreign_expn_data[&expn_id]
428 }
429 }
430
431 fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
432 if ancestor == ExpnId::root() {
434 return true;
435 }
436 if expn_id.krate != ancestor.krate {
437 return false;
438 }
439 loop {
440 if expn_id == ancestor {
441 return true;
442 }
443 if expn_id == ExpnId::root() {
444 return false;
445 }
446 expn_id = self.expn_data(expn_id).parent;
447 }
448 }
449
450 fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
451 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
452 self.syntax_context_data[ctxt.0 as usize].opaque
453 }
454
455 fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
456 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
457 self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
458 }
459
460 fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
461 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
462 self.syntax_context_data[ctxt.0 as usize].outer_expn
463 }
464
465 fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
466 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
467 let data = &self.syntax_context_data[ctxt.0 as usize];
468 (data.outer_expn, data.outer_transparency)
469 }
470
471 fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
472 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
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.apply_mark_internal(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::SemiTransparent {
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.apply_mark_internal(ctxt, expn_id, transparency);
558 }
559
560 for (expn_id, transparency) in self.marks(ctxt) {
570 call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency);
571 }
572 self.apply_mark_internal(call_site_ctxt, expn_id, transparency)
573 }
574
575 fn apply_mark_internal(
576 &mut self,
577 ctxt: SyntaxContext,
578 expn_id: ExpnId,
579 transparency: Transparency,
580 ) -> SyntaxContext {
581 let syntax_context_data = &mut self.syntax_context_data;
582 debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
583 let mut opaque = syntax_context_data[ctxt.0 as usize].opaque;
584 let mut opaque_and_semitransparent =
585 syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent;
586
587 if transparency >= Transparency::Opaque {
588 let parent = opaque;
589 opaque = *self
590 .syntax_context_map
591 .entry((parent, expn_id, transparency))
592 .or_insert_with(|| {
593 let new_opaque = SyntaxContext::from_usize(syntax_context_data.len());
594 syntax_context_data.push(SyntaxContextData {
595 outer_expn: expn_id,
596 outer_transparency: transparency,
597 parent,
598 opaque: new_opaque,
599 opaque_and_semitransparent: new_opaque,
600 dollar_crate_name: kw::DollarCrate,
601 });
602 new_opaque
603 });
604 }
605
606 if transparency >= Transparency::SemiTransparent {
607 let parent = opaque_and_semitransparent;
608 opaque_and_semitransparent = *self
609 .syntax_context_map
610 .entry((parent, expn_id, transparency))
611 .or_insert_with(|| {
612 let new_opaque_and_semitransparent =
613 SyntaxContext::from_usize(syntax_context_data.len());
614 syntax_context_data.push(SyntaxContextData {
615 outer_expn: expn_id,
616 outer_transparency: transparency,
617 parent,
618 opaque,
619 opaque_and_semitransparent: new_opaque_and_semitransparent,
620 dollar_crate_name: kw::DollarCrate,
621 });
622 new_opaque_and_semitransparent
623 });
624 }
625
626 let parent = ctxt;
627 *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| {
628 syntax_context_data.push(SyntaxContextData {
629 outer_expn: expn_id,
630 outer_transparency: transparency,
631 parent,
632 opaque,
633 opaque_and_semitransparent,
634 dollar_crate_name: kw::DollarCrate,
635 });
636 SyntaxContext::from_usize(syntax_context_data.len() - 1)
637 })
638 }
639}
640
641pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
642 HygieneData::with(|data| data.walk_chain(span, to))
643}
644
645pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
651 HygieneData::with(|data| data.walk_chain_collapsed(span, to))
652}
653
654pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
655 let mut to_update = vec![];
658 HygieneData::with(|data| {
659 for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() {
660 if scdata.dollar_crate_name == kw::DollarCrate {
661 to_update.push((idx, kw::DollarCrate));
662 } else if !scdata.is_decode_placeholder() {
663 break;
664 }
665 }
666 });
667 for (idx, name) in &mut to_update {
670 *name = get_name(SyntaxContext::from_usize(*idx));
671 }
672 HygieneData::with(|data| {
673 for (idx, name) in to_update {
674 data.syntax_context_data[idx].dollar_crate_name = name;
675 }
676 })
677}
678
679pub fn debug_hygiene_data(verbose: bool) -> String {
680 HygieneData::with(|data| {
681 if verbose {
682 format!("{data:#?}")
683 } else {
684 let mut s = String::from("Expansions:");
685 let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
686 s.push_str(&format!(
687 "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
688 id,
689 expn_data.parent,
690 expn_data.call_site.ctxt(),
691 expn_data.def_site.ctxt(),
692 expn_data.kind,
693 ))
694 };
695 data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
696 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
697 debug_expn_data((&id.to_expn_id(), expn_data))
698 });
699
700 #[allow(rustc::potential_query_instability)]
703 let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
704 foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
705 foreign_expn_data.into_iter().for_each(debug_expn_data);
706 s.push_str("\n\nSyntaxContexts:");
707 data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
708 s.push_str(&format!(
709 "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
710 id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
711 ));
712 });
713 s
714 }
715 })
716}
717
718impl SyntaxContext {
719 #[inline]
720 pub const fn root() -> Self {
721 SyntaxContext(0)
722 }
723
724 #[inline]
725 pub const fn is_root(self) -> bool {
726 self.0 == SyntaxContext::root().as_u32()
727 }
728
729 #[inline]
730 pub(crate) const fn as_u32(self) -> u32 {
731 self.0
732 }
733
734 #[inline]
735 pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
736 SyntaxContext(raw)
737 }
738
739 #[inline]
740 pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
741 SyntaxContext(raw as u32)
742 }
743
744 fn from_usize(raw: usize) -> SyntaxContext {
745 SyntaxContext(u32::try_from(raw).unwrap())
746 }
747
748 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
750 HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
751 }
752
753 pub fn remove_mark(&mut self) -> ExpnId {
770 HygieneData::with(|data| data.remove_mark(self).0)
771 }
772
773 pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
774 HygieneData::with(|data| data.marks(self))
775 }
776
777 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
803 HygieneData::with(|data| data.adjust(self, expn_id))
804 }
805
806 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 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 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 #[inline]
911 pub fn outer_expn(self) -> ExpnId {
912 HygieneData::with(|data| data.outer_expn(self))
913 }
914
915 #[inline]
918 pub fn outer_expn_data(self) -> ExpnData {
919 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
920 }
921
922 #[inline]
923 fn outer_mark(self) -> (ExpnId, Transparency) {
924 HygieneData::with(|data| data.outer_mark(self))
925 }
926
927 pub(crate) fn dollar_crate_name(self) -> Symbol {
928 HygieneData::with(|data| {
929 debug_assert!(!data.syntax_context_data[self.0 as usize].is_decode_placeholder());
930 data.syntax_context_data[self.0 as usize].dollar_crate_name
931 })
932 }
933
934 pub fn edition(self) -> Edition {
935 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
936 }
937}
938
939impl fmt::Debug for SyntaxContext {
940 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
941 write!(f, "#{}", self.0)
942 }
943}
944
945impl Span {
946 pub fn mark_with_reason(
949 self,
950 allow_internal_unstable: Option<Arc<[Symbol]>>,
951 reason: DesugaringKind,
952 edition: Edition,
953 ctx: impl HashStableContext,
954 ) -> Span {
955 let expn_data = ExpnData {
956 allow_internal_unstable,
957 ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
958 };
959 let expn_id = LocalExpnId::fresh(expn_data, ctx);
960 self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
961 }
962}
963
964#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
967pub struct ExpnData {
968 pub kind: ExpnKind,
971 pub parent: ExpnId,
973 pub call_site: Span,
983 disambiguator: u32,
994
995 pub def_site: Span,
1002 pub allow_internal_unstable: Option<Arc<[Symbol]>>,
1006 pub edition: Edition,
1008 pub macro_def_id: Option<DefId>,
1011 pub parent_module: Option<DefId>,
1013 pub(crate) allow_internal_unsafe: bool,
1015 pub local_inner_macros: bool,
1017 pub(crate) collapse_debuginfo: bool,
1020 pub hide_backtrace: bool,
1022}
1023
1024impl !PartialEq for ExpnData {}
1025impl !Hash for ExpnData {}
1026
1027impl ExpnData {
1028 pub fn new(
1029 kind: ExpnKind,
1030 parent: ExpnId,
1031 call_site: Span,
1032 def_site: Span,
1033 allow_internal_unstable: Option<Arc<[Symbol]>>,
1034 edition: Edition,
1035 macro_def_id: Option<DefId>,
1036 parent_module: Option<DefId>,
1037 allow_internal_unsafe: bool,
1038 local_inner_macros: bool,
1039 collapse_debuginfo: bool,
1040 hide_backtrace: bool,
1041 ) -> ExpnData {
1042 ExpnData {
1043 kind,
1044 parent,
1045 call_site,
1046 def_site,
1047 allow_internal_unstable,
1048 edition,
1049 macro_def_id,
1050 parent_module,
1051 disambiguator: 0,
1052 allow_internal_unsafe,
1053 local_inner_macros,
1054 collapse_debuginfo,
1055 hide_backtrace,
1056 }
1057 }
1058
1059 pub fn default(
1061 kind: ExpnKind,
1062 call_site: Span,
1063 edition: Edition,
1064 macro_def_id: Option<DefId>,
1065 parent_module: Option<DefId>,
1066 ) -> ExpnData {
1067 ExpnData {
1068 kind,
1069 parent: ExpnId::root(),
1070 call_site,
1071 def_site: DUMMY_SP,
1072 allow_internal_unstable: None,
1073 edition,
1074 macro_def_id,
1075 parent_module,
1076 disambiguator: 0,
1077 allow_internal_unsafe: false,
1078 local_inner_macros: false,
1079 collapse_debuginfo: false,
1080 hide_backtrace: false,
1081 }
1082 }
1083
1084 pub fn allow_unstable(
1085 kind: ExpnKind,
1086 call_site: Span,
1087 edition: Edition,
1088 allow_internal_unstable: Arc<[Symbol]>,
1089 macro_def_id: Option<DefId>,
1090 parent_module: Option<DefId>,
1091 ) -> ExpnData {
1092 ExpnData {
1093 allow_internal_unstable: Some(allow_internal_unstable),
1094 ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1095 }
1096 }
1097
1098 #[inline]
1099 pub fn is_root(&self) -> bool {
1100 matches!(self.kind, ExpnKind::Root)
1101 }
1102
1103 #[inline]
1104 fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1105 let mut hasher = StableHasher::new();
1106 self.hash_stable(ctx, &mut hasher);
1107 hasher.finish()
1108 }
1109}
1110
1111#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1113pub enum ExpnKind {
1114 Root,
1116 Macro(MacroKind, Symbol),
1118 AstPass(AstPass),
1120 Desugaring(DesugaringKind),
1122}
1123
1124impl ExpnKind {
1125 pub fn descr(&self) -> String {
1126 match *self {
1127 ExpnKind::Root => kw::PathRoot.to_string(),
1128 ExpnKind::Macro(macro_kind, name) => match macro_kind {
1129 MacroKind::Bang => format!("{name}!"),
1130 MacroKind::Attr => format!("#[{name}]"),
1131 MacroKind::Derive => format!("#[derive({name})]"),
1132 },
1133 ExpnKind::AstPass(kind) => kind.descr().to_string(),
1134 ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1135 }
1136 }
1137}
1138
1139#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
1141#[derive(HashStable_Generic)]
1142pub enum MacroKind {
1143 Bang,
1145 Attr,
1147 Derive,
1149}
1150
1151impl MacroKind {
1152 pub fn descr(self) -> &'static str {
1153 match self {
1154 MacroKind::Bang => "macro",
1155 MacroKind::Attr => "attribute macro",
1156 MacroKind::Derive => "derive macro",
1157 }
1158 }
1159
1160 pub fn descr_expected(self) -> &'static str {
1161 match self {
1162 MacroKind::Attr => "attribute",
1163 _ => self.descr(),
1164 }
1165 }
1166
1167 pub fn article(self) -> &'static str {
1168 match self {
1169 MacroKind::Attr => "an",
1170 _ => "a",
1171 }
1172 }
1173}
1174
1175#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1177pub enum AstPass {
1178 StdImports,
1179 TestHarness,
1180 ProcMacroHarness,
1181}
1182
1183impl AstPass {
1184 pub fn descr(self) -> &'static str {
1185 match self {
1186 AstPass::StdImports => "standard library imports",
1187 AstPass::TestHarness => "test harness",
1188 AstPass::ProcMacroHarness => "proc macro harness",
1189 }
1190 }
1191}
1192
1193#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1195pub enum DesugaringKind {
1196 CondTemporary,
1201 QuestionMark,
1202 TryBlock,
1203 YeetExpr,
1204 OpaqueTy,
1208 Async,
1209 Await,
1210 ForLoop,
1211 WhileLoop,
1212 BoundModifier,
1214 Contract,
1216 PatTyRange,
1218}
1219
1220impl DesugaringKind {
1221 pub fn descr(self) -> &'static str {
1223 match self {
1224 DesugaringKind::CondTemporary => "`if` or `while` condition",
1225 DesugaringKind::Async => "`async` block or function",
1226 DesugaringKind::Await => "`await` expression",
1227 DesugaringKind::QuestionMark => "operator `?`",
1228 DesugaringKind::TryBlock => "`try` block",
1229 DesugaringKind::YeetExpr => "`do yeet` expression",
1230 DesugaringKind::OpaqueTy => "`impl Trait`",
1231 DesugaringKind::ForLoop => "`for` loop",
1232 DesugaringKind::WhileLoop => "`while` loop",
1233 DesugaringKind::BoundModifier => "trait bound modifier",
1234 DesugaringKind::Contract => "contract check",
1235 DesugaringKind::PatTyRange => "pattern type",
1236 }
1237 }
1238}
1239
1240#[derive(Default)]
1241pub struct HygieneEncodeContext {
1242 serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1246 latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1251
1252 serialized_expns: Lock<FxHashSet<ExpnId>>,
1253
1254 latest_expns: Lock<FxHashSet<ExpnId>>,
1255}
1256
1257impl HygieneEncodeContext {
1258 pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1260 if !self.serialized_expns.lock().contains(&expn) {
1261 self.latest_expns.lock().insert(expn);
1262 }
1263 }
1264
1265 pub fn encode<T>(
1266 &self,
1267 encoder: &mut T,
1268 mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData),
1269 mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1270 ) {
1271 while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1274 debug!(
1275 "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1276 self.latest_ctxts.lock().len(),
1277 self.latest_ctxts
1278 );
1279
1280 let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) };
1283
1284 #[allow(rustc::potential_query_instability)]
1288 for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
1289 if self.serialized_ctxts.lock().insert(ctxt) {
1290 encode_ctxt(encoder, index, data);
1291 }
1292 });
1293
1294 let latest_expns = { mem::take(&mut *self.latest_expns.lock()) };
1295
1296 #[allow(rustc::potential_query_instability)]
1298 for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
1299 if self.serialized_expns.lock().insert(expn) {
1300 encode_expn(encoder, expn, data, hash);
1301 }
1302 });
1303 }
1304 debug!("encode_hygiene: Done serializing SyntaxContextData");
1305 }
1306}
1307
1308#[derive(Default)]
1309struct HygieneDecodeContextInner {
1311 remapped_ctxts: Vec<Option<SyntaxContext>>,
1317
1318 decoding: FxHashMap<u32, SyntaxContext>,
1320}
1321
1322#[derive(Default)]
1323pub struct HygieneDecodeContext {
1325 inner: Lock<HygieneDecodeContextInner>,
1326
1327 local_in_progress: WorkerLocal<RefCell<FxHashSet<u32>>>,
1329}
1330
1331pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1333 HygieneData::with(|hygiene_data| {
1334 let expn_id = hygiene_data.local_expn_data.next_index();
1335 hygiene_data.local_expn_data.push(Some(data));
1336 let _eid = hygiene_data.local_expn_hashes.push(hash);
1337 debug_assert_eq!(expn_id, _eid);
1338
1339 let expn_id = expn_id.to_expn_id();
1340
1341 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1342 debug_assert!(_old_id.is_none());
1343 expn_id
1344 })
1345}
1346
1347pub fn register_expn_id(
1349 krate: CrateNum,
1350 local_id: ExpnIndex,
1351 data: ExpnData,
1352 hash: ExpnHash,
1353) -> ExpnId {
1354 debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1355 let expn_id = ExpnId { krate, local_id };
1356 HygieneData::with(|hygiene_data| {
1357 let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1358 let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1359 debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1360 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1361 debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1362 });
1363 expn_id
1364}
1365
1366pub fn decode_expn_id(
1368 krate: CrateNum,
1369 index: u32,
1370 decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1371) -> ExpnId {
1372 if index == 0 {
1373 trace!("decode_expn_id: deserialized root");
1374 return ExpnId::root();
1375 }
1376
1377 let index = ExpnIndex::from_u32(index);
1378
1379 debug_assert_ne!(krate, LOCAL_CRATE);
1381 let expn_id = ExpnId { krate, local_id: index };
1382
1383 if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1385 return expn_id;
1386 }
1387
1388 let (expn_data, hash) = decode_data(expn_id);
1391
1392 register_expn_id(krate, index, expn_data, hash)
1393}
1394
1395pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
1400 d: &mut D,
1401 context: &HygieneDecodeContext,
1402 decode_data: F,
1403) -> SyntaxContext {
1404 let raw_id: u32 = Decodable::decode(d);
1405 if raw_id == 0 {
1406 trace!("decode_syntax_context: deserialized root");
1407 return SyntaxContext::root();
1409 }
1410
1411 let pending_ctxt = {
1412 let mut inner = context.inner.lock();
1413
1414 if let Some(ctxt) = inner.remapped_ctxts.get(raw_id as usize).copied().flatten() {
1417 return ctxt;
1419 }
1420
1421 match inner.decoding.entry(raw_id) {
1422 Entry::Occupied(ctxt_entry) => {
1423 let pending_ctxt = *ctxt_entry.get();
1424 match context.local_in_progress.borrow_mut().entry(raw_id) {
1425 SetEntry::Occupied(..) => return pending_ctxt,
1431 SetEntry::Vacant(entry) => {
1436 entry.insert();
1437 pending_ctxt
1438 }
1439 }
1440 }
1441 Entry::Vacant(entry) => {
1442 context.local_in_progress.borrow_mut().insert(raw_id);
1444
1445 let new_ctxt = HygieneData::with(|hygiene_data| {
1448 hygiene_data.syntax_context_data.push(SyntaxContextData::decode_placeholder());
1451 SyntaxContext::from_usize(hygiene_data.syntax_context_data.len() - 1)
1452 });
1453 entry.insert(new_ctxt);
1454 new_ctxt
1455 }
1456 }
1457 };
1458
1459 let ctxt_data = decode_data(d, raw_id);
1462 let ctxt_key = ctxt_data.key();
1463
1464 let ctxt = HygieneData::with(|hygiene_data| {
1465 match hygiene_data.syntax_context_map.get(&ctxt_key) {
1466 Some(&ctxt) => ctxt,
1474 None => {
1477 let ctxt_data_ref =
1478 &mut hygiene_data.syntax_context_data[pending_ctxt.as_u32() as usize];
1479 let prev_ctxt_data = mem::replace(ctxt_data_ref, ctxt_data);
1480 ctxt_data_ref.dollar_crate_name = kw::DollarCrate;
1484 if !prev_ctxt_data.is_decode_placeholder() {
1486 assert_eq!(prev_ctxt_data, *ctxt_data_ref);
1489 }
1490 hygiene_data.syntax_context_map.insert(ctxt_key, pending_ctxt);
1491 pending_ctxt
1492 }
1493 }
1494 });
1495
1496 context.local_in_progress.borrow_mut().remove(&raw_id);
1498
1499 let mut inner = context.inner.lock();
1500 let new_len = raw_id as usize + 1;
1501 if inner.remapped_ctxts.len() < new_len {
1502 inner.remapped_ctxts.resize(new_len, None);
1503 }
1504 inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
1505 inner.decoding.remove(&raw_id);
1506
1507 ctxt
1508}
1509
1510fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextData)>(
1511 ctxts: impl Iterator<Item = SyntaxContext>,
1512 mut f: F,
1513) {
1514 let all_data: Vec<_> = HygieneData::with(|data| {
1515 ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
1516 });
1517 for (ctxt, data) in all_data.into_iter() {
1518 f(ctxt.0, ctxt, &data);
1519 }
1520}
1521
1522fn for_all_expns_in(
1523 expns: impl Iterator<Item = ExpnId>,
1524 mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
1525) {
1526 let all_data: Vec<_> = HygieneData::with(|data| {
1527 expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
1528 });
1529 for (expn, data, hash) in all_data.into_iter() {
1530 f(expn, &data, hash);
1531 }
1532}
1533
1534impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1535 fn encode(&self, e: &mut E) {
1536 self.to_expn_id().encode(e);
1537 }
1538}
1539
1540impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1541 fn decode(d: &mut D) -> Self {
1542 ExpnId::expect_local(ExpnId::decode(d))
1543 }
1544}
1545
1546pub fn raw_encode_syntax_context<E: Encoder>(
1547 ctxt: SyntaxContext,
1548 context: &HygieneEncodeContext,
1549 e: &mut E,
1550) {
1551 if !context.serialized_ctxts.lock().contains(&ctxt) {
1552 context.latest_ctxts.lock().insert(ctxt);
1553 }
1554 ctxt.0.encode(e);
1555}
1556
1557fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1567 assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1569 assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1570 let mut expn_hash = expn_data.hash_expn(&mut ctx);
1571
1572 let disambiguator = HygieneData::with(|data| {
1573 let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1576 let disambiguator = *disambig;
1577 *disambig += 1;
1578 disambiguator
1579 });
1580
1581 if disambiguator != 0 {
1582 debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1583
1584 expn_data.disambiguator = disambiguator;
1585 expn_hash = expn_data.hash_expn(&mut ctx);
1586
1587 #[cfg(debug_assertions)]
1589 HygieneData::with(|data| {
1590 assert_eq!(
1591 data.expn_data_disambiguators.get(&expn_hash),
1592 None,
1593 "Hash collision after disambiguator update!",
1594 );
1595 });
1596 }
1597
1598 ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1599}
1600
1601impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1602 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1603 const TAG_EXPANSION: u8 = 0;
1604 const TAG_NO_EXPANSION: u8 = 1;
1605
1606 if self.is_root() {
1607 TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1608 } else {
1609 TAG_EXPANSION.hash_stable(ctx, hasher);
1610 let (expn_id, transparency) = self.outer_mark();
1611 expn_id.hash_stable(ctx, hasher);
1612 transparency.hash_stable(ctx, hasher);
1613 }
1614 }
1615}
1616
1617impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1618 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1619 assert_default_hashing_controls(ctx, "ExpnId");
1620 let hash = if *self == ExpnId::root() {
1621 Fingerprint::ZERO
1623 } else {
1624 self.expn_hash().0
1625 };
1626
1627 hash.hash_stable(ctx, hasher);
1628 }
1629}