From d052d28d70b31fac942765da137f794835e6536e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 29 Nov 2017 01:05:31 -0800 Subject: Improve interaction between macros 2.0 and `macro_rules!`. --- src/libsyntax_pos/hygiene.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/libsyntax_pos') diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ab6c3f7d62d..23c29e6c6dd 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -181,6 +181,33 @@ impl SyntaxContext { /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { + if mark.kind() == MarkKind::Modern { + return self.apply_mark_internal(mark); + } + + let call_site_ctxt = + mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()).modern(); + if call_site_ctxt == SyntaxContext::empty() { + return self.apply_mark_internal(mark); + } + + // Otherwise, `mark` is a macros 1.0 definition and the call site is in a + // macros 2.0 expansion, i.e. a macros 1.0 invocation is in a macros 2.0 definition. + // + // In this case, the tokens from the macros 1.0 definition inherit the hygiene + // at their invocation. That is, we pretend that the macros 1.0 definition + // was defined at its invocation (i.e. inside the macros 2.0 definition) + // so that the macros 2.0 definition remains hygienic. + // + // See the example at `test/run-pass/hygiene/legacy_interaction.rs`. + let mut ctxt = call_site_ctxt; + for mark in self.marks() { + ctxt = ctxt.apply_mark_internal(mark); + } + ctxt.apply_mark_internal(mark) + } + + fn apply_mark_internal(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; let mut modern = syntax_contexts[self.0 as usize].modern; @@ -215,6 +242,18 @@ impl SyntaxContext { }) } + pub fn marks(mut self) -> Vec { + HygieneData::with(|data| { + let mut marks = Vec::new(); + while self != SyntaxContext::empty() { + marks.push(data.syntax_contexts[self.0 as usize].outer_mark); + self = data.syntax_contexts[self.0 as usize].prev_ctxt; + } + marks.reverse(); + marks + }) + } + /// Adjust this context for resolution in a scope created by the given expansion. /// For example, consider the following three resolutions of `f`: /// ```rust -- cgit 1.4.1-3-g733a5