diff options
Diffstat (limited to '')
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() +} |