summaryrefslogtreecommitdiffstats
path: root/src/test/ui/proc-macro/auxiliary
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/proc-macro/auxiliary')
-rw-r--r--src/test/ui/proc-macro/auxiliary/add-impl.rs21
-rw-r--r--src/test/ui/proc-macro/auxiliary/amputate-span.rs14
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/cmp.rs21
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/mod.rs24
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/parse.rs55
-rw-r--r--src/test/ui/proc-macro/auxiliary/append-impl.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/assert-span-pos.rs37
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-args.rs28
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-cfg.rs21
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-on-trait.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs51
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs49
-rw-r--r--src/test/ui/proc-macro/auxiliary/attribute-spans-preserved.rs35
-rw-r--r--src/test/ui/proc-macro/auxiliary/attributes-included.rs150
-rw-r--r--src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs23
-rw-r--r--src/test/ui/proc-macro/auxiliary/bang-macro.rs17
-rw-r--r--src/test/ui/proc-macro/auxiliary/bang_proc_macro2.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/builtin-attrs.rs27
-rw-r--r--src/test/ui/proc-macro/auxiliary/call-deprecated.rs19
-rw-r--r--src/test/ui/proc-macro/auxiliary/call-site.rs27
-rw-r--r--src/test/ui/proc-macro/auxiliary/cond_plugin.rs38
-rw-r--r--src/test/ui/proc-macro/auxiliary/count_compound_ops.rs32
-rw-r--r--src/test/ui/proc-macro/auxiliary/custom-attr-only-one-derive.rs18
-rw-r--r--src/test/ui/proc-macro/auxiliary/custom-quote.rs32
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-a.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-atob.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-attr-cfg.rs14
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs17
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-b.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-bad.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-clona.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-ctod.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-foo.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs2
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs12
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-nothing.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-same-struct.rs21
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-two-attrs.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-union.rs18
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-unstable-2.rs17
-rw-r--r--src/test/ui/proc-macro/auxiliary/derive-unstable.rs14
-rw-r--r--src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs22
-rw-r--r--src/test/ui/proc-macro/auxiliary/double.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/duplicate.rs32
-rw-r--r--src/test/ui/proc-macro/auxiliary/edition-imports-2015.rs20
-rw-r--r--src/test/ui/proc-macro/auxiliary/empty-crate.rs5
-rw-r--r--src/test/ui/proc-macro/auxiliary/expand-expr.rs149
-rw-r--r--src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs22
-rw-r--r--src/test/ui/proc-macro/auxiliary/external-crate-var.rs40
-rw-r--r--src/test/ui/proc-macro/auxiliary/first-second.rs20
-rw-r--r--src/test/ui/proc-macro/auxiliary/gen-lifetime-token.rs25
-rw-r--r--src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs23
-rw-r--r--src/test/ui/proc-macro/auxiliary/gen-macro-rules.rs12
-rw-r--r--src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/generate-mod.rs58
-rw-r--r--src/test/ui/proc-macro/auxiliary/hygiene_example.rs7
-rw-r--r--src/test/ui/proc-macro/auxiliary/hygiene_example_codegen.rs27
-rw-r--r--src/test/ui/proc-macro/auxiliary/included-file.txt1
-rw-r--r--src/test/ui/proc-macro/auxiliary/invalid-punct-ident.rs28
-rw-r--r--src/test/ui/proc-macro/auxiliary/is-available.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-38586.rs11
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-39889.rs17
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-42708.rs18
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-50061.rs12
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-50493.rs21
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-59191.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-66286.rs14
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-75801.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-79242.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-79825.rs14
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-83510.rs19
-rw-r--r--src/test/ui/proc-macro/auxiliary/issue-91800-macro.rs26
-rw-r--r--src/test/ui/proc-macro/auxiliary/lifetimes-rpass.rs26
-rw-r--r--src/test/ui/proc-macro/auxiliary/lifetimes.rs20
-rw-r--r--src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs89
-rw-r--r--src/test/ui/proc-macro/auxiliary/make-macro.rs18
-rw-r--r--src/test/ui/proc-macro/auxiliary/meta-delim.rs12
-rw-r--r--src/test/ui/proc-macro/auxiliary/meta-macro.rs15
-rw-r--r--src/test/ui/proc-macro/auxiliary/mixed-site-span.rs40
-rw-r--r--src/test/ui/proc-macro/auxiliary/modify-ast.rs47
-rw-r--r--src/test/ui/proc-macro/auxiliary/multiple-derives.rs22
-rw-r--r--src/test/ui/proc-macro/auxiliary/multispan.rs37
-rw-r--r--src/test/ui/proc-macro/auxiliary/negative-token.rs18
-rw-r--r--src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs16
-rw-r--r--src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs25
-rw-r--r--src/test/ui/proc-macro/auxiliary/not-joint.rs30
-rw-r--r--src/test/ui/proc-macro/auxiliary/parent-source-spans.rs43
-rw-r--r--src/test/ui/proc-macro/auxiliary/proc-macro-panic.rs13
-rw-r--r--src/test/ui/proc-macro/auxiliary/raw-ident.rs35
-rw-r--r--src/test/ui/proc-macro/auxiliary/recollect.rs12
-rw-r--r--src/test/ui/proc-macro/auxiliary/resolved-located-at.rs31
-rw-r--r--src/test/ui/proc-macro/auxiliary/span-api-tests.rs45
-rw-r--r--src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs49
-rw-r--r--src/test/ui/proc-macro/auxiliary/span-test-macros.rs9
-rw-r--r--src/test/ui/proc-macro/auxiliary/subspan.rs38
-rw-r--r--src/test/ui/proc-macro/auxiliary/test-macros.rs180
-rw-r--r--src/test/ui/proc-macro/auxiliary/three-equals.rs49
-rw-r--r--src/test/ui/proc-macro/auxiliary/weird-hygiene.rs48
99 files changed, 2736 insertions, 0 deletions
diff --git a/src/test/ui/proc-macro/auxiliary/add-impl.rs b/src/test/ui/proc-macro/auxiliary/add-impl.rs
new file mode 100644
index 000000000..741e64875
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/add-impl.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(AddImpl)]
+// #[cfg(proc_macro)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ "impl B {
+ fn foo(&self) {}
+ }
+
+ fn foo() {}
+
+ mod bar { pub fn foo() {} }
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/amputate-span.rs b/src/test/ui/proc-macro/auxiliary/amputate-span.rs
new file mode 100644
index 000000000..1a82119ae
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/amputate-span.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn drop_first_token(attr: TokenStream, input: TokenStream) -> TokenStream {
+ assert!(attr.is_empty());
+ input.into_iter().skip(1).collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/api/cmp.rs b/src/test/ui/proc-macro/auxiliary/api/cmp.rs
new file mode 100644
index 000000000..5784a6e5d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/api/cmp.rs
@@ -0,0 +1,21 @@
+use proc_macro::{LineColumn, Punct, Spacing};
+
+pub fn test() {
+ test_line_column_ord();
+ test_punct_eq();
+}
+
+fn test_line_column_ord() {
+ let line0_column0 = LineColumn { line: 0, column: 0 };
+ let line0_column1 = LineColumn { line: 0, column: 1 };
+ let line1_column0 = LineColumn { line: 1, column: 0 };
+ assert!(line0_column0 < line0_column1);
+ assert!(line0_column1 < line1_column0);
+}
+
+fn test_punct_eq() {
+ let colon_alone = Punct::new(':', Spacing::Alone);
+ assert_eq!(colon_alone, ':');
+ let colon_joint = Punct::new(':', Spacing::Joint);
+ assert_eq!(colon_joint, ':');
+}
diff --git a/src/test/ui/proc-macro/auxiliary/api/mod.rs b/src/test/ui/proc-macro/auxiliary/api/mod.rs
new file mode 100644
index 000000000..739c25132
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/api/mod.rs
@@ -0,0 +1,24 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![crate_name = "proc_macro_api_tests"]
+#![feature(proc_macro_span)]
+#![deny(dead_code)] // catch if a test function is never called
+
+extern crate proc_macro;
+
+mod cmp;
+mod parse;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn run(input: TokenStream) -> TokenStream {
+ assert!(input.is_empty());
+
+ cmp::test();
+ parse::test();
+
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/api/parse.rs b/src/test/ui/proc-macro/auxiliary/api/parse.rs
new file mode 100644
index 000000000..27391f831
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/api/parse.rs
@@ -0,0 +1,55 @@
+// ignore-tidy-linelength
+
+use proc_macro::Literal;
+
+pub fn test() {
+ test_display_literal();
+ test_parse_literal();
+}
+
+fn test_display_literal() {
+ assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10");
+ assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize");
+ assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0");
+ assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32");
+ assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0");
+ assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64");
+ assert_eq!(
+ Literal::f64_unsuffixed(1e100).to_string(),
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
+ );
+
+ assert_eq!(
+ Literal::string("a \t ❤ ' \" \u{1}").to_string(),
+ "\"a \\t ❤ ' \\\" \\u{1}\"",
+ );
+ assert_eq!(Literal::character('a').to_string(), "'a'");
+ assert_eq!(Literal::character('\t').to_string(), "'\\t'");
+ assert_eq!(Literal::character('❤').to_string(), "'❤'");
+ assert_eq!(Literal::character('\'').to_string(), "'\\''");
+ assert_eq!(Literal::character('"').to_string(), "'\"'");
+ assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'");
+}
+
+fn test_parse_literal() {
+ assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
+ assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
+ assert_eq!("'a'".parse::<Literal>().unwrap().to_string(), "'a'");
+ assert_eq!("\"\n\"".parse::<Literal>().unwrap().to_string(), "\"\n\"");
+ assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
+ assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
+ assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
+ assert_eq!("-10ulong".parse::<Literal>().unwrap().to_string(), "-10ulong");
+
+ assert!("true".parse::<Literal>().is_err());
+ assert!(".8".parse::<Literal>().is_err());
+ assert!("0 1".parse::<Literal>().is_err());
+ assert!("'a".parse::<Literal>().is_err());
+ assert!(" 0".parse::<Literal>().is_err());
+ assert!("0 ".parse::<Literal>().is_err());
+ assert!("/* comment */0".parse::<Literal>().is_err());
+ assert!("0/* comment */".parse::<Literal>().is_err());
+ assert!("0// comment".parse::<Literal>().is_err());
+ assert!("- 10".parse::<Literal>().is_err());
+ assert!("-'x'".parse::<Literal>().is_err());
+}
diff --git a/src/test/ui/proc-macro/auxiliary/append-impl.rs b/src/test/ui/proc-macro/auxiliary/append-impl.rs
new file mode 100644
index 000000000..b032b1337
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/append-impl.rs
@@ -0,0 +1,16 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Append)]
+pub fn derive_a(input: TokenStream) -> TokenStream {
+ "impl Append for A {
+ fn foo(&self) {}
+ }
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/assert-span-pos.rs b/src/test/ui/proc-macro/auxiliary/assert-span-pos.rs
new file mode 100644
index 000000000..455c5c7c3
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/assert-span-pos.rs
@@ -0,0 +1,37 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_diagnostic, proc_macro_span)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span};
+
+fn lit_span(tt: TokenTree) -> (Span, String) {
+ match tt {
+ TokenTree::Literal(..) |
+ TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()),
+ _ => panic!("expected a literal in token tree, got: {:?}", tt)
+ }
+}
+
+#[proc_macro]
+pub fn assert_span_pos(input: TokenStream) -> TokenStream {
+ let mut tokens = input.into_iter();
+ let (sp1, str1) = lit_span(tokens.next().expect("first argument"));
+ let _ = tokens.next();
+ let (_sp2, str2) = lit_span(tokens.next().expect("second argument"));
+
+ let line: usize = str1.parse().unwrap();
+ let col: usize = str2.parse().unwrap();
+
+ let sp1s = sp1.start();
+ if (line, col) != (sp1s.line, sp1s.column) {
+ let msg = format!("line/column mismatch: ({}, {}) != ({}, {})", line, col,
+ sp1s.line, sp1s.column);
+ sp1.error(msg).emit();
+ }
+
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attr-args.rs b/src/test/ui/proc-macro/auxiliary/attr-args.rs
new file mode 100644
index 000000000..5f76a4484
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attr-args.rs
@@ -0,0 +1,28 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = args.to_string();
+
+ assert_eq!(args, r#"text = "Hello, world!""#);
+
+ let input = input.to_string();
+
+ assert_eq!(input, "fn foo() {}");
+
+ r#"
+ fn foo() -> &'static str { "Hello, world!" }
+ "#.parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn identity(attr_args: TokenStream, _: TokenStream) -> TokenStream {
+ attr_args
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attr-cfg.rs b/src/test/ui/proc-macro/auxiliary/attr-cfg.rs
new file mode 100644
index 000000000..2f0054cc1
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attr-cfg.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn attr_cfg(args: TokenStream, input: TokenStream) -> TokenStream {
+ let input_str = input.to_string();
+
+ assert_eq!(input_str, "fn outer() -> u8
+{
+ #[cfg(foo)] fn inner() -> u8 { 1 } #[cfg(bar)] fn inner() -> u8 { 2 }
+ inner()
+}");
+
+ input
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs b/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs
new file mode 100644
index 000000000..3787b8eec
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {
+ drop(attr);
+ assert_eq!(item.to_string(), "fn foo() {}");
+ "fn foo(&self);".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs
new file mode 100644
index 000000000..5b386b46b
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs
@@ -0,0 +1,51 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "let string = \"Hello, world!\" ;");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "println! (\"{}\", string) ;");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "print_str(\"string\")");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "println! (\"{}\", string)");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn no_output(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert!(!item.to_string().is_empty());
+ "".parse().unwrap()
+
+}
+
+#[proc_macro_attribute]
+pub fn noop(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert!(!item.to_string().is_empty());
+ item
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs
new file mode 100644
index 000000000..4d6dc06b4
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs
@@ -0,0 +1,49 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "let string = \"Hello, world!\" ;");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_my_macro_stmt(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "my_macro! (\"{}\", string) ;");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "print_str(\"string\")");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn expect_my_macro_expr(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert_eq!(item.to_string(), "my_macro! (\"{}\", string)");
+ item
+}
+
+#[proc_macro_attribute]
+pub fn duplicate(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ format!("{}, {}", item, item).parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn no_output(attr: TokenStream, item: TokenStream) -> TokenStream {
+ assert!(attr.to_string().is_empty());
+ assert!(!item.to_string().is_empty());
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attribute-spans-preserved.rs b/src/test/ui/proc-macro/auxiliary/attribute-spans-preserved.rs
new file mode 100644
index 000000000..4d3279584
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attribute-spans-preserved.rs
@@ -0,0 +1,35 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn foo(attr: TokenStream, f: TokenStream) -> TokenStream {
+ let mut tokens = f.into_iter();
+ assert_eq!(tokens.next().unwrap().to_string(), "#");
+ let next_attr = match tokens.next().unwrap() {
+ TokenTree::Group(g) => g,
+ _ => panic!(),
+ };
+
+ let fn_tok = tokens.next().unwrap();
+ let ident_tok = tokens.next().unwrap();
+ let args_tok = tokens.next().unwrap();
+ let body = tokens.next().unwrap();
+
+ let new_body = attr.into_iter()
+ .chain(next_attr.stream().into_iter().skip(1));
+
+ let tokens = vec![
+ fn_tok,
+ ident_tok,
+ args_tok,
+ Group::new(Delimiter::Brace, new_body.collect()).into(),
+ ].into_iter().collect::<TokenStream>();
+ println!("{}", tokens);
+ return tokens
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attributes-included.rs b/src/test/ui/proc-macro/auxiliary/attributes-included.rs
new file mode 100644
index 000000000..a5eb40b28
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attributes-included.rs
@@ -0,0 +1,150 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Delimiter, Literal, Spacing, Group};
+
+#[proc_macro_attribute]
+pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream {
+ assert!(attr.is_empty());
+ let input = input.into_iter().collect::<Vec<_>>();
+ {
+ let mut cursor = &input[..];
+ assert_inline(&mut cursor);
+ assert_doc(&mut cursor);
+ assert_inline(&mut cursor);
+ assert_doc(&mut cursor);
+ assert_foo(&mut cursor);
+ assert!(cursor.is_empty());
+ }
+ fold_stream(input.into_iter().collect())
+}
+
+#[proc_macro_attribute]
+pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream {
+ assert!(attr.is_empty());
+ let input = input.into_iter().collect::<Vec<_>>();
+ {
+ let mut cursor = &input[..];
+ assert_inline(&mut cursor);
+ assert_doc(&mut cursor);
+ assert_invoc(&mut cursor);
+ assert_inline(&mut cursor);
+ assert_doc(&mut cursor);
+ assert_foo(&mut cursor);
+ assert!(cursor.is_empty());
+ }
+ input.into_iter().collect()
+}
+
+fn assert_inline(slice: &mut &[TokenTree]) {
+ match &slice[0] {
+ TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
+ _ => panic!("expected '#' char"),
+ }
+ match &slice[1] {
+ TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
+ _ => panic!("expected brackets"),
+ }
+ *slice = &slice[2..];
+}
+
+fn assert_doc(slice: &mut &[TokenTree]) {
+ match &slice[0] {
+ TokenTree::Punct(tt) => {
+ assert_eq!(tt.as_char(), '#');
+ assert_eq!(tt.spacing(), Spacing::Alone);
+ }
+ _ => panic!("expected #"),
+ }
+ let inner = match &slice[1] {
+ TokenTree::Group(tt) => {
+ assert_eq!(tt.delimiter(), Delimiter::Bracket);
+ tt.stream()
+ }
+ _ => panic!("expected brackets"),
+ };
+ let tokens = inner.into_iter().collect::<Vec<_>>();
+ let tokens = &tokens[..];
+
+ if tokens.len() != 3 {
+ panic!("expected three tokens in doc")
+ }
+
+ match &tokens[0] {
+ TokenTree::Ident(tt) => assert_eq!("doc", &*tt.to_string()),
+ _ => panic!("expected `doc`"),
+ }
+ match &tokens[1] {
+ TokenTree::Punct(tt) => {
+ assert_eq!(tt.as_char(), '=');
+ assert_eq!(tt.spacing(), Spacing::Alone);
+ }
+ _ => panic!("expected equals"),
+ }
+ match tokens[2] {
+ TokenTree::Literal(_) => {}
+ _ => panic!("expected literal"),
+ }
+
+ *slice = &slice[2..];
+}
+
+fn assert_invoc(slice: &mut &[TokenTree]) {
+ match &slice[0] {
+ TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
+ _ => panic!("expected '#' char"),
+ }
+ match &slice[1] {
+ TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
+ _ => panic!("expected brackets"),
+ }
+ *slice = &slice[2..];
+}
+
+fn assert_foo(slice: &mut &[TokenTree]) {
+ match &slice[0] {
+ TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "fn"),
+ _ => panic!("expected fn"),
+ }
+ match &slice[1] {
+ TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "foo"),
+ _ => panic!("expected foo"),
+ }
+ match &slice[2] {
+ TokenTree::Group(tt) => {
+ assert_eq!(tt.delimiter(), Delimiter::Parenthesis);
+ assert!(tt.stream().is_empty());
+ }
+ _ => panic!("expected parens"),
+ }
+ match &slice[3] {
+ TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Brace),
+ _ => panic!("expected braces"),
+ }
+ *slice = &slice[4..];
+}
+
+fn fold_stream(input: TokenStream) -> TokenStream {
+ input.into_iter().map(fold_tree).collect()
+}
+
+fn fold_tree(input: TokenTree) -> TokenTree {
+ match input {
+ TokenTree::Group(b) => {
+ TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
+ }
+ TokenTree::Punct(b) => TokenTree::Punct(b),
+ TokenTree::Ident(a) => TokenTree::Ident(a),
+ TokenTree::Literal(a) => {
+ if a.to_string() != "\"foo\"" {
+ TokenTree::Literal(a)
+ } else {
+ TokenTree::Literal(Literal::i32_unsuffixed(3))
+ }
+ }
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs
new file mode 100644
index 000000000..93a339840
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs
@@ -0,0 +1,23 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(allow_internal_unsafe)]
+#![feature(allow_internal_unstable)]
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+#[allow_internal_unstable(proc_macro_internals)]
+#[allow_internal_unsafe]
+#[deprecated(since = "1.0.0", note = "test")]
+pub fn with_attrs(_: TokenStream) -> TokenStream {
+ "
+ extern crate proc_macro;
+ use ::proc_macro::bridge;
+
+ fn contains_unsafe() { unsafe {} }
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/bang-macro.rs b/src/test/ui/proc-macro/auxiliary/bang-macro.rs
new file mode 100644
index 000000000..ff0002282
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/bang-macro.rs
@@ -0,0 +1,17 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn rewrite(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+
+ assert_eq!(input, r#""Hello, world!""#);
+
+ r#""NOT Hello, world!""#.parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/bang_proc_macro2.rs b/src/test/ui/proc-macro/auxiliary/bang_proc_macro2.rs
new file mode 100644
index 000000000..fcaaba602
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/bang_proc_macro2.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bang_proc_macro2(_: TokenStream) -> TokenStream {
+ "let x = foobar2;".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/builtin-attrs.rs b/src/test/ui/proc-macro/auxiliary/builtin-attrs.rs
new file mode 100644
index 000000000..6edafae39
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/builtin-attrs.rs
@@ -0,0 +1,27 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn feature(_: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn repr(_: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
+ "struct Test;".parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn bench(_: TokenStream, input: TokenStream) -> TokenStream {
+ "struct Bench;".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/call-deprecated.rs b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs
new file mode 100644
index 000000000..2f484809a
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/call-deprecated.rs
@@ -0,0 +1,19 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+#[deprecated(since = "1.0.0", note = "test")]
+pub fn attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+#[deprecated(since = "1.0.0", note = "test")]
+pub fn attr_remove(_: TokenStream, _: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/call-site.rs b/src/test/ui/proc-macro/auxiliary/call-site.rs
new file mode 100644
index 000000000..e64a5a343
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/call-site.rs
@@ -0,0 +1,27 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn check(input: TokenStream) -> TokenStream {
+ // Parsed `x2` can refer to `x2` from `input`
+ let parsed1: TokenStream = "let x3 = x2;".parse().unwrap();
+ // `x3` parsed from one string can refer to `x3` parsed from another string.
+ let parsed2: TokenStream = "let x4 = x3;".parse().unwrap();
+ // Manually assembled `x4` can refer to parsed `x4`.
+ let manual: Vec<TokenTree> = vec![
+ Ident::new("let", Span::call_site()).into(),
+ Ident::new("x5", Span::call_site()).into(),
+ Punct::new('=', Spacing::Alone).into(),
+ Ident::new("x4", Span::call_site()).into(),
+ Punct::new(';', Spacing::Alone).into(),
+ ];
+ input.into_iter().chain(parsed1.into_iter())
+ .chain(parsed2.into_iter())
+ .chain(manual.into_iter())
+ .collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/cond_plugin.rs b/src/test/ui/proc-macro/auxiliary/cond_plugin.rs
new file mode 100644
index 000000000..8d3c4ec23
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/cond_plugin.rs
@@ -0,0 +1,38 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn cond(input: TokenStream) -> TokenStream {
+ let mut conds = Vec::new();
+ let mut input = input.into_iter().peekable();
+ while let Some(tree) = input.next() {
+ let cond = match tree {
+ TokenTree::Group(tt) => tt.stream(),
+ _ => panic!("Invalid input"),
+ };
+ let mut cond_trees = cond.clone().into_iter();
+ let test = cond_trees.next().expect("Unexpected empty condition in `cond!`");
+ let rhs = cond_trees.collect::<TokenStream>();
+ if rhs.is_empty() {
+ panic!("Invalid macro usage in cond: {}", cond);
+ }
+ let is_else = match test {
+ TokenTree::Ident(ref word) => &*word.to_string() == "else",
+ _ => false,
+ };
+ conds.push(if is_else || input.peek().is_none() {
+ quote!({ $rhs })
+ } else {
+ quote!(if $test { $rhs } else)
+ });
+ }
+
+ conds.into_iter().flat_map(|x| x.into_iter()).collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/count_compound_ops.rs b/src/test/ui/proc-macro/auxiliary/count_compound_ops.rs
new file mode 100644
index 000000000..3a656d648
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/count_compound_ops.rs
@@ -0,0 +1,32 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Spacing, Literal, quote};
+
+#[proc_macro]
+pub fn count_compound_ops(input: TokenStream) -> TokenStream {
+ assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3);
+ let l = Literal::u32_suffixed(count_compound_ops_helper(input));
+ TokenTree::from(l).into()
+}
+
+fn count_compound_ops_helper(input: TokenStream) -> u32 {
+ let mut count = 0;
+ for token in input {
+ match &token {
+ TokenTree::Punct(tt) if tt.spacing() == Spacing::Alone => {
+ count += 1;
+ }
+ TokenTree::Group(tt) => {
+ count += count_compound_ops_helper(tt.stream());
+ }
+ _ => {}
+ }
+ }
+ count
+}
diff --git a/src/test/ui/proc-macro/auxiliary/custom-attr-only-one-derive.rs b/src/test/ui/proc-macro/auxiliary/custom-attr-only-one-derive.rs
new file mode 100644
index 000000000..41f73f596
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/custom-attr-only-one-derive.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Foo)]
+pub fn foo(a: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
+
+#[proc_macro_derive(Bar, attributes(custom))]
+pub fn bar(a: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/custom-quote.rs b/src/test/ui/proc-macro/auxiliary/custom-quote.rs
new file mode 100644
index 000000000..3b7811748
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/custom-quote.rs
@@ -0,0 +1,32 @@
+// force-host
+// no-prefer-dynamic
+// ignore-tidy-linelength
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use std::iter::FromIterator;
+use std::str::FromStr;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn custom_quote(input: TokenStream) -> TokenStream {
+ let mut tokens: Vec<_> = input.into_iter().collect();
+ assert_eq!(tokens.len(), 1, "Unexpected input: {:?}", tokens);
+ match tokens.pop() {
+ Some(TokenTree::Ident(ident)) => {
+ assert_eq!(ident.to_string(), "my_ident");
+
+ let proc_macro_crate = TokenStream::from_str("::proc_macro").unwrap();
+ let quoted_span = proc_macro::quote_span(proc_macro_crate, ident.span());
+ let prefix = TokenStream::from_str(r#"let mut ident = proc_macro::Ident::new("my_ident", proc_macro::Span::call_site());"#).unwrap();
+ let set_span_method = TokenStream::from_str("ident.set_span").unwrap();
+ let set_span_arg = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis, quoted_span)));
+ let suffix = TokenStream::from_str(";proc_macro::TokenStream::from(proc_macro::TokenTree::Ident(ident))").unwrap();
+ let full_stream = TokenStream::from_iter([prefix, set_span_method, set_span_arg, suffix]);
+ full_stream
+ }
+ _ => unreachable!()
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-a.rs b/src/test/ui/proc-macro/auxiliary/derive-a.rs
new file mode 100644
index 000000000..79a3864bf
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-a.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(A)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert!(input.contains("struct A ;"));
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-atob.rs b/src/test/ui/proc-macro/auxiliary/derive-atob.rs
new file mode 100644
index 000000000..207b7fd32
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-atob.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(AToB)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert_eq!(input, "struct A ;");
+ "struct B;".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-attr-cfg.rs b/src/test/ui/proc-macro/auxiliary/derive-attr-cfg.rs
new file mode 100644
index 000000000..e7e9634e0
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-attr-cfg.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Foo, attributes(foo))]
+pub fn derive(input: TokenStream) -> TokenStream {
+ assert!(!input.to_string().contains("#[cfg(any())]"));
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs b/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs
new file mode 100644
index 000000000..641a95f78
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs
@@ -0,0 +1,17 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(B, attributes(B, C))]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert!(input.contains("#[B [arbitrary tokens]]"));
+ assert!(input.contains("struct B {"));
+ assert!(input.contains("#[C]"));
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-b.rs b/src/test/ui/proc-macro/auxiliary/derive-b.rs
new file mode 100644
index 000000000..e7ab6c072
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-b.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(B, attributes(B))]
+pub fn derive_b(input: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-bad.rs b/src/test/ui/proc-macro/auxiliary/derive-bad.rs
new file mode 100644
index 000000000..90bb9b1ba
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-bad.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(A)]
+pub fn derive_a(_input: TokenStream) -> TokenStream {
+ "struct A { inner }".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-clona.rs b/src/test/ui/proc-macro/auxiliary/derive-clona.rs
new file mode 100644
index 000000000..4a35c9d0d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-clona.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Clona)]
+pub fn derive_clonea(input: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-ctod.rs b/src/test/ui/proc-macro/auxiliary/derive-ctod.rs
new file mode 100644
index 000000000..2efe5a913
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-ctod.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(CToD)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert_eq!(input, "struct C ;");
+ "struct D;".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-foo.rs b/src/test/ui/proc-macro/auxiliary/derive-foo.rs
new file mode 100644
index 000000000..3ea027d4f
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-foo.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(FooWithLongName)]
+pub fn derive_foo(input: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs
new file mode 100644
index 000000000..ab532da29
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowed-2.rs
@@ -0,0 +1,2 @@
+#[macro_export]
+macro_rules! empty_helper { () => () }
diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs
new file mode 100644
index 000000000..370a1a279
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_derive(same_name, attributes(same_name))]
+pub fn derive_a(_: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs
new file mode 100644
index 000000000..41d3a1846
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_derive(GenHelperUse)]
+pub fn derive_a(_: TokenStream) -> TokenStream {
+ "
+ #[empty_helper]
+ struct Uwu;
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-nothing.rs b/src/test/ui/proc-macro/auxiliary/derive-nothing.rs
new file mode 100644
index 000000000..b6d1e133a
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-nothing.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Nothing)]
+pub fn nothing(input: TokenStream) -> TokenStream {
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs b/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs
new file mode 100644
index 000000000..7598d632c
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(AToB)]
+pub fn derive1(input: TokenStream) -> TokenStream {
+ println!("input1: {:?}", input.to_string());
+ assert_eq!(input.to_string(), "struct A ;");
+ "#[derive(BToC)] struct B;".parse().unwrap()
+}
+
+#[proc_macro_derive(BToC)]
+pub fn derive2(input: TokenStream) -> TokenStream {
+ assert_eq!(input.to_string(), "struct B ;");
+ "struct C;".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-two-attrs.rs b/src/test/ui/proc-macro/auxiliary/derive-two-attrs.rs
new file mode 100644
index 000000000..a6f0eec12
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-two-attrs.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_derive(A, attributes(b))]
+pub fn foo(_x: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-union.rs b/src/test/ui/proc-macro/auxiliary/derive-union.rs
new file mode 100644
index 000000000..05883170c
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-union.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(UnionTest)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert!(input.contains("#[repr(C)]"));
+ assert!(input.contains("union Test {"));
+ assert!(input.contains("a : u8,"));
+ assert!(input.contains("}"));
+ "".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-unstable-2.rs b/src/test/ui/proc-macro/auxiliary/derive-unstable-2.rs
new file mode 100644
index 000000000..eac21b049
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-unstable-2.rs
@@ -0,0 +1,17 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Unstable)]
+pub fn derive(_input: TokenStream) -> TokenStream {
+
+ "
+ #[rustc_foo]
+ fn foo() {}
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs
new file mode 100644
index 000000000..2ccd3f882
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Unstable)]
+pub fn derive(_input: TokenStream) -> TokenStream {
+
+ "unsafe fn foo() -> u32 { ::std::intrinsics::abort() }".parse().unwrap()
+}
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 000000000..bdcdb7922
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/dollar-crate-external.rs
@@ -0,0 +1,22 @@
+pub type S = u8;
+
+#[macro_export]
+macro_rules! external {
+ () => {
+ print_bang! {
+ struct M($crate::S);
+ }
+
+ #[print_attr]
+ struct A($crate::S);
+
+ #[derive(Print)]
+ struct D($crate::S);
+ };
+}
+
+#[macro_export]
+macro_rules! issue_62325 { () => {
+ #[print_attr]
+ struct B(identity!($crate::S));
+}}
diff --git a/src/test/ui/proc-macro/auxiliary/double.rs b/src/test/ui/proc-macro/auxiliary/double.rs
new file mode 100644
index 000000000..99eb4e375
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/double.rs
@@ -0,0 +1,16 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+// Outputs another copy of the struct. Useful for testing the tokens
+// seen by the proc_macro.
+#[proc_macro_derive(Double)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ quote!(mod foo { $input })
+}
diff --git a/src/test/ui/proc-macro/auxiliary/duplicate.rs b/src/test/ui/proc-macro/auxiliary/duplicate.rs
new file mode 100644
index 000000000..b8f82b46f
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/duplicate.rs
@@ -0,0 +1,32 @@
+// force-host
+// no-prefer-dynamic
+
+#![deny(unused)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn duplicate(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let mut new_name = Some(attr.into_iter().nth(0).unwrap());
+ let mut encountered_idents = 0;
+ let input = item.to_string();
+ let ret = item
+ .into_iter()
+ .map(move |token| match token {
+ TokenTree::Ident(_) if encountered_idents == 1 => {
+ encountered_idents += 1;
+ new_name.take().unwrap()
+ }
+ TokenTree::Ident(_) => {
+ encountered_idents += 1;
+ token
+ }
+ _ => token,
+ })
+ .collect::<TokenStream>();
+ let mut input_again = input.parse::<TokenStream>().unwrap();
+ input_again.extend(ret);
+ input_again
+}
diff --git a/src/test/ui/proc-macro/auxiliary/edition-imports-2015.rs b/src/test/ui/proc-macro/auxiliary/edition-imports-2015.rs
new file mode 100644
index 000000000..27c59b805
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/edition-imports-2015.rs
@@ -0,0 +1,20 @@
+// edition:2015
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Derive2015)]
+pub fn derive_2015(_: TokenStream) -> TokenStream {
+ "
+ use import::Path;
+
+ fn check_absolute() {
+ let x = ::absolute::Path;
+ }
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/empty-crate.rs b/src/test/ui/proc-macro/auxiliary/empty-crate.rs
new file mode 100644
index 000000000..1cf7534b2
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/empty-crate.rs
@@ -0,0 +1,5 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(unused_variables)]
diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
new file mode 100644
index 000000000..5463e79d7
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
@@ -0,0 +1,149 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(warnings)]
+#![feature(proc_macro_expand, proc_macro_span)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+use std::str::FromStr;
+
+// Flatten the TokenStream, removing any toplevel `Delimiter::None`s for
+// comparison.
+fn flatten(ts: TokenStream) -> Vec<TokenTree> {
+ ts.into_iter()
+ .flat_map(|tt| match &tt {
+ TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
+ flatten(group.stream())
+ }
+ _ => vec![tt],
+ })
+ .collect()
+}
+
+// Assert that two TokenStream values are roughly equal to one-another.
+fn assert_ts_eq(lhs: &TokenStream, rhs: &TokenStream) {
+ let ltts = flatten(lhs.clone());
+ let rtts = flatten(rhs.clone());
+
+ if ltts.len() != rtts.len() {
+ panic!(
+ "expected the same number of tts ({} == {})\nlhs:\n{:#?}\nrhs:\n{:#?}",
+ ltts.len(),
+ rtts.len(),
+ lhs,
+ rhs
+ )
+ }
+
+ for (ltt, rtt) in ltts.iter().zip(&rtts) {
+ match (ltt, rtt) {
+ (TokenTree::Group(l), TokenTree::Group(r)) => {
+ assert_eq!(
+ l.delimiter(),
+ r.delimiter(),
+ "expected delimiters to match for {:?} and {:?}",
+ l,
+ r
+ );
+ assert_ts_eq(&l.stream(), &r.stream());
+ }
+ (TokenTree::Punct(l), TokenTree::Punct(r)) => assert_eq!(
+ (l.as_char(), l.spacing()),
+ (r.as_char(), r.spacing()),
+ "expected punct to match for {:?} and {:?}",
+ l,
+ r
+ ),
+ (TokenTree::Ident(l), TokenTree::Ident(r)) => assert_eq!(
+ l.to_string(),
+ r.to_string(),
+ "expected ident to match for {:?} and {:?}",
+ l,
+ r
+ ),
+ (TokenTree::Literal(l), TokenTree::Literal(r)) => assert_eq!(
+ l.to_string(),
+ r.to_string(),
+ "expected literal to match for {:?} and {:?}",
+ l,
+ r
+ ),
+ (l, r) => panic!("expected type to match for {:?} and {:?}", l, r),
+ }
+ }
+}
+
+#[proc_macro]
+pub fn expand_expr_is(input: TokenStream) -> TokenStream {
+ let mut iter = input.into_iter();
+ let mut expected_tts = Vec::new();
+ loop {
+ match iter.next() {
+ Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
+ Some(tt) => expected_tts.push(tt),
+ None => panic!("expected comma"),
+ }
+ }
+
+ let expected = expected_tts.into_iter().collect::<TokenStream>();
+ let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
+ assert!(
+ expected.to_string() == expanded.to_string(),
+ "assert failed\nexpected: `{}`\nexpanded: `{}`",
+ expected.to_string(),
+ expanded.to_string()
+ );
+
+ // Also compare the raw tts to make sure they line up.
+ assert_ts_eq(&expected, &expanded);
+
+ TokenStream::new()
+}
+
+#[proc_macro]
+pub fn expand_expr_fail(input: TokenStream) -> TokenStream {
+ match input.expand_expr() {
+ Ok(ts) => panic!("expand_expr unexpectedly succeeded: `{}`", ts),
+ Err(_) => TokenStream::new(),
+ }
+}
+
+#[proc_macro]
+pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
+ // Check that the passed in `file!()` invocation and a parsed `file!`
+ // invocation expand to the same literal.
+ let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
+ let parse_t = TokenStream::from_str("file!{}")
+ .unwrap()
+ .expand_expr()
+ .expect("expand_expr failed on internal macro")
+ .to_string();
+ assert_eq!(input_t, parse_t);
+
+ // Check that the literal matches `Span::call_site().source_file().path()`
+ let expect_t =
+ Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
+ assert_eq!(input_t, expect_t);
+
+ TokenStream::new()
+}
+
+#[proc_macro]
+pub fn recursive_expand(_: TokenStream) -> TokenStream {
+ // Recursively call until we hit the recursion limit and get an error.
+ //
+ // NOTE: This doesn't panic if expansion fails because that'll cause a very
+ // large number of errors to fill the output.
+ TokenStream::from_str("recursive_expand!{}")
+ .unwrap()
+ .expand_expr()
+ .unwrap_or(std::iter::once(TokenTree::Literal(Literal::u32_suffixed(0))).collect())
+}
+
+#[proc_macro]
+pub fn echo_pm(input: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs b/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs
new file mode 100644
index 000000000..d779d57af
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs
@@ -0,0 +1,22 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(warnings)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(A)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert!(input.contains("struct A ;"));
+ r#"
+ impl A {
+ fn a(&self) {
+ panic!("hello");
+ }
+ }
+ "#.parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/external-crate-var.rs b/src/test/ui/proc-macro/auxiliary/external-crate-var.rs
new file mode 100644
index 000000000..4319e9212
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/external-crate-var.rs
@@ -0,0 +1,40 @@
+pub struct ExternFoo;
+
+pub trait ExternTrait {
+ const CONST: u32;
+ type Assoc;
+}
+
+impl ExternTrait for ExternFoo {
+ const CONST: u32 = 0;
+ type Assoc = ExternFoo;
+}
+
+#[macro_export]
+macro_rules! external { () => {
+ mod bar {
+ #[derive(Double)]
+ struct Bar($crate::ExternFoo);
+ }
+
+ mod qself {
+ #[derive(Double)]
+ struct QSelf(<$crate::ExternFoo as $crate::ExternTrait>::Assoc);
+ }
+
+ mod qself_recurse {
+ #[derive(Double)]
+ struct QSelfRecurse(<
+ <$crate::ExternFoo as $crate::ExternTrait>::Assoc
+ as $crate::ExternTrait>::Assoc
+ );
+ }
+
+ mod qself_in_const {
+ #[derive(Double)]
+ #[repr(u32)]
+ enum QSelfInConst {
+ Variant = <$crate::ExternFoo as $crate::ExternTrait>::CONST,
+ }
+ }
+} }
diff --git a/src/test/ui/proc-macro/auxiliary/first-second.rs b/src/test/ui/proc-macro/auxiliary/first-second.rs
new file mode 100644
index 000000000..6331608fb
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/first-second.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group, Delimiter};
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let tokens: TokenStream = "#[derive(Second)]".parse().unwrap();
+ let wrapped = TokenTree::Group(Group::new(Delimiter::None, item.into_iter().collect()));
+ tokens.into_iter().chain(std::iter::once(wrapped)).collect()
+}
+
+#[proc_macro_derive(Second)]
+pub fn second(item: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/gen-lifetime-token.rs b/src/test/ui/proc-macro/auxiliary/gen-lifetime-token.rs
new file mode 100644
index 000000000..d1a1c584f
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/gen-lifetime-token.rs
@@ -0,0 +1,25 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn bar(_input: TokenStream) -> TokenStream {
+ let mut ret = Vec::<TokenTree>::new();
+ ret.push(Ident::new("static", Span::call_site()).into());
+ ret.push(Ident::new("FOO", Span::call_site()).into());
+ ret.push(Punct::new(':', Spacing::Alone).into());
+ ret.push(Punct::new('&', Spacing::Alone).into());
+ ret.push(Punct::new('\'', Spacing::Joint).into());
+ ret.push(Ident::new("static", Span::call_site()).into());
+ ret.push(Ident::new("i32", Span::call_site()).into());
+ ret.push(Punct::new('=', Spacing::Alone).into());
+ ret.push(Punct::new('&', Spacing::Alone).into());
+ ret.push(Literal::i32_unsuffixed(1).into());
+ ret.push(Punct::new(';', Spacing::Alone).into());
+ ret.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs b/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs
new file mode 100644
index 000000000..548fefe76
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs
@@ -0,0 +1,23 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn gen_macro_rules(_: TokenStream) -> TokenStream {
+ "
+ macro_rules! generated {() => {
+ struct ItemDef;
+ let local_def = 0;
+
+ ItemUse; // OK
+ local_use; // ERROR
+ break 'label_use; // ERROR
+
+ type DollarCrate = $crate::ItemUse; // OK
+ }}
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/gen-macro-rules.rs b/src/test/ui/proc-macro/auxiliary/gen-macro-rules.rs
new file mode 100644
index 000000000..d4b67d6b0
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/gen-macro-rules.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(repro)]
+pub fn proc_macro_hack_expr(_input: TokenStream) -> TokenStream {
+ "macro_rules! m {()=>{}}".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs
new file mode 100644
index 000000000..3f3e12eed
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs
@@ -0,0 +1,16 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn dollar_ident(input: TokenStream) -> TokenStream {
+ let black_hole = input.into_iter().next().unwrap();
+ quote! {
+ $black_hole!($$var);
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/generate-mod.rs b/src/test/ui/proc-macro/auxiliary/generate-mod.rs
new file mode 100644
index 000000000..e950f7d62
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/generate-mod.rs
@@ -0,0 +1,58 @@
+// run-pass
+// force-host
+// no-prefer-dynamic
+// ignore-pass
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn check(_: TokenStream) -> TokenStream {
+ "
+ type Alias = FromOutside; // OK
+ struct Outer;
+ mod inner {
+ type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+ type Inner = Outer; // `Outer` shouldn't be available from here
+ }
+ ".parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn check_attr(_: TokenStream, _: TokenStream) -> TokenStream {
+ "
+ type AliasAttr = FromOutside; // OK
+ struct OuterAttr;
+ mod inner_attr {
+ type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+ type Inner = OuterAttr; // `OuterAttr` shouldn't be available from here
+ }
+ ".parse().unwrap()
+}
+
+#[proc_macro_derive(CheckDerive)]
+pub fn check_derive(_: TokenStream) -> TokenStream {
+ "
+ type AliasDerive = FromOutside; // OK
+ struct OuterDerive;
+ mod inner_derive {
+ type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+ type Inner = OuterDerive; // `OuterDerive` shouldn't be available from here
+ }
+ ".parse().unwrap()
+}
+
+#[proc_macro_derive(CheckDeriveLint)]
+pub fn check_derive_lint(_: TokenStream) -> TokenStream {
+ "
+ type AliasDeriveLint = FromOutside; // OK
+ struct OuterDeriveLint;
+ #[allow(proc_macro_derive_resolution_fallback)]
+ mod inner_derive_lint {
+ type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+ type Inner = OuterDeriveLint; // `OuterDeriveLint` shouldn't be available from here
+ }
+ ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/hygiene_example.rs b/src/test/ui/proc-macro/auxiliary/hygiene_example.rs
new file mode 100644
index 000000000..f7e7e0b57
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/hygiene_example.rs
@@ -0,0 +1,7 @@
+extern crate hygiene_example_codegen;
+
+pub use hygiene_example_codegen::hello;
+
+pub fn print(string: &str) {
+ println!("{}", string);
+}
diff --git a/src/test/ui/proc-macro/auxiliary/hygiene_example_codegen.rs b/src/test/ui/proc-macro/auxiliary/hygiene_example_codegen.rs
new file mode 100644
index 000000000..2bd4d3336
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/hygiene_example_codegen.rs
@@ -0,0 +1,27 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
+
+use proc_macro_renamed::{TokenStream, quote};
+
+#[proc_macro]
+pub fn hello(input: TokenStream) -> TokenStream {
+ quote!(hello_helper!($input))
+ //^ `hello_helper!` always resolves to the following proc macro,
+ //| no matter where `hello!` is used.
+}
+
+#[proc_macro]
+pub fn hello_helper(input: TokenStream) -> TokenStream {
+ quote! {
+ extern crate hygiene_example; // This is never a conflict error
+ let string = format!("hello {}", $input);
+ //^ `format!` always resolves to the prelude macro,
+ //| even if a different `format!` is in scope where `hello!` is used.
+ hygiene_example::print(&string)
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/included-file.txt b/src/test/ui/proc-macro/auxiliary/included-file.txt
new file mode 100644
index 000000000..b4720047d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/included-file.txt
@@ -0,0 +1 @@
+Included file contents
diff --git a/src/test/ui/proc-macro/auxiliary/invalid-punct-ident.rs b/src/test/ui/proc-macro/auxiliary/invalid-punct-ident.rs
new file mode 100644
index 000000000..518dfd0d6
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/invalid-punct-ident.rs
@@ -0,0 +1,28 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_raw_ident)]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn invalid_punct(_: TokenStream) -> TokenStream {
+ TokenTree::from(Punct::new('`', Spacing::Alone)).into()
+}
+
+#[proc_macro]
+pub fn invalid_ident(_: TokenStream) -> TokenStream {
+ TokenTree::from(Ident::new("*", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn invalid_raw_ident(_: TokenStream) -> TokenStream {
+ TokenTree::from(Ident::new_raw("self", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn lexer_failure(_: TokenStream) -> TokenStream {
+ "a b ) c".parse().expect("parsing failed without panic")
+}
diff --git a/src/test/ui/proc-macro/auxiliary/is-available.rs b/src/test/ui/proc-macro/auxiliary/is-available.rs
new file mode 100644
index 000000000..03f5265e3
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/is-available.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{Literal, TokenStream, TokenTree};
+
+#[proc_macro]
+pub fn from_inside_proc_macro(_input: TokenStream) -> TokenStream {
+ proc_macro::is_available().to_string().parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-38586.rs b/src/test/ui/proc-macro/auxiliary/issue-38586.rs
new file mode 100644
index 000000000..f3a19081c
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-38586.rs
@@ -0,0 +1,11 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+#[proc_macro_derive(A)]
+pub fn derive_a(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ "fn f() { println!(\"{}\", foo); }".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-39889.rs b/src/test/ui/proc-macro/auxiliary/issue-39889.rs
new file mode 100644
index 000000000..e7af66da7
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-39889.rs
@@ -0,0 +1,17 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Issue39889)]
+pub fn f(_input: TokenStream) -> TokenStream {
+ let rules = r#"
+ macro_rules! id {
+ ($($tt:tt)*) => { $($tt)* };
+ }
+ "#;
+ rules.parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-42708.rs b/src/test/ui/proc-macro/auxiliary/issue-42708.rs
new file mode 100644
index 000000000..dae05204b
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-42708.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Test)]
+pub fn derive(_input: TokenStream) -> TokenStream {
+ "fn f(s: S) { s.x }".parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn attr_test(_attr: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-50061.rs b/src/test/ui/proc-macro/auxiliary/issue-50061.rs
new file mode 100644
index 000000000..f5fe8cabb
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-50061.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn check(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-50493.rs b/src/test/ui/proc-macro/auxiliary/issue-50493.rs
new file mode 100644
index 000000000..f72024948
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-50493.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Derive)]
+pub fn derive(_: TokenStream) -> TokenStream {
+ let code = "
+ fn one(r: Restricted) {
+ r.field;
+ }
+ fn two(r: Restricted) {
+ r.field;
+ }
+ ";
+
+ code.parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-59191.rs b/src/test/ui/proc-macro/auxiliary/issue-59191.rs
new file mode 100644
index 000000000..d9ee77067
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-59191.rs
@@ -0,0 +1,16 @@
+// edition:2018
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn no_main(_attrs: TokenStream, _input: TokenStream) -> TokenStream {
+ let new_krate = r#"
+ fn main() {}
+ "#;
+ new_krate.parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-66286.rs b/src/test/ui/proc-macro/auxiliary/issue-66286.rs
new file mode 100644
index 000000000..6217f1c7e
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-66286.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn vec_ice(_attr: TokenStream, input: TokenStream) -> TokenStream {
+ // This redundant convert is necessary to reproduce ICE.
+ input.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-75801.rs b/src/test/ui/proc-macro/auxiliary/issue-75801.rs
new file mode 100644
index 000000000..d6c031d7d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-75801.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn foo(_args: TokenStream, item: TokenStream) -> TokenStream {
+ item
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-79242.rs b/src/test/ui/proc-macro/auxiliary/issue-79242.rs
new file mode 100644
index 000000000..e586980f0
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-79242.rs
@@ -0,0 +1,16 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn dummy(input: TokenStream) -> TokenStream {
+ // Iterate to force internal conversion of nonterminals
+ // to `proc_macro` structs
+ for _ in input {}
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-79825.rs b/src/test/ui/proc-macro/auxiliary/issue-79825.rs
new file mode 100644
index 000000000..930891b1d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-79825.rs
@@ -0,0 +1,14 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn assert_input(args: TokenStream, input: TokenStream) -> TokenStream {
+ assert_eq!(input.to_string(), "trait Alias = Sized ;");
+ assert!(args.is_empty());
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-83510.rs b/src/test/ui/proc-macro/auxiliary/issue-83510.rs
new file mode 100644
index 000000000..1d6ef3914
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-83510.rs
@@ -0,0 +1,19 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn dance_like_you_want_to_ice(_: TokenStream) -> TokenStream {
+ r#"
+ impl Foo {
+ type Bar = Box<()> + Baz;
+ }
+ "#
+ .parse()
+ .unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/issue-91800-macro.rs b/src/test/ui/proc-macro/auxiliary/issue-91800-macro.rs
new file mode 100644
index 000000000..958a8bed9
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/issue-91800-macro.rs
@@ -0,0 +1,26 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+fn compile_error() -> TokenStream {
+ r#"compile_error!("")"#.parse().unwrap()
+}
+
+#[proc_macro_derive(MyTrait)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ compile_error()
+}
+#[proc_macro_attribute]
+pub fn attribute_macro(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
+ input.extend(compile_error());
+ input
+}
+#[proc_macro]
+pub fn fn_macro(_item: TokenStream) -> TokenStream {
+ compile_error()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/lifetimes-rpass.rs b/src/test/ui/proc-macro/auxiliary/lifetimes-rpass.rs
new file mode 100644
index 000000000..4e5d22e6e
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/lifetimes-rpass.rs
@@ -0,0 +1,26 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn lifetimes_bang(input: TokenStream) -> TokenStream {
+ // Roundtrip through token trees
+ input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn lifetimes_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ // Roundtrip through AST
+ input
+}
+
+#[proc_macro_derive(Lifetimes)]
+pub fn lifetimes_derive(input: TokenStream) -> TokenStream {
+ // Roundtrip through a string
+ format!("mod m {{ {} }}", input).parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/lifetimes.rs b/src/test/ui/proc-macro/auxiliary/lifetimes.rs
new file mode 100644
index 000000000..212164dd2
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/lifetimes.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn single_quote_alone(_: TokenStream) -> TokenStream {
+ // `&'a u8`, but the `'` token is not joint
+ let trees: Vec<TokenTree> = vec![
+ Punct::new('&', Spacing::Alone).into(),
+ Punct::new('\'', Spacing::Alone).into(),
+ Ident::new("a", Span::call_site()).into(),
+ Ident::new("u8", Span::call_site()).into(),
+ ];
+ trees.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
new file mode 100644
index 000000000..c72306c3d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs
@@ -0,0 +1,89 @@
+// force-host
+// no-prefer-dynamic
+
+// These are tests for syntax that is accepted by the Rust parser but
+// unconditionally rejected semantically after macro expansion. Attribute macros
+// are permitted to accept such syntax as long as they replace it with something
+// that makes sense to Rust.
+//
+// We also inspect some of the spans to verify the syntax is not triggering the
+// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081).
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_span)]
+
+extern crate proc_macro;
+use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree};
+use std::path::Component;
+
+// unsafe mod m {
+// pub unsafe mod inner;
+// }
+#[proc_macro_attribute]
+pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+ let tokens = &mut input.into_iter();
+ expect(tokens, "unsafe");
+ expect(tokens, "mod");
+ expect(tokens, "m");
+ let tokens = &mut expect_brace(tokens);
+ expect(tokens, "pub");
+ expect(tokens, "unsafe");
+ expect(tokens, "mod");
+ let ident = expect(tokens, "inner");
+ expect(tokens, ";");
+ check_useful_span(ident, "unsafe-mod.rs");
+ TokenStream::new()
+}
+
+// unsafe extern {
+// type T;
+// }
+#[proc_macro_attribute]
+pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+ let tokens = &mut input.into_iter();
+ expect(tokens, "unsafe");
+ expect(tokens, "extern");
+ let tokens = &mut expect_brace(tokens);
+ expect(tokens, "type");
+ let ident = expect(tokens, "T");
+ expect(tokens, ";");
+ check_useful_span(ident, "unsafe-foreign-mod.rs");
+ TokenStream::new()
+}
+
+// unsafe extern "C++" {}
+#[proc_macro_attribute]
+pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream {
+ let tokens = &mut input.into_iter();
+ expect(tokens, "unsafe");
+ expect(tokens, "extern");
+ let abi = expect(tokens, "\"C++\"");
+ expect_brace(tokens);
+ check_useful_span(abi, "unsafe-foreign-mod.rs");
+ TokenStream::new()
+}
+
+fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree {
+ match tokens.next() {
+ Some(token) if token.to_string() == expected => token,
+ wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected),
+ }
+}
+
+fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter {
+ match tokens.next() {
+ Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
+ group.stream().into_iter()
+ }
+ wrong => panic!("unexpected token: {:?}, expected `{{`", wrong),
+ }
+}
+
+fn check_useful_span(token: TokenTree, expected_filename: &str) {
+ let span = token.span();
+ assert!(span.start().column < span.end().column);
+
+ let source_path = span.source_file().path();
+ let filename = source_path.components().last().unwrap();
+ assert_eq!(filename, Component::Normal(expected_filename.as_ref()));
+}
diff --git a/src/test/ui/proc-macro/auxiliary/make-macro.rs b/src/test/ui/proc-macro/auxiliary/make-macro.rs
new file mode 100644
index 000000000..3c851b6de
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/make-macro.rs
@@ -0,0 +1,18 @@
+// force-host
+
+#[macro_export]
+macro_rules! make_it {
+ ($name:ident) => {
+ #[proc_macro]
+ pub fn $name(input: TokenStream) -> TokenStream {
+ println!("Def site: {:?}", Span::def_site());
+ println!("Input: {:?}", input);
+ let new: TokenStream = input.into_iter().map(|mut t| {
+ t.set_span(Span::def_site());
+ t
+ }).collect();
+ println!("Respanned: {:?}", new);
+ new
+ }
+ };
+}
diff --git a/src/test/ui/proc-macro/auxiliary/meta-delim.rs b/src/test/ui/proc-macro/auxiliary/meta-delim.rs
new file mode 100644
index 000000000..54e3d7857
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/meta-delim.rs
@@ -0,0 +1,12 @@
+macro_rules! produce_it {
+ ($dollar_one:tt $foo:ident $my_name:ident) => {
+ #[macro_export]
+ macro_rules! meta_delim {
+ ($dollar_one ($dollar_one $my_name:ident)*) => {
+ stringify!($dollar_one ($dollar_one $my_name)*)
+ }
+ }
+ }
+}
+
+produce_it!($my_name name);
diff --git a/src/test/ui/proc-macro/auxiliary/meta-macro.rs b/src/test/ui/proc-macro/auxiliary/meta-macro.rs
new file mode 100644
index 000000000..0a9b9887d
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/meta-macro.rs
@@ -0,0 +1,15 @@
+// force-host
+// no-prefer-dynamic
+// edition:2018
+
+#![feature(proc_macro_def_site)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+extern crate make_macro;
+use proc_macro::{TokenStream, Span};
+
+make_macro::make_it!(print_def_site);
+
+#[proc_macro]
+pub fn dummy(input: TokenStream) -> TokenStream { input }
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 000000000..c2a498700
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/mixed-site-span.rs
@@ -0,0 +1,40 @@
+// force-host
+// no-prefer-dynamic
+
+#![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/auxiliary/modify-ast.rs b/src/test/ui/proc-macro/auxiliary/modify-ast.rs
new file mode 100644
index 000000000..cc582c152
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/modify-ast.rs
@@ -0,0 +1,47 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn assert1(_a: TokenStream, b: TokenStream) -> TokenStream {
+ assert_eq(b.clone(), "pub fn foo() {}".parse().unwrap());
+ b
+}
+
+#[proc_macro_derive(Foo, attributes(foo))]
+pub fn assert2(a: TokenStream) -> TokenStream {
+ assert_eq(a, "pub struct MyStructc { _a: i32, }".parse().unwrap());
+ TokenStream::new()
+}
+
+fn assert_eq(a: TokenStream, b: TokenStream) {
+ let mut a = a.into_iter();
+ let mut b = b.into_iter();
+ for (a, b) in a.by_ref().zip(&mut b) {
+ match (a, b) {
+ (TokenTree::Group(a), TokenTree::Group(b)) => {
+ assert_eq!(a.delimiter(), b.delimiter());
+ assert_eq(a.stream(), b.stream());
+ }
+ (TokenTree::Punct(a), TokenTree::Punct(b)) => {
+ assert_eq!(a.as_char(), b.as_char());
+ assert_eq!(a.spacing(), b.spacing());
+ }
+ (TokenTree::Literal(a), TokenTree::Literal(b)) => {
+ assert_eq!(a.to_string(), b.to_string());
+ }
+ (TokenTree::Ident(a), TokenTree::Ident(b)) => {
+ assert_eq!(a.to_string(), b.to_string());
+ }
+ (a, b) => panic!("{:?} != {:?}", a, b),
+ }
+ }
+
+ assert!(a.next().is_none());
+ assert!(b.next().is_none());
+}
diff --git a/src/test/ui/proc-macro/auxiliary/multiple-derives.rs b/src/test/ui/proc-macro/auxiliary/multiple-derives.rs
new file mode 100644
index 000000000..e3f6607b2
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/multiple-derives.rs
@@ -0,0 +1,22 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+macro_rules! make_derives {
+ ($($name:ident),*) => {
+ $(
+ #[proc_macro_derive($name)]
+ pub fn $name(input: TokenStream) -> TokenStream {
+ println!("Derive {}: {}", stringify!($name), input);
+ TokenStream::new()
+ }
+ )*
+ }
+}
+
+make_derives!(First, Second, Third, Fourth, Fifth);
diff --git a/src/test/ui/proc-macro/auxiliary/multispan.rs b/src/test/ui/proc-macro/auxiliary/multispan.rs
new file mode 100644
index 000000000..c05d15643
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/multispan.rs
@@ -0,0 +1,37 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
+
+fn parse(input: TokenStream) -> Result<(), Diagnostic> {
+ let mut hi_spans = vec![];
+ for tree in input {
+ if let TokenTree::Ident(ref ident) = tree {
+ if ident.to_string() == "hi" {
+ hi_spans.push(ident.span());
+ }
+ }
+ }
+
+ if !hi_spans.is_empty() {
+ return Err(Span::def_site()
+ .error("hello to you, too!")
+ .span_note(hi_spans, "found these 'hi's"));
+ }
+
+ Ok(())
+}
+
+#[proc_macro]
+pub fn hello(input: TokenStream) -> TokenStream {
+ if let Err(diag) = parse(input) {
+ diag.emit();
+ }
+
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/negative-token.rs b/src/test/ui/proc-macro/auxiliary/negative-token.rs
new file mode 100644
index 000000000..8b89f2e37
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/negative-token.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn neg_one(_input: TokenStream) -> TokenStream {
+ TokenTree::Literal(Literal::i32_suffixed(-1)).into()
+}
+
+#[proc_macro]
+pub fn neg_one_float(_input: TokenStream) -> TokenStream {
+ TokenTree::Literal(Literal::f32_suffixed(-1.0)).into()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs
new file mode 100644
index 000000000..27676a5cb
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs
@@ -0,0 +1,16 @@
+pub struct FirstStruct;
+
+#[macro_export]
+macro_rules! outer_macro {
+ ($name:ident, $attr_struct_name:ident) => {
+ #[macro_export]
+ macro_rules! inner_macro {
+ ($bang_macro:ident, $attr_macro:ident) => {
+ $bang_macro!($name);
+ #[$attr_macro] struct $attr_struct_name {}
+ }
+ }
+ }
+}
+
+outer_macro!(FirstStruct, FirstAttrStruct);
diff --git a/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs b/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs
new file mode 100644
index 000000000..ea5ff4665
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/nonterminal-recollect-attr.rs
@@ -0,0 +1,25 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, quote};
+
+#[proc_macro_attribute]
+pub fn first_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ let recollected: TokenStream = input.into_iter().collect();
+ println!("First recollected: {:#?}", recollected);
+ quote! {
+ #[second_attr]
+ $recollected
+ }
+}
+
+#[proc_macro_attribute]
+pub fn second_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ let recollected: TokenStream = input.into_iter().collect();
+ println!("Second recollected: {:#?}", recollected);
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/not-joint.rs b/src/test/ui/proc-macro/auxiliary/not-joint.rs
new file mode 100644
index 000000000..e6c09f762
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/not-joint.rs
@@ -0,0 +1,30 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn tokens(input: TokenStream) -> TokenStream {
+ assert_nothing_joint(input);
+ TokenStream::new()
+}
+
+#[proc_macro_attribute]
+pub fn nothing(_: TokenStream, input: TokenStream) -> TokenStream {
+ assert_nothing_joint(input);
+ TokenStream::new()
+}
+
+fn assert_nothing_joint(s: TokenStream) {
+ for tt in s {
+ match tt {
+ TokenTree::Group(g) => assert_nothing_joint(g.stream()),
+ TokenTree::Punct(p) => assert_eq!(p.spacing(), Spacing::Alone),
+ _ => {}
+ }
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/parent-source-spans.rs b/src/test/ui/proc-macro/auxiliary/parent-source-spans.rs
new file mode 100644
index 000000000..594f10883
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/parent-source-spans.rs
@@ -0,0 +1,43 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_diagnostic, proc_macro_span)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span};
+
+fn lit_span(tt: TokenTree) -> (Span, String) {
+ match tt {
+ TokenTree::Literal(..) |
+ TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()),
+ _ => panic!("expected a literal in token tree, got: {:?}", tt)
+ }
+}
+
+#[proc_macro]
+pub fn parent_source_spans(input: TokenStream) -> TokenStream {
+ let mut tokens = input.into_iter();
+ let (sp1, str1) = lit_span(tokens.next().expect("first string"));
+ let _ = tokens.next();
+ let (sp2, str2) = lit_span(tokens.next().expect("second string"));
+
+ sp1.error(format!("first final: {}", str1)).emit();
+ sp2.error(format!("second final: {}", str2)).emit();
+
+ if let (Some(p1), Some(p2)) = (sp1.parent(), sp2.parent()) {
+ p1.error(format!("first parent: {}", str1)).emit();
+ p2.error(format!("second parent: {}", str2)).emit();
+
+ if let (Some(gp1), Some(gp2)) = (p1.parent(), p2.parent()) {
+ gp1.error(format!("first grandparent: {}", str1)).emit();
+ gp2.error(format!("second grandparent: {}", str2)).emit();
+ }
+ }
+
+ sp1.source().error(format!("first source: {}", str1)).emit();
+ sp2.source().error(format!("second source: {}", str2)).emit();
+
+ "ok".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/proc-macro-panic.rs b/src/test/ui/proc-macro/auxiliary/proc-macro-panic.rs
new file mode 100644
index 000000000..fc15bb9c5
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/proc-macro-panic.rs
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, Ident, Span};
+
+#[proc_macro]
+pub fn panic_in_libproc_macro(_: TokenStream) -> TokenStream {
+ Ident::new("", Span::call_site());
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/raw-ident.rs b/src/test/ui/proc-macro/auxiliary/raw-ident.rs
new file mode 100644
index 000000000..9daee21aa
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/raw-ident.rs
@@ -0,0 +1,35 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, TokenTree, Ident, Punct, Spacing, Span};
+
+#[proc_macro]
+pub fn make_struct(input: TokenStream) -> TokenStream {
+ match input.into_iter().next().unwrap() {
+ TokenTree::Ident(ident) => {
+ vec![
+ TokenTree::Ident(Ident::new("struct", Span::call_site())),
+ TokenTree::Ident(Ident::new_raw(&ident.to_string(), Span::call_site())),
+ TokenTree::Punct(Punct::new(';', Spacing::Alone))
+ ].into_iter().collect()
+ }
+ _ => panic!()
+ }
+}
+
+#[proc_macro]
+pub fn make_bad_struct(input: TokenStream) -> TokenStream {
+ match input.into_iter().next().unwrap() {
+ TokenTree::Ident(ident) => {
+ vec![
+ TokenTree::Ident(Ident::new_raw("struct", Span::call_site())),
+ TokenTree::Ident(Ident::new(&ident.to_string(), Span::call_site())),
+ TokenTree::Punct(Punct::new(';', Spacing::Alone))
+ ].into_iter().collect()
+ }
+ _ => panic!()
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/recollect.rs b/src/test/ui/proc-macro/auxiliary/recollect.rs
new file mode 100644
index 000000000..d4494a5af
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/recollect.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn recollect(tokens: TokenStream) -> TokenStream {
+ tokens.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/resolved-located-at.rs b/src/test/ui/proc-macro/auxiliary/resolved-located-at.rs
new file mode 100644
index 000000000..db660824f
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/resolved-located-at.rs
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_def_site)]
+#![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn resolve_located_at(input: TokenStream) -> TokenStream {
+ match &*input.into_iter().collect::<Vec<_>>() {
+ [a, b, ..] => {
+ // The error is reported at input `a`.
+ let mut diag = Diagnostic::new(Level::Error, "expected error");
+ diag.set_spans(Span::def_site().located_at(a.span()));
+ diag.emit();
+
+ // Resolves to `struct S;` at def site, but the error is reported at input `b`.
+ let s = TokenTree::Ident(Ident::new("S", b.span().resolved_at(Span::def_site())));
+ quote!({
+ struct S;
+
+ $s
+ })
+ }
+ _ => panic!("unexpected input"),
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/span-api-tests.rs b/src/test/ui/proc-macro/auxiliary/span-api-tests.rs
new file mode 100644
index 000000000..ad1e770a4
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/span-api-tests.rs
@@ -0,0 +1,45 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_span)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+// Re-emits the input tokens by parsing them from strings
+#[proc_macro]
+pub fn reemit(input: TokenStream) -> TokenStream {
+ input.to_string().parse().unwrap()
+}
+
+#[proc_macro]
+pub fn assert_fake_source_file(input: TokenStream) -> TokenStream {
+ for tk in input {
+ let source_file = tk.span().source_file();
+ assert!(!source_file.is_real(), "Source file is real: {:?}", source_file);
+ }
+
+ "".parse().unwrap()
+}
+
+#[proc_macro]
+pub fn assert_source_file(input: TokenStream) -> TokenStream {
+ for tk in input {
+ let source_file = tk.span().source_file();
+ assert!(source_file.is_real(), "Source file is not real: {:?}", source_file);
+ }
+
+ "".parse().unwrap()
+}
+
+#[proc_macro]
+pub fn macro_stringify(input: TokenStream) -> TokenStream {
+ let mut tokens = input.into_iter();
+ let first_span = tokens.next().expect("first token").span();
+ let last_span = tokens.last().map(|x| x.span()).unwrap_or(first_span);
+ let span = first_span.join(last_span).expect("joined span");
+ let src = span.source_text().expect("source_text");
+ TokenTree::Literal(Literal::string(&src)).into()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs b/src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs
new file mode 100644
index 000000000..49292acfe
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/span-from-proc-macro.rs
@@ -0,0 +1,49 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![feature(proc_macro_internals)] // FIXME - this shouldn't be necessary
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+extern crate custom_quote;
+
+use proc_macro::{quote, TokenStream};
+
+macro_rules! expand_to_quote {
+ () => {
+ quote! {
+ let bang_error: bool = 25;
+ }
+ }
+}
+
+#[proc_macro]
+pub fn error_from_bang(_input: TokenStream) -> TokenStream {
+ expand_to_quote!()
+}
+
+#[proc_macro]
+pub fn other_error_from_bang(_input: TokenStream) -> TokenStream {
+ custom_quote::custom_quote! {
+ my_ident
+ }
+}
+
+#[proc_macro_attribute]
+pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream {
+ quote! {
+ struct AttributeError {
+ field: MissingType
+ }
+ }
+}
+
+#[proc_macro_derive(ErrorFromDerive)]
+pub fn error_from_derive(_input: TokenStream) -> TokenStream {
+ quote! {
+ enum DeriveError {
+ Variant(OtherMissingType)
+ }
+ }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/span-test-macros.rs b/src/test/ui/proc-macro/auxiliary/span-test-macros.rs
new file mode 100644
index 000000000..9a78f0a89
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/span-test-macros.rs
@@ -0,0 +1,9 @@
+#[macro_export]
+macro_rules! reemit_legacy {
+ ($($tok:tt)*) => ($($tok)*)
+}
+
+#[macro_export]
+macro_rules! say_hello_extern {
+ ($macname:ident) => ( $macname! { "Hello, world!" })
+}
diff --git a/src/test/ui/proc-macro/auxiliary/subspan.rs b/src/test/ui/proc-macro/auxiliary/subspan.rs
new file mode 100644
index 000000000..f92adc040
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/subspan.rs
@@ -0,0 +1,38 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_diagnostic, proc_macro_span)]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
+
+fn parse(input: TokenStream) -> Result<(), Diagnostic> {
+ if let Some(TokenTree::Literal(lit)) = input.into_iter().next() {
+ let mut spans = vec![];
+ let string = lit.to_string();
+ for hi in string.matches("hi") {
+ let index = hi.as_ptr() as usize - string.as_ptr() as usize;
+ let subspan = lit.subspan(index..(index + hi.len())).unwrap();
+ spans.push(subspan);
+ }
+
+ if !spans.is_empty() {
+ Err(Span::call_site().error("found 'hi's").span_note(spans, "here"))
+ } else {
+ Ok(())
+ }
+ } else {
+ Err(Span::call_site().error("invalid input: expected string literal"))
+ }
+}
+
+#[proc_macro]
+pub fn subspan(input: TokenStream) -> TokenStream {
+ if let Err(diag) = parse(input) {
+ diag.emit();
+ }
+
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/test-macros.rs b/src/test/ui/proc-macro/auxiliary/test-macros.rs
new file mode 100644
index 000000000..7a46aee46
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/test-macros.rs
@@ -0,0 +1,180 @@
+// force-host
+// no-prefer-dynamic
+
+// Proc macros commonly used by tests.
+// `panic`/`print` -> `panic_bang`/`print_bang` to avoid conflicts with standard macros.
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, TokenTree};
+
+// Macro that return empty token stream.
+
+#[proc_macro]
+pub fn empty(_: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[proc_macro_attribute]
+pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+#[proc_macro_derive(Empty, attributes(empty_helper))]
+pub fn empty_derive(_: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+// Macro that panics.
+
+#[proc_macro]
+pub fn panic_bang(_: TokenStream) -> TokenStream {
+ panic!("panic-bang");
+}
+
+#[proc_macro_attribute]
+pub fn panic_attr(_: TokenStream, _: TokenStream) -> TokenStream {
+ panic!("panic-attr");
+}
+
+#[proc_macro_derive(Panic, attributes(panic_helper))]
+pub fn panic_derive(_: TokenStream) -> TokenStream {
+ panic!("panic-derive");
+}
+
+// Macros that return the input stream.
+
+#[proc_macro]
+pub fn identity(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn identity_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(Identity, attributes(identity_helper))]
+pub fn identity_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+// Macros that iterate and re-collect the input stream.
+
+#[proc_macro]
+pub fn recollect(input: TokenStream) -> TokenStream {
+ input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn recollect_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ input.into_iter().collect()
+}
+
+#[proc_macro_derive(Recollect, attributes(recollect_helper))]
+pub fn recollect_derive(input: TokenStream) -> TokenStream {
+ input.into_iter().collect()
+}
+
+// Macros that print their input in the original and re-collected forms (if they differ).
+
+fn print_helper(input: TokenStream, kind: &str) -> TokenStream {
+ print_helper_ext(input, kind, true)
+}
+
+fn deep_recollect(input: TokenStream) -> TokenStream {
+ input.into_iter().map(|tree| {
+ match tree {
+ TokenTree::Group(group) => {
+ let inner = deep_recollect(group.stream());
+ let mut new_group = TokenTree::Group(
+ proc_macro::Group::new(group.delimiter(), inner)
+ );
+ new_group.set_span(group.span());
+ new_group
+ }
+ _ => tree,
+ }
+ }).collect()
+}
+
+fn print_helper_ext(input: TokenStream, kind: &str, debug: bool) -> TokenStream {
+ let input_display = format!("{}", input);
+ let input_debug = format!("{:#?}", input);
+ let recollected = input.clone().into_iter().collect();
+ let recollected_display = format!("{}", recollected);
+ let recollected_debug = format!("{:#?}", recollected);
+
+ let deep_recollected = deep_recollect(input);
+ let deep_recollected_display = format!("{}", deep_recollected);
+ let deep_recollected_debug = format!("{:#?}", deep_recollected);
+
+
+
+ println!("PRINT-{} INPUT (DISPLAY): {}", kind, input_display);
+ if recollected_display != input_display {
+ println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display);
+ }
+
+ if deep_recollected_display != recollected_display {
+ println!("PRINT-{} DEEP-RE-COLLECTED (DISPLAY): {}", kind, deep_recollected_display);
+ }
+
+ if debug {
+ println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug);
+ if recollected_debug != input_debug {
+ println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug);
+ }
+ if deep_recollected_debug != recollected_debug {
+ println!("PRINT-{} DEEP-RE-COLLETED (DEBUG): {}", kind, deep_recollected_debug);
+ }
+ }
+ recollected
+}
+
+#[proc_macro]
+pub fn print_bang(input: TokenStream) -> TokenStream {
+ print_helper(input, "BANG")
+}
+
+#[proc_macro]
+pub fn print_bang_consume(input: TokenStream) -> TokenStream {
+ print_helper(input, "BANG");
+ TokenStream::new()
+}
+
+#[proc_macro_attribute]
+pub fn print_attr(args: TokenStream, input: TokenStream) -> TokenStream {
+ let debug = match &args.into_iter().collect::<Vec<_>>()[..] {
+ [TokenTree::Ident(ident)] if ident.to_string() == "nodebug" => false,
+ _ => true,
+ };
+ print_helper_ext(input, "ATTR", debug)
+}
+
+#[proc_macro_attribute]
+pub fn print_attr_args(args: TokenStream, input: TokenStream) -> TokenStream {
+ print_helper(args, "ATTR_ARGS");
+ input
+}
+
+#[proc_macro_attribute]
+pub fn print_target_and_args(args: TokenStream, input: TokenStream) -> TokenStream {
+ print_helper(args, "ATTR_ARGS");
+ print_helper(input.clone(), "ATTR");
+ input
+}
+
+#[proc_macro_attribute]
+pub fn print_target_and_args_consume(args: TokenStream, input: TokenStream) -> TokenStream {
+ print_helper(args, "ATTR_ARGS");
+ print_helper(input.clone(), "ATTR");
+ TokenStream::new()
+}
+
+#[proc_macro_derive(Print, attributes(print_helper))]
+pub fn print_derive(input: TokenStream) -> TokenStream {
+ print_helper(input, "DERIVE");
+ TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/three-equals.rs b/src/test/ui/proc-macro/auxiliary/three-equals.rs
new file mode 100644
index 000000000..e740e86e5
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/three-equals.rs
@@ -0,0 +1,49 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
+
+fn parse(input: TokenStream) -> Result<(), Diagnostic> {
+ let mut count = 0;
+ let mut last_span = Span::def_site();
+ for tree in input {
+ let span = tree.span();
+ if count >= 3 {
+ return Err(span.error(format!("expected EOF, found `{}`.", tree))
+ .span_note(last_span, "last good input was here")
+ .help("input must be: `===`"))
+ }
+
+ if let TokenTree::Punct(ref tt) = tree {
+ if tt.as_char() == '=' {
+ count += 1;
+ last_span = span;
+ continue
+ }
+ }
+ return Err(span.error(format!("expected `=`, found `{}`.", tree)));
+ }
+
+ if count < 3 {
+ return Err(Span::def_site()
+ .error(format!("found {} equal signs, need exactly 3", count))
+ .help("input must be: `===`"))
+ }
+
+ Ok(())
+}
+
+#[proc_macro]
+pub fn three_equals(input: TokenStream) -> TokenStream {
+ if let Err(diag) = parse(input) {
+ diag.emit();
+ return TokenStream::new();
+ }
+
+ "3".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs b/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs
new file mode 100644
index 000000000..338e436df
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs
@@ -0,0 +1,48 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group};
+
+fn find_my_ident(tokens: TokenStream) -> Option<TokenStream> {
+ for token in tokens {
+ if let TokenTree::Ident(ident) = &token {
+ if ident.to_string() == "hidden_ident" {
+ return Some(vec![token].into_iter().collect())
+ }
+ } else if let TokenTree::Group(g) = token {
+ if let Some(stream) = find_my_ident(g.stream()) {
+ return Some(stream)
+ }
+ }
+ }
+ return None;
+}
+
+
+#[proc_macro_derive(WeirdDerive)]
+pub fn weird_derive(item: TokenStream) -> TokenStream {
+ let my_ident = find_my_ident(item).expect("Missing 'my_ident'!");
+ let tokens: TokenStream = "call_it!();".parse().unwrap();
+ let final_call = tokens.into_iter().map(|tree| {
+ if let TokenTree::Group(g) = tree {
+ return Group::new(g.delimiter(), my_ident.clone()).into()
+ } else {
+ return tree
+ }
+ }).collect();
+ final_call
+}
+
+#[proc_macro]
+pub fn recollect(item: TokenStream) -> TokenStream {
+ item.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn recollect_attr(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
+ item.into_iter().collect()
+}