diff options
| author | bors <bors@rust-lang.org> | 2018-12-20 12:42:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-12-20 12:42:54 +0000 |
| commit | 9622f9dc4745eb59fd229477f453ae83e8044db9 (patch) | |
| tree | 4d230e44e0f31c6c44a2728e4a1e89d513bfb441 /src/test | |
| parent | 4755e2f3b635ad7391ba88b18672b05cbae5ba4c (diff) | |
| parent | edab6c74923cacb3058fb7942577ad27e7cd32ff (diff) | |
Auto merge of #56647 - petrochenkov:dcrate2, r=alexcrichton
Rework treatment of `$crate` in procedural macros Important clarification: `$crate` below means "processed `$crate`" or "output `$crate`". In the input of a decl macro `$crate` is just two separate tokens, but in the *output of a decl macro* `$crate` is a single keyword identifier (https://github.com/rust-lang/rust/issues/55640#issuecomment-435692791). First of all, this PR removes the `eliminate_crate_var` hack. `$crate::foo` is no longer replaced with `::foo` or `::crate_name::foo` in the input of derive proc macros, it's passed to the macro instead with its precise span and hygiene data, and can be treated as any other path segment keyword (like `crate` or `self`) after that. (Note: `eliminate_crate_var` was never used for non-derive proc macros.) This creates an annoying problem - derive macros still may stringify their input before processing and expect `$crate` survive that stringification and refer to the same crate (the Rust 1.15-1.29 way of doing things). Moreover, the input of proc macro attributes and derives (but not fn-like proc macros) also effectively survives stringification before being passed to the macro (also for legacy implementation reasons). So we kind of resurrect the `eliminate_crate_var` hack in reduced form, but apply it only to AST pretty-printing. If an AST fragment is pretty-printed, the resulting *text* will have `$crate` replaced with `crate` or `::crate_name`. This should be enough to keep all the legacy cases working. Closes https://github.com/rust-lang/rust/issues/55640 Closes https://github.com/rust-lang/rust/issues/56622 r? @ghost
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/pretty/issue-4264.pp | 4 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/auxiliary/dollar-crate.rs | 28 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/dollar-crate.rs | 40 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/dollar-crate.stderr | 29 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/dollar-crate.stdout | 240 |
6 files changed, 355 insertions, 2 deletions
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 5f42b86c82a..3b01ab3a47b 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -39,8 +39,8 @@ pub fn bar() ({ - ((::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::fmt::Arguments>::new_v1 + (($crate::fmt::format as + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<$crate::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test" as diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs new file mode 100644 index 00000000000..8f15a2b975b --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs @@ -0,0 +1,16 @@ +pub type S = u8; + +#[macro_export] +macro_rules! external { + () => { + dollar_crate::m! { + struct M($crate::S); + } + + #[dollar_crate::a] + struct A($crate::S); + + #[derive(dollar_crate::d)] + struct D($crate::S); + }; +} diff --git a/src/test/ui/proc-macro/auxiliary/dollar-crate.rs b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs new file mode 100644 index 00000000000..d0ea850d4e3 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/dollar-crate.rs @@ -0,0 +1,28 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn m(input: TokenStream) -> TokenStream { + println!("PROC MACRO INPUT (PRETTY-PRINTED): {}", input); + println!("PROC MACRO INPUT: {:#?}", input); + input.into_iter().collect() +} + +#[proc_macro_attribute] +pub fn a(_args: TokenStream, input: TokenStream) -> TokenStream { + println!("ATTRIBUTE INPUT (PRETTY-PRINTED): {}", input); + println!("ATTRIBUTE INPUT: {:#?}", input); + input.into_iter().collect() +} + +#[proc_macro_derive(d)] +pub fn d(input: TokenStream) -> TokenStream { + println!("DERIVE INPUT (PRETTY-PRINTED): {}", input); + println!("DERIVE INPUT: {:#?}", input); + input.into_iter().collect() +} diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs new file mode 100644 index 00000000000..1460e9a3b2d --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.rs @@ -0,0 +1,40 @@ +// edition:2018 +// aux-build:dollar-crate.rs +// aux-build:dollar-crate-external.rs + +// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`. +// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)" +// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)" + +extern crate dollar_crate; +extern crate dollar_crate_external; + +type S = u8; + +mod local { + use crate::dollar_crate; + + macro_rules! local { + () => { + dollar_crate::m! { + struct M($crate::S); + } + + #[dollar_crate::a] + struct A($crate::S); + + #[derive(dollar_crate::d)] + struct D($crate::S); //~ ERROR the name `D` is defined multiple times + }; + } + + local!(); +} + +mod external { + use crate::dollar_crate_external; + + dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times +} + +fn main() {} diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr new file mode 100644 index 00000000000..08de3c7d1a6 --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.stderr @@ -0,0 +1,29 @@ +error[E0428]: the name `D` is defined multiple times + --> $DIR/dollar-crate.rs:27:13 + | +LL | struct D($crate::S); //~ ERROR the name `D` is defined multiple times + | ^^^^^^^^^^^^^^^^^^^^ + | | + | `D` redefined here + | previous definition of the type `D` here +... +LL | local!(); + | --------- in this macro invocation + | + = note: `D` must be defined only once in the type namespace of this module + +error[E0428]: the name `D` is defined multiple times + --> $DIR/dollar-crate.rs:37:5 + | +LL | dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `D` redefined here + | previous definition of the type `D` here + | + = note: `D` must be defined only once in the type namespace of this module + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0428`. diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout new file mode 100644 index 00000000000..c47b3603f41 --- /dev/null +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -0,0 +1,240 @@ +PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; +PROC MACRO INPUT: TokenStream [ + Ident { + ident: "struct", + span: #2 bytes(LO..HI) + }, + Ident { + ident: "M", + span: #2 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #2 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #2 bytes(LO..HI) + } + ], + span: #2 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #2 bytes(LO..HI) + } +] +ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S); +ATTRIBUTE INPUT: TokenStream [ + Ident { + ident: "struct", + span: #2 bytes(LO..HI) + }, + Ident { + ident: "A", + span: #2 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #2 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #2 bytes(LO..HI) + } + ], + span: #2 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #2 bytes(LO..HI) + } +] +DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S); +DERIVE INPUT: TokenStream [ + Ident { + ident: "struct", + span: #2 bytes(LO..HI) + }, + Ident { + ident: "D", + span: #2 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #2 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #2 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #2 bytes(LO..HI) + } + ], + span: #2 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #2 bytes(LO..HI) + } +] +PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; +PROC MACRO INPUT: TokenStream [ + Ident { + ident: "struct", + span: #10 bytes(LO..HI) + }, + Ident { + ident: "M", + span: #10 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #10 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #10 bytes(LO..HI) + } + ], + span: #10 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #10 bytes(LO..HI) + } +] +ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S); +ATTRIBUTE INPUT: TokenStream [ + Ident { + ident: "struct", + span: #10 bytes(LO..HI) + }, + Ident { + ident: "A", + span: #10 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #10 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #10 bytes(LO..HI) + } + ], + span: #10 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #10 bytes(LO..HI) + } +] +DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S); +DERIVE INPUT: TokenStream [ + Ident { + ident: "struct", + span: #10 bytes(LO..HI) + }, + Ident { + ident: "D", + span: #10 bytes(LO..HI) + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "$crate", + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Joint, + span: #10 bytes(LO..HI) + }, + Punct { + ch: ':', + spacing: Alone, + span: #10 bytes(LO..HI) + }, + Ident { + ident: "S", + span: #10 bytes(LO..HI) + } + ], + span: #10 bytes(LO..HI) + }, + Punct { + ch: ';', + spacing: Alone, + span: #10 bytes(LO..HI) + } +] |
