diff options
| author | Tyler Mandry <tmandry@gmail.com> | 2019-10-03 16:25:39 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-03 16:25:39 -0700 |
| commit | 2a9bd759949cebd4b0176b773fdf61a07f517d55 (patch) | |
| tree | e6b843cad8b43ae65d295ee91e0c945336954e96 /src/test | |
| parent | da0afc163848ea0530bee2099bfd79fc40bbf39a (diff) | |
| parent | d1310dc6c989e191d85c73c943d4175fbf1dccb8 (diff) | |
| download | rust-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/test')
| -rw-r--r-- | src/test/ui/proc-macro/auxiliary/mixed-site-span.rs | 42 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/dollar-crate-issue-62325.stdout | 22 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/dollar-crate.stdout | 48 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/mixed-site-span.rs | 26 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/mixed-site-span.stderr | 49 |
5 files changed, 152 insertions, 35 deletions
diff --git a/src/test/ui/proc-macro/auxiliary/mixed-site-span.rs b/src/test/ui/proc-macro/auxiliary/mixed-site-span.rs new file mode 100644 index 00000000000..dea5ea04aa8 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/mixed-site-span.rs @@ -0,0 +1,42 @@ +// force-host +// no-prefer-dynamic + +#![feature(proc_macro_hygiene)] +#![feature(proc_macro_mixed_site)] +#![feature(proc_macro_quote)] + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn proc_macro_rules(input: TokenStream) -> TokenStream { + if input.is_empty() { + let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site())); + let item_def = id("ItemDef"); + let local_def = id("local_def"); + let item_use = id("ItemUse"); + let local_use = id("local_use"); + let mut single_quote = Punct::new('\'', Spacing::Joint); + single_quote.set_span(Span::mixed_site()); + let label_use: TokenStream = [ + TokenTree::from(single_quote), + id("label_use"), + ].iter().cloned().collect(); + quote!( + struct $item_def; + let $local_def = 0; + + $item_use; // OK + $local_use; // ERROR + break $label_use; // ERROR + ) + } else { + let mut dollar_crate = input.into_iter().next().unwrap(); + dollar_crate.set_span(Span::mixed_site()); + quote!( + type A = $dollar_crate::ItemUse; + ) + } +} diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index 7ee8078b2c5..619b2fd5321 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -59,54 +59,54 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct B (identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "B", - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: '!', spacing: Alone, - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ], - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ], - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #8 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index 4f7e000265e..5fdc6f8ee96 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -124,40 +124,40 @@ PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "M", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ], - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ] PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S); @@ -165,40 +165,40 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "A", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ], - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S); @@ -206,39 +206,39 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "D", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ], - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI), + span: #13 bytes(LO..HI), }, ] diff --git a/src/test/ui/proc-macro/mixed-site-span.rs b/src/test/ui/proc-macro/mixed-site-span.rs new file mode 100644 index 00000000000..69c32a96ca0 --- /dev/null +++ b/src/test/ui/proc-macro/mixed-site-span.rs @@ -0,0 +1,26 @@ +// Proc macros using `mixed_site` spans exhibit usual properties of `macro_rules` hygiene. + +// aux-build:mixed-site-span.rs + +#![feature(proc_macro_hygiene)] + +#[macro_use] +extern crate mixed_site_span; + +struct ItemUse; + +fn main() { + 'label_use: loop { + let local_use = 1; + proc_macro_rules!(); + //~^ ERROR use of undeclared label `'label_use` + //~| ERROR cannot find value `local_use` in this scope + ItemDef; // OK + local_def; //~ ERROR cannot find value `local_def` in this scope + } +} + +macro_rules! pass_dollar_crate { + () => (proc_macro_rules!($crate);) //~ ERROR cannot find type `ItemUse` in crate `$crate` +} +pass_dollar_crate!(); diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr new file mode 100644 index 00000000000..475e3e0ca35 --- /dev/null +++ b/src/test/ui/proc-macro/mixed-site-span.stderr @@ -0,0 +1,49 @@ +error[E0426]: use of undeclared label `'label_use` + --> $DIR/mixed-site-span.rs:15:9 + | +LL | proc_macro_rules!(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | undeclared label `'label_use` + | in this macro invocation + +error[E0425]: cannot find value `local_use` in this scope + --> $DIR/mixed-site-span.rs:15:9 + | +LL | proc_macro_rules!(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | not found in this scope + | in this macro invocation + +error[E0425]: cannot find value `local_def` in this scope + --> $DIR/mixed-site-span.rs:19:9 + | +LL | local_def; + | ^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `ItemUse` in crate `$crate` + --> $DIR/auxiliary/mixed-site-span.rs:14:1 + | +LL | / pub fn proc_macro_rules(input: TokenStream) -> TokenStream { +LL | | if input.is_empty() { +LL | | let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site())); +LL | | let item_def = id("ItemDef"); +... | +LL | | } +LL | | } + | |_^ not found in `$crate` + | + ::: $DIR/mixed-site-span.rs:26:1 + | +LL | pass_dollar_crate!(); + | --------------------- in this macro invocation +help: possible candidate is found in another module, you can import it into scope + | +LL | use ItemUse; + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0412, E0425, E0426. +For more information about an error, try `rustc --explain E0412`. |
