about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-20 12:42:54 +0000
committerbors <bors@rust-lang.org>2018-12-20 12:42:54 +0000
commit9622f9dc4745eb59fd229477f453ae83e8044db9 (patch)
tree4d230e44e0f31c6c44a2728e4a1e89d513bfb441 /src/test
parent4755e2f3b635ad7391ba88b18672b05cbae5ba4c (diff)
parentedab6c74923cacb3058fb7942577ad27e7cd32ff (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.pp4
-rw-r--r--src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/dollar-crate.rs28
-rw-r--r--src/test/ui/proc-macro/dollar-crate.rs40
-rw-r--r--src/test/ui/proc-macro/dollar-crate.stderr29
-rw-r--r--src/test/ui/proc-macro/dollar-crate.stdout240
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)
+    }
+]