diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 4390085cd049a..ea77ae0e17286 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -67,21 +67,32 @@ pub struct SyntaxContextData { outer_transparency: Transparency, parent: SyntaxContext, /// This context, but with all transparent and semi-transparent expansions filtered away. - opaque: SyntaxContext, + opaque: Option, /// This context, but with all transparent expansions filtered away. - opaque_and_semitransparent: SyntaxContext, + opaque_and_semitransparent: Option, /// Name of the crate to which `$crate` with this context would resolve. dollar_crate_name: Symbol, } impl SyntaxContextData { + fn from_key((parent, outer_expn, outer_transparency): SyntaxContextKey) -> SyntaxContextData { + SyntaxContextData { + outer_expn, + outer_transparency, + parent, + opaque: None, + opaque_and_semitransparent: None, + dollar_crate_name: kw::DollarCrate, + } + } + fn root() -> SyntaxContextData { SyntaxContextData { outer_expn: ExpnId::root(), outer_transparency: Transparency::Opaque, parent: SyntaxContext::root(), - opaque: SyntaxContext::root(), - opaque_and_semitransparent: SyntaxContext::root(), + opaque: Some(SyntaxContext::root()), + opaque_and_semitransparent: Some(SyntaxContext::root()), dollar_crate_name: kw::DollarCrate, } } @@ -447,14 +458,43 @@ impl HygieneData { } } - fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { + fn normalize_to_macros_2_0(&mut self, ctxt: SyntaxContext) -> SyntaxContext { debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - self.syntax_context_data[ctxt.0 as usize].opaque + if let Some(opaque) = self.syntax_context_data[ctxt.0 as usize].opaque { + return opaque; + } + + let SyntaxContextData { outer_expn, outer_transparency, parent, .. } = + self.syntax_context_data[ctxt.0 as usize]; + let parent_opaque = self.normalize_to_macros_2_0(parent); + let opaque = match outer_transparency { + Transparency::Transparent | Transparency::SemiTransparent => parent_opaque, + Transparency::Opaque => self.alloc_ctxt(parent_opaque, outer_expn, outer_transparency), + }; + self.syntax_context_data[ctxt.0 as usize].opaque = Some(opaque); + opaque } - fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { + fn normalize_to_macro_rules(&mut self, ctxt: SyntaxContext) -> SyntaxContext { debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent + if let Some(opaque_and_semitransparent) = + self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent + { + return opaque_and_semitransparent; + } + + let SyntaxContextData { outer_expn, outer_transparency, parent, .. } = + self.syntax_context_data[ctxt.0 as usize]; + let parent_opaque_and_semitransparent = self.normalize_to_macro_rules(parent); + let opaque_and_semitransparent = match outer_transparency { + Transparency::Transparent => parent_opaque_and_semitransparent, + Transparency::SemiTransparent | Transparency::Opaque => { + self.alloc_ctxt(parent_opaque_and_semitransparent, outer_expn, outer_transparency) + } + }; + self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent = + Some(opaque_and_semitransparent); + opaque_and_semitransparent } fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { @@ -543,7 +583,7 @@ impl HygieneData { ) -> SyntaxContext { assert_ne!(expn_id, ExpnId::root()); if transparency == Transparency::Opaque { - return self.apply_mark_internal(ctxt, expn_id, transparency); + return self.alloc_ctxt(ctxt, expn_id, transparency); } let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt(); @@ -554,7 +594,7 @@ impl HygieneData { }; if call_site_ctxt.is_root() { - return self.apply_mark_internal(ctxt, expn_id, transparency); + return self.alloc_ctxt(ctxt, expn_id, transparency); } // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a @@ -567,73 +607,25 @@ impl HygieneData { // // See the example at `test/ui/hygiene/legacy_interaction.rs`. for (expn_id, transparency) in self.marks(ctxt) { - call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency); + call_site_ctxt = self.alloc_ctxt(call_site_ctxt, expn_id, transparency); } - self.apply_mark_internal(call_site_ctxt, expn_id, transparency) + self.alloc_ctxt(call_site_ctxt, expn_id, transparency) } - fn apply_mark_internal( + /// Allocate a new context with the given key, or retrieve it from cache if the given key + /// already exists. The auxiliary fields are calculated from the key. + fn alloc_ctxt( &mut self, - ctxt: SyntaxContext, + parent: SyntaxContext, expn_id: ExpnId, transparency: Transparency, ) -> SyntaxContext { - let syntax_context_data = &mut self.syntax_context_data; - debug_assert!(!syntax_context_data[ctxt.0 as usize].is_decode_placeholder()); - let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; - let mut opaque_and_semitransparent = - syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; - - if transparency >= Transparency::Opaque { - let parent = opaque; - opaque = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque = SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque: new_opaque, - opaque_and_semitransparent: new_opaque, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque - }); - } + debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder()); - if transparency >= Transparency::SemiTransparent { - let parent = opaque_and_semitransparent; - opaque_and_semitransparent = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque_and_semitransparent = - SyntaxContext::from_usize(syntax_context_data.len()); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent: new_opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque_and_semitransparent - }); - } - - let parent = ctxt; - *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - SyntaxContext::from_usize(syntax_context_data.len() - 1) + let key = (parent, expn_id, transparency); + *self.syntax_context_map.entry(key).or_insert_with(|| { + self.syntax_context_data.push(SyntaxContextData::from_key(key)); + SyntaxContext::from_usize(self.syntax_context_data.len() - 1) }) } } diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index c80a33206fb4f..6fd6cb474693b 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -5,19 +5,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#4), + span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#5), + span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4), }, ] #![feature /* 0#0 */(prelude_import)] @@ -59,7 +59,7 @@ macro_rules! outer struct S /* 0#0 */; macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } -struct S /* 0#4 */; +struct S /* 0#5 */; // OK, not a duplicate definition of `S` fn main /* 0#0 */() {} @@ -70,7 +70,7 @@ crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") -crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") @@ -83,9 +83,9 @@ SyntaxContexts: #1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) #2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent) #3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent) -#4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) -#5: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque) +#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque) #6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque) -#7: parent: #5, outer_mark: (crate0::{{expn4}}, Transparent) -#8: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent) +#7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent) +#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent) */