about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorTyler Mandry <tmandry@gmail.com>2019-10-03 16:25:39 -0700
committerGitHub <noreply@github.com>2019-10-03 16:25:39 -0700
commit2a9bd759949cebd4b0176b773fdf61a07f517d55 (patch)
treee6b843cad8b43ae65d295ee91e0c945336954e96 /src/libsyntax
parentda0afc163848ea0530bee2099bfd79fc40bbf39a (diff)
parentd1310dc6c989e191d85c73c943d4175fbf1dccb8 (diff)
downloadrust-2a9bd759949cebd4b0176b773fdf61a07f517d55.tar.gz
rust-2a9bd759949cebd4b0176b773fdf61a07f517d55.zip
Rollup merge of #64690 - petrochenkov:mixed, r=dtolnay
proc_macro API: Expose `macro_rules` hygiene

Proc macros do not have direct access to our oldest and most stable hygiene kind - `macro_rules` hygiene.

To emulate it macro authors have to go through two steps - first generate a temporary `macro_rules` item (using a derive, at least until https://github.com/rust-lang/rust/pull/64035 is merged), then generate a macro call to that item. Popular crates like [proc_macro_hack](https://crates.io/crates/proc-macro-hack) use this trick to generate hygienic identifiers from proc macros.

I'd say that these workarounds with nested macro definitions have more chances to hit some corner cases in our hygiene system, in which we don't have full confidence.
So, let's provide a direct access to `macro_rules` hygiene instead.

This PR does that by adding a new method `Span::mixed_site` (bikeshedding is welcome) in addition to existing `Span::call_site` (stable) and `Span::def_site` (unstable).
Identifiers with this span resolve at def-site in for local variables, labels and `$crate`, and resolve at call-site for everything else, i.e. exactly like identifiers produced by `macro_rules`.

This API addition opens the way to stabilizing proc macros in expression positions (https://github.com/rust-lang/rust/issues/54727), for which use of call-site hygiene or workarounds with temporary items would be quite unfortunate.
(`macro_rules` expanded in expression position, on the other hand, are stable since 1.0 and widely used.)

r? @dtolnay @alexcrichton
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs6
-rw-r--r--src/libsyntax/ext/proc_macro_server.rs5
2 files changed, 11 insertions, 0 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 54cfb80573e..583fb3f7701 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -953,6 +953,12 @@ impl<'a> ExtCtxt<'a> {
         span.with_call_site_ctxt(self.current_expansion.id)
     }
 
+    /// Equivalent of `Span::mixed_site` from the proc macro API,
+    /// except that the location is taken from the span passed as an argument.
+    pub fn with_mixed_site_ctxt(&self, span: Span) -> Span {
+        span.with_mixed_site_ctxt(self.current_expansion.id)
+    }
+
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs
index dfec9ee2880..021ec46d987 100644
--- a/src/libsyntax/ext/proc_macro_server.rs
+++ b/src/libsyntax/ext/proc_macro_server.rs
@@ -355,6 +355,7 @@ pub(crate) struct Rustc<'a> {
     sess: &'a ParseSess,
     def_site: Span,
     call_site: Span,
+    mixed_site: Span,
 }
 
 impl<'a> Rustc<'a> {
@@ -364,6 +365,7 @@ impl<'a> Rustc<'a> {
             sess: cx.parse_sess,
             def_site: cx.with_def_site_ctxt(expn_data.def_site),
             call_site: cx.with_call_site_ctxt(expn_data.call_site),
+            mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
         }
     }
 
@@ -664,6 +666,9 @@ impl server::Span for Rustc<'_> {
     fn call_site(&mut self) -> Self::Span {
         self.call_site
     }
+    fn mixed_site(&mut self) -> Self::Span {
+        self.mixed_site
+    }
     fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
         self.sess.source_map().lookup_char_pos(span.lo()).file
     }