diff options
| author | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2017-11-29 01:05:31 -0800 |
|---|---|---|
| committer | Jeffrey Seyfried <jeffrey.seyfried@gmail.com> | 2017-12-13 13:33:03 -0800 |
| commit | d052d28d70b31fac942765da137f794835e6536e (patch) | |
| tree | b339c73c8f824f39bab9aa06dc785964f46e917d /src/libsyntax_pos | |
| parent | 3dfbc88a626625be01e112da11ec367e2fc71bb3 (diff) | |
| download | rust-d052d28d70b31fac942765da137f794835e6536e.tar.gz rust-d052d28d70b31fac942765da137f794835e6536e.zip | |
Improve interaction between macros 2.0 and `macro_rules!`.
Diffstat (limited to 'src/libsyntax_pos')
| -rw-r--r-- | src/libsyntax_pos/hygiene.rs | 39 |
1 files changed, 39 insertions, 0 deletions
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<Mark> { + 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 |
