diff options
Diffstat (limited to 'tests/ui/macros')
499 files changed, 16528 insertions, 0 deletions
diff --git a/tests/ui/macros/ambiguity-legacy-vs-modern.rs b/tests/ui/macros/ambiguity-legacy-vs-modern.rs new file mode 100644 index 000000000..216b9dd05 --- /dev/null +++ b/tests/ui/macros/ambiguity-legacy-vs-modern.rs @@ -0,0 +1,46 @@ +// Some non-controversial subset of ambiguities "modern macro name" vs "macro_rules" +// is disambiguated to mitigate regressions from macro modularization. +// Scoping for `macro_rules` behaves like scoping for `let` at module level, in general. + +#![feature(decl_macro)] + +fn same_unnamed_mod() { + macro m() { 0 } + + macro_rules! m { () => (()) } + + m!() // OK +} + +fn nested_unnamed_mod() { + macro m() { 0 } + + { + macro_rules! m { () => (()) } + + m!() // OK + } +} + +fn nested_unnamed_mod_fail() { + macro_rules! m { () => (()) } + + { + macro m() { 0 } + + m!() //~ ERROR `m` is ambiguous + } +} + +fn nexted_named_mod_fail() { + macro m() { 0 } + + #[macro_use] + mod inner { + macro_rules! m { () => (()) } + } + + m!() //~ ERROR `m` is ambiguous +} + +fn main() {} diff --git a/tests/ui/macros/ambiguity-legacy-vs-modern.stderr b/tests/ui/macros/ambiguity-legacy-vs-modern.stderr new file mode 100644 index 000000000..330aa6acf --- /dev/null +++ b/tests/ui/macros/ambiguity-legacy-vs-modern.stderr @@ -0,0 +1,39 @@ +error[E0659]: `m` is ambiguous + --> $DIR/ambiguity-legacy-vs-modern.rs:31:9 + | +LL | m!() + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module +note: `m` could refer to the macro defined here + --> $DIR/ambiguity-legacy-vs-modern.rs:26:5 + | +LL | macro_rules! m { () => (()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: `m` could also refer to the macro defined here + --> $DIR/ambiguity-legacy-vs-modern.rs:29:9 + | +LL | macro m() { 0 } + | ^^^^^^^^^^^^^^^ + +error[E0659]: `m` is ambiguous + --> $DIR/ambiguity-legacy-vs-modern.rs:43:5 + | +LL | m!() + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module +note: `m` could refer to the macro defined here + --> $DIR/ambiguity-legacy-vs-modern.rs:40:9 + | +LL | macro_rules! m { () => (()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: `m` could also refer to the macro defined here + --> $DIR/ambiguity-legacy-vs-modern.rs:36:5 + | +LL | macro m() { 0 } + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/assert-as-macro.rs b/tests/ui/macros/assert-as-macro.rs new file mode 100644 index 000000000..23c054808 --- /dev/null +++ b/tests/ui/macros/assert-as-macro.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:assertion failed: 1 == 2 +// ignore-emscripten no processes + +fn main() { + assert!(1 == 2); +} diff --git a/tests/ui/macros/assert-eq-macro-msg.rs b/tests/ui/macros/assert-eq-macro-msg.rs new file mode 100644 index 000000000..accbd2d1e --- /dev/null +++ b/tests/ui/macros/assert-eq-macro-msg.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:panicked at 'assertion failed: `(left == right)` +// error-pattern: left: `2` +// error-pattern:right: `3`: 1 + 1 definitely should be 3' +// ignore-emscripten no processes + +fn main() { + assert_eq!(1 + 1, 3, "1 + 1 definitely should be 3"); +} diff --git a/tests/ui/macros/assert-eq-macro-panic.rs b/tests/ui/macros/assert-eq-macro-panic.rs new file mode 100644 index 000000000..5e505c30b --- /dev/null +++ b/tests/ui/macros/assert-eq-macro-panic.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:assertion failed: `(left == right)` +// error-pattern: left: `14` +// error-pattern:right: `15` +// ignore-emscripten no processes + +fn main() { + assert_eq!(14, 15); +} diff --git a/tests/ui/macros/assert-eq-macro-success.rs b/tests/ui/macros/assert-eq-macro-success.rs new file mode 100644 index 000000000..57858b348 --- /dev/null +++ b/tests/ui/macros/assert-eq-macro-success.rs @@ -0,0 +1,13 @@ +// run-pass +#[derive(PartialEq, Debug)] +struct Point { x : isize } + +pub fn main() { + assert_eq!(14,14); + assert_eq!("abc".to_string(),"abc".to_string()); + assert_eq!(Box::new(Point{x:34}),Box::new(Point{x:34})); + assert_eq!(&Point{x:34},&Point{x:34}); + assert_eq!(42, 42, "foo bar"); + assert_eq!(42, 42, "a {} c", "b"); + assert_eq!(42, 42, "{x}, {y}, {z}", x = 1, y = 2, z = 3); +} diff --git a/tests/ui/macros/assert-eq-macro-unsized.rs b/tests/ui/macros/assert-eq-macro-unsized.rs new file mode 100644 index 000000000..00823216b --- /dev/null +++ b/tests/ui/macros/assert-eq-macro-unsized.rs @@ -0,0 +1,4 @@ +// run-pass +pub fn main() { + assert_eq!([1, 2, 3][..], vec![1, 2, 3][..]); +} diff --git a/tests/ui/macros/assert-format-lazy.rs b/tests/ui/macros/assert-format-lazy.rs new file mode 100644 index 000000000..c7f05d763 --- /dev/null +++ b/tests/ui/macros/assert-format-lazy.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: -C debug_assertions=yes + +#[allow(unreachable_code)] +fn main() { + assert!(true, "Failed: {:?}", panic!("assert! evaluated format expressions")); + debug_assert!(true, "Failed: {:?}", panic!("debug_assert! evaluated format expressions")); + assert_eq!(1, 1, "Failed: {:?}", panic!("assert_eq! evaluated format expressions")); + debug_assert_eq!(1, 1, "Failed: {:?}", panic!("debug_assert_eq! evaluated format expressions")); + assert_ne!(1, 2, "Failed: {:?}", panic!("assert_ne! evaluated format expressions")); + debug_assert_ne!(1, 2, "Failed: {:?}", panic!("debug_assert_ne! evaluated format expressions")); +} diff --git a/tests/ui/macros/assert-macro-explicit.rs b/tests/ui/macros/assert-macro-explicit.rs new file mode 100644 index 000000000..578ef5632 --- /dev/null +++ b/tests/ui/macros/assert-macro-explicit.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:panicked at 'assertion failed: false' +// ignore-emscripten no processes + +fn main() { + assert!(false); +} diff --git a/tests/ui/macros/assert-macro-fmt.rs b/tests/ui/macros/assert-macro-fmt.rs new file mode 100644 index 000000000..b8d319d85 --- /dev/null +++ b/tests/ui/macros/assert-macro-fmt.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:panicked at 'test-assert-fmt 42 rust' +// ignore-emscripten no processes + +fn main() { + assert!(false, "test-assert-fmt {} {}", 42, "rust"); +} diff --git a/tests/ui/macros/assert-macro-owned.rs b/tests/ui/macros/assert-macro-owned.rs new file mode 100644 index 000000000..753675872 --- /dev/null +++ b/tests/ui/macros/assert-macro-owned.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:panicked at 'test-assert-owned' +// ignore-emscripten no processes + +#![allow(non_fmt_panics)] + +fn main() { + assert!(false, "test-assert-owned".to_string()); +} diff --git a/tests/ui/macros/assert-macro-static.rs b/tests/ui/macros/assert-macro-static.rs new file mode 100644 index 000000000..dc5274a7e --- /dev/null +++ b/tests/ui/macros/assert-macro-static.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:panicked at 'test-assert-static' +// ignore-emscripten no processes + +fn main() { + assert!(false, "test-assert-static"); +} diff --git a/tests/ui/macros/assert-matches-macro-msg.rs b/tests/ui/macros/assert-matches-macro-msg.rs new file mode 100644 index 000000000..fd8cd5a1a --- /dev/null +++ b/tests/ui/macros/assert-matches-macro-msg.rs @@ -0,0 +1,13 @@ +// run-fail +// error-pattern:panicked at 'assertion failed: `(left matches right)` +// error-pattern: left: `2` +// error-pattern:right: `3`: 1 + 1 definitely should be 3' +// ignore-emscripten no processes + +#![feature(assert_matches)] + +use std::assert_matches::assert_matches; + +fn main() { + assert_matches!(1 + 1, 3, "1 + 1 definitely should be 3"); +} diff --git a/tests/ui/macros/assert-ne-macro-msg.rs b/tests/ui/macros/assert-ne-macro-msg.rs new file mode 100644 index 000000000..fc0472b99 --- /dev/null +++ b/tests/ui/macros/assert-ne-macro-msg.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:panicked at 'assertion failed: `(left != right)` +// error-pattern: left: `2` +// error-pattern:right: `2`: 1 + 1 definitely should not be 2' +// ignore-emscripten no processes + +fn main() { + assert_ne!(1 + 1, 2, "1 + 1 definitely should not be 2"); +} diff --git a/tests/ui/macros/assert-ne-macro-panic.rs b/tests/ui/macros/assert-ne-macro-panic.rs new file mode 100644 index 000000000..4f507d7b5 --- /dev/null +++ b/tests/ui/macros/assert-ne-macro-panic.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:assertion failed: `(left != right)` +// error-pattern: left: `14` +// error-pattern:right: `14` +// ignore-emscripten no processes + +fn main() { + assert_ne!(14, 14); +} diff --git a/tests/ui/macros/assert-ne-macro-success.rs b/tests/ui/macros/assert-ne-macro-success.rs new file mode 100644 index 000000000..89b3a4c9d --- /dev/null +++ b/tests/ui/macros/assert-ne-macro-success.rs @@ -0,0 +1,13 @@ +// run-pass +#[derive(PartialEq, Debug)] +struct Point { x : isize } + +pub fn main() { + assert_ne!(666,14); + assert_ne!("666".to_string(),"abc".to_string()); + assert_ne!(Box::new(Point{x:666}),Box::new(Point{x:34})); + assert_ne!(&Point{x:666},&Point{x:34}); + assert_ne!(666, 42, "no gods no masters"); + assert_ne!(666, 42, "6 {} 6", "6"); + assert_ne!(666, 42, "{x}, {y}, {z}", x = 6, y = 6, z = 6); +} diff --git a/tests/ui/macros/assert-ne-macro-unsized.rs b/tests/ui/macros/assert-ne-macro-unsized.rs new file mode 100644 index 000000000..e8a86e3da --- /dev/null +++ b/tests/ui/macros/assert-ne-macro-unsized.rs @@ -0,0 +1,4 @@ +// run-pass +pub fn main() { + assert_ne!([6, 6, 6][..], vec![1, 2, 3][..]); +} diff --git a/tests/ui/macros/assert-trailing-junk.rs b/tests/ui/macros/assert-trailing-junk.rs new file mode 100644 index 000000000..da725e19e --- /dev/null +++ b/tests/ui/macros/assert-trailing-junk.rs @@ -0,0 +1,27 @@ +// revisions: with-generic-asset without-generic-asset +// [with-generic-asset] compile-flags: --cfg feature="generic_assert" + +// Ensure assert macro does not ignore trailing garbage. +// +// See https://github.com/rust-lang/rust/issues/60024 for details. + +fn main() { + assert!(true some extra junk, "whatever"); + //~^ ERROR expected one of + + assert!(true some extra junk); + //~^ ERROR expected one of + + assert!(true, "whatever" blah); + //~^ ERROR no rules expected + + assert!(true "whatever" blah); + //~^ ERROR unexpected string literal + //~^^ ERROR no rules expected + + assert!(true;); + //~^ ERROR macro requires an expression + + assert!(false || true "error message"); + //~^ ERROR unexpected string literal +} diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr new file mode 100644 index 000000000..1e73320e4 --- /dev/null +++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr @@ -0,0 +1,58 @@ +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:9:18 + | +LL | assert!(true some extra junk, "whatever"); + | ^^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:12:18 + | +LL | assert!(true some extra junk); + | ^^^^ expected one of `,`, `.`, `?`, or an operator + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:15:30 + | +LL | assert!(true, "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + | + = note: while trying to match sequence start + +error: unexpected string literal + --> $DIR/assert-trailing-junk.rs:18:18 + | +LL | assert!(true "whatever" blah); + | -^^^^^^^^^^ + | | + | help: try adding a comma + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:18:29 + | +LL | assert!(true "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + | + = note: while trying to match sequence start + +error: macro requires an expression as an argument + --> $DIR/assert-trailing-junk.rs:22:5 + | +LL | assert!(true;); + | ^^^^^^^^^^^^-^ + | | + | help: try removing semicolon + +error: unexpected string literal + --> $DIR/assert-trailing-junk.rs:25:27 + | +LL | assert!(false || true "error message"); + | -^^^^^^^^^^^^^^^ + | | + | help: try adding a comma + +error: aborting due to 7 previous errors + diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr new file mode 100644 index 000000000..1e73320e4 --- /dev/null +++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr @@ -0,0 +1,58 @@ +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:9:18 + | +LL | assert!(true some extra junk, "whatever"); + | ^^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `,`, `.`, `?`, or an operator, found `some` + --> $DIR/assert-trailing-junk.rs:12:18 + | +LL | assert!(true some extra junk); + | ^^^^ expected one of `,`, `.`, `?`, or an operator + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:15:30 + | +LL | assert!(true, "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + | + = note: while trying to match sequence start + +error: unexpected string literal + --> $DIR/assert-trailing-junk.rs:18:18 + | +LL | assert!(true "whatever" blah); + | -^^^^^^^^^^ + | | + | help: try adding a comma + +error: no rules expected the token `blah` + --> $DIR/assert-trailing-junk.rs:18:29 + | +LL | assert!(true "whatever" blah); + | -^^^^ no rules expected this token in macro call + | | + | help: missing comma here + | + = note: while trying to match sequence start + +error: macro requires an expression as an argument + --> $DIR/assert-trailing-junk.rs:22:5 + | +LL | assert!(true;); + | ^^^^^^^^^^^^-^ + | | + | help: try removing semicolon + +error: unexpected string literal + --> $DIR/assert-trailing-junk.rs:25:27 + | +LL | assert!(false || true "error message"); + | -^^^^^^^^^^^^^^^ + | | + | help: try adding a comma + +error: aborting due to 7 previous errors + diff --git a/tests/ui/macros/assert.rs b/tests/ui/macros/assert.rs new file mode 100644 index 000000000..a314db907 --- /dev/null +++ b/tests/ui/macros/assert.rs @@ -0,0 +1,9 @@ +// revisions: with-generic-asset without-generic-asset +// [with-generic-asset] compile-flags: --cfg feature="generic_assert" + +fn main() { + assert!(); //~ ERROR requires a boolean expression + assert!(struct); //~ ERROR expected expression + debug_assert!(); //~ ERROR requires a boolean expression + debug_assert!(struct); //~ ERROR expected expression +} diff --git a/tests/ui/macros/assert.with-generic-asset.stderr b/tests/ui/macros/assert.with-generic-asset.stderr new file mode 100644 index 000000000..51d8f28a3 --- /dev/null +++ b/tests/ui/macros/assert.with-generic-asset.stderr @@ -0,0 +1,28 @@ +error: macro requires a boolean expression as an argument + --> $DIR/assert.rs:5:5 + | +LL | assert!(); + | ^^^^^^^^^ boolean expression required + +error: expected expression, found keyword `struct` + --> $DIR/assert.rs:6:13 + | +LL | assert!(struct); + | ^^^^^^ expected expression + +error: macro requires a boolean expression as an argument + --> $DIR/assert.rs:7:5 + | +LL | debug_assert!(); + | ^^^^^^^^^^^^^^^ boolean expression required + | + = note: this error originates in the macro `debug_assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found keyword `struct` + --> $DIR/assert.rs:8:19 + | +LL | debug_assert!(struct); + | ^^^^^^ expected expression + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/assert.without-generic-asset.stderr b/tests/ui/macros/assert.without-generic-asset.stderr new file mode 100644 index 000000000..51d8f28a3 --- /dev/null +++ b/tests/ui/macros/assert.without-generic-asset.stderr @@ -0,0 +1,28 @@ +error: macro requires a boolean expression as an argument + --> $DIR/assert.rs:5:5 + | +LL | assert!(); + | ^^^^^^^^^ boolean expression required + +error: expected expression, found keyword `struct` + --> $DIR/assert.rs:6:13 + | +LL | assert!(struct); + | ^^^^^^ expected expression + +error: macro requires a boolean expression as an argument + --> $DIR/assert.rs:7:5 + | +LL | debug_assert!(); + | ^^^^^^^^^^^^^^^ boolean expression required + | + = note: this error originates in the macro `debug_assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found keyword `struct` + --> $DIR/assert.rs:8:19 + | +LL | debug_assert!(struct); + | ^^^^^^ expected expression + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/attr-empty-expr.rs b/tests/ui/macros/attr-empty-expr.rs new file mode 100644 index 000000000..d4d1a3ee7 --- /dev/null +++ b/tests/ui/macros/attr-empty-expr.rs @@ -0,0 +1,11 @@ +// AST-based macro attributes expanding to an empty expression produce an error and not ICE. + +#![feature(custom_test_frameworks)] +#![feature(stmt_expr_attributes)] +#![feature(test)] + +fn main() { + let _ = #[test] 0; //~ ERROR removing an expression is not supported in this position + let _ = #[bench] 1; //~ ERROR removing an expression is not supported in this position + let _ = #[test_case] 2; //~ ERROR removing an expression is not supported in this position +} diff --git a/tests/ui/macros/attr-empty-expr.stderr b/tests/ui/macros/attr-empty-expr.stderr new file mode 100644 index 000000000..53721053b --- /dev/null +++ b/tests/ui/macros/attr-empty-expr.stderr @@ -0,0 +1,20 @@ +error: removing an expression is not supported in this position + --> $DIR/attr-empty-expr.rs:8:13 + | +LL | let _ = #[test] 0; + | ^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/attr-empty-expr.rs:9:13 + | +LL | let _ = #[bench] 1; + | ^^^^^^^^ + +error: removing an expression is not supported in this position + --> $DIR/attr-empty-expr.rs:10:13 + | +LL | let _ = #[test_case] 2; + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/attr-from-macro.rs b/tests/ui/macros/attr-from-macro.rs new file mode 100644 index 000000000..bb3a5c94d --- /dev/null +++ b/tests/ui/macros/attr-from-macro.rs @@ -0,0 +1,20 @@ +// aux-build:attr-from-macro.rs +// run-pass + +extern crate attr_from_macro; + +attr_from_macro::creator! { + struct Foo; + enum Bar; + enum FooBar; +} + +fn main() { + // Checking the `repr(u32)` on the enum. + assert_eq!(4, std::mem::size_of::<Bar>()); + // Checking the `repr(u16)` on the enum. + assert_eq!(2, std::mem::size_of::<FooBar>()); + + // Checking the Debug impl on the types. + eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A); +} diff --git a/tests/ui/macros/auxiliary/attr-from-macro.rs b/tests/ui/macros/auxiliary/attr-from-macro.rs new file mode 100644 index 000000000..9b388675c --- /dev/null +++ b/tests/ui/macros/auxiliary/attr-from-macro.rs @@ -0,0 +1,15 @@ +#[macro_export] +macro_rules! creator { + (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => { + #[derive(Debug)] + pub struct $name1; + + #[derive(Debug)] + #[repr(u32)] + pub enum $name2 { A } + + #[derive(Debug)] + #[repr(u16)] + pub enum $name3 { A } + } +} diff --git a/tests/ui/macros/auxiliary/define-macro.rs b/tests/ui/macros/auxiliary/define-macro.rs new file mode 100644 index 000000000..4956907c5 --- /dev/null +++ b/tests/ui/macros/auxiliary/define-macro.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! define_macro { + ($i:ident) => { + macro_rules! $i { () => {} } + } +} diff --git a/tests/ui/macros/auxiliary/deprecated-macros.rs b/tests/ui/macros/auxiliary/deprecated-macros.rs new file mode 100644 index 000000000..657a7252a --- /dev/null +++ b/tests/ui/macros/auxiliary/deprecated-macros.rs @@ -0,0 +1,3 @@ +#[deprecated(since = "1.0.0", note = "deprecation note")] +#[macro_export] +macro_rules! deprecated_macro{ () => () } diff --git a/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs b/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs new file mode 100644 index 000000000..bbe6a48c5 --- /dev/null +++ b/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs @@ -0,0 +1,10 @@ +pub type S = u8; + +macro_rules! generate_exported { () => { + #[macro_export] + macro_rules! exported { + () => ($crate::S) + } +}} + +generate_exported!(); diff --git a/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs new file mode 100644 index 000000000..26d4c96d5 --- /dev/null +++ b/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs @@ -0,0 +1,11 @@ +// edition:2018 + +#[macro_export] +macro_rules! custom_matches { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { + match $expression { + $( $pattern )|+ $( if $guard )? => true, + _ => false + } + } +} diff --git a/tests/ui/macros/auxiliary/issue-100199.rs b/tests/ui/macros/auxiliary/issue-100199.rs new file mode 100644 index 000000000..9e190b542 --- /dev/null +++ b/tests/ui/macros/auxiliary/issue-100199.rs @@ -0,0 +1,18 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::{quote, Ident, Span, TokenStream, TokenTree}; + +#[proc_macro_attribute] +pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream { + let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site())); + let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site())); + quote!( + struct Foo<T: $crate_ident::$trait_ident> {} + ) +} diff --git a/tests/ui/macros/auxiliary/issue-19163.rs b/tests/ui/macros/auxiliary/issue-19163.rs new file mode 100644 index 000000000..0c0d9e43c --- /dev/null +++ b/tests/ui/macros/auxiliary/issue-19163.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] + +#[macro_export] +macro_rules! mywrite { + ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) +} diff --git a/tests/ui/macros/auxiliary/issue-40469.rs b/tests/ui/macros/auxiliary/issue-40469.rs new file mode 100644 index 000000000..4f2f41f2c --- /dev/null +++ b/tests/ui/macros/auxiliary/issue-40469.rs @@ -0,0 +1 @@ +macro_rules! m { () => { $crate::main(); } } diff --git a/tests/ui/macros/auxiliary/issue-75982.rs b/tests/ui/macros/auxiliary/issue-75982.rs new file mode 100644 index 000000000..1e1a6126a --- /dev/null +++ b/tests/ui/macros/auxiliary/issue-75982.rs @@ -0,0 +1,12 @@ +const _: () = { + #[macro_export] + macro_rules! first_macro { + () => {} + } + mod foo { + #[macro_export] + macro_rules! second_macro { + () => {} + } + } +}; diff --git a/tests/ui/macros/auxiliary/macro-comma-support.rs b/tests/ui/macros/auxiliary/macro-comma-support.rs new file mode 100644 index 000000000..6a452c185 --- /dev/null +++ b/tests/ui/macros/auxiliary/macro-comma-support.rs @@ -0,0 +1 @@ +() diff --git a/tests/ui/macros/auxiliary/macro-def-site-super.rs b/tests/ui/macros/auxiliary/macro-def-site-super.rs new file mode 100644 index 000000000..cab747c2c --- /dev/null +++ b/tests/ui/macros/auxiliary/macro-def-site-super.rs @@ -0,0 +1,13 @@ +#![feature(decl_macro)] + +mod inner1 { + pub struct Struct {} + + pub mod inner2 { + pub macro mac() { + super::Struct + } + } +} + +pub use inner1::inner2 as public; diff --git a/tests/ui/macros/auxiliary/macro-in-other-crate.rs b/tests/ui/macros/auxiliary/macro-in-other-crate.rs new file mode 100644 index 000000000..db8e92018 --- /dev/null +++ b/tests/ui/macros/auxiliary/macro-in-other-crate.rs @@ -0,0 +1,14 @@ +#[macro_export] +macro_rules! mac { + ($ident:ident) => { let $ident = 42; } +} + +#[macro_export] +macro_rules! inline { + () => () +} + +#[macro_export] +macro_rules! from_prelude { + () => () +} diff --git a/tests/ui/macros/auxiliary/macro-include-items-expr.rs b/tests/ui/macros/auxiliary/macro-include-items-expr.rs new file mode 100644 index 000000000..7394f194b --- /dev/null +++ b/tests/ui/macros/auxiliary/macro-include-items-expr.rs @@ -0,0 +1,3 @@ +// ignore-test: this is not a test + +1 diff --git a/tests/ui/macros/auxiliary/macro-include-items-item.rs b/tests/ui/macros/auxiliary/macro-include-items-item.rs new file mode 100644 index 000000000..7d54745e0 --- /dev/null +++ b/tests/ui/macros/auxiliary/macro-include-items-item.rs @@ -0,0 +1,3 @@ +// ignore-test: this is not a test + +fn foo() { bar() } diff --git a/tests/ui/macros/auxiliary/macro_crate_def_only.rs b/tests/ui/macros/auxiliary/macro_crate_def_only.rs new file mode 100644 index 000000000..c267eefde --- /dev/null +++ b/tests/ui/macros/auxiliary/macro_crate_def_only.rs @@ -0,0 +1,4 @@ +#[macro_export] +macro_rules! make_a_5 { + () => (5) +} diff --git a/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs b/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs new file mode 100644 index 000000000..2e2440462 --- /dev/null +++ b/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs @@ -0,0 +1,12 @@ +pub fn increment(x: usize) -> usize { + x + 1 +} + +#[macro_export] +macro_rules! increment { + ($x:expr) => ($crate::increment($x)) +} + +pub fn check_local() { + assert_eq!(increment!(3), 4); +} diff --git a/tests/ui/macros/auxiliary/macro_export_inner_module.rs b/tests/ui/macros/auxiliary/macro_export_inner_module.rs new file mode 100644 index 000000000..d71af9ee6 --- /dev/null +++ b/tests/ui/macros/auxiliary/macro_export_inner_module.rs @@ -0,0 +1,6 @@ +pub mod inner { + #[macro_export] + macro_rules! foo { + () => (1) + } +} diff --git a/tests/ui/macros/auxiliary/macro_with_super_1.rs b/tests/ui/macros/auxiliary/macro_with_super_1.rs new file mode 100644 index 000000000..b015500df --- /dev/null +++ b/tests/ui/macros/auxiliary/macro_with_super_1.rs @@ -0,0 +1,16 @@ +#![crate_type = "lib"] + +#[macro_export] +macro_rules! declare { + () => ( + pub fn aaa() {} + + pub mod bbb { + use super::aaa; + + pub fn ccc() { + aaa(); + } + } + ) +} diff --git a/tests/ui/macros/auxiliary/or-pattern.rs b/tests/ui/macros/auxiliary/or-pattern.rs new file mode 100644 index 000000000..a319c405e --- /dev/null +++ b/tests/ui/macros/auxiliary/or-pattern.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] + +#[macro_export] +macro_rules! a { + ($x:pat|) => (); +} diff --git a/tests/ui/macros/auxiliary/proc_macro_def.rs b/tests/ui/macros/auxiliary/proc_macro_def.rs new file mode 100644 index 000000000..0497e4ae0 --- /dev/null +++ b/tests/ui/macros/auxiliary/proc_macro_def.rs @@ -0,0 +1,35 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_attribute] +pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream { + let name = item.into_iter().nth(1).unwrap(); + quote!(fn $name() -> bool { true }) +} + +#[proc_macro_attribute] +pub fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream { + quote!($item) +} + +#[proc_macro] +pub fn tru(_ts: TokenStream) -> TokenStream { + quote!(true) +} + +#[proc_macro] +pub fn ret_tru(_ts: TokenStream) -> TokenStream { + quote!(return true;) +} + +#[proc_macro] +pub fn identity(ts: TokenStream) -> TokenStream { + quote!($ts) +} diff --git a/tests/ui/macros/auxiliary/proc_macro_sequence.rs b/tests/ui/macros/auxiliary/proc_macro_sequence.rs new file mode 100644 index 000000000..1331480d8 --- /dev/null +++ b/tests/ui/macros/auxiliary/proc_macro_sequence.rs @@ -0,0 +1,27 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_span, proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::{quote, Span, TokenStream, TokenTree}; + +fn assert_same_span(a: Span, b: Span) { + assert_eq!(a.start(), b.start()); + assert_eq!(a.end(), b.end()); +} + +// This macro generates a macro with the same macro definition as `manual_foo` in +// `same-sequence-span.rs` but with the same span for all sequences. +#[proc_macro] +pub fn make_foo(_: TokenStream) -> TokenStream { + let result = quote! { + macro_rules! generated_foo { + (1 $$x:expr $$($$y:tt,)* $$(= $$z:tt)*) => {}; + } + }; + + result +} diff --git a/tests/ui/macros/auxiliary/two_macros-rpass.rs b/tests/ui/macros/auxiliary/two_macros-rpass.rs new file mode 100644 index 000000000..441a978dd --- /dev/null +++ b/tests/ui/macros/auxiliary/two_macros-rpass.rs @@ -0,0 +1,5 @@ +#[macro_export] +macro_rules! macro_one { ($($t:tt)*) => ($($t)*) } + +#[macro_export] +macro_rules! macro_two { ($($t:tt)*) => ($($t)*) } diff --git a/tests/ui/macros/auxiliary/two_macros.rs b/tests/ui/macros/auxiliary/two_macros.rs new file mode 100644 index 000000000..2330c75c8 --- /dev/null +++ b/tests/ui/macros/auxiliary/two_macros.rs @@ -0,0 +1,5 @@ +#[macro_export] +macro_rules! macro_one { () => ("one") } + +#[macro_export] +macro_rules! macro_two { () => ("two") } diff --git a/tests/ui/macros/auxiliary/unstable-macros.rs b/tests/ui/macros/auxiliary/unstable-macros.rs new file mode 100644 index 000000000..3aadd4b0c --- /dev/null +++ b/tests/ui/macros/auxiliary/unstable-macros.rs @@ -0,0 +1,16 @@ +#![feature(decl_macro)] +#![feature(staged_api)] +#![stable(feature = "unit_test", since = "1.0.0")] + +#[unstable(feature = "unstable_macros", issue = "none")] +#[macro_export] +macro_rules! unstable_macro{ () => () } + +#[stable(feature = "deprecated_macros", since = "1.0.0")] +#[deprecated(since = "1.0.0", note = "deprecation note")] +#[macro_export] +macro_rules! deprecated_macro{ () => () } + +// FIXME: Cannot use a `pub` macro 2.0 in a staged API crate due to reachability issues. +// #[unstable(feature = "unstable_macros", issue = "none")] +// pub macro unstable_macro_modern() {} diff --git a/tests/ui/macros/auxiliary/use-macro-self.rs b/tests/ui/macros/auxiliary/use-macro-self.rs new file mode 100644 index 000000000..f1307411a --- /dev/null +++ b/tests/ui/macros/auxiliary/use-macro-self.rs @@ -0,0 +1,6 @@ +pub mod foobarius {} + +#[macro_export] +macro_rules! foobarius { + () => { () } +} diff --git a/tests/ui/macros/bad-concat.rs b/tests/ui/macros/bad-concat.rs new file mode 100644 index 000000000..263cd074d --- /dev/null +++ b/tests/ui/macros/bad-concat.rs @@ -0,0 +1,8 @@ +fn main() { + let x: u32 = 42; + let y: f64 = 3.14; + let z = "foo"; + let _ = concat!(x, y, z, "bar"); + //~^ ERROR expected a literal + //~| NOTE only literals +} diff --git a/tests/ui/macros/bad-concat.stderr b/tests/ui/macros/bad-concat.stderr new file mode 100644 index 000000000..4316fd312 --- /dev/null +++ b/tests/ui/macros/bad-concat.stderr @@ -0,0 +1,10 @@ +error: expected a literal + --> $DIR/bad-concat.rs:5:21 + | +LL | let _ = concat!(x, y, z, "bar"); + | ^ ^ ^ + | + = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` + +error: aborting due to previous error + diff --git a/tests/ui/macros/bad_hello.rs b/tests/ui/macros/bad_hello.rs new file mode 100644 index 000000000..aaa9e243a --- /dev/null +++ b/tests/ui/macros/bad_hello.rs @@ -0,0 +1,6 @@ +fn main() { + println!(3 + 4); + //~^ ERROR format argument must be a string literal + println!(3, 4); + //~^ ERROR format argument must be a string literal +} diff --git a/tests/ui/macros/bad_hello.stderr b/tests/ui/macros/bad_hello.stderr new file mode 100644 index 000000000..fc9bb82b7 --- /dev/null +++ b/tests/ui/macros/bad_hello.stderr @@ -0,0 +1,24 @@ +error: format argument must be a string literal + --> $DIR/bad_hello.rs:2:14 + | +LL | println!(3 + 4); + | ^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", 3 + 4); + | +++++ + +error: format argument must be a string literal + --> $DIR/bad_hello.rs:4:14 + | +LL | println!(3, 4); + | ^ + | +help: you might be missing a string literal to format with + | +LL | println!("{} {}", 3, 4); + | ++++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/bang-after-name.fixed b/tests/ui/macros/bang-after-name.fixed new file mode 100644 index 000000000..c107ddd5d --- /dev/null +++ b/tests/ui/macros/bang-after-name.fixed @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/tests/ui/macros/bang-after-name.rs b/tests/ui/macros/bang-after-name.rs new file mode 100644 index 000000000..7654d8c44 --- /dev/null +++ b/tests/ui/macros/bang-after-name.rs @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo! { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/tests/ui/macros/bang-after-name.stderr b/tests/ui/macros/bang-after-name.stderr new file mode 100644 index 000000000..f609c4943 --- /dev/null +++ b/tests/ui/macros/bang-after-name.stderr @@ -0,0 +1,8 @@ +error: macro names aren't followed by a `!` + --> $DIR/bang-after-name.rs:4:17 + | +LL | macro_rules! foo! { + | ^ help: remove the `!` + +error: aborting due to previous error + diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs new file mode 100644 index 000000000..bbdd465d5 --- /dev/null +++ b/tests/ui/macros/best-failure.rs @@ -0,0 +1,11 @@ +macro_rules! number { + (neg false, $self:ident) => { $self }; + ($signed:tt => $ty:ty;) => { + number!(neg $signed, $self); + //~^ ERROR no rules expected the token `$` + }; +} + +number! { false => u8; } + +fn main() {} diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr new file mode 100644 index 000000000..a52fc5e3d --- /dev/null +++ b/tests/ui/macros/best-failure.stderr @@ -0,0 +1,21 @@ +error: no rules expected the token `$` + --> $DIR/best-failure.rs:4:30 + | +LL | macro_rules! number { + | ------------------- when calling this macro +... +LL | number!(neg $signed, $self); + | ^^^^^ no rules expected this token in macro call +... +LL | number! { false => u8; } + | ------------------------ in this macro invocation + | +note: while trying to match meta-variable `$self:ident` + --> $DIR/best-failure.rs:2:17 + | +LL | (neg false, $self:ident) => { $self }; + | ^^^^^^^^^^^ + = note: this error originates in the macro `number` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/builtin-prelude-no-accidents.rs b/tests/ui/macros/builtin-prelude-no-accidents.rs new file mode 100644 index 000000000..01691a82d --- /dev/null +++ b/tests/ui/macros/builtin-prelude-no-accidents.rs @@ -0,0 +1,8 @@ +// Names of public modules in libstd and libcore don't accidentally get into prelude +// because macros with the same names are in prelude. + +fn main() { + env::current_dir; //~ ERROR use of undeclared crate or module `env` + type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic` + type B = vec::Vec<u8>; //~ ERROR use of undeclared crate or module `vec` +} diff --git a/tests/ui/macros/builtin-prelude-no-accidents.stderr b/tests/ui/macros/builtin-prelude-no-accidents.stderr new file mode 100644 index 000000000..56af618d4 --- /dev/null +++ b/tests/ui/macros/builtin-prelude-no-accidents.stderr @@ -0,0 +1,21 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `env` + --> $DIR/builtin-prelude-no-accidents.rs:5:5 + | +LL | env::current_dir; + | ^^^ use of undeclared crate or module `env` + +error[E0433]: failed to resolve: use of undeclared crate or module `panic` + --> $DIR/builtin-prelude-no-accidents.rs:6:14 + | +LL | type A = panic::PanicInfo; + | ^^^^^ use of undeclared crate or module `panic` + +error[E0433]: failed to resolve: use of undeclared crate or module `vec` + --> $DIR/builtin-prelude-no-accidents.rs:7:14 + | +LL | type B = vec::Vec<u8>; + | ^^^ use of undeclared crate or module `vec` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/builtin-std-paths-fail.rs b/tests/ui/macros/builtin-std-paths-fail.rs new file mode 100644 index 000000000..c1a4e32a6 --- /dev/null +++ b/tests/ui/macros/builtin-std-paths-fail.rs @@ -0,0 +1,25 @@ +#[derive( + core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core` + //~| ERROR could not find `RustcDecodable` in `core` + core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core` + //~| ERROR could not find `RustcDecodable` in `core` +)] +#[core::bench] //~ ERROR could not find `bench` in `core` +#[core::global_allocator] //~ ERROR could not find `global_allocator` in `core` +#[core::test_case] //~ ERROR could not find `test_case` in `core` +#[core::test] //~ ERROR could not find `test` in `core` +struct Core; + +#[derive( + std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std` + //~| ERROR could not find `RustcDecodable` in `std` + std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std` + //~| ERROR could not find `RustcDecodable` in `std` +)] +#[std::bench] //~ ERROR could not find `bench` in `std` +#[std::global_allocator] //~ ERROR could not find `global_allocator` in `std` +#[std::test_case] //~ ERROR could not find `test_case` in `std` +#[std::test] //~ ERROR could not find `test` in `std` +struct Std; + +fn main() {} diff --git a/tests/ui/macros/builtin-std-paths-fail.stderr b/tests/ui/macros/builtin-std-paths-fail.stderr new file mode 100644 index 000000000..ba6261011 --- /dev/null +++ b/tests/ui/macros/builtin-std-paths-fail.stderr @@ -0,0 +1,99 @@ +error[E0433]: failed to resolve: could not find `RustcDecodable` in `core` + --> $DIR/builtin-std-paths-fail.rs:2:11 + | +LL | core::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `core` + --> $DIR/builtin-std-paths-fail.rs:4:11 + | +LL | core::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `core` + --> $DIR/builtin-std-paths-fail.rs:2:11 + | +LL | core::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `core` + --> $DIR/builtin-std-paths-fail.rs:4:11 + | +LL | core::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core` + +error[E0433]: failed to resolve: could not find `bench` in `core` + --> $DIR/builtin-std-paths-fail.rs:7:9 + | +LL | #[core::bench] + | ^^^^^ could not find `bench` in `core` + +error[E0433]: failed to resolve: could not find `global_allocator` in `core` + --> $DIR/builtin-std-paths-fail.rs:8:9 + | +LL | #[core::global_allocator] + | ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `core` + +error[E0433]: failed to resolve: could not find `test_case` in `core` + --> $DIR/builtin-std-paths-fail.rs:9:9 + | +LL | #[core::test_case] + | ^^^^^^^^^ could not find `test_case` in `core` + +error[E0433]: failed to resolve: could not find `test` in `core` + --> $DIR/builtin-std-paths-fail.rs:10:9 + | +LL | #[core::test] + | ^^^^ could not find `test` in `core` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `std` + --> $DIR/builtin-std-paths-fail.rs:14:10 + | +LL | std::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `std` + --> $DIR/builtin-std-paths-fail.rs:16:10 + | +LL | std::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `std` + --> $DIR/builtin-std-paths-fail.rs:14:10 + | +LL | std::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std` + +error[E0433]: failed to resolve: could not find `RustcDecodable` in `std` + --> $DIR/builtin-std-paths-fail.rs:16:10 + | +LL | std::RustcDecodable, + | ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std` + +error[E0433]: failed to resolve: could not find `bench` in `std` + --> $DIR/builtin-std-paths-fail.rs:19:8 + | +LL | #[std::bench] + | ^^^^^ could not find `bench` in `std` + +error[E0433]: failed to resolve: could not find `global_allocator` in `std` + --> $DIR/builtin-std-paths-fail.rs:20:8 + | +LL | #[std::global_allocator] + | ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `std` + +error[E0433]: failed to resolve: could not find `test_case` in `std` + --> $DIR/builtin-std-paths-fail.rs:21:8 + | +LL | #[std::test_case] + | ^^^^^^^^^ could not find `test_case` in `std` + +error[E0433]: failed to resolve: could not find `test` in `std` + --> $DIR/builtin-std-paths-fail.rs:22:8 + | +LL | #[std::test] + | ^^^^ could not find `test` in `std` + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/builtin-std-paths.rs b/tests/ui/macros/builtin-std-paths.rs new file mode 100644 index 000000000..2083f9ba3 --- /dev/null +++ b/tests/ui/macros/builtin-std-paths.rs @@ -0,0 +1,32 @@ +// check-pass + +#[derive( + core::clone::Clone, + core::marker::Copy, + core::fmt::Debug, + core::default::Default, + core::cmp::Eq, + core::hash::Hash, + core::cmp::Ord, + core::cmp::PartialEq, + core::cmp::PartialOrd, +)] +struct Core; + +#[derive( + std::clone::Clone, + std::marker::Copy, + std::fmt::Debug, + std::default::Default, + std::cmp::Eq, + std::hash::Hash, + std::cmp::Ord, + std::cmp::PartialEq, + std::cmp::PartialOrd, +)] +struct Std; + +fn main() { + core::column!(); + std::column!(); +} diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs new file mode 100644 index 000000000..2aac50a9d --- /dev/null +++ b/tests/ui/macros/cfg.rs @@ -0,0 +1,6 @@ +fn main() { + cfg!(); //~ ERROR macro requires a cfg-pattern + cfg!(123); //~ ERROR expected identifier + cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string + cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern +} diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr new file mode 100644 index 000000000..2633d5f72 --- /dev/null +++ b/tests/ui/macros/cfg.stderr @@ -0,0 +1,31 @@ +error: macro requires a cfg-pattern as an argument + --> $DIR/cfg.rs:2:5 + | +LL | cfg!(); + | ^^^^^^ cfg-pattern required + | + = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected identifier, found `123` + --> $DIR/cfg.rs:3:10 + | +LL | cfg!(123); + | ^^^ expected identifier + +error[E0565]: literal in `cfg` predicate value must be a string + --> $DIR/cfg.rs:4:16 + | +LL | cfg!(foo = 123); + | ^^^ + +error: expected 1 cfg-pattern + --> $DIR/cfg.rs:5:5 + | +LL | cfg!(foo, bar); + | ^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/macros/colorful-write-macros.rs b/tests/ui/macros/colorful-write-macros.rs new file mode 100644 index 000000000..eb1872cc7 --- /dev/null +++ b/tests/ui/macros/colorful-write-macros.rs @@ -0,0 +1,34 @@ +// run-pass +#![allow(dead_code)] +use std::io::Write; +use std::fmt; + +struct Foo<'a> { + writer: &'a mut (dyn Write+'a), + other: &'a str, +} + +struct Bar; + +impl fmt::Write for Bar { + fn write_str(&mut self, _: &str) -> fmt::Result { + Ok(()) + } +} + +fn borrowing_writer_from_struct_and_formatting_struct_field(foo: Foo) { + write!(foo.writer, "{}", foo.other).unwrap(); +} + +fn main() { + let mut w = Vec::new(); + write!(&mut w as &mut dyn Write, "").unwrap(); + write!(&mut w, "").unwrap(); // should coerce + println!("ok"); + + let mut s = Bar; + { + use std::fmt::Write; + write!(&mut s, "test").unwrap(); + } +} diff --git a/tests/ui/macros/concat-bytes-error.rs b/tests/ui/macros/concat-bytes-error.rs new file mode 100644 index 000000000..db5d3cab0 --- /dev/null +++ b/tests/ui/macros/concat-bytes-error.rs @@ -0,0 +1,50 @@ +#![feature(concat_bytes)] + +fn main() { + concat_bytes!(pie); //~ ERROR expected a byte literal + concat_bytes!(pie, pie); //~ ERROR expected a byte literal + concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals + concat_bytes!(2.8); //~ ERROR cannot concatenate float literals + concat_bytes!(300); //~ ERROR cannot concatenate numeric literals + concat_bytes!('a'); //~ ERROR cannot concatenate character literals + concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals + concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals + concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals + concat_bytes!([ + "hi", //~ ERROR cannot concatenate string literals + ]); + concat_bytes!([ + 'a', //~ ERROR cannot concatenate character literals + ]); + concat_bytes!([ + true, //~ ERROR cannot concatenate boolean literals + ]); + concat_bytes!([ + false, //~ ERROR cannot concatenate boolean literals + ]); + concat_bytes!([ + 2.6, //~ ERROR cannot concatenate float literals + ]); + concat_bytes!([ + 265, //~ ERROR numeric literal is out of bounds + ]); + concat_bytes!([ + -33, //~ ERROR expected a byte literal + ]); + concat_bytes!([ + b"hi!", //~ ERROR cannot concatenate doubly nested array + ]); + concat_bytes!([ + [5, 6, 7], //~ ERROR cannot concatenate doubly nested array + ]); + concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals + concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8` + concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number + concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number + concat_bytes!([pie; -2]); //~ ERROR repeat count is not a positive number + concat_bytes!([pie; 2]); //~ ERROR expected a byte literal + concat_bytes!([2.2; 0]); //~ ERROR cannot concatenate float literals + concat_bytes!([5.5; ()]); //~ ERROR repeat count is not a positive number + concat_bytes!([[1, 2, 3]; 3]); //~ ERROR cannot concatenate doubly nested array + concat_bytes!([[42; 2]; 3]); //~ ERROR cannot concatenate doubly nested array +} diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr new file mode 100644 index 000000000..d6cd1a3d1 --- /dev/null +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -0,0 +1,181 @@ +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:4:19 + | +LL | concat_bytes!(pie); + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:5:19 + | +LL | concat_bytes!(pie, pie); + | ^^^ ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:6:19 + | +LL | concat_bytes!("tnrsi", "tnri"); + | ^^^^^^^ help: try using a byte string: `b"tnrsi"` + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:7:19 + | +LL | concat_bytes!(2.8); + | ^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:8:19 + | +LL | concat_bytes!(300); + | ^^^ help: try wrapping the number in an array: `[300]` + +error: cannot concatenate character literals + --> $DIR/concat-bytes-error.rs:9:19 + | +LL | concat_bytes!('a'); + | ^^^ help: try using a byte character: `b'a'` + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:10:19 + | +LL | concat_bytes!(true, false); + | ^^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:11:19 + | +LL | concat_bytes!(42, b"va", b'l'); + | ^^ help: try wrapping the number in an array: `[42]` + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:12:19 + | +LL | concat_bytes!(42, b"va", b'l', [1, 2]); + | ^^ help: try wrapping the number in an array: `[42]` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:14:9 + | +LL | "hi", + | ^^^^ + +error: cannot concatenate character literals + --> $DIR/concat-bytes-error.rs:17:9 + | +LL | 'a', + | ^^^ help: try using a byte character: `b'a'` + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:20:9 + | +LL | true, + | ^^^^ + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:23:9 + | +LL | false, + | ^^^^^ + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:26:9 + | +LL | 2.6, + | ^^^ + +error: numeric literal is out of bounds + --> $DIR/concat-bytes-error.rs:29:9 + | +LL | 265, + | ^^^ + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:32:9 + | +LL | -33, + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:35:9 + | +LL | b"hi!", + | ^^^^^^ + | + = note: byte strings are treated as arrays of bytes + = help: try flattening the array + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:38:9 + | +LL | [5, 6, 7], + | ^^^^^^^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:40:19 + | +LL | concat_bytes!(5u16); + | ^^^^ help: try wrapping the number in an array: `[5u16]` + +error: numeric literal is not a `u8` + --> $DIR/concat-bytes-error.rs:41:20 + | +LL | concat_bytes!([5u16]); + | ^^^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:42:23 + | +LL | concat_bytes!([3; ()]); + | ^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:43:23 + | +LL | concat_bytes!([3; -2]); + | ^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:44:25 + | +LL | concat_bytes!([pie; -2]); + | ^^ + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:45:20 + | +LL | concat_bytes!([pie; 2]); + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:46:20 + | +LL | concat_bytes!([2.2; 0]); + | ^^^ + +error: repeat count is not a positive number + --> $DIR/concat-bytes-error.rs:47:25 + | +LL | concat_bytes!([5.5; ()]); + | ^^ + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:48:20 + | +LL | concat_bytes!([[1, 2, 3]; 3]); + | ^^^^^^^^^ + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:49:20 + | +LL | concat_bytes!([[42; 2]; 3]); + | ^^^^^^^ + +error: aborting due to 28 previous errors + diff --git a/tests/ui/macros/concat-bytes.rs b/tests/ui/macros/concat-bytes.rs new file mode 100644 index 000000000..fd8f99417 --- /dev/null +++ b/tests/ui/macros/concat-bytes.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(concat_bytes)] + +fn main() { + assert_eq!(concat_bytes!(), &[]); + assert_eq!( + concat_bytes!(b'A', b"BC", [68, b'E', 70], [b'G'; 1], [72; 2], [73u8; 3], [65; 0]), + b"ABCDEFGHHIII", + ); + assert_eq!( + concat_bytes!( + concat_bytes!(b"AB", b"CD"), + concat_bytes!(b"EF", b"GH"), + ), + b"ABCDEFGH", + ); +} diff --git a/tests/ui/macros/concat-rpass.rs b/tests/ui/macros/concat-rpass.rs new file mode 100644 index 000000000..0c30a39d6 --- /dev/null +++ b/tests/ui/macros/concat-rpass.rs @@ -0,0 +1,18 @@ +// run-pass + +pub fn main() { + assert_eq!(format!(concat!("foo", "bar", "{}"), "baz"), "foobarbaz".to_string()); + assert_eq!(format!(concat!()), "".to_string()); + // check trailing comma is allowed in concat + assert_eq!(concat!("qux", "quux",).to_string(), "quxquux".to_string()); + + assert_eq!( + concat!(1, 2, 3, 4f32, 4.0, 'a', true), + "12344.0atrue" + ); + + assert!(match "12344.0atrue" { + concat!(1, 2, 3, 4f32, 4.0, 'a', true) => true, + _ => false + }) +} diff --git a/tests/ui/macros/concat.rs b/tests/ui/macros/concat.rs new file mode 100644 index 000000000..d7ab7d626 --- /dev/null +++ b/tests/ui/macros/concat.rs @@ -0,0 +1,6 @@ +fn main() { + concat!(b'f'); //~ ERROR: cannot concatenate a byte string literal + concat!(b"foo"); //~ ERROR: cannot concatenate a byte string literal + concat!(foo); //~ ERROR: expected a literal + concat!(foo()); //~ ERROR: expected a literal +} diff --git a/tests/ui/macros/concat.stderr b/tests/ui/macros/concat.stderr new file mode 100644 index 000000000..61fb9de1e --- /dev/null +++ b/tests/ui/macros/concat.stderr @@ -0,0 +1,30 @@ +error: cannot concatenate a byte string literal + --> $DIR/concat.rs:2:13 + | +LL | concat!(b'f'); + | ^^^^ + +error: cannot concatenate a byte string literal + --> $DIR/concat.rs:3:13 + | +LL | concat!(b"foo"); + | ^^^^^^ + +error: expected a literal + --> $DIR/concat.rs:4:13 + | +LL | concat!(foo); + | ^^^ + | + = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` + +error: expected a literal + --> $DIR/concat.rs:5:13 + | +LL | concat!(foo()); + | ^^^^^ + | + = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/conditional-debug-macro-on.rs b/tests/ui/macros/conditional-debug-macro-on.rs new file mode 100644 index 000000000..8665da897 --- /dev/null +++ b/tests/ui/macros/conditional-debug-macro-on.rs @@ -0,0 +1,8 @@ +// run-pass +pub fn main() { + // exits early if println! evaluates its arguments, otherwise it + // will hit the panic. + println!("{:?}", { if true { return; } }); + + panic!(); +} diff --git a/tests/ui/macros/cross-crate-pat-span.rs b/tests/ui/macros/cross-crate-pat-span.rs new file mode 100644 index 000000000..ed67142ce --- /dev/null +++ b/tests/ui/macros/cross-crate-pat-span.rs @@ -0,0 +1,12 @@ +// edition:2021 +// check-pass +// aux-build: foreign-crate-macro-pat.rs +// +// Tests that the edition of the foreign crate is used +// when determining the behavior of the `:pat` matcher. + +extern crate foreign_crate_macro_pat; + +fn main() { + let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9'); +} diff --git a/tests/ui/macros/derive-in-eager-expansion-hang.rs b/tests/ui/macros/derive-in-eager-expansion-hang.rs new file mode 100644 index 000000000..0729e14d5 --- /dev/null +++ b/tests/ui/macros/derive-in-eager-expansion-hang.rs @@ -0,0 +1,14 @@ +// Regression test for the issue #44692 + +macro_rules! hang { () => { + { //~ ERROR format argument must be a string literal + #[derive(Clone)] + struct S; + + "" + } +}} + +fn main() { + format_args!(hang!()); +} diff --git a/tests/ui/macros/derive-in-eager-expansion-hang.stderr b/tests/ui/macros/derive-in-eager-expansion-hang.stderr new file mode 100644 index 000000000..e0a4f3878 --- /dev/null +++ b/tests/ui/macros/derive-in-eager-expansion-hang.stderr @@ -0,0 +1,22 @@ +error: format argument must be a string literal + --> $DIR/derive-in-eager-expansion-hang.rs:4:5 + | +LL | / { +LL | | #[derive(Clone)] +LL | | struct S; +LL | | +LL | | "" +LL | | } + | |_____^ +... +LL | format_args!(hang!()); + | ------- in this macro invocation + | + = note: this error originates in the macro `hang` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might be missing a string literal to format with + | +LL | format_args!("{}", hang!()); + | +++++ + +error: aborting due to previous error + diff --git a/tests/ui/macros/die-macro-2.rs b/tests/ui/macros/die-macro-2.rs new file mode 100644 index 000000000..ebbce528a --- /dev/null +++ b/tests/ui/macros/die-macro-2.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:test +// ignore-emscripten no processes + +fn main() { + panic!("test"); +} diff --git a/tests/ui/macros/die-macro-expr.rs b/tests/ui/macros/die-macro-expr.rs new file mode 100644 index 000000000..c4b5f68dd --- /dev/null +++ b/tests/ui/macros/die-macro-expr.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:test +// ignore-emscripten no processes + +fn main() { + let __isize: isize = panic!("test"); +} diff --git a/tests/ui/macros/die-macro-pure.rs b/tests/ui/macros/die-macro-pure.rs new file mode 100644 index 000000000..588fbe61b --- /dev/null +++ b/tests/ui/macros/die-macro-pure.rs @@ -0,0 +1,11 @@ +// run-fail +// error-pattern:test +// ignore-emscripten no processes + +fn f() { + panic!("test"); +} + +fn main() { + f(); +} diff --git a/tests/ui/macros/die-macro.rs b/tests/ui/macros/die-macro.rs new file mode 100644 index 000000000..2a726efe8 --- /dev/null +++ b/tests/ui/macros/die-macro.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] +// Just testing that panic!() type checks in statement or expr + + +#![allow(unreachable_code)] + +fn f() { + panic!(); + + let _x: isize = panic!(); +} + +pub fn main() { + +} diff --git a/tests/ui/macros/doc-comment.rs b/tests/ui/macros/doc-comment.rs new file mode 100644 index 000000000..9de39e9b5 --- /dev/null +++ b/tests/ui/macros/doc-comment.rs @@ -0,0 +1,25 @@ +// check-pass +// Tests that we properly handle a nested macro expansion +// involving a `#[doc]` attribute +#![deny(missing_docs)] +//! Crate docs + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + } +} + +macro_rules! make_comment { + () => { + doc_comment!("Function docs", + pub fn bar() {} + ); + } +} + + +make_comment!(); + +fn main() {} diff --git a/tests/ui/macros/dollar-crate-nested-encoding.rs b/tests/ui/macros/dollar-crate-nested-encoding.rs new file mode 100644 index 000000000..5242f7830 --- /dev/null +++ b/tests/ui/macros/dollar-crate-nested-encoding.rs @@ -0,0 +1,8 @@ +// check-pass +// aux-build:dollar-crate-nested-encoding.rs + +extern crate dollar_crate_nested_encoding; + +type A = dollar_crate_nested_encoding::exported!(); + +fn main() {} diff --git a/tests/ui/macros/duplicate-builtin.rs b/tests/ui/macros/duplicate-builtin.rs new file mode 100644 index 000000000..35f0f4290 --- /dev/null +++ b/tests/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/tests/ui/macros/duplicate-builtin.stderr b/tests/ui/macros/duplicate-builtin.stderr new file mode 100644 index 000000000..58accea27 --- /dev/null +++ b/tests/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/tests/ui/macros/edition-macro-pats.rs b/tests/ui/macros/edition-macro-pats.rs new file mode 100644 index 000000000..040894712 --- /dev/null +++ b/tests/ui/macros/edition-macro-pats.rs @@ -0,0 +1,12 @@ +// run-pass +// edition:2021 + +macro_rules! foo { + (a $x:pat_param) => {}; + (b $x:pat) => {}; +} + +fn main() { + foo!(a None); + foo!(b 1 | 2); +} diff --git a/tests/ui/macros/empty-trailing-stmt.rs b/tests/ui/macros/empty-trailing-stmt.rs new file mode 100644 index 000000000..3d78ed4a4 --- /dev/null +++ b/tests/ui/macros/empty-trailing-stmt.rs @@ -0,0 +1,10 @@ +macro_rules! empty { + () => { } +} + +fn foo() -> bool { //~ ERROR mismatched + { true } //~ ERROR mismatched + empty!(); +} + +fn main() {} diff --git a/tests/ui/macros/empty-trailing-stmt.stderr b/tests/ui/macros/empty-trailing-stmt.stderr new file mode 100644 index 000000000..97a2edd39 --- /dev/null +++ b/tests/ui/macros/empty-trailing-stmt.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/empty-trailing-stmt.rs:6:7 + | +LL | { true } + | ^^^^ expected `()`, found `bool` + | +help: you might have meant to return this value + | +LL | { return true; } + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/empty-trailing-stmt.rs:5:13 + | +LL | fn foo() -> bool { + | --- ^^^^ expected `bool`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/macros/format-args-temporaries-async.rs b/tests/ui/macros/format-args-temporaries-async.rs new file mode 100644 index 000000000..d959329b9 --- /dev/null +++ b/tests/ui/macros/format-args-temporaries-async.rs @@ -0,0 +1,37 @@ +// check-pass +// edition:2021 + +use std::fmt::{self, Display}; +use std::future::Future; +use std::io; +use std::pin::Pin; +use std::task::{Context, Poll}; + +struct AsyncStdout; + +impl AsyncStdout { + fn write_fmt<'a>(&'a mut self, _args: fmt::Arguments) -> WriteFmtFuture<'a, Self> + where + Self: Unpin, + { + WriteFmtFuture(self) + } +} + +struct WriteFmtFuture<'a, T>(&'a mut T); + +impl<'a, T> Future for WriteFmtFuture<'a, T> { + type Output = io::Result<()>; + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { + unimplemented!() + } +} + +async fn async_main() { + let _write = write!(&mut AsyncStdout, "...").await; + let _writeln = writeln!(&mut AsyncStdout, "...").await; +} + +fn main() { + let _ = async_main; +} diff --git a/tests/ui/macros/format-args-temporaries-in-write.rs b/tests/ui/macros/format-args-temporaries-in-write.rs new file mode 100644 index 000000000..339ccbc33 --- /dev/null +++ b/tests/ui/macros/format-args-temporaries-in-write.rs @@ -0,0 +1,50 @@ +// check-fail + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + // Empty but this is a necessary part of the repro. Otherwise borrow + // checker is fine with 'a dangling at the time that MutexGuard goes out + // of scope. + } +} + +struct Out; + +impl Out { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + // FIXME(dtolnay): We actually want both of these to work. I think it's + // sadly unimplementable today though. + + let _write = { + let mutex = Mutex; + write!(Out, "{}", mutex.lock()) /* no semicolon */ + //~^ ERROR `mutex` does not live long enough + }; + + let _writeln = { + let mutex = Mutex; + writeln!(Out, "{}", mutex.lock()) /* no semicolon */ + //~^ ERROR `mutex` does not live long enough + }; +} diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr new file mode 100644 index 000000000..287cd7d67 --- /dev/null +++ b/tests/ui/macros/format-args-temporaries-in-write.stderr @@ -0,0 +1,33 @@ +error[E0597]: `mutex` does not live long enough + --> $DIR/format-args-temporaries-in-write.rs:41:27 + | +LL | write!(Out, "{}", mutex.lock()) /* no semicolon */ + | ^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | + +error[E0597]: `mutex` does not live long enough + --> $DIR/format-args-temporaries-in-write.rs:47:29 + | +LL | writeln!(Out, "{}", mutex.lock()) /* no semicolon */ + | ^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | +LL | }; + | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` + | | + | `mutex` dropped here while still borrowed + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/macros/format-args-temporaries.rs b/tests/ui/macros/format-args-temporaries.rs new file mode 100644 index 000000000..59323828b --- /dev/null +++ b/tests/ui/macros/format-args-temporaries.rs @@ -0,0 +1,54 @@ +// check-pass + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + // Empty but this is a necessary part of the repro. Otherwise borrow + // checker is fine with 'a dangling at the time that MutexGuard goes out + // of scope. + } +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + let _print = { + let mutex = Mutex; + print!("{}", mutex.lock()) /* no semicolon */ + }; + + let _println = { + let mutex = Mutex; + println!("{}", mutex.lock()) /* no semicolon */ + }; + + let _eprint = { + let mutex = Mutex; + eprint!("{}", mutex.lock()) /* no semicolon */ + }; + + let _eprintln = { + let mutex = Mutex; + eprintln!("{}", mutex.lock()) /* no semicolon */ + }; + + let _panic = { + let mutex = Mutex; + panic!("{}", mutex.lock()) /* no semicolon */ + }; +} diff --git a/tests/ui/macros/format-foreign.rs b/tests/ui/macros/format-foreign.rs new file mode 100644 index 000000000..ac65838f2 --- /dev/null +++ b/tests/ui/macros/format-foreign.rs @@ -0,0 +1,17 @@ +fn main() { + println!("%.*3$s %s!\n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments + println!("%1$*2$.*3$f", 123.456); //~ ERROR never used + println!(r###"%.*3$s + %s!\n +"###, "Hello,", "World", 4); + //~^ ERROR multiple unused formatting arguments + // correctly account for raw strings in inline suggestions + + // This should *not* produce hints, on the basis that there's equally as + // many "correct" format specifiers. It's *probably* just an actual typo. + println!("{} %f", "one", 2.0); //~ ERROR never used + + println!("Hi there, $NAME.", NAME="Tim"); //~ ERROR never used + println!("$1 $0 $$ $NAME", 1, 2, NAME=3); + //~^ ERROR multiple unused formatting arguments +} diff --git a/tests/ui/macros/format-foreign.stderr b/tests/ui/macros/format-foreign.stderr new file mode 100644 index 000000000..7971c2ab2 --- /dev/null +++ b/tests/ui/macros/format-foreign.stderr @@ -0,0 +1,82 @@ +error: multiple unused formatting arguments + --> $DIR/format-foreign.rs:2:30 + | +LL | println!("%.*3$s %s!\n", "Hello,", "World", 4); + | -------------- ^^^^^^^^ ^^^^^^^ ^ argument never used + | | | | + | | | argument never used + | | argument never used + | multiple missing formatting specifiers + | + = note: printf formatting is not supported; see the documentation for `std::fmt` +help: format specifiers use curly braces + | +LL | println!("{:.2$} {}!\n", "Hello,", "World", 4); + | ~~~~~~ ~~ + +error: argument never used + --> $DIR/format-foreign.rs:3:29 + | +LL | println!("%1$*2$.*3$f", 123.456); + | ----------- ^^^^^^^ argument never used + | | + | help: format specifiers use curly braces: `{0:1$.2$}` + | + = note: printf formatting is not supported; see the documentation for `std::fmt` + +error: multiple unused formatting arguments + --> $DIR/format-foreign.rs:6:7 + | +LL | println!(r###"%.*3$s + | ______________- +LL | | %s!\n +LL | | "###, "Hello,", "World", 4); + | | - ^^^^^^^^ ^^^^^^^ ^ argument never used + | | | | | + | | | | argument never used + | |____| argument never used + | multiple missing formatting specifiers + | + = note: printf formatting is not supported; see the documentation for `std::fmt` +help: format specifiers use curly braces + | +LL ~ println!(r###"{:.2$} +LL ~ {}!\n + | + +error: argument never used + --> $DIR/format-foreign.rs:12:30 + | +LL | println!("{} %f", "one", 2.0); + | ------- ^^^ argument never used + | | + | formatting specifier missing + +error: named argument never used + --> $DIR/format-foreign.rs:14:39 + | +LL | println!("Hi there, $NAME.", NAME="Tim"); + | ----- ^^^^^ named argument never used + | | + | help: format specifiers use curly braces: `{NAME}` + | + = note: shell formatting is not supported; see the documentation for `std::fmt` + +error: multiple unused formatting arguments + --> $DIR/format-foreign.rs:15:32 + | +LL | println!("$1 $0 $$ $NAME", 1, 2, NAME=3); + | ---------------- ^ ^ ^ named argument never used + | | | | + | | | argument never used + | | argument never used + | multiple missing formatting specifiers + | + = note: shell formatting is not supported; see the documentation for `std::fmt` +help: format specifiers use curly braces + | +LL | println!("{1} {0} $$ {NAME}", 1, 2, NAME=3); + | ~~~ ~~~ ~~~~~~ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/macros/format-parse-errors.rs b/tests/ui/macros/format-parse-errors.rs new file mode 100644 index 000000000..ffa7a2817 --- /dev/null +++ b/tests/ui/macros/format-parse-errors.rs @@ -0,0 +1,17 @@ +fn main() { + let foo = ""; + let bar = ""; + format!(); //~ ERROR requires at least a format string argument + format!(struct); //~ ERROR expected expression + format!("s", name =); //~ ERROR expected expression + format!( + "s {foo} {} {}", + foo = foo, + bar, //~ ERROR positional arguments cannot follow named arguments + ); + format!("s {foo}", foo = struct); //~ ERROR expected expression + format!("s", struct); //~ ERROR expected expression + + // This error should come after parsing errors to ensure they are non-fatal. + format!(123); //~ ERROR format argument must be a string literal +} diff --git a/tests/ui/macros/format-parse-errors.stderr b/tests/ui/macros/format-parse-errors.stderr new file mode 100644 index 000000000..f9ea4c633 --- /dev/null +++ b/tests/ui/macros/format-parse-errors.stderr @@ -0,0 +1,53 @@ +error: requires at least a format string argument + --> $DIR/format-parse-errors.rs:4:5 + | +LL | format!(); + | ^^^^^^^^^ + | + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found keyword `struct` + --> $DIR/format-parse-errors.rs:5:13 + | +LL | format!(struct); + | ^^^^^^ expected expression + +error: expected expression, found end of macro arguments + --> $DIR/format-parse-errors.rs:6:24 + | +LL | format!("s", name =); + | ^ expected expression + +error: positional arguments cannot follow named arguments + --> $DIR/format-parse-errors.rs:10:9 + | +LL | foo = foo, + | --------- named argument +LL | bar, + | ^^^ positional arguments must be before named arguments + +error: expected expression, found keyword `struct` + --> $DIR/format-parse-errors.rs:12:30 + | +LL | format!("s {foo}", foo = struct); + | ^^^^^^ expected expression + +error: expected expression, found keyword `struct` + --> $DIR/format-parse-errors.rs:13:18 + | +LL | format!("s", struct); + | ^^^^^^ expected expression + +error: format argument must be a string literal + --> $DIR/format-parse-errors.rs:16:13 + | +LL | format!(123); + | ^^^ + | +help: you might be missing a string literal to format with + | +LL | format!("{}", 123); + | +++++ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/macros/format-unused-lables.rs b/tests/ui/macros/format-unused-lables.rs new file mode 100644 index 000000000..56382b101 --- /dev/null +++ b/tests/ui/macros/format-unused-lables.rs @@ -0,0 +1,18 @@ +fn main() { + println!("Test", 123, 456, 789); + //~^ ERROR multiple unused formatting arguments + + println!("Test2", + 123, //~ ERROR multiple unused formatting arguments + 456, + 789 + ); + + println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used + + println!("Some more $STUFF", + "woo!", //~ ERROR multiple unused formatting arguments + STUFF= + "things" + , UNUSED="args"); +} diff --git a/tests/ui/macros/format-unused-lables.stderr b/tests/ui/macros/format-unused-lables.stderr new file mode 100644 index 000000000..fad87fa2a --- /dev/null +++ b/tests/ui/macros/format-unused-lables.stderr @@ -0,0 +1,50 @@ +error: multiple unused formatting arguments + --> $DIR/format-unused-lables.rs:2:22 + | +LL | println!("Test", 123, 456, 789); + | ------ ^^^ ^^^ ^^^ argument never used + | | | | + | | | argument never used + | | argument never used + | multiple missing formatting specifiers + +error: multiple unused formatting arguments + --> $DIR/format-unused-lables.rs:6:9 + | +LL | println!("Test2", + | ------- multiple missing formatting specifiers +LL | 123, + | ^^^ argument never used +LL | 456, + | ^^^ argument never used +LL | 789 + | ^^^ argument never used + +error: named argument never used + --> $DIR/format-unused-lables.rs:11:35 + | +LL | println!("Some stuff", UNUSED="args"); + | ------------ ^^^^^^ named argument never used + | | + | formatting specifier missing + +error: multiple unused formatting arguments + --> $DIR/format-unused-lables.rs:14:9 + | +LL | println!("Some more $STUFF", + | ------------------ + | | | + | | help: format specifiers use curly braces: `{STUFF}` + | multiple missing formatting specifiers +LL | "woo!", + | ^^^^^^ argument never used +LL | STUFF= +LL | "things" + | ^^^^^^^^ named argument never used +LL | , UNUSED="args"); + | ^^^^^^ named argument never used + | + = note: shell formatting is not supported; see the documentation for `std::fmt` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/global-asm.rs b/tests/ui/macros/global-asm.rs new file mode 100644 index 000000000..26e90edce --- /dev/null +++ b/tests/ui/macros/global-asm.rs @@ -0,0 +1,7 @@ +use std::arch::global_asm; + +fn main() { + global_asm!(); //~ ERROR requires at least a template string argument + global_asm!(struct); //~ ERROR expected expression + global_asm!(123); //~ ERROR asm template must be a string literal +} diff --git a/tests/ui/macros/global-asm.stderr b/tests/ui/macros/global-asm.stderr new file mode 100644 index 000000000..3c26ec65a --- /dev/null +++ b/tests/ui/macros/global-asm.stderr @@ -0,0 +1,20 @@ +error: requires at least a template string argument + --> $DIR/global-asm.rs:4:5 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^ + +error: expected expression, found keyword `struct` + --> $DIR/global-asm.rs:5:17 + | +LL | global_asm!(struct); + | ^^^^^^ expected expression + +error: asm template must be a string literal + --> $DIR/global-asm.rs:6:17 + | +LL | global_asm!(123); + | ^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/html-literals.rs b/tests/ui/macros/html-literals.rs new file mode 100644 index 000000000..26f00fed9 --- /dev/null +++ b/tests/ui/macros/html-literals.rs @@ -0,0 +1,95 @@ +// run-pass + +#![allow(non_camel_case_types)] +// A test of the macro system. Can we do HTML literals? + +/* + +This is an HTML parser written as a macro. It's all CPS, and we have +to carry around a bunch of state. The arguments to macros all look like this: + +{ tag_stack* # expr* # tokens } + +The stack keeps track of where we are in the tree. The expr is a list +of children of the current node. The tokens are everything that's +left. + +*/ +use HTMLFragment::{tag, text}; + +macro_rules! html { + ( $($body:tt)* ) => ( + parse_node!( []; []; $($body)* ) + ) +} + +macro_rules! parse_node { + ( + [:$head:ident ($(:$head_nodes:expr),*) + $(:$tags:ident ($(:$tag_nodes:expr),*))*]; + [$(:$nodes:expr),*]; + </$tag:ident> $($rest:tt)* + ) => ( + parse_node!( + [$(: $tags ($(:$tag_nodes),*))*]; + [$(:$head_nodes,)* :tag(stringify!($head).to_string(), + vec![$($nodes),*])]; + $($rest)* + ) + ); + + ( + [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; + [$(:$nodes:expr),*]; + <$tag:ident> $($rest:tt)* + ) => ( + parse_node!( + [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*]; + []; + $($rest)* + ) + ); + + ( + [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; + [$(:$nodes:expr),*]; + . $($rest:tt)* + ) => ( + parse_node!( + [$(: $tags ($(:$tag_nodes),*))*]; + [$(:$nodes,)* :text(".".to_string())]; + $($rest)* + ) + ); + + ( + [$(:$tags:ident ($(:$tag_nodes:expr),*) )*]; + [$(:$nodes:expr),*]; + $word:ident $($rest:tt)* + ) => ( + parse_node!( + [$(: $tags ($(:$tag_nodes),*))*]; + [$(:$nodes,)* :text(stringify!($word).to_string())]; + $($rest)* + ) + ); + + ( []; [:$e:expr]; ) => ( $e ); +} + +pub fn main() { + let _page = html! ( + <html> + <head><title>This is the title.</title></head> + <body> + <p>This is some text</p> + </body> + </html> + ); +} + +#[allow(unused_tuple_struct_fields)] +enum HTMLFragment { + tag(String, Vec<HTMLFragment> ), + text(String), +} diff --git a/tests/ui/macros/include-single-expr-helper-1.rs b/tests/ui/macros/include-single-expr-helper-1.rs new file mode 100644 index 000000000..aa6380bd2 --- /dev/null +++ b/tests/ui/macros/include-single-expr-helper-1.rs @@ -0,0 +1,5 @@ +// ignore-test auxiliary file for include-single-expr.rs + +0 + +// trailing comment permitted diff --git a/tests/ui/macros/include-single-expr-helper.rs b/tests/ui/macros/include-single-expr-helper.rs new file mode 100644 index 000000000..84d8b6960 --- /dev/null +++ b/tests/ui/macros/include-single-expr-helper.rs @@ -0,0 +1,5 @@ +// ignore-test auxiliary file for include-single-expr.rs + +0 +10 +100 diff --git a/tests/ui/macros/include-single-expr.rs b/tests/ui/macros/include-single-expr.rs new file mode 100644 index 000000000..0f4c29ec0 --- /dev/null +++ b/tests/ui/macros/include-single-expr.rs @@ -0,0 +1,6 @@ +// error-pattern include macro expected single expression + +fn main() { + include!("include-single-expr-helper.rs"); + include!("include-single-expr-helper-1.rs"); +} diff --git a/tests/ui/macros/include-single-expr.stderr b/tests/ui/macros/include-single-expr.stderr new file mode 100644 index 000000000..80eecf8f1 --- /dev/null +++ b/tests/ui/macros/include-single-expr.stderr @@ -0,0 +1,10 @@ +error: include macro expected single expression in source + --> $DIR/include-single-expr-helper.rs:4:1 + | +LL | 10 + | ^^ + | + = note: `#[deny(incomplete_include)]` on by default + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-100199.rs b/tests/ui/macros/issue-100199.rs new file mode 100644 index 000000000..6e50afa07 --- /dev/null +++ b/tests/ui/macros/issue-100199.rs @@ -0,0 +1,16 @@ +#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root +struct Foo {} +// The above must be on the first line so that it's span points to pos 0. +// This used to trigger an ICE because the diagnostic emitter would get +// an unexpected dummy span (lo == 0 == hi) while attempting to print a +// suggestion. + +// aux-build: issue-100199.rs + +extern crate issue_100199; + +mod traits { + pub trait MyTrait {} +} + +fn main() {} diff --git a/tests/ui/macros/issue-100199.stderr b/tests/ui/macros/issue-100199.stderr new file mode 100644 index 000000000..2cb45dc12 --- /dev/null +++ b/tests/ui/macros/issue-100199.stderr @@ -0,0 +1,15 @@ +error[E0405]: cannot find trait `MyTrait` in the crate root + --> $DIR/issue-100199.rs:1:1 + | +LL | #[issue_100199::struct_with_bound] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root + | + = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider importing this trait + | +LL | use traits::MyTrait; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/macros/issue-102878.rs b/tests/ui/macros/issue-102878.rs new file mode 100644 index 000000000..aac589193 --- /dev/null +++ b/tests/ui/macros/issue-102878.rs @@ -0,0 +1,10 @@ +macro_rules!test{($l:expr,$_:r)=>({const:y y)} +//~^ ERROR mismatched closing delimiter: `)` +//~| ERROR invalid fragment specifier `r` +//~| ERROR expected identifier, found keyword `const` +//~| ERROR expected identifier, found keyword `const` +//~| ERROR expected identifier, found `:` + +fn s(){test!(1,i)} + +fn main() {} diff --git a/tests/ui/macros/issue-102878.stderr b/tests/ui/macros/issue-102878.stderr new file mode 100644 index 000000000..e0b8855a3 --- /dev/null +++ b/tests/ui/macros/issue-102878.stderr @@ -0,0 +1,60 @@ +error: mismatched closing delimiter: `)` + --> $DIR/issue-102878.rs:1:35 + | +LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} + | -^ ^ mismatched closing delimiter + | || + | |unclosed delimiter + | closing delimiter possibly meant for this + +error: invalid fragment specifier `r` + --> $DIR/issue-102878.rs:1:27 + | +LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} + | ^^^^ + | + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + +error: expected identifier, found keyword `const` + --> $DIR/issue-102878.rs:1:36 + | +LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} + | ^^^^^ expected identifier, found keyword +... +LL | fn s(){test!(1,i)} + | ---------- in this macro invocation + | + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) +help: escape `const` to use it as an identifier + | +LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)} + | ++ + +error: expected identifier, found keyword `const` + --> $DIR/issue-102878.rs:1:36 + | +LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} + | ^^^^^ expected identifier, found keyword +... +LL | fn s(){test!(1,i)} + | ---------- in this macro invocation + | + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) +help: escape `const` to use it as an identifier + | +LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)} + | ++ + +error: expected identifier, found `:` + --> $DIR/issue-102878.rs:1:41 + | +LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} + | ^ expected identifier +... +LL | fn s(){test!(1,i)} + | ---------- in this macro invocation + | + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors + diff --git a/tests/ui/macros/issue-103529.rs b/tests/ui/macros/issue-103529.rs new file mode 100644 index 000000000..fa05baed7 --- /dev/null +++ b/tests/ui/macros/issue-103529.rs @@ -0,0 +1,13 @@ +macro_rules! m { + ($s:stmt) => {} +} + +m! { mut x } +//~^ ERROR expected expression, found keyword `mut` +//~| ERROR expected a statement +m! { auto x } +//~^ ERROR invalid variable declaration +m! { var x } +//~^ ERROR invalid variable declaration + +fn main() {} diff --git a/tests/ui/macros/issue-103529.stderr b/tests/ui/macros/issue-103529.stderr new file mode 100644 index 000000000..61e322afc --- /dev/null +++ b/tests/ui/macros/issue-103529.stderr @@ -0,0 +1,39 @@ +error: expected expression, found keyword `mut` + --> $DIR/issue-103529.rs:5:6 + | +LL | m! { mut x } + | ^^^ expected expression + +error: expected a statement + --> $DIR/issue-103529.rs:5:10 + | +LL | ($s:stmt) => {} + | ------- while parsing argument for this `stmt` macro fragment +... +LL | m! { mut x } + | ^ + +error: invalid variable declaration + --> $DIR/issue-103529.rs:8:6 + | +LL | m! { auto x } + | ^^^^ + | +help: write `let` instead of `auto` to introduce a new variable + | +LL | m! { let x } + | ~~~ + +error: invalid variable declaration + --> $DIR/issue-103529.rs:10:6 + | +LL | m! { var x } + | ^^^ + | +help: write `let` instead of `var` to introduce a new variable + | +LL | m! { let x } + | ~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs new file mode 100644 index 000000000..24150376e --- /dev/null +++ b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs @@ -0,0 +1,8 @@ +#![feature(concat_bytes)] + +fn main() { + concat_bytes!(7Y); + //~^ ERROR invalid suffix `Y` for number literal + concat_bytes!(888888888888888888888888888888888888888); + //~^ ERROR integer literal is too large +} diff --git a/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr new file mode 100644 index 000000000..8807279c2 --- /dev/null +++ b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr @@ -0,0 +1,18 @@ +error: invalid suffix `Y` for number literal + --> $DIR/issue-104769-concat_bytes-invalid-literal.rs:4:19 + | +LL | concat_bytes!(7Y); + | ^^ invalid suffix `Y` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error: integer literal is too large + --> $DIR/issue-104769-concat_bytes-invalid-literal.rs:6:19 + | +LL | concat_bytes!(888888888888888888888888888888888888888); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: value exceeds limit of `340282366920938463463374607431768211455` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-105011.rs b/tests/ui/macros/issue-105011.rs new file mode 100644 index 000000000..da12c3814 --- /dev/null +++ b/tests/ui/macros/issue-105011.rs @@ -0,0 +1,3 @@ +fn main() { + println!(""y); //~ ERROR suffixes on string literals are invalid +} diff --git a/tests/ui/macros/issue-105011.stderr b/tests/ui/macros/issue-105011.stderr new file mode 100644 index 000000000..e898af7fa --- /dev/null +++ b/tests/ui/macros/issue-105011.stderr @@ -0,0 +1,8 @@ +error: suffixes on string literals are invalid + --> $DIR/issue-105011.rs:2:14 + | +LL | println!(""y); + | ^^^ invalid suffix `y` + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-10536.rs b/tests/ui/macros/issue-10536.rs new file mode 100644 index 000000000..f536d8f94 --- /dev/null +++ b/tests/ui/macros/issue-10536.rs @@ -0,0 +1,19 @@ +// We only want to assert that this doesn't ICE, we don't particularly care +// about whether it nor it fails to compile. + +macro_rules! foo{ + () => {{ + macro_rules! bar{() => (())} + 1 + }} +} + +pub fn main() { + foo!(); + + assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two` + + // regardless of whether nested macro_rules works, the following should at + // least throw a conventional error. + assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two` +} diff --git a/tests/ui/macros/issue-10536.stderr b/tests/ui/macros/issue-10536.stderr new file mode 100644 index 000000000..cc0484458 --- /dev/null +++ b/tests/ui/macros/issue-10536.stderr @@ -0,0 +1,14 @@ +error: expected one of `(`, `[`, or `{`, found `two` + --> $DIR/issue-10536.rs:14:19 + | +LL | assert!({one! two()}); + | ^^^ expected one of `(`, `[`, or `{` + +error: expected one of `(`, `[`, or `{`, found `two` + --> $DIR/issue-10536.rs:18:19 + | +LL | assert!({one! two}); + | ^^^ expected one of `(`, `[`, or `{` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-16098.rs b/tests/ui/macros/issue-16098.rs new file mode 100644 index 000000000..00acc20fc --- /dev/null +++ b/tests/ui/macros/issue-16098.rs @@ -0,0 +1,16 @@ +macro_rules! prob1 { + (0) => { + 0 + }; + ($n:expr) => { + if ($n % 3 == 0) || ($n % 5 == 0) { + $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!` + } else { + prob1!($n - 1); + } + }; +} + +fn main() { + println!("Problem 1: {}", prob1!(1000)); +} diff --git a/tests/ui/macros/issue-16098.stderr b/tests/ui/macros/issue-16098.stderr new file mode 100644 index 000000000..64280219d --- /dev/null +++ b/tests/ui/macros/issue-16098.stderr @@ -0,0 +1,14 @@ +error: recursion limit reached while expanding `prob1!` + --> $DIR/issue-16098.rs:7:18 + | +LL | $n + prob1!($n - 1); + | ^^^^^^^^^^^^^^ +... +LL | println!("Problem 1: {}", prob1!(1000)); + | ------------ in this macro invocation + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`) + = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-19163.rs b/tests/ui/macros/issue-19163.rs new file mode 100644 index 000000000..d98c5912a --- /dev/null +++ b/tests/ui/macros/issue-19163.rs @@ -0,0 +1,11 @@ +// aux-build:issue-19163.rs + +#[macro_use] extern crate issue_19163; + +use std::io::Write; + +fn main() { + let mut v = vec![]; + mywrite!(&v, "Hello world"); + //~^ ERROR cannot borrow data in a `&` reference as mutable +} diff --git a/tests/ui/macros/issue-19163.stderr b/tests/ui/macros/issue-19163.stderr new file mode 100644 index 000000000..ae1ae1426 --- /dev/null +++ b/tests/ui/macros/issue-19163.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/issue-19163.rs:9:5 + | +LL | mywrite!(&v, "Hello world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/macros/issue-21356.rs b/tests/ui/macros/issue-21356.rs new file mode 100644 index 000000000..ae623929d --- /dev/null +++ b/tests/ui/macros/issue-21356.rs @@ -0,0 +1,6 @@ +#![allow(unused_macros)] + +macro_rules! test { ($wrong:t_ty ..) => () } + //~^ ERROR: invalid fragment specifier `t_ty` + +fn main() {} diff --git a/tests/ui/macros/issue-21356.stderr b/tests/ui/macros/issue-21356.stderr new file mode 100644 index 000000000..17014c6ce --- /dev/null +++ b/tests/ui/macros/issue-21356.stderr @@ -0,0 +1,10 @@ +error: invalid fragment specifier `t_ty` + --> $DIR/issue-21356.rs:3:22 + | +LL | macro_rules! test { ($wrong:t_ty ..) => () } + | ^^^^^^^^^^^ + | + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-22463.rs b/tests/ui/macros/issue-22463.rs new file mode 100644 index 000000000..fdf5a2fca --- /dev/null +++ b/tests/ui/macros/issue-22463.rs @@ -0,0 +1,20 @@ +// run-pass +macro_rules! items { + () => { + type A = (); + fn a() {} + } +} + +trait Foo { + type A; + fn a(); +} + +impl Foo for () { + items!(); +} + +fn main() { + +} diff --git a/tests/ui/macros/issue-25274.rs b/tests/ui/macros/issue-25274.rs new file mode 100644 index 000000000..65b29bba8 --- /dev/null +++ b/tests/ui/macros/issue-25274.rs @@ -0,0 +1,18 @@ +// run-pass + +macro_rules! test { + ( + fn fun() -> Option<Box<$t:ty>>; + ) => { + fn fun(x: $t) -> Option<Box<$t>> + { Some(Box::new(x)) } + } +} + +test! { + fn fun() -> Option<Box<i32>>; +} + +fn main() { + println!("{}", fun(0).unwrap()); +} diff --git a/tests/ui/macros/issue-25385.rs b/tests/ui/macros/issue-25385.rs new file mode 100644 index 000000000..ea042a6c7 --- /dev/null +++ b/tests/ui/macros/issue-25385.rs @@ -0,0 +1,12 @@ +macro_rules! foo { + ($e:expr) => { $e.foo() } + //~^ ERROR no method named `foo` found +} + +fn main() { + let a = 1i32; + foo!(a); + + foo!(1i32.foo()); + //~^ ERROR no method named `foo` found +} diff --git a/tests/ui/macros/issue-25385.stderr b/tests/ui/macros/issue-25385.stderr new file mode 100644 index 000000000..39dbdd753 --- /dev/null +++ b/tests/ui/macros/issue-25385.stderr @@ -0,0 +1,20 @@ +error[E0599]: no method named `foo` found for type `i32` in the current scope + --> $DIR/issue-25385.rs:2:23 + | +LL | ($e:expr) => { $e.foo() } + | ^^^ method not found in `i32` +... +LL | foo!(a); + | ------- in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: no method named `foo` found for type `i32` in the current scope + --> $DIR/issue-25385.rs:10:15 + | +LL | foo!(1i32.foo()); + | ^^^ method not found in `i32` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/macros/issue-26322.rs b/tests/ui/macros/issue-26322.rs new file mode 100644 index 000000000..c1dc80eb7 --- /dev/null +++ b/tests/ui/macros/issue-26322.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +macro_rules! columnline { + () => ( + (column!(), line!()) + ) +} + +macro_rules! indirectcolumnline { + () => ( + (||{ columnline!() })() + ) +} + +fn main() { + let closure = || { + columnline!() + }; + let iflet = if let Some(_) = Some(0) { + columnline!() + } else { (0, 0) }; + let cl = columnline!(); + assert_eq!(closure(), (9, 19)); + assert_eq!(iflet, (9, 22)); + assert_eq!(cl, (14, 24)); + let indirect = indirectcolumnline!(); + assert_eq!(indirect, (20, 28)); +} diff --git a/tests/ui/macros/issue-29084.rs b/tests/ui/macros/issue-29084.rs new file mode 100644 index 000000000..d16252686 --- /dev/null +++ b/tests/ui/macros/issue-29084.rs @@ -0,0 +1,13 @@ +macro_rules! foo { + ($d:expr) => {{ + fn bar(d: u8) { } + bar(&mut $d); + //~^ ERROR mismatched types + //~| expected `u8`, found `&mut u8` + }} +} + +fn main() { + foo!(0u8); + //~^ in this expansion of foo! +} diff --git a/tests/ui/macros/issue-29084.stderr b/tests/ui/macros/issue-29084.stderr new file mode 100644 index 000000000..f83e19213 --- /dev/null +++ b/tests/ui/macros/issue-29084.stderr @@ -0,0 +1,24 @@ +error[E0308]: mismatched types + --> $DIR/issue-29084.rs:4:13 + | +LL | bar(&mut $d); + | --- ^^^^^^^ expected `u8`, found `&mut u8` + | | + | arguments to this function are incorrect +... +LL | foo!(0u8); + | --------- in this macro invocation + | +note: function defined here + --> $DIR/issue-29084.rs:3:12 + | +LL | fn bar(d: u8) { } + | ^^^ ----- +... +LL | foo!(0u8); + | --------- in this macro invocation + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/macros/issue-30143.rs b/tests/ui/macros/issue-30143.rs new file mode 100644 index 000000000..ac4c1da5c --- /dev/null +++ b/tests/ui/macros/issue-30143.rs @@ -0,0 +1,11 @@ +use std::fmt::Write; + +fn main() { + println!(0); + //~^ ERROR format argument must be a string literal + eprintln!('a'); + //~^ ERROR format argument must be a string literal + let mut s = String::new(); + writeln!(s, true).unwrap(); + //~^ ERROR format argument must be a string literal +} diff --git a/tests/ui/macros/issue-30143.stderr b/tests/ui/macros/issue-30143.stderr new file mode 100644 index 000000000..fd2378dbc --- /dev/null +++ b/tests/ui/macros/issue-30143.stderr @@ -0,0 +1,35 @@ +error: format argument must be a string literal + --> $DIR/issue-30143.rs:4:14 + | +LL | println!(0); + | ^ + | +help: you might be missing a string literal to format with + | +LL | println!("{}", 0); + | +++++ + +error: format argument must be a string literal + --> $DIR/issue-30143.rs:6:15 + | +LL | eprintln!('a'); + | ^^^ + | +help: you might be missing a string literal to format with + | +LL | eprintln!("{}", 'a'); + | +++++ + +error: format argument must be a string literal + --> $DIR/issue-30143.rs:9:17 + | +LL | writeln!(s, true).unwrap(); + | ^^^^ + | +help: you might be missing a string literal to format with + | +LL | writeln!(s, "{}", true).unwrap(); + | +++++ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-33185.rs b/tests/ui/macros/issue-33185.rs new file mode 100644 index 000000000..0d6669146 --- /dev/null +++ b/tests/ui/macros/issue-33185.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(dead_code)] + +#[macro_export] +macro_rules! state { + ( $( $name:ident : $field:ty )* ) => ( + #[derive(Default)] + struct State { + $($name : $field),* + } + ) +} + +state! { x: i64 } + +pub fn main() { +} diff --git a/tests/ui/macros/issue-34171.rs b/tests/ui/macros/issue-34171.rs new file mode 100644 index 000000000..157c58c45 --- /dev/null +++ b/tests/ui/macros/issue-34171.rs @@ -0,0 +1,10 @@ +// check-pass + +macro_rules! null { ($i:tt) => {} } +macro_rules! apply_null { + ($i:item) => { null! { $i } } +} + +fn main() { + apply_null!(#[cfg(all())] fn f() {}); +} diff --git a/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs new file mode 100644 index 000000000..d78139365 --- /dev/null +++ b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs @@ -0,0 +1,15 @@ +macro_rules! make_item { + ($a:ident) => { + struct $a; + }; //~^ ERROR expected expression + //~| ERROR expected expression +} + +fn a() { + make_item!(A) +} +fn b() { + make_item!(B) +} + +fn main() {} diff --git a/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr new file mode 100644 index 000000000..00139662d --- /dev/null +++ b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr @@ -0,0 +1,34 @@ +error: expected expression, found keyword `struct` + --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9 + | +LL | struct $a; + | ^^^^^^ expected expression +... +LL | make_item!(A) + | ------------- in this macro invocation + | + = note: the macro call doesn't expand to an expression, but it can expand to a statement + = note: this error originates in the macro `make_item` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add `;` to interpret the expansion as a statement + | +LL | make_item!(A); + | + + +error: expected expression, found keyword `struct` + --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9 + | +LL | struct $a; + | ^^^^^^ expected expression +... +LL | make_item!(B) + | ------------- in this macro invocation + | + = note: the macro call doesn't expand to an expression, but it can expand to a statement + = note: this error originates in the macro `make_item` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add `;` to interpret the expansion as a statement + | +LL | make_item!(B); + | + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-35450.rs b/tests/ui/macros/issue-35450.rs new file mode 100644 index 000000000..ac4c16306 --- /dev/null +++ b/tests/ui/macros/issue-35450.rs @@ -0,0 +1,5 @@ +macro_rules! m { ($($t:tt)*) => { $($t)* } } + +fn main() { + m!($t); //~ ERROR expected expression +} diff --git a/tests/ui/macros/issue-35450.stderr b/tests/ui/macros/issue-35450.stderr new file mode 100644 index 000000000..f2065689f --- /dev/null +++ b/tests/ui/macros/issue-35450.stderr @@ -0,0 +1,8 @@ +error: expected expression, found `$` + --> $DIR/issue-35450.rs:4:8 + | +LL | m!($t); + | ^ expected expression + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-37175.rs b/tests/ui/macros/issue-37175.rs new file mode 100644 index 000000000..9ec9d48d1 --- /dev/null +++ b/tests/ui/macros/issue-37175.rs @@ -0,0 +1,5 @@ +// run-pass +macro_rules! m { (<$t:ty>) => { stringify!($t) } } +fn main() { + println!("{}", m!(<Vec<i32>>)); +} diff --git a/tests/ui/macros/issue-38715.rs b/tests/ui/macros/issue-38715.rs new file mode 100644 index 000000000..85ed97663 --- /dev/null +++ b/tests/ui/macros/issue-38715.rs @@ -0,0 +1,17 @@ +#[macro_export] +macro_rules! foo { () => {} } + +#[macro_export] +macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times + +mod inner1 { + #[macro_export] + macro_rules! bar { () => {} } +} + +mod inner2 { + #[macro_export] + macro_rules! bar { () => {} } //~ ERROR the name `bar` is defined multiple times +} + +fn main() {} diff --git a/tests/ui/macros/issue-38715.stderr b/tests/ui/macros/issue-38715.stderr new file mode 100644 index 000000000..828a7f459 --- /dev/null +++ b/tests/ui/macros/issue-38715.stderr @@ -0,0 +1,25 @@ +error[E0428]: the name `foo` is defined multiple times + --> $DIR/issue-38715.rs:5:1 + | +LL | macro_rules! foo { () => {} } + | ---------------- previous definition of the macro `foo` here +... +LL | macro_rules! foo { () => {} } + | ^^^^^^^^^^^^^^^^ `foo` redefined here + | + = note: `foo` must be defined only once in the macro namespace of this module + +error[E0428]: the name `bar` is defined multiple times + --> $DIR/issue-38715.rs:14:5 + | +LL | macro_rules! bar { () => {} } + | ---------------- previous definition of the macro `bar` here +... +LL | macro_rules! bar { () => {} } + | ^^^^^^^^^^^^^^^^ `bar` redefined here + | + = note: `bar` must be defined only once in the macro namespace of this module + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/macros/issue-39388.rs b/tests/ui/macros/issue-39388.rs new file mode 100644 index 000000000..a8e31a648 --- /dev/null +++ b/tests/ui/macros/issue-39388.rs @@ -0,0 +1,9 @@ +#![allow(unused_macros)] + +macro_rules! assign { + (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?` + $($a)* = $($b)* + } +} + +fn main() {} diff --git a/tests/ui/macros/issue-39388.stderr b/tests/ui/macros/issue-39388.stderr new file mode 100644 index 000000000..62e7dff54 --- /dev/null +++ b/tests/ui/macros/issue-39388.stderr @@ -0,0 +1,8 @@ +error: expected one of: `*`, `+`, or `?` + --> $DIR/issue-39388.rs:4:22 + | +LL | (($($a:tt)*) = ($($b:tt))*) => { + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs new file mode 100644 index 000000000..2229f2c39 --- /dev/null +++ b/tests/ui/macros/issue-39404.rs @@ -0,0 +1,7 @@ +#![allow(unused)] + +macro_rules! m { ($i) => {} } +//~^ ERROR missing fragment specifier +//~| WARN previously accepted + +fn main() {} diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr new file mode 100644 index 000000000..3886a70bb --- /dev/null +++ b/tests/ui/macros/issue-39404.stderr @@ -0,0 +1,12 @@ +error: missing fragment specifier + --> $DIR/issue-39404.rs:3:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-40469.rs b/tests/ui/macros/issue-40469.rs new file mode 100644 index 000000000..25e08ef85 --- /dev/null +++ b/tests/ui/macros/issue-40469.rs @@ -0,0 +1,9 @@ +// run-pass +// ignore-pretty issue #37195 + +#![allow(dead_code)] + +include!("auxiliary/issue-40469.rs"); +fn f() { m!(); } + +fn main() {} diff --git a/tests/ui/macros/issue-40770.rs b/tests/ui/macros/issue-40770.rs new file mode 100644 index 000000000..c9713c157 --- /dev/null +++ b/tests/ui/macros/issue-40770.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(unused_macros)] +macro_rules! m { + ($e:expr) => { + macro_rules! n { () => { $e } } + } +} + +fn main() { + m!(foo!()); +} diff --git a/tests/ui/macros/issue-41776.rs b/tests/ui/macros/issue-41776.rs new file mode 100644 index 000000000..24696d86d --- /dev/null +++ b/tests/ui/macros/issue-41776.rs @@ -0,0 +1,3 @@ +fn main() { + include!(line!()); //~ ERROR argument must be a string literal +} diff --git a/tests/ui/macros/issue-41776.stderr b/tests/ui/macros/issue-41776.stderr new file mode 100644 index 000000000..e06873b50 --- /dev/null +++ b/tests/ui/macros/issue-41776.stderr @@ -0,0 +1,8 @@ +error: argument must be a string literal + --> $DIR/issue-41776.rs:2:14 + | +LL | include!(line!()); + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-41803.rs b/tests/ui/macros/issue-41803.rs new file mode 100644 index 000000000..bccfdc611 --- /dev/null +++ b/tests/ui/macros/issue-41803.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(unused_macro_rules)] + +/// A compile-time map from identifiers to arbitrary (heterogeneous) expressions +macro_rules! ident_map { + ( $name:ident = { $($key:ident => $e:expr,)* } ) => { + macro_rules! $name { + $( + ( $key ) => { $e }; + )* + // Empty invocation expands to nothing. Needed when the map is empty. + () => {}; + } + }; +} + +ident_map!(my_map = { + main => 0, +}); + +fn main() { + my_map!(main); +} diff --git a/tests/ui/macros/issue-42954.fixed b/tests/ui/macros/issue-42954.fixed new file mode 100644 index 000000000..a73054c92 --- /dev/null +++ b/tests/ui/macros/issue-42954.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +#![allow(unused_must_use, unused_comparisons)] + +macro_rules! is_plainly_printable { + ($i: ident) => { + ($i as u32) < 0 //~ `<` is interpreted as a start of generic arguments + }; +} + +fn main() { + let c = 'a'; + is_plainly_printable!(c); +} diff --git a/tests/ui/macros/issue-42954.rs b/tests/ui/macros/issue-42954.rs new file mode 100644 index 000000000..5f9b0e31d --- /dev/null +++ b/tests/ui/macros/issue-42954.rs @@ -0,0 +1,14 @@ +// run-rustfix + +#![allow(unused_must_use, unused_comparisons)] + +macro_rules! is_plainly_printable { + ($i: ident) => { + $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments + }; +} + +fn main() { + let c = 'a'; + is_plainly_printable!(c); +} diff --git a/tests/ui/macros/issue-42954.stderr b/tests/ui/macros/issue-42954.stderr new file mode 100644 index 000000000..396a91994 --- /dev/null +++ b/tests/ui/macros/issue-42954.stderr @@ -0,0 +1,19 @@ +error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison + --> $DIR/issue-42954.rs:7:19 + | +LL | $i as u32 < 0 + | ^ - interpreted as generic arguments + | | + | not interpreted as comparison +... +LL | is_plainly_printable!(c); + | ------------------------ in this macro invocation + | + = note: this error originates in the macro `is_plainly_printable` (in Nightly builds, run with -Z macro-backtrace for more info) +help: try comparing the cast value + | +LL | ($i as u32) < 0 + | + + + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-44127.rs b/tests/ui/macros/issue-44127.rs new file mode 100644 index 000000000..21b2e6826 --- /dev/null +++ b/tests/ui/macros/issue-44127.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(decl_macro)] + +pub struct Foo { + bar: u32, +} +pub macro pattern($a:pat) { + Foo { bar: $a } +} + +fn main() { + match (Foo { bar: 3 }) { + pattern!(3) => println!("Test OK"), + _ => unreachable!(), + } +} diff --git a/tests/ui/macros/issue-5060.rs b/tests/ui/macros/issue-5060.rs new file mode 100644 index 000000000..c4760bc02 --- /dev/null +++ b/tests/ui/macros/issue-5060.rs @@ -0,0 +1,16 @@ +// run-pass +macro_rules! print_hd_tl { + ($field_hd:ident, $($field_tl:ident),+) => ({ + print!("{}", stringify!($field_hd)); + print!("::["); + $( + print!("{}", stringify!($field_tl)); + print!(", "); + )+ + print!("]\n"); + }) +} + +pub fn main() { + print_hd_tl!(x, y, z, w) +} diff --git a/tests/ui/macros/issue-51848.rs b/tests/ui/macros/issue-51848.rs new file mode 100644 index 000000000..4792bdd64 --- /dev/null +++ b/tests/ui/macros/issue-51848.rs @@ -0,0 +1,20 @@ +// In case of macro expansion, the errors should be matched using the deepest callsite in the +// macro call stack whose span is in the current file + +macro_rules! macro_with_error { + ( ) => { + println!("{"); //~ ERROR invalid + }; +} + +fn foo() { + +} + +fn main() { + macro_with_error!(); + //^ In case of a local macro we want the error to be matched in the macro definition, not here + + println!("}"); //~ ERROR invalid + //^ In case of an external macro we want the error to be matched here +} diff --git a/tests/ui/macros/issue-51848.stderr b/tests/ui/macros/issue-51848.stderr new file mode 100644 index 000000000..c25bedf37 --- /dev/null +++ b/tests/ui/macros/issue-51848.stderr @@ -0,0 +1,24 @@ +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/issue-51848.rs:6:20 + | +LL | println!("{"); + | -^ expected `'}'` in format string + | | + | because of this opening brace +... +LL | macro_with_error!(); + | ------------------- in this macro invocation + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in the macro `macro_with_error` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid format string: unmatched `}` found + --> $DIR/issue-51848.rs:18:15 + | +LL | println!("}"); + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-52169.rs b/tests/ui/macros/issue-52169.rs new file mode 100644 index 000000000..f178cd30c --- /dev/null +++ b/tests/ui/macros/issue-52169.rs @@ -0,0 +1,15 @@ +// run-pass + +#[allow(unused_macro_rules)] +macro_rules! a { + ($i:literal) => { "right" }; + ($i:tt) => { "wrong" }; +} + +macro_rules! b { + ($i:literal) => { a!($i) }; +} + +fn main() { + assert_eq!(b!(0), "right"); +} diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs new file mode 100644 index 000000000..b24d7e1f6 --- /dev/null +++ b/tests/ui/macros/issue-54441.rs @@ -0,0 +1,11 @@ +macro_rules! m { + () => { + let //~ ERROR macro expansion ignores token `let` and any following + }; +} + +extern "C" { + m!(); +} + +fn main() {} diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr new file mode 100644 index 000000000..bbbca211b --- /dev/null +++ b/tests/ui/macros/issue-54441.stderr @@ -0,0 +1,13 @@ +error: macro expansion ignores token `let` and any following + --> $DIR/issue-54441.rs:3:9 + | +LL | let + | ^^^ +... +LL | m!(); + | ---- caused by the macro expansion here + | + = note: the usage of `m!` is likely invalid in foreign item context + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-57597.rs b/tests/ui/macros/issue-57597.rs new file mode 100644 index 000000000..ebeb3fe07 --- /dev/null +++ b/tests/ui/macros/issue-57597.rs @@ -0,0 +1,80 @@ +// Regression test for #57597. +// +// Make sure that nested matchers work correctly rather than causing an infinite loop or crash. + +// edition:2018 + +macro_rules! foo1 { + ($($($i:ident)?)+) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo2 { + ($($($i:ident)?)*) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo3 { + ($($($i:ident)?)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo4 { + ($($($($i:ident)?)?)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo5 { + ($($($($i:ident)*)?)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo6 { + ($($($($i:ident)?)*)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo7 { + ($($($($i:ident)?)?)*) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo8 { + ($($($($i:ident)*)*)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo9 { + ($($($($i:ident)?)*)*) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo10 { + ($($($($i:ident)?)*)+) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo11 { + ($($($($i:ident)+)?)*) => {}; + //~^ ERROR repetition matches empty token tree +} + +macro_rules! foo12 { + ($($($($i:ident)+)*)?) => {}; + //~^ ERROR repetition matches empty token tree +} + +fn main() { + foo1!(); + foo2!(); + foo3!(); + foo4!(); + foo5!(); + foo6!(); + foo7!(); + foo8!(); + foo9!(); + foo10!(); + foo11!(); + foo12!(); +} diff --git a/tests/ui/macros/issue-57597.stderr b/tests/ui/macros/issue-57597.stderr new file mode 100644 index 000000000..0a02ac8c4 --- /dev/null +++ b/tests/ui/macros/issue-57597.stderr @@ -0,0 +1,74 @@ +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:8:7 + | +LL | ($($($i:ident)?)+) => {}; + | ^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:13:7 + | +LL | ($($($i:ident)?)*) => {}; + | ^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:18:7 + | +LL | ($($($i:ident)?)?) => {}; + | ^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:23:7 + | +LL | ($($($($i:ident)?)?)?) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:28:7 + | +LL | ($($($($i:ident)*)?)?) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:33:7 + | +LL | ($($($($i:ident)?)*)?) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:38:7 + | +LL | ($($($($i:ident)?)?)*) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:43:7 + | +LL | ($($($($i:ident)*)*)?) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:48:7 + | +LL | ($($($($i:ident)?)*)*) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:53:7 + | +LL | ($($($($i:ident)?)*)+) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:58:7 + | +LL | ($($($($i:ident)+)?)*) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: repetition matches empty token tree + --> $DIR/issue-57597.rs:63:7 + | +LL | ($($($($i:ident)+)*)?) => {}; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/macros/issue-58490.rs b/tests/ui/macros/issue-58490.rs new file mode 100644 index 000000000..97e71c9a1 --- /dev/null +++ b/tests/ui/macros/issue-58490.rs @@ -0,0 +1,26 @@ +// Regression test for #58490 + +macro_rules! a { + ( @1 $i:item ) => { + a! { @2 $i } + }; + ( @2 $i:item ) => { + $i + }; +} +mod b { + a! { + @1 + #[macro_export] + macro_rules! b { () => () } + } + #[macro_export] + macro_rules! b { () => () } + //~^ ERROR: the name `b` is defined multiple times +} +mod c { + #[allow(unused_imports)] + use crate::b; +} + +fn main() {} diff --git a/tests/ui/macros/issue-58490.stderr b/tests/ui/macros/issue-58490.stderr new file mode 100644 index 000000000..b1f0896f3 --- /dev/null +++ b/tests/ui/macros/issue-58490.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `b` is defined multiple times + --> $DIR/issue-58490.rs:18:5 + | +LL | macro_rules! b { () => () } + | -------------- previous definition of the macro `b` here +... +LL | macro_rules! b { () => () } + | ^^^^^^^^^^^^^^ `b` redefined here + | + = note: `b` must be defined only once in the macro namespace of this module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/macros/issue-61033-1.rs b/tests/ui/macros/issue-61033-1.rs new file mode 100644 index 000000000..18df3f6ee --- /dev/null +++ b/tests/ui/macros/issue-61033-1.rs @@ -0,0 +1,10 @@ +// Regression test for issue #61033. + +macro_rules! test1 { + ($x:ident, $($tt:tt)*) => { $($tt)+ } //~ ERROR this must repeat at least once +} + +fn main() { + test1!(x,); + let _recovery_witness: () = 0; //~ ERROR mismatched types +} diff --git a/tests/ui/macros/issue-61033-1.stderr b/tests/ui/macros/issue-61033-1.stderr new file mode 100644 index 000000000..18205c343 --- /dev/null +++ b/tests/ui/macros/issue-61033-1.stderr @@ -0,0 +1,17 @@ +error: this must repeat at least once + --> $DIR/issue-61033-1.rs:4:34 + | +LL | ($x:ident, $($tt:tt)*) => { $($tt)+ } + | ^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-61033-1.rs:9:33 + | +LL | let _recovery_witness: () = 0; + | -- ^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/macros/issue-61033-2.rs b/tests/ui/macros/issue-61033-2.rs new file mode 100644 index 000000000..1760ba158 --- /dev/null +++ b/tests/ui/macros/issue-61033-2.rs @@ -0,0 +1,25 @@ +// Regression test for issue #61033. + +macro_rules! test2 { + ( + $(* $id1:ident)* + $(+ $id2:ident)* + ) => { + $( + //~^ ERROR meta-variable `id1` repeats 2 times + //~| ERROR meta-variable `id1` repeats 2 times + $id1 + $id2 // $id1 and $id2 may repeat different numbers of times + )* + } +} + +fn main() { + test2! { + * a * b + + a + b + c + } + test2! { + * a * b + + a + b + c + d + } +} diff --git a/tests/ui/macros/issue-61033-2.stderr b/tests/ui/macros/issue-61033-2.stderr new file mode 100644 index 000000000..cdfe7934a --- /dev/null +++ b/tests/ui/macros/issue-61033-2.stderr @@ -0,0 +1,24 @@ +error: meta-variable `id1` repeats 2 times, but `id2` repeats 3 times + --> $DIR/issue-61033-2.rs:8:10 + | +LL | $( + | __________^ +LL | | +LL | | +LL | | $id1 + $id2 // $id1 and $id2 may repeat different numbers of times +LL | | )* + | |_________^ + +error: meta-variable `id1` repeats 2 times, but `id2` repeats 4 times + --> $DIR/issue-61033-2.rs:8:10 + | +LL | $( + | __________^ +LL | | +LL | | +LL | | $id1 + $id2 // $id1 and $id2 may repeat different numbers of times +LL | | )* + | |_________^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-61053-different-kleene.rs b/tests/ui/macros/issue-61053-different-kleene.rs new file mode 100644 index 000000000..9b7babdbb --- /dev/null +++ b/tests/ui/macros/issue-61053-different-kleene.rs @@ -0,0 +1,30 @@ +#![deny(meta_variable_misuse)] + +macro_rules! foo { + () => {}; + ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* }; + //~^ ERROR meta-variable repeats with + ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; //~ERROR meta-variable repeats with +} + +macro_rules! bar { + () => {}; + (test) => { + macro_rules! nested { + () => {}; + ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* }; + //~^ ERROR meta-variable repeats with + ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; //~ERROR meta-variable repeats with + } + }; + ( $( $i:ident = $($j:ident),+ );* ) => { + $(macro_rules! $i { + () => { 0 $( + $j )* }; //~ ERROR meta-variable repeats with + })* + }; +} + +fn main() { + foo!(); + bar!(); +} diff --git a/tests/ui/macros/issue-61053-different-kleene.stderr b/tests/ui/macros/issue-61053-different-kleene.stderr new file mode 100644 index 000000000..aa8bac13b --- /dev/null +++ b/tests/ui/macros/issue-61053-different-kleene.stderr @@ -0,0 +1,45 @@ +error: meta-variable repeats with different Kleene operator + --> $DIR/issue-61053-different-kleene.rs:5:57 + | +LL | ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* }; + | - expected repetition ^^ - conflicting repetition + | +note: the lint level is defined here + --> $DIR/issue-61053-different-kleene.rs:1:9 + | +LL | #![deny(meta_variable_misuse)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: meta-variable repeats with different Kleene operator + --> $DIR/issue-61053-different-kleene.rs:7:41 + | +LL | ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; + | - ^^ - conflicting repetition + | | + | expected repetition + +error: meta-variable repeats with different Kleene operator + --> $DIR/issue-61053-different-kleene.rs:15:65 + | +LL | ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* }; + | - expected repetition ^^ - conflicting repetition + +error: meta-variable repeats with different Kleene operator + --> $DIR/issue-61053-different-kleene.rs:17:49 + | +LL | ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; + | - ^^ - conflicting repetition + | | + | expected repetition + +error: meta-variable repeats with different Kleene operator + --> $DIR/issue-61053-different-kleene.rs:22:28 + | +LL | ( $( $i:ident = $($j:ident),+ );* ) => { + | - expected repetition +LL | $(macro_rules! $i { +LL | () => { 0 $( + $j )* }; + | ^^ - conflicting repetition + +error: aborting due to 5 previous errors + diff --git a/tests/ui/macros/issue-61053-duplicate-binder.rs b/tests/ui/macros/issue-61053-duplicate-binder.rs new file mode 100644 index 000000000..34aa571c1 --- /dev/null +++ b/tests/ui/macros/issue-61053-duplicate-binder.rs @@ -0,0 +1,14 @@ +#![deny(meta_variable_misuse)] + +macro_rules! foo { + () => {}; + (error) => { + macro_rules! bar { + ($x:tt $x:tt) => { $x }; //~ ERROR duplicate matcher binding + } + }; +} + +fn main() { + foo!(); +} diff --git a/tests/ui/macros/issue-61053-duplicate-binder.stderr b/tests/ui/macros/issue-61053-duplicate-binder.stderr new file mode 100644 index 000000000..5a2af45d0 --- /dev/null +++ b/tests/ui/macros/issue-61053-duplicate-binder.stderr @@ -0,0 +1,16 @@ +error: duplicate matcher binding + --> $DIR/issue-61053-duplicate-binder.rs:7:20 + | +LL | ($x:tt $x:tt) => { $x }; + | -- ^^ + | | + | previous declaration + | +note: the lint level is defined here + --> $DIR/issue-61053-duplicate-binder.rs:1:9 + | +LL | #![deny(meta_variable_misuse)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-61053-missing-repetition.rs b/tests/ui/macros/issue-61053-missing-repetition.rs new file mode 100644 index 000000000..6b36c730b --- /dev/null +++ b/tests/ui/macros/issue-61053-missing-repetition.rs @@ -0,0 +1,28 @@ +#![deny(meta_variable_misuse)] + +macro_rules! foo { + () => {}; + ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; + //~^ ERROR variable 'j' is still repeating +} + +macro_rules! bar { + () => {}; + (test) => { + macro_rules! nested { + () => {}; + ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; + //~^ ERROR variable 'j' is still repeating + } + }; + ( $( $i:ident = $($j:ident),+ );* ) => { + $(macro_rules! $i { + () => { $j }; //~ ERROR variable 'j' is still repeating + })* + }; +} + +fn main() { + foo!(); + bar!(); +} diff --git a/tests/ui/macros/issue-61053-missing-repetition.stderr b/tests/ui/macros/issue-61053-missing-repetition.stderr new file mode 100644 index 000000000..738f711f0 --- /dev/null +++ b/tests/ui/macros/issue-61053-missing-repetition.stderr @@ -0,0 +1,33 @@ +error: variable 'j' is still repeating at this depth + --> $DIR/issue-61053-missing-repetition.rs:5:52 + | +LL | ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; + | - ^^ + | | + | expected repetition + | +note: the lint level is defined here + --> $DIR/issue-61053-missing-repetition.rs:1:9 + | +LL | #![deny(meta_variable_misuse)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: variable 'j' is still repeating at this depth + --> $DIR/issue-61053-missing-repetition.rs:14:60 + | +LL | ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; + | - ^^ + | | + | expected repetition + +error: variable 'j' is still repeating at this depth + --> $DIR/issue-61053-missing-repetition.rs:20:21 + | +LL | ( $( $i:ident = $($j:ident),+ );* ) => { + | - expected repetition +LL | $(macro_rules! $i { +LL | () => { $j }; + | ^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-61053-unbound.rs b/tests/ui/macros/issue-61053-unbound.rs new file mode 100644 index 000000000..b75cdce0c --- /dev/null +++ b/tests/ui/macros/issue-61053-unbound.rs @@ -0,0 +1,28 @@ +#![deny(meta_variable_misuse)] + +macro_rules! foo { + () => {}; + ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + //~^ ERROR unknown macro variable +} + +macro_rules! bar { + () => {}; + (test) => { + macro_rules! nested { + () => {}; + ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + //~^ ERROR unknown macro variable + } + }; + ( $( $i:ident = $($j:ident),+ );* ) => { + $(macro_rules! $i { + () => { $( $i = $k)+ }; //~ ERROR unknown macro variable + })* + }; +} + +fn main() { + foo!(); + bar!(); +} diff --git a/tests/ui/macros/issue-61053-unbound.stderr b/tests/ui/macros/issue-61053-unbound.stderr new file mode 100644 index 000000000..0d64effc9 --- /dev/null +++ b/tests/ui/macros/issue-61053-unbound.stderr @@ -0,0 +1,26 @@ +error: unknown macro variable `k` + --> $DIR/issue-61053-unbound.rs:5:55 + | +LL | ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + | ^^ + | +note: the lint level is defined here + --> $DIR/issue-61053-unbound.rs:1:9 + | +LL | #![deny(meta_variable_misuse)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unknown macro variable `k` + --> $DIR/issue-61053-unbound.rs:14:63 + | +LL | ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + | ^^ + +error: unknown macro variable `k` + --> $DIR/issue-61053-unbound.rs:20:29 + | +LL | () => { $( $i = $k)+ }; + | ^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-63102.rs b/tests/ui/macros/issue-63102.rs new file mode 100644 index 000000000..6af5b1868 --- /dev/null +++ b/tests/ui/macros/issue-63102.rs @@ -0,0 +1,8 @@ +// check-pass + +#![feature(decl_macro)] +macro foo { + () => {}, +} + +fn main() {} diff --git a/tests/ui/macros/issue-6596-1.rs b/tests/ui/macros/issue-6596-1.rs new file mode 100644 index 000000000..25f1d6500 --- /dev/null +++ b/tests/ui/macros/issue-6596-1.rs @@ -0,0 +1,10 @@ +macro_rules! e { + ($inp:ident) => ( + $nonexistent + //~^ ERROR expected expression, found `$` + ); +} + +fn main() { + e!(foo); +} diff --git a/tests/ui/macros/issue-6596-1.stderr b/tests/ui/macros/issue-6596-1.stderr new file mode 100644 index 000000000..7ab3685c5 --- /dev/null +++ b/tests/ui/macros/issue-6596-1.stderr @@ -0,0 +1,13 @@ +error: expected expression, found `$` + --> $DIR/issue-6596-1.rs:3:9 + | +LL | $nonexistent + | ^^^^^^^^^^^^ expected expression +... +LL | e!(foo); + | ------- in this macro invocation + | + = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-68058.rs b/tests/ui/macros/issue-68058.rs new file mode 100644 index 000000000..24da2620c --- /dev/null +++ b/tests/ui/macros/issue-68058.rs @@ -0,0 +1,14 @@ +// check-pass + +macro_rules! foo { + ($doc: expr) => { + fn f() { + #[doc = $doc] + () + } + }; +} + +foo!("doc"); + +fn main() {} diff --git a/tests/ui/macros/issue-68060.rs b/tests/ui/macros/issue-68060.rs new file mode 100644 index 000000000..fb40cd538 --- /dev/null +++ b/tests/ui/macros/issue-68060.rs @@ -0,0 +1,15 @@ +fn main() { + (0..) + .map( + #[target_feature(enable = "")] + //~^ ERROR: attribute should be applied to a function + //~| ERROR: feature named `` is not valid + //~| NOTE: `` is not valid for this target + #[track_caller] + //~^ ERROR: `#[track_caller]` on closures is currently unstable + //~| NOTE: see issue #87417 + |_| (), + //~^ NOTE: not a function + ) + .next(); +} diff --git a/tests/ui/macros/issue-68060.stderr b/tests/ui/macros/issue-68060.stderr new file mode 100644 index 000000000..52e6ed92e --- /dev/null +++ b/tests/ui/macros/issue-68060.stderr @@ -0,0 +1,27 @@ +error: attribute should be applied to a function definition + --> $DIR/issue-68060.rs:4:13 + | +LL | #[target_feature(enable = "")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | |_| (), + | ------ not a function definition + +error: the feature named `` is not valid for this target + --> $DIR/issue-68060.rs:4:30 + | +LL | #[target_feature(enable = "")] + | ^^^^^^^^^^^ `` is not valid for this target + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/issue-68060.rs:8:13 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/issue-69838-dir/bar.rs b/tests/ui/macros/issue-69838-dir/bar.rs new file mode 100644 index 000000000..ec12f8c5c --- /dev/null +++ b/tests/ui/macros/issue-69838-dir/bar.rs @@ -0,0 +1,3 @@ +// ignore-test -- this is an auxiliary file as part of another test. + +pub fn i_am_in_bar() {} diff --git a/tests/ui/macros/issue-69838-dir/included.rs b/tests/ui/macros/issue-69838-dir/included.rs new file mode 100644 index 000000000..9900b8fd5 --- /dev/null +++ b/tests/ui/macros/issue-69838-dir/included.rs @@ -0,0 +1,3 @@ +// ignore-test -- this is an auxiliary file as part of another test. + +pub mod bar; diff --git a/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs b/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs new file mode 100644 index 000000000..2a4e97f0e --- /dev/null +++ b/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs @@ -0,0 +1,7 @@ +// check-pass + +include!("issue-69838-dir/included.rs"); + +fn main() { + bar::i_am_in_bar(); +} diff --git a/tests/ui/macros/issue-70446.rs b/tests/ui/macros/issue-70446.rs new file mode 100644 index 000000000..407094d55 --- /dev/null +++ b/tests/ui/macros/issue-70446.rs @@ -0,0 +1,13 @@ +// check-pass + +macro_rules! foo { + ($(: $p:path)? $(: $l:lifetime)? ) => { bar! {$(: $p)? $(: $l)? } }; +} + +macro_rules! bar { + ($(: $p:path)? $(: $l:lifetime)? ) => {}; +} + +foo! {: 'a } + +fn main() {} diff --git a/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs b/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs new file mode 100644 index 000000000..e76b09d4b --- /dev/null +++ b/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs @@ -0,0 +1,13 @@ +// aux-build:issue-75982.rs +// check-pass + +// Regression test for issue #75982 +// Tests that don't ICE when invoking a foreign macro +// that occurs inside a module with a weird parent. + +extern crate issue_75982; + +fn main() { + issue_75982::first_macro!(); + issue_75982::second_macro!(); +} diff --git a/tests/ui/macros/issue-77475.rs b/tests/ui/macros/issue-77475.rs new file mode 100644 index 000000000..7b32a33ea --- /dev/null +++ b/tests/ui/macros/issue-77475.rs @@ -0,0 +1,10 @@ +// check-pass +// Regression test of #77475, this used to be ICE. + +#![feature(decl_macro)] + +use crate as _; + +pub macro ice(){} + +fn main() {} diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.rs b/tests/ui/macros/issue-78325-inconsistent-resolution.rs new file mode 100644 index 000000000..919eca4f9 --- /dev/null +++ b/tests/ui/macros/issue-78325-inconsistent-resolution.rs @@ -0,0 +1,12 @@ +macro_rules! define_other_core { + ( ) => { + extern crate std as core; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + }; +} + +fn main() { + core::panic!(); +} + +define_other_core!(); diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr new file mode 100644 index 000000000..53a0a0793 --- /dev/null +++ b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/issue-78325-inconsistent-resolution.rs:3:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core!(); + | -------------------- in this macro invocation + | + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-78333.rs b/tests/ui/macros/issue-78333.rs new file mode 100644 index 000000000..c376f2067 --- /dev/null +++ b/tests/ui/macros/issue-78333.rs @@ -0,0 +1,13 @@ +// build-pass + +#![no_implicit_prelude] + +fn main() { + ::std::panic!(); + ::std::todo!(); + ::std::unimplemented!(); + ::std::assert_eq!(0, 0); + ::std::assert_ne!(0, 1); + ::std::dbg!(123); + ::std::unreachable!(); +} diff --git a/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs b/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs new file mode 100644 index 000000000..9d1fae7a2 --- /dev/null +++ b/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs @@ -0,0 +1,14 @@ +// check-pass + +// regression test for #78892 + +macro_rules! mac { + ($lint_name:ident) => {{ + #[allow($lint_name)] + let _ = (); + }}; +} + +fn main() { + mac!(dead_code) +} diff --git a/tests/ui/macros/issue-81006.rs b/tests/ui/macros/issue-81006.rs new file mode 100644 index 000000000..602eb5974 --- /dev/null +++ b/tests/ui/macros/issue-81006.rs @@ -0,0 +1,10 @@ +// check-fail + +// First format below would cause a panic, second would generate error with incorrect span + +fn main() { + let _ = format!("→{}→\n"); + //~^ ERROR 1 positional argument in format string, but no arguments were given + let _ = format!("→{} \n"); + //~^ ERROR 1 positional argument in format string, but no arguments were given +} diff --git a/tests/ui/macros/issue-81006.stderr b/tests/ui/macros/issue-81006.stderr new file mode 100644 index 000000000..14a8cbe01 --- /dev/null +++ b/tests/ui/macros/issue-81006.stderr @@ -0,0 +1,14 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-81006.rs:6:23 + | +LL | let _ = format!("→{}→\n"); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-81006.rs:8:23 + | +LL | let _ = format!("→{} \n"); + | ^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-83340.rs b/tests/ui/macros/issue-83340.rs new file mode 100644 index 000000000..d26200295 --- /dev/null +++ b/tests/ui/macros/issue-83340.rs @@ -0,0 +1,8 @@ +// check-fail + +fn main() { + println!( + "\ +\n {} │", //~ ERROR: 1 positional argument in format string, but no arguments were given + ); +} diff --git a/tests/ui/macros/issue-83340.stderr b/tests/ui/macros/issue-83340.stderr new file mode 100644 index 000000000..1935de02b --- /dev/null +++ b/tests/ui/macros/issue-83340.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-83340.rs:6:4 + | +LL | \n {} │", + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-83344.rs b/tests/ui/macros/issue-83344.rs new file mode 100644 index 000000000..c5f7f7235 --- /dev/null +++ b/tests/ui/macros/issue-83344.rs @@ -0,0 +1,6 @@ +// check-fail + +fn main() { + println!("{}\ +"); //~^ ERROR: 1 positional argument in format string, but no arguments were given +} diff --git a/tests/ui/macros/issue-83344.stderr b/tests/ui/macros/issue-83344.stderr new file mode 100644 index 000000000..1ef70f87a --- /dev/null +++ b/tests/ui/macros/issue-83344.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-83344.rs:4:15 + | +LL | println!("{}\ + | ^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-84195-lint-anon-const.rs b/tests/ui/macros/issue-84195-lint-anon-const.rs new file mode 100644 index 000000000..71c768320 --- /dev/null +++ b/tests/ui/macros/issue-84195-lint-anon-const.rs @@ -0,0 +1,14 @@ +// Regression test for issue #84195 +// Checks that we properly fire lints that occur inside +// anon consts. + +#![deny(semicolon_in_expressions_from_macros)] + +macro_rules! len { + () => { 0; }; //~ ERROR trailing semicolon + //~| WARN this was previously accepted +} + +fn main() { + let val: [u8; len!()] = []; +} diff --git a/tests/ui/macros/issue-84195-lint-anon-const.stderr b/tests/ui/macros/issue-84195-lint-anon-const.stderr new file mode 100644 index 000000000..29ccd17e0 --- /dev/null +++ b/tests/ui/macros/issue-84195-lint-anon-const.stderr @@ -0,0 +1,39 @@ +error: trailing semicolon in macro used in expression position + --> $DIR/issue-84195-lint-anon-const.rs:8:14 + | +LL | () => { 0; }; + | ^ +... +LL | let val: [u8; len!()] = []; + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> +note: the lint level is defined here + --> $DIR/issue-84195-lint-anon-const.rs:5:9 + | +LL | #![deny(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +Future incompatibility report: Future breakage diagnostic: +error: trailing semicolon in macro used in expression position + --> $DIR/issue-84195-lint-anon-const.rs:8:14 + | +LL | () => { 0; }; + | ^ +... +LL | let val: [u8; len!()] = []; + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> +note: the lint level is defined here + --> $DIR/issue-84195-lint-anon-const.rs:5:9 + | +LL | #![deny(semicolon_in_expressions_from_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/issue-84429-matches-edition.rs b/tests/ui/macros/issue-84429-matches-edition.rs new file mode 100644 index 000000000..53f134c26 --- /dev/null +++ b/tests/ui/macros/issue-84429-matches-edition.rs @@ -0,0 +1,9 @@ +// edition:2021 +// check-pass +// +// Regression test for issue #84429 +// Tests that we can properly invoke `matches!` from a 2021-edition crate. + +fn main() { + let _b = matches!(b'3', b'0' ..= b'9'); +} diff --git a/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs new file mode 100644 index 000000000..7a1e62d49 --- /dev/null +++ b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs @@ -0,0 +1,16 @@ +// Regression test for #84632: Recursion limit is ignored +// for builtin macros that eagerly expands. + +#![recursion_limit = "15"] +macro_rules! a { + () => (""); + (A) => (concat!("", a!())); + (A, $($A:ident),*) => (concat!("", a!($($A),*))) + //~^ ERROR recursion limit reached + //~| HELP consider increasing the recursion limit +} + +fn main() { + a!(A, A, A, A, A); + a!(A, A, A, A, A, A, A, A, A, A, A); +} diff --git a/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr new file mode 100644 index 000000000..e266617bd --- /dev/null +++ b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr @@ -0,0 +1,14 @@ +error: recursion limit reached while expanding `concat!` + --> $DIR/issue-84632-eager-expansion-recursion-limit.rs:8:28 + | +LL | (A, $($A:ident),*) => (concat!("", a!($($A),*))) + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | a!(A, A, A, A, A, A, A, A, A, A, A); + | ----------------------------------- in this macro invocation + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`) + = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-86082-option-env-invalid-char.rs b/tests/ui/macros/issue-86082-option-env-invalid-char.rs new file mode 100644 index 000000000..b556b24d6 --- /dev/null +++ b/tests/ui/macros/issue-86082-option-env-invalid-char.rs @@ -0,0 +1,10 @@ +// check-pass +// +// Regression test for issue #86082 +// +// Checks that option_env! does not panic on receiving an invalid +// environment variable name. + +fn main() { + option_env!("\0="); +} diff --git a/tests/ui/macros/issue-86865.rs b/tests/ui/macros/issue-86865.rs new file mode 100644 index 000000000..01e0a20a5 --- /dev/null +++ b/tests/ui/macros/issue-86865.rs @@ -0,0 +1,11 @@ +use std::fmt::Write; + +fn main() { + println!(b"foo"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` + let mut s = String::new(); + write!(s, b"foo{}", "bar"); + //~^ ERROR format argument must be a string literal + //~| HELP consider removing the leading `b` +} diff --git a/tests/ui/macros/issue-86865.stderr b/tests/ui/macros/issue-86865.stderr new file mode 100644 index 000000000..eed755366 --- /dev/null +++ b/tests/ui/macros/issue-86865.stderr @@ -0,0 +1,18 @@ +error: format argument must be a string literal + --> $DIR/issue-86865.rs:4:14 + | +LL | println!(b"foo"); + | -^^^^^ + | | + | help: consider removing the leading `b` + +error: format argument must be a string literal + --> $DIR/issue-86865.rs:8:15 + | +LL | write!(s, b"foo{}", "bar"); + | -^^^^^^^ + | | + | help: consider removing the leading `b` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/issue-8709.rs b/tests/ui/macros/issue-8709.rs new file mode 100644 index 000000000..ea7525d44 --- /dev/null +++ b/tests/ui/macros/issue-8709.rs @@ -0,0 +1,14 @@ +// run-pass + +macro_rules! sty { + ($t:ty) => (stringify!($t)) +} + +macro_rules! spath { + ($t:path) => (stringify!($t)) +} + +fn main() { + assert_eq!(sty!(isize), "isize"); + assert_eq!(spath!(std::option), "std::option"); +} diff --git a/tests/ui/macros/issue-87877.rs b/tests/ui/macros/issue-87877.rs new file mode 100644 index 000000000..a40e2c5f9 --- /dev/null +++ b/tests/ui/macros/issue-87877.rs @@ -0,0 +1,25 @@ +// check-pass + +macro_rules! two_items { + () => { + extern "C" {} + extern "C" {} + }; +} + +macro_rules! single_expr_funneler { + ($expr:expr) => { + $expr; // note the semicolon, it changes the statement kind during parsing + }; +} + +macro_rules! single_item_funneler { + ($item:item) => { + $item + }; +} + +fn main() { + single_expr_funneler! { two_items! {} } + single_item_funneler! { two_items! {} } +} diff --git a/tests/ui/macros/issue-88206.rs b/tests/ui/macros/issue-88206.rs new file mode 100644 index 000000000..14e2f6606 --- /dev/null +++ b/tests/ui/macros/issue-88206.rs @@ -0,0 +1,66 @@ +// compile-flags: -Z deduplicate-diagnostics=yes + +#![warn(unused_imports)] + +use std::str::*; +//~^ NOTE `from_utf8` is imported here, but it is a function +//~| NOTE `from_utf8_mut` is imported here, but it is a function +//~| NOTE `from_utf8_unchecked` is imported here, but it is a function + +mod hey { + pub trait Serialize {} + pub trait Deserialize {} + + pub struct X(i32); +} + +use hey::{Serialize, Deserialize, X}; +//~^ NOTE `Serialize` is imported here, but it is only a trait, without a derive macro +//~| NOTE `Deserialize` is imported here, but it is a trait +//~| NOTE `X` is imported here, but it is a struct + +#[derive(Serialize)] +//~^ ERROR cannot find derive macro `Serialize` +struct A; + +#[derive(from_utf8_mut)] +//~^ ERROR cannot find derive macro `from_utf8_mut` +struct B; + +#[derive(println)] +//~^ ERROR cannot find derive macro `println` +//~| NOTE `println` is in scope, but it is a function-like macro +struct C; + +#[Deserialize] +//~^ ERROR cannot find attribute `Deserialize` +struct D; + +#[from_utf8_unchecked] +//~^ ERROR cannot find attribute `from_utf8_unchecked` +struct E; + +#[println] +//~^ ERROR cannot find attribute `println` +//~| NOTE `println` is in scope, but it is a function-like macro +struct F; + +fn main() { + from_utf8!(); + //~^ ERROR cannot find macro `from_utf8` + + Box!(); + //~^ ERROR cannot find macro `Box` + //~| NOTE `Box` is in scope, but it is a struct + + Copy!(); + //~^ ERROR cannot find macro `Copy` + //~| NOTE `Copy` is in scope, but it is a derive macro + + test!(); + //~^ ERROR cannot find macro `test` + //~| NOTE `test` is in scope, but it is an attribute + + X!(); + //~^ ERROR cannot find macro `X` +} diff --git a/tests/ui/macros/issue-88206.stderr b/tests/ui/macros/issue-88206.stderr new file mode 100644 index 000000000..f7f5b5648 --- /dev/null +++ b/tests/ui/macros/issue-88206.stderr @@ -0,0 +1,114 @@ +error: cannot find macro `X` in this scope + --> $DIR/issue-88206.rs:64:5 + | +LL | X!(); + | ^ + | +note: `X` is imported here, but it is a struct, not a macro + --> $DIR/issue-88206.rs:17:35 + | +LL | use hey::{Serialize, Deserialize, X}; + | ^ + +error: cannot find macro `test` in this scope + --> $DIR/issue-88206.rs:60:5 + | +LL | test!(); + | ^^^^ + | + = note: `test` is in scope, but it is an attribute: `#[test]` + +error: cannot find macro `Copy` in this scope + --> $DIR/issue-88206.rs:56:5 + | +LL | Copy!(); + | ^^^^ + | + = note: `Copy` is in scope, but it is a derive macro: `#[derive(Copy)]` + +error: cannot find macro `Box` in this scope + --> $DIR/issue-88206.rs:52:5 + | +LL | Box!(); + | ^^^ + | + = note: `Box` is in scope, but it is a struct, not a macro + +error: cannot find macro `from_utf8` in this scope + --> $DIR/issue-88206.rs:49:5 + | +LL | from_utf8!(); + | ^^^^^^^^^ + | +note: `from_utf8` is imported here, but it is a function, not a macro + --> $DIR/issue-88206.rs:5:5 + | +LL | use std::str::*; + | ^^^^^^^^^^^ + +error: cannot find attribute `println` in this scope + --> $DIR/issue-88206.rs:43:3 + | +LL | #[println] + | ^^^^^^^ + | + = note: `println` is in scope, but it is a function-like macro + +error: cannot find attribute `from_utf8_unchecked` in this scope + --> $DIR/issue-88206.rs:39:3 + | +LL | #[from_utf8_unchecked] + | ^^^^^^^^^^^^^^^^^^^ + | +note: `from_utf8_unchecked` is imported here, but it is a function, not an attribute + --> $DIR/issue-88206.rs:5:5 + | +LL | use std::str::*; + | ^^^^^^^^^^^ + +error: cannot find attribute `Deserialize` in this scope + --> $DIR/issue-88206.rs:35:3 + | +LL | #[Deserialize] + | ^^^^^^^^^^^ + | +note: `Deserialize` is imported here, but it is a trait, not an attribute + --> $DIR/issue-88206.rs:17:22 + | +LL | use hey::{Serialize, Deserialize, X}; + | ^^^^^^^^^^^ + +error: cannot find derive macro `println` in this scope + --> $DIR/issue-88206.rs:30:10 + | +LL | #[derive(println)] + | ^^^^^^^ + | + = note: `println` is in scope, but it is a function-like macro + +error: cannot find derive macro `from_utf8_mut` in this scope + --> $DIR/issue-88206.rs:26:10 + | +LL | #[derive(from_utf8_mut)] + | ^^^^^^^^^^^^^ + | +note: `from_utf8_mut` is imported here, but it is a function, not a derive macro + --> $DIR/issue-88206.rs:5:5 + | +LL | use std::str::*; + | ^^^^^^^^^^^ + +error: cannot find derive macro `Serialize` in this scope + --> $DIR/issue-88206.rs:22:10 + | +LL | #[derive(Serialize)] + | ^^^^^^^^^ + | +note: `Serialize` is imported here, but it is only a trait, without a derive macro + --> $DIR/issue-88206.rs:17:11 + | +LL | use hey::{Serialize, Deserialize, X}; + | ^^^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/macros/issue-88228.rs b/tests/ui/macros/issue-88228.rs new file mode 100644 index 000000000..60ba2eab7 --- /dev/null +++ b/tests/ui/macros/issue-88228.rs @@ -0,0 +1,23 @@ +// compile-flags: -Z deduplicate-diagnostics=yes +// edition:2018 + +mod hey { + pub use Copy as Bla; + pub use std::println as bla; +} + +#[derive(Bla)] +//~^ ERROR cannot find derive macro `Bla` +//~| HELP consider importing this derive macro +struct A; + +#[derive(println)] +//~^ ERROR cannot find derive macro `println` +//~|`println` is in scope, but it is a function-like macro +struct B; + +fn main() { + bla!(); + //~^ ERROR cannot find macro `bla` + //~| HELP consider importing this macro +} diff --git a/tests/ui/macros/issue-88228.stderr b/tests/ui/macros/issue-88228.stderr new file mode 100644 index 000000000..fe8a1deae --- /dev/null +++ b/tests/ui/macros/issue-88228.stderr @@ -0,0 +1,28 @@ +error: cannot find macro `bla` in this scope + --> $DIR/issue-88228.rs:20:5 + | +LL | bla!(); + | ^^^ + | + = help: consider importing this macro: + crate::hey::bla + +error: cannot find derive macro `println` in this scope + --> $DIR/issue-88228.rs:14:10 + | +LL | #[derive(println)] + | ^^^^^^^ + | + = note: `println` is in scope, but it is a function-like macro + +error: cannot find derive macro `Bla` in this scope + --> $DIR/issue-88228.rs:9:10 + | +LL | #[derive(Bla)] + | ^^^ + | + = help: consider importing this derive macro: + crate::hey::Bla + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/issue-8851.rs b/tests/ui/macros/issue-8851.rs new file mode 100644 index 000000000..faacfe5f8 --- /dev/null +++ b/tests/ui/macros/issue-8851.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(dead_code)] +// after fixing #9384 and implementing hygiene for match bindings, +// this now fails because the insertion of the 'y' into the match +// doesn't cause capture. Making this macro hygienic (as I've done) +// could very well make this test case completely pointless.... + +// pretty-expanded FIXME #23616 + +enum T { + A(isize), + B(usize) +} + +macro_rules! test { + ($id:ident, $e:expr) => ( + fn foo(t: T) -> isize { + match t { + T::A($id) => $e, + T::B($id) => $e + } + } + ) +} + +test!(y, 10 + (y as isize)); + +pub fn main() { + foo(T::A(20)); +} diff --git a/tests/ui/macros/issue-92267.rs b/tests/ui/macros/issue-92267.rs new file mode 100644 index 000000000..f1daaeb74 --- /dev/null +++ b/tests/ui/macros/issue-92267.rs @@ -0,0 +1,3 @@ +// check-fail + +pub fn main() { println!("🦀%%%", 0) } //~ ERROR argument never used diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr new file mode 100644 index 000000000..5359f68cd --- /dev/null +++ b/tests/ui/macros/issue-92267.stderr @@ -0,0 +1,16 @@ +error: argument never used + --> $DIR/issue-92267.rs:3:34 + | +LL | pub fn main() { println!("🦀%%%", 0) } + | ^ argument never used + | +note: format specifiers use curly braces, and the conversion specifier ` + ` is unknown or unsupported + --> $DIR/issue-92267.rs:3:30 + | +LL | pub fn main() { println!("🦀%%%", 0) } + | ^^ + = note: printf formatting is not supported; see the documentation for `std::fmt` + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-95267.rs b/tests/ui/macros/issue-95267.rs new file mode 100644 index 000000000..a2fe402bc --- /dev/null +++ b/tests/ui/macros/issue-95267.rs @@ -0,0 +1,14 @@ +// check-pass + +// The doc comment here is ignored. This is a bug, but #95267 showed that +// existing programs rely on this behaviour, and changing it would require some +// care and a transition period. +macro_rules! f { + ( + /// ab + ) => {}; +} + +fn main() { + f!(); +} diff --git a/tests/ui/macros/issue-95533.rs b/tests/ui/macros/issue-95533.rs new file mode 100644 index 000000000..905c14dc5 --- /dev/null +++ b/tests/ui/macros/issue-95533.rs @@ -0,0 +1,8 @@ +// check-pass + +#![no_implicit_prelude] +// the macro should not rely on the prelude being imported +::std::thread_local! { static P: () = (); } +::std::thread_local! { static Q: () = const { () }; } + +fn main () {} diff --git a/tests/ui/macros/issue-98466-allow.rs b/tests/ui/macros/issue-98466-allow.rs new file mode 100644 index 000000000..c260148c1 --- /dev/null +++ b/tests/ui/macros/issue-98466-allow.rs @@ -0,0 +1,16 @@ +// check-pass +#![allow(named_arguments_used_positionally)] + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {}", _x = 5); + println!("_x is {}", y = _x); + println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {}", _x = 5); + let _f = format!("_x is {}", y = _x); + let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); +} diff --git a/tests/ui/macros/issue-98466.fixed b/tests/ui/macros/issue-98466.fixed new file mode 100644 index 000000000..e46e22f00 --- /dev/null +++ b/tests/ui/macros/issue-98466.fixed @@ -0,0 +1,51 @@ +// check-pass +// run-rustfix + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {_x}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("_x is {y}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {_x}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("_x is {y}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let s = "0.009"; + // Confirm that named arguments used in formatting are correctly considered. + println!(".{:0<width$}", s, width = _x); + + let region = "abc"; + let width = 8; + let ls = "abcde"; + let full = "abcde"; + // Confirm that named arguments used in formatting are correctly considered. + println!( + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = width, + ui = ls, + v = full, + ); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4); +} diff --git a/tests/ui/macros/issue-98466.rs b/tests/ui/macros/issue-98466.rs new file mode 100644 index 000000000..2c3b099af --- /dev/null +++ b/tests/ui/macros/issue-98466.rs @@ -0,0 +1,51 @@ +// check-pass +// run-rustfix + +fn main() { + let mut _x: usize; + _x = 1; + println!("_x is {}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("_x is {}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let mut _x: usize; + _x = 1; + let _f = format!("_x is {}", _x = 5); + //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("_x is {}", y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + let s = "0.009"; + // Confirm that named arguments used in formatting are correctly considered. + println!(".{:0<width$}", s, width = _x); + + let region = "abc"; + let width = 8; + let ls = "abcde"; + let full = "abcde"; + // Confirm that named arguments used in formatting are correctly considered. + println!( + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = width, + ui = ls, + v = full, + ); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4); + + // Confirm that named arguments used in formatting are correctly considered. + println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4); +} diff --git a/tests/ui/macros/issue-98466.stderr b/tests/ui/macros/issue-98466.stderr new file mode 100644 index 000000000..c93451c76 --- /dev/null +++ b/tests/ui/macros/issue-98466.stderr @@ -0,0 +1,81 @@ +warning: named argument `_x` is not used by name + --> $DIR/issue-98466.rs:7:26 + | +LL | println!("_x is {}", _x = 5); + | -- ^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position + | + = note: `#[warn(named_arguments_used_positionally)]` on by default +help: use the named argument by name to avoid ambiguity + | +LL | println!("_x is {_x}", _x = 5); + | ++ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:10:26 + | +LL | println!("_x is {}", y = _x); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("_x is {y}", y = _x); + | + + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:13:83 + | +LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + | + + +warning: named argument `_x` is not used by name + --> $DIR/issue-98466.rs:19:34 + | +LL | let _f = format!("_x is {}", _x = 5); + | -- ^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("_x is {_x}", _x = 5); + | ++ + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:22:34 + | +LL | let _f = format!("_x is {}", y = _x); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("_x is {y}", y = _x); + | + + +warning: named argument `y` is not used by name + --> $DIR/issue-98466.rs:25:91 + | +LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); + | + + +warning: 6 warnings emitted + diff --git a/tests/ui/macros/issue-99261.rs b/tests/ui/macros/issue-99261.rs new file mode 100644 index 000000000..40d26d08c --- /dev/null +++ b/tests/ui/macros/issue-99261.rs @@ -0,0 +1,17 @@ +// check-pass + +#![deny(named_arguments_used_positionally)] + +fn main() { + let value: f64 = 314.15926; + let digits_before_decimal = 1; + let digits_after_decimal = 2; + let width = digits_before_decimal + 1 + digits_after_decimal; + + println!( + "{value:0>width$.digits_after_decimal$}", + value = value, + width = width, + digits_after_decimal = digits_after_decimal, + ); +} diff --git a/tests/ui/macros/issue-99265.fixed b/tests/ui/macros/issue-99265.fixed new file mode 100644 index 000000000..f3be9c628 --- /dev/null +++ b/tests/ui/macros/issue-99265.fixed @@ -0,0 +1,139 @@ +// check-pass +// run-rustfix + +fn main() { + println!("{b} {a}", a=1, b=2); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {a} {b} {c} {d}", 0, a=1, b=2, c=3, d=4); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:width$}!", "x", width = 5); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!( + "{}, Hello {f:width$.precision$} {g:width2$.precision2$}! {f}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + 1, + f = 0.02f32, + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + width = 5, + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + precision = 2, + //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + g = 0.02f32, + //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] + width2 = 5, + //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally + precision2 = 2 + //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] + ); + + println!("Hello {f:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + + let width = 5; + let precision = 2; + println!("Hello {f:width$.precision$}!", f = 0.02f32); + + let val = 5; + println!("{v:v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$.v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$.v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("{a} {a} {a}", a = 1); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("aaaaaaaaaaaaaaa\ + {a:b$.c$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("aaaaaaaaaaaaaaa\ + {a:b$.c$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("{{{x:width$.precision$}}}", x = 1.0, width = 3, precision = 2); + //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/tests/ui/macros/issue-99265.rs b/tests/ui/macros/issue-99265.rs new file mode 100644 index 000000000..e7cf60876 --- /dev/null +++ b/tests/ui/macros/issue-99265.rs @@ -0,0 +1,139 @@ +// check-pass +// run-rustfix + +fn main() { + println!("{b} {}", a=1, b=2); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:1$}!", "x", width = 5); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!( + "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + 1, + f = 0.02f32, + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + width = 5, + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + precision = 2, + //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + g = 0.02f32, + //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] + width2 = 5, + //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally + precision2 = 2 + //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] + ); + + println!("Hello {:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {0:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + + let width = 5; + let precision = 2; + println!("Hello {f:width$.precision$}!", f = 0.02f32); + + let val = 5; + println!("{:0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{0:0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{:0$.0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{0:0$.0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {a} {0}", a = 1); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("aaaaaaaaaaaaaaa\ + {:1$.2$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("aaaaaaaaaaaaaaa\ + {0:1$.2$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/tests/ui/macros/issue-99265.stderr b/tests/ui/macros/issue-99265.stderr new file mode 100644 index 000000000..9185dbff6 --- /dev/null +++ b/tests/ui/macros/issue-99265.stderr @@ -0,0 +1,562 @@ +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:5:24 + | +LL | println!("{b} {}", a=1, b=2); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | + = note: `#[warn(named_arguments_used_positionally)]` on by default +help: use the named argument by name to avoid ambiguity + | +LL | println!("{b} {a}", a=1, b=2); + | + + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:9:35 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {a} {} {} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:9:40 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `b` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {b} {} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:9:45 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `c` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {} {c} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `d` is not used by name + --> $DIR/issue-99265.rs:9:50 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `d` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {} {} {d}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:19:35 + | +LL | println!("Hello {:1$}!", "x", width = 5); + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:width$}!", "x", width = 5); + | ~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:23:33 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | + + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:23:57 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `precision` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:23:46 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:31:34 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | --------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:31:58 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `precision` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:31:47 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:49:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | --------- this formatting argument uses named argument `f` by position +... +LL | f = 0.02f32, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {f:2$.3$} {4:5$.6$}! {1}", + | ~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:54:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `precision` by position +... +LL | precision = 2, + | ^^^^^^^^^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}", + | ~~~~~~~~~~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:52:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `width` by position +... +LL | width = 5, + | ^^^^^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:width$.3$} {4:5$.6$}! {1}", + | ~~~~~~ + +warning: named argument `g` is not used by name + --> $DIR/issue-99265.rs:56:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | --------- this formatting argument uses named argument `g` by position +... +LL | g = 0.02f32, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {g:5$.6$}! {1}", + | ~ + +warning: named argument `precision2` is not used by name + --> $DIR/issue-99265.rs:60:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `precision2` by position +... +LL | precision2 = 2 + | ^^^^^^^^^^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}", + | ~~~~~~~~~~~ + +warning: named argument `width2` is not used by name + --> $DIR/issue-99265.rs:58:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `width2` by position +... +LL | width2 = 5, + | ^^^^^^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}", + | ~~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:49:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | --- this formatting argument uses named argument `f` by position +... +LL | f = 0.02f32, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {f}", + | ~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:64:31 + | +LL | println!("Hello {:0.1}!", f = 0.02f32); + | ------ ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:0.1}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:68:32 + | +LL | println!("Hello {0:0.1}!", f = 0.02f32); + | ------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:0.1}!", f = 0.02f32); + | ~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:79:23 + | +LL | println!("{:0$}", v = val); + | ----- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$}", v = val); + | + + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:79:23 + | +LL | println!("{:0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:84:24 + | +LL | println!("{0:0$}", v = val); + | ------ ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$}", v = val); + | ~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:84:24 + | +LL | println!("{0:0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$.0$}", v = val); + | + + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:0$.v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:v$.0$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | --------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$.0$}", v = val); + | ~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:0$.v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:v$.0$}", v = val); + | ~~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:104:28 + | +LL | println!("{} {a} {0}", a = 1); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{a} {a} {0}", a = 1); + | + + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:104:28 + | +LL | println!("{} {a} {0}", a = 1); + | --- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {a} {a}", a = 1); + | ~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:115:14 + | +LL | {:1$.2$}", + | -------- this formatting argument uses named argument `a` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {a:1$.2$}", + | + + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:115:30 + | +LL | {:1$.2$}", + | -- this formatting argument uses named argument `c` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {:1$.c$}", + | ~~ + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:115:23 + | +LL | {:1$.2$}", + | -- this formatting argument uses named argument `b` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {:b$.2$}", + | ~~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:126:14 + | +LL | {0:1$.2$}", + | --------- this formatting argument uses named argument `a` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {a:1$.2$}", + | ~ + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:126:30 + | +LL | {0:1$.2$}", + | -- this formatting argument uses named argument `c` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {0:1$.c$}", + | ~~ + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:126:23 + | +LL | {0:1$.2$}", + | -- this formatting argument uses named argument `b` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {0:b$.2$}", + | ~~ + +warning: named argument `x` is not used by name + --> $DIR/issue-99265.rs:132:30 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | -------- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `x` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | + + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:132:50 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | -- ^^^^^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `precision` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:132:39 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | -- ^^^^^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `width` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2); + | ~~~~~~ + +warning: 42 warnings emitted + diff --git a/tests/ui/macros/issue-99907.fixed b/tests/ui/macros/issue-99907.fixed new file mode 100644 index 000000000..9e0e1b80e --- /dev/null +++ b/tests/ui/macros/issue-99907.fixed @@ -0,0 +1,24 @@ +// check-pass +// run-rustfix + +fn main() { + println!("Hello {f:.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:1.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/tests/ui/macros/issue-99907.rs b/tests/ui/macros/issue-99907.rs new file mode 100644 index 000000000..eebcfc2ef --- /dev/null +++ b/tests/ui/macros/issue-99907.rs @@ -0,0 +1,24 @@ +// check-pass +// run-rustfix + +fn main() { + println!("Hello {:.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:1.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello { }!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello { }!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/tests/ui/macros/issue-99907.stderr b/tests/ui/macros/issue-99907.stderr new file mode 100644 index 000000000..eefb28dee --- /dev/null +++ b/tests/ui/macros/issue-99907.stderr @@ -0,0 +1,68 @@ +warning: named argument `f` is not used by name + --> $DIR/issue-99907.rs:5:30 + | +LL | println!("Hello {:.1}!", f = 0.02f32); + | ----- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | + = note: `#[warn(named_arguments_used_positionally)]` on by default +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:.1}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99907.rs:9:31 + | +LL | println!("Hello {:1.1}!", f = 0.02f32); + | ------ ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:1.1}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99907.rs:13:27 + | +LL | println!("Hello {}!", f = 0.02f32); + | -- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99907.rs:17:28 + | +LL | println!("Hello { }!", f = 0.02f32); + | --- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99907.rs:21:29 + | +LL | println!("Hello { }!", f = 0.02f32); + | ---- ^ this named argument is referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f}!", f = 0.02f32); + | + + +warning: 5 warnings emitted + diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs new file mode 100644 index 000000000..f8e847563 --- /dev/null +++ b/tests/ui/macros/lint-trailing-macro-call.rs @@ -0,0 +1,16 @@ +// check-pass +// +// Ensures that we properly lint +// a removed 'expression' resulting from a macro +// in trailing expression position + +macro_rules! expand_it { + () => { + #[cfg(FALSE)] 25; //~ WARN trailing semicolon in macro + //~| WARN this was previously + } +} + +fn main() { + expand_it!() +} diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr new file mode 100644 index 000000000..13cecc3a3 --- /dev/null +++ b/tests/ui/macros/lint-trailing-macro-call.stderr @@ -0,0 +1,35 @@ +warning: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:9:25 + | +LL | #[cfg(FALSE)] 25; + | ^ +... +LL | expand_it!() + | ------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/lint-trailing-macro-call.rs:9:25 + | +LL | #[cfg(FALSE)] 25; + | ^ +... +LL | expand_it!() + | ------------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs new file mode 100644 index 000000000..396748109 --- /dev/null +++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs @@ -0,0 +1,8 @@ +fn main() {} + +macro_rules! ambiguity { + ($($i:ident)* $j:ident) => {}; +} + +ambiguity!(error); //~ ERROR local ambiguity +ambiguity!(error); //~ ERROR local ambiguity diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr new file mode 100644 index 000000000..68b278fd3 --- /dev/null +++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr @@ -0,0 +1,14 @@ +error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12 + | +LL | ambiguity!(error); + | ^^^^^ + +error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12 + | +LL | ambiguity!(error); + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs b/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs new file mode 100644 index 000000000..2d78ae6f9 --- /dev/null +++ b/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs @@ -0,0 +1,22 @@ +// run-pass +// pretty-expanded FIXME #23616 + +#![feature(trace_macros, log_syntax)] + +// make sure these macros can be used as in the various places that +// macros can occur. + +// items +trace_macros!(false); +log_syntax!(); + +fn main() { + + // statements + trace_macros!(false); + log_syntax!(); + + // expressions + (trace_macros!(false), + log_syntax!()); +} diff --git a/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout b/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout new file mode 100644 index 000000000..b28b04f64 --- /dev/null +++ b/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout @@ -0,0 +1,3 @@ + + + diff --git a/tests/ui/macros/macro-2.rs b/tests/ui/macros/macro-2.rs new file mode 100644 index 000000000..a315981b6 --- /dev/null +++ b/tests/ui/macros/macro-2.rs @@ -0,0 +1,12 @@ +// run-pass +pub fn main() { + + macro_rules! mylambda_tt { + ($x:ident, $body:expr) => ({ + fn f($x: isize) -> isize { return $body; } + f + }) + } + + assert_eq!(mylambda_tt!(y, y * 2)(8), 16); +} diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs new file mode 100644 index 000000000..6781c9a9e --- /dev/null +++ b/tests/ui/macros/macro-as-fn-body.rs @@ -0,0 +1,33 @@ +// +// run-pass +// +// Description - ensure Interpolated blocks can act as valid function bodies +// Covered cases: free functions, struct methods, and default trait functions + +macro_rules! def_fn { + ($body:block) => { + fn bar() $body + } +} + +trait Foo { + def_fn!({ println!("foo"); }); +} + +struct Baz {} + +impl Foo for Baz {} + +struct Qux {} + +impl Qux { + def_fn!({ println!("qux"); }); +} + +def_fn!({ println!("quux"); }); + +pub fn main() { + Baz::bar(); + Qux::bar(); + bar(); +} diff --git a/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs b/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs new file mode 100644 index 000000000..66597c0ac --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs @@ -0,0 +1,50 @@ +// run-pass + +#![allow(unused_mut)] + +// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *) +// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +` +// or `+` but does not match `pat` or `pat ? pat`. + +// edition:2015 + +macro_rules! foo { + // Check for `?`. + ($($a:ident)? ? $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `+`. + ($($a:ident)? + $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `*`. + ($($a:ident)? * $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `;`, not a kleene operator. + ($($a:ident)? ; $num:expr) => { + let mut x = 0; + + $( + x += $a; + )? + + assert_eq!(x, $num); + }; +} + +pub fn main() { + let a = 1; + + // Accept 0 repetitions. + foo!( ; 0); + foo!( + 0); + foo!( * 0); + foo!( ? 0); + + // Accept 1 repetition. + foo!(a ; 1); + foo!(a + 1); + foo!(a * 1); + foo!(a ? 1); +} diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs new file mode 100644 index 000000000..f68100d45 --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs @@ -0,0 +1,42 @@ +// Tests that `?` is a Kleene op and not a macro separator in the 2015 edition. + +// edition:2015 + +macro_rules! foo { + ($(a)?) => {}; +} + +// The Kleene op `?` does not admit a separator before it. +macro_rules! baz { + ($(a),?) => {}; //~ERROR the `?` macro repetition operator +} + +macro_rules! barplus { + ($(a)?+) => {}; // ok. matches "a+" and "+" +} + +macro_rules! barstar { + ($(a)?*) => {}; // ok. matches "a*" and "*" +} + +pub fn main() { + foo!(); + foo!(a); + foo!(a?); //~ ERROR no rules expected the token `?` + foo!(a?a); //~ ERROR no rules expected the token `?` + foo!(a?a?a); //~ ERROR no rules expected the token `?` + + barplus!(); //~ERROR unexpected end of macro invocation + barplus!(a); //~ERROR unexpected end of macro invocation + barplus!(a?); //~ ERROR no rules expected the token `?` + barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a+); + barplus!(+); + + barstar!(); //~ERROR unexpected end of macro invocation + barstar!(a); //~ERROR unexpected end of macro invocation + barstar!(a?); //~ ERROR no rules expected the token `?` + barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a*); + barstar!(*); +} diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr new file mode 100644 index 000000000..7c45b85bc --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr @@ -0,0 +1,161 @@ +error: the `?` macro repetition operator does not take a separator + --> $DIR/macro-at-most-once-rep-2015.rs:11:10 + | +LL | ($(a),?) => {}; + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:25:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:26:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:27:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a?a); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:29:5 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(); + | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:30:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a); + | ^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:31:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?); + | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:32:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?a); + | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:36:5 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(); + | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2015.rs:37:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a); + | ^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:38:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?); + | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2015.rs:39:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?a); + | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs b/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs new file mode 100644 index 000000000..b37f38530 --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs @@ -0,0 +1,50 @@ +// run-pass + +#![allow(unused_mut)] + +// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *) +// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +` +// or `+` but does not match `pat` or `pat ? pat`. + +// edition:2018 + +macro_rules! foo { + // Check for `?`. + ($($a:ident)? ? $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `+`. + ($($a:ident)? + $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `*`. + ($($a:ident)? * $num:expr) => { + foo!($($a)? ; $num); + }; + // Check for `;`, not a kleene operator. + ($($a:ident)? ; $num:expr) => { + let mut x = 0; + + $( + x += $a; + )? + + assert_eq!(x, $num); + }; +} + +pub fn main() { + let a = 1; + + // Accept 0 repetitions. + foo!( ; 0); + foo!( + 0); + foo!( * 0); + foo!( ? 0); + + // Accept 1 repetition. + foo!(a ; 1); + foo!(a + 1); + foo!(a * 1); + foo!(a ? 1); +} diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs new file mode 100644 index 000000000..886a25bbc --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs @@ -0,0 +1,42 @@ +// Tests that `?` is a Kleene op and not a macro separator in the 2018 edition. + +// edition:2018 + +macro_rules! foo { + ($(a)?) => {}; +} + +// The Kleene op `?` does not admit a separator before it. +macro_rules! baz { + ($(a),?) => {}; //~ERROR the `?` macro repetition operator +} + +macro_rules! barplus { + ($(a)?+) => {}; // ok. matches "a+" and "+" +} + +macro_rules! barstar { + ($(a)?*) => {}; // ok. matches "a*" and "*" +} + +pub fn main() { + foo!(); + foo!(a); + foo!(a?); //~ ERROR no rules expected the token `?` + foo!(a?a); //~ ERROR no rules expected the token `?` + foo!(a?a?a); //~ ERROR no rules expected the token `?` + + barplus!(); //~ERROR unexpected end of macro invocation + barplus!(a); //~ERROR unexpected end of macro invocation + barplus!(a?); //~ ERROR no rules expected the token `?` + barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a+); + barplus!(+); + + barstar!(); //~ERROR unexpected end of macro invocation + barstar!(a); //~ERROR unexpected end of macro invocation + barstar!(a?); //~ ERROR no rules expected the token `?` + barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a*); + barstar!(*); +} diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr new file mode 100644 index 000000000..696520b28 --- /dev/null +++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr @@ -0,0 +1,161 @@ +error: the `?` macro repetition operator does not take a separator + --> $DIR/macro-at-most-once-rep-2018.rs:11:10 + | +LL | ($(a),?) => {}; + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:25:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:26:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:27:11 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a?a?a); + | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2018.rs:29:5 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(); + | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2018.rs:30:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a); + | ^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:31:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?); + | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:32:15 + | +LL | macro_rules! barplus { + | -------------------- when calling this macro +... +LL | barplus!(a?a); + | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2018.rs:36:5 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(); + | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: unexpected end of macro invocation + --> $DIR/macro-at-most-once-rep-2018.rs:37:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a); + | ^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:38:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?); + | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: no rules expected the token `?` + --> $DIR/macro-at-most-once-rep-2018.rs:39:15 + | +LL | macro_rules! barstar { + | -------------------- when calling this macro +... +LL | barstar!(a?a); + | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/macros/macro-attribute-expansion.rs b/tests/ui/macros/macro-attribute-expansion.rs new file mode 100644 index 000000000..f01e5c44a --- /dev/null +++ b/tests/ui/macros/macro-attribute-expansion.rs @@ -0,0 +1,16 @@ +// run-pass +macro_rules! descriptions { + ($name:ident is $desc:expr) => { + // Check that we will correctly expand attributes + #[doc = $desc] + #[allow(dead_code)] + const $name : &'static str = $desc; + } +} + +// item +descriptions! { DOG is "an animal" } +descriptions! { RUST is "a language" } + +pub fn main() { +} diff --git a/tests/ui/macros/macro-attribute.rs b/tests/ui/macros/macro-attribute.rs new file mode 100644 index 000000000..88834a967 --- /dev/null +++ b/tests/ui/macros/macro-attribute.rs @@ -0,0 +1,2 @@ +#[doc = $not_there] //~ ERROR expected expression, found `$` +fn main() { } diff --git a/tests/ui/macros/macro-attribute.stderr b/tests/ui/macros/macro-attribute.stderr new file mode 100644 index 000000000..3316d3872 --- /dev/null +++ b/tests/ui/macros/macro-attribute.stderr @@ -0,0 +1,8 @@ +error: expected expression, found `$` + --> $DIR/macro-attribute.rs:1:9 + | +LL | #[doc = $not_there] + | ^ expected expression + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs new file mode 100644 index 000000000..d382e8b71 --- /dev/null +++ b/tests/ui/macros/macro-attributes.rs @@ -0,0 +1,23 @@ +// run-pass + +macro_rules! compiles_fine { + (#[$at:meta]) => { + // test that the different types of attributes work + #[attribute] + /// Documentation! + #[$at] + + // check that the attributes are recognised by requiring this + // to be removed to avoid a compile error + #[cfg(always_remove)] + static MISTYPED: () = "foo"; + } +} + +// item +compiles_fine!(#[foo]); + +pub fn main() { + // statement + compiles_fine!(#[bar]); +} diff --git a/tests/ui/macros/macro-backtrace-invalid-internals.rs b/tests/ui/macros/macro-backtrace-invalid-internals.rs new file mode 100644 index 000000000..9501e7cd0 --- /dev/null +++ b/tests/ui/macros/macro-backtrace-invalid-internals.rs @@ -0,0 +1,61 @@ +// Macros in statement vs expression position handle backtraces differently. + +macro_rules! fake_method_stmt { + () => { + 1.fake() //~ ERROR no method + } +} + +macro_rules! fake_field_stmt { + () => { + 1.fake //~ ERROR doesn't have fields + } +} + +macro_rules! fake_anon_field_stmt { + () => { + (1).0 //~ ERROR doesn't have fields + } +} + +macro_rules! fake_method_expr { + () => { + 1.fake() //~ ERROR no method + } +} + +macro_rules! fake_field_expr { + () => { + 1.fake //~ ERROR doesn't have fields + } +} + +macro_rules! fake_anon_field_expr { + () => { + (1).0 //~ ERROR doesn't have fields + } +} + +macro_rules! real_method_stmt { + () => { + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + } +} + +macro_rules! real_method_expr { + () => { + 2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}` + } +} + +fn main() { + fake_method_stmt!(); + fake_field_stmt!(); + fake_anon_field_stmt!(); + real_method_stmt!(); + + let _ = fake_method_expr!(); + let _ = fake_field_expr!(); + let _ = fake_anon_field_expr!(); + let _ = real_method_expr!(); +} diff --git a/tests/ui/macros/macro-backtrace-invalid-internals.stderr b/tests/ui/macros/macro-backtrace-invalid-internals.stderr new file mode 100644 index 000000000..aa8f06a0d --- /dev/null +++ b/tests/ui/macros/macro-backtrace-invalid-internals.stderr @@ -0,0 +1,100 @@ +error[E0599]: no method named `fake` found for type `{integer}` in the current scope + --> $DIR/macro-backtrace-invalid-internals.rs:5:13 + | +LL | 1.fake() + | ^^^^ method not found in `{integer}` +... +LL | fake_method_stmt!(); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `fake_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:11:13 + | +LL | 1.fake + | ^^^^ +... +LL | fake_field_stmt!(); + | ------------------ in this macro invocation + | + = note: this error originates in the macro `fake_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:17:15 + | +LL | (1).0 + | ^ +... +LL | fake_anon_field_stmt!(); + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `fake_anon_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` + --> $DIR/macro-backtrace-invalid-internals.rs:41:15 + | +LL | 2.0.neg() + | ^^^ +... +LL | real_method_stmt!(); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `real_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you must specify a concrete type for this numeric value, like `f32` + | +LL | 2.0_f32.neg() + | ~~~~~~~ + +error[E0599]: no method named `fake` found for type `{integer}` in the current scope + --> $DIR/macro-backtrace-invalid-internals.rs:23:13 + | +LL | 1.fake() + | ^^^^ method not found in `{integer}` +... +LL | let _ = fake_method_expr!(); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `fake_method_expr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:29:13 + | +LL | 1.fake + | ^^^^ +... +LL | let _ = fake_field_expr!(); + | ------------------ in this macro invocation + | + = note: this error originates in the macro `fake_field_expr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:35:15 + | +LL | (1).0 + | ^ +... +LL | let _ = fake_anon_field_expr!(); + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `fake_anon_field_expr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` + --> $DIR/macro-backtrace-invalid-internals.rs:47:15 + | +LL | 2.0.neg() + | ^^^ +... +LL | let _ = real_method_expr!(); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `real_method_expr` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you must specify a concrete type for this numeric value, like `f32` + | +LL | 2.0_f32.neg() + | ~~~~~~~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0599, E0610, E0689. +For more information about an error, try `rustc --explain E0599`. diff --git a/tests/ui/macros/macro-backtrace-nested.rs b/tests/ui/macros/macro-backtrace-nested.rs new file mode 100644 index 000000000..13d80163d --- /dev/null +++ b/tests/ui/macros/macro-backtrace-nested.rs @@ -0,0 +1,20 @@ +// In expression position, but not statement position, when we expand a macro, +// we replace the span of the expanded expression with that of the call site. + +macro_rules! nested_expr { + () => (fake) //~ ERROR cannot find + //~^ ERROR cannot find +} + +macro_rules! call_nested_expr { + () => (nested_expr!()) +} + +macro_rules! call_nested_expr_sum { + () => { 1 + nested_expr!(); } +} + +fn main() { + 1 + call_nested_expr!(); + call_nested_expr_sum!(); +} diff --git a/tests/ui/macros/macro-backtrace-nested.stderr b/tests/ui/macros/macro-backtrace-nested.stderr new file mode 100644 index 000000000..dadedfbe8 --- /dev/null +++ b/tests/ui/macros/macro-backtrace-nested.stderr @@ -0,0 +1,25 @@ +error[E0425]: cannot find value `fake` in this scope + --> $DIR/macro-backtrace-nested.rs:5:12 + | +LL | () => (fake) + | ^^^^ not found in this scope +... +LL | 1 + call_nested_expr!(); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `nested_expr` which comes from the expansion of the macro `call_nested_expr` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `fake` in this scope + --> $DIR/macro-backtrace-nested.rs:5:12 + | +LL | () => (fake) + | ^^^^ not found in this scope +... +LL | call_nested_expr_sum!(); + | ----------------------- in this macro invocation + | + = note: this error originates in the macro `nested_expr` which comes from the expansion of the macro `call_nested_expr_sum` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-backtrace-println.rs b/tests/ui/macros/macro-backtrace-println.rs new file mode 100644 index 000000000..859dd019d --- /dev/null +++ b/tests/ui/macros/macro-backtrace-println.rs @@ -0,0 +1,19 @@ +// The `format_args!` syntax extension issues errors before code expansion +// has completed, but we still need a backtrace. + +// This test includes stripped-down versions of `print!` and `println!`, +// because we can't otherwise verify the lines of the backtrace. + +fn print(_args: std::fmt::Arguments) {} + +macro_rules! myprint { + ($($arg:tt)*) => (print(format_args!($($arg)*))); +} + +macro_rules! myprintln { + ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR no arguments were given +} + +fn main() { + myprintln!("{}"); +} diff --git a/tests/ui/macros/macro-backtrace-println.stderr b/tests/ui/macros/macro-backtrace-println.stderr new file mode 100644 index 000000000..b4e2883e8 --- /dev/null +++ b/tests/ui/macros/macro-backtrace-println.stderr @@ -0,0 +1,13 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-backtrace-println.rs:14:30 + | +LL | ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); + | ^^^^^^^^^^^^^^^^^^^ +... +LL | myprintln!("{}"); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `concat` which comes from the expansion of the macro `myprintln` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-block-nonterminal.rs b/tests/ui/macros/macro-block-nonterminal.rs new file mode 100644 index 000000000..a6c9dd6e1 --- /dev/null +++ b/tests/ui/macros/macro-block-nonterminal.rs @@ -0,0 +1,11 @@ +// run-pass + +macro_rules! do_block{ + ($val:block) => {$val} +} + +fn main() { + let s; + do_block!({ s = "it works!"; }); + assert_eq!(s, "it works!"); +} diff --git a/tests/ui/macros/macro-comma-behavior-rpass.rs b/tests/ui/macros/macro-comma-behavior-rpass.rs new file mode 100644 index 000000000..8406b4e78 --- /dev/null +++ b/tests/ui/macros/macro-comma-behavior-rpass.rs @@ -0,0 +1,98 @@ +// run-pass +// needs-unwind +#![allow(unused_imports)] +// Ideally, any macro call with a trailing comma should behave +// identically to a call without the comma. +// +// This checks the behavior of macros with trailing commas in key +// places where regressions in behavior seem highly possible (due +// to it being e.g., a place where the addition of an argument +// causes it to go down a code path with subtly different behavior). +// +// There is a companion failing test. + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#[cfg(core)] +use core::fmt; +#[cfg(std)] +use std::fmt; + +// an easy mistake in the implementation of 'assert!' +// would cause this to say "explicit panic" +#[test] +#[should_panic(expected = "assertion failed")] +fn assert_1arg() { + assert!(false,); +} + +// same as 'assert_1arg' +#[test] +#[should_panic(expected = "assertion failed")] +fn debug_assert_1arg() { + debug_assert!(false,); +} + +// make sure we don't accidentally forward to `write!("text")` +#[cfg(std)] +#[test] +fn writeln_1arg() { + use fmt::Write; + + let mut s = String::new(); + writeln!(&mut s,).unwrap(); + assert_eq!(&s, "\n"); +} + +// A number of format_args-like macros have special-case treatment +// for a single message string, which is not formatted. +// +// This test ensures that the addition of a trailing comma does not +// suddenly cause these strings to get formatted when they otherwise +// would not be. This is an easy mistake to make by having such a macro +// accept ", $($tok:tt)*" instead of ", $($tok:tt)+" after its minimal +// set of arguments. +// +// (Example: Issue #48042) +#[test] +#[allow(non_fmt_panics)] +fn to_format_or_not_to_format() { + // ("{}" is the easiest string to test because if this gets + // sent to format_args!, it'll simply fail to compile. + // "{{}}" is an example of an input that could compile and + // produce an incorrect program, but testing the panics + // would be burdensome.) + let falsum = || false; + + assert!(true, "{}",); + + // assert_eq!(1, 1, "{}",); // see check-fail + // assert_ne!(1, 2, "{}",); // see check-fail + + debug_assert!(true, "{}",); + + // debug_assert_eq!(1, 1, "{}",); // see check-fail + // debug_assert_ne!(1, 2, "{}",); // see check-fail + // eprint!("{}",); // see check-fail + // eprintln!("{}",); // see check-fail + // format!("{}",); // see check-fail + // format_args!("{}",); // see check-fail + + if falsum() { + panic!("{}",); + } + + // print!("{}",); // see check-fail + // println!("{}",); // see check-fail + // unimplemented!("{}",); // see check-fail + + if falsum() { + unreachable!("{}",); + } + + // write!(&mut stdout, "{}",); // see check-fail + // writeln!(&mut stdout, "{}",); // see check-fail +} diff --git a/tests/ui/macros/macro-comma-behavior.core.stderr b/tests/ui/macros/macro-comma-behavior.core.stderr new file mode 100644 index 000000000..ac15e9fa8 --- /dev/null +++ b/tests/ui/macros/macro-comma-behavior.core.stderr @@ -0,0 +1,50 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:21:23 + | +LL | assert_eq!(1, 1, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:24:23 + | +LL | assert_ne!(1, 2, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:30:29 + | +LL | debug_assert_eq!(1, 1, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:33:29 + | +LL | debug_assert_ne!(1, 2, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:52:19 + | +LL | format_args!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:68:21 + | +LL | unimplemented!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:77:24 + | +LL | write!(f, "{}",)?; + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:81:26 + | +LL | writeln!(f, "{}",)?; + | ^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs new file mode 100644 index 000000000..27d50ff3d --- /dev/null +++ b/tests/ui/macros/macro-comma-behavior.rs @@ -0,0 +1,89 @@ +// Companion test to the similarly-named file in run-pass. + +// compile-flags: -C debug_assertions=yes +// revisions: std core + +#![feature(lang_items)] +#![cfg_attr(core, no_std)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; +#[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} +#[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; +#[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } + +// (see documentation of the similarly-named test in run-pass) +fn to_format_or_not_to_format() { + let falsum = || false; + + // assert!(true, "{}",); // see run-pass + + assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // debug_assert!(true, "{}",); // see run-pass + + debug_assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + debug_assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + #[cfg(std)] { + eprint!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + eprintln!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + format!("{}",); + //[std]~^ ERROR no arguments + } + + format_args!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { panic!("{}",); } // see run-pass + + #[cfg(std)] { + print!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + println!("{}",); + //[std]~^ ERROR no arguments + } + + unimplemented!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { unreachable!("{}",); } // see run-pass + + struct S; + impl fmt::Display for S { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}",)?; + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + writeln!(f, "{}",)?; + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + Ok(()) + } + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-comma-behavior.std.stderr b/tests/ui/macros/macro-comma-behavior.std.stderr new file mode 100644 index 000000000..7fd060e22 --- /dev/null +++ b/tests/ui/macros/macro-comma-behavior.std.stderr @@ -0,0 +1,80 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:21:23 + | +LL | assert_eq!(1, 1, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:24:23 + | +LL | assert_ne!(1, 2, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:30:29 + | +LL | debug_assert_eq!(1, 1, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:33:29 + | +LL | debug_assert_ne!(1, 2, "{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:38:18 + | +LL | eprint!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:43:20 + | +LL | eprintln!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:48:18 + | +LL | format!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:52:19 + | +LL | format_args!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:59:17 + | +LL | print!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:64:19 + | +LL | println!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:68:21 + | +LL | unimplemented!("{}",); + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:77:24 + | +LL | write!(f, "{}",)?; + | ^^ + +error: 1 positional argument in format string, but no arguments were given + --> $DIR/macro-comma-behavior.rs:81:26 + | +LL | writeln!(f, "{}",)?; + | ^^ + +error: aborting due to 13 previous errors + diff --git a/tests/ui/macros/macro-comma-support-rpass.rs b/tests/ui/macros/macro-comma-support-rpass.rs new file mode 100644 index 000000000..25b8c3cc6 --- /dev/null +++ b/tests/ui/macros/macro-comma-support-rpass.rs @@ -0,0 +1,355 @@ +// run-pass +// This is meant to be a comprehensive test of invocations with/without +// trailing commas (or other, similar optionally-trailing separators). +// Every macro is accounted for, even those not tested in this file. +// (There will be a note indicating why). + +// std and core are both tested because they may contain separate +// implementations for some macro_rules! macros as an implementation +// detail. + +// ignore-pretty issue #37195 + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#![allow(deprecated)] // for deprecated `try!()` macro +#![feature(concat_idents)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +#[test] +fn assert() { + assert!(true); + assert!(true,); + assert!(true, "hello"); + assert!(true, "hello",); + assert!(true, "hello {}", "world"); + assert!(true, "hello {}", "world",); +} + +#[test] +fn assert_eq() { + assert_eq!(1, 1); + assert_eq!(1, 1,); + assert_eq!(1, 1, "hello"); + assert_eq!(1, 1, "hello",); + assert_eq!(1, 1, "hello {}", "world"); + assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn assert_ne() { + assert_ne!(1, 2); + assert_ne!(1, 2,); + assert_ne!(1, 2, "hello"); + assert_ne!(1, 2, "hello",); + assert_ne!(1, 2, "hello {}", "world"); + assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn cfg() { + let _ = cfg!(pants); + let _ = cfg!(pants,); + let _ = cfg!(pants = "pants"); + let _ = cfg!(pants = "pants",); + let _ = cfg!(all(pants)); + let _ = cfg!(all(pants),); + let _ = cfg!(all(pants,)); + let _ = cfg!(all(pants,),); +} + +#[test] +fn column() { + let _ = column!(); +} + +// compile_error! is in a check-fail companion to this test + +#[test] +fn concat() { + let _ = concat!(); + let _ = concat!("hello"); + let _ = concat!("hello",); + let _ = concat!("hello", " world"); + let _ = concat!("hello", " world",); +} + +#[test] +fn concat_idents() { + fn foo() {} + fn foobar() {} + + concat_idents!(foo)(); + concat_idents!(foo,)(); + concat_idents!(foo, bar)(); + concat_idents!(foo, bar,)(); +} + +#[test] +fn debug_assert() { + debug_assert!(true); + debug_assert!(true, ); + debug_assert!(true, "hello"); + debug_assert!(true, "hello",); + debug_assert!(true, "hello {}", "world"); + debug_assert!(true, "hello {}", "world",); +} + +#[test] +fn debug_assert_eq() { + debug_assert_eq!(1, 1); + debug_assert_eq!(1, 1,); + debug_assert_eq!(1, 1, "hello"); + debug_assert_eq!(1, 1, "hello",); + debug_assert_eq!(1, 1, "hello {}", "world"); + debug_assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn debug_assert_ne() { + debug_assert_ne!(1, 2); + debug_assert_ne!(1, 2,); + debug_assert_ne!(1, 2, "hello"); + debug_assert_ne!(1, 2, "hello",); + debug_assert_ne!(1, 2, "hello {}", "world"); + debug_assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn env() { + let _ = env!("PATH"); + let _ = env!("PATH",); + let _ = env!("PATH", "not found"); + let _ = env!("PATH", "not found",); +} + +#[cfg(std)] +#[test] +fn eprint() { + eprint!("hello"); + eprint!("hello",); + eprint!("hello {}", "world"); + eprint!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn eprintln() { + eprintln!(); + eprintln!("hello"); + eprintln!("hello",); + eprintln!("hello {}", "world"); + eprintln!("hello {}", "world",); +} + +#[test] +fn file() { + let _ = file!(); +} + +#[cfg(std)] +#[test] +fn format() { + let _ = format!("hello"); + let _ = format!("hello",); + let _ = format!("hello {}", "world"); + let _ = format!("hello {}", "world",); +} + +#[test] +fn format_args() { + let _ = format_args!("hello"); + let _ = format_args!("hello",); + let _ = format_args!("hello {}", "world"); + let _ = format_args!("hello {}", "world",); +} + +#[test] +fn include() { + let _ = include!("auxiliary/macro-comma-support.rs"); + let _ = include!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_bytes() { + let _ = include_bytes!("auxiliary/macro-comma-support.rs"); + let _ = include_bytes!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_str() { + let _ = include_str!("auxiliary/macro-comma-support.rs"); + let _ = include_str!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn line() { + let _ = line!(); +} + +#[test] +fn matches() { + let _ = matches!(1, x if x > 0); + let _ = matches!(1, x if x > 0,); +} + +#[test] +fn module_path() { + let _ = module_path!(); +} + +#[test] +fn option_env() { + let _ = option_env!("PATH"); + let _ = option_env!("PATH",); +} + +#[test] +fn panic() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { panic!(); } + if falsum() { panic!("hello"); } + if falsum() { panic!("hello",); } + if falsum() { panic!("hello {}", "world"); } + if falsum() { panic!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn print() { + print!("hello"); + print!("hello",); + print!("hello {}", "world"); + print!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn println() { + println!(); + println!("hello"); + println!("hello",); + println!("hello {}", "world"); + println!("hello {}", "world",); +} + +// stringify! is N/A + +#[cfg(std)] +#[test] +fn thread_local() { + // this has an optional trailing *semicolon* + thread_local! { + #[allow(unused)] pub static A: () = () + } + + thread_local! { + #[allow(unused)] pub static AA: () = (); + } + + thread_local! { + #[allow(unused)] pub static AAA: () = (); + #[allow(unused)] pub static AAAA: () = () + } + + thread_local! { + #[allow(unused)] pub static AAAAG: () = (); + #[allow(unused)] pub static AAAAGH: () = (); + } +} + +#[test] +fn try() { + fn inner() -> Result<(), ()> { + try!(Ok(())); + try!(Ok(()),); + Ok(()) + } + + inner().unwrap(); +} + +#[test] +fn unimplemented() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unimplemented!(); } + if falsum() { unimplemented!("hello"); } + if falsum() { unimplemented!("hello",); } + if falsum() { unimplemented!("hello {}", "world"); } + if falsum() { unimplemented!("hello {}", "world",); } +} + +#[test] +fn unreachable() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unreachable!(); } + if falsum() { unreachable!("hello"); } + if falsum() { unreachable!("hello",); } + if falsum() { unreachable!("hello {}", "world"); } + if falsum() { unreachable!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn vec() { + let _: Vec<()> = vec![]; + let _ = vec![0]; + let _ = vec![0,]; + let _ = vec![0, 1]; + let _ = vec![0, 1,]; +} + +// give a test body access to a fmt::Formatter, which seems +// to be the easiest way to use 'write!' on core. +macro_rules! test_with_formatter { + ( + #[test] + fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block + ) => { + #[test] + fn $fname() { + struct Struct; + impl fmt::Display for Struct { + fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result { + Ok($block) + } + } + + // suppress "unused" + assert!(true, "{}", Struct); + } + }; +} + +test_with_formatter! { + #[test] + fn write(f: &mut fmt::Formatter) { + let _ = write!(f, "hello"); + let _ = write!(f, "hello",); + let _ = write!(f, "hello {}", "world"); + let _ = write!(f, "hello {}", "world",); + } +} + +test_with_formatter! { + #[test] + fn writeln(f: &mut fmt::Formatter) { + let _ = writeln!(f); + let _ = writeln!(f,); + let _ = writeln!(f, "hello"); + let _ = writeln!(f, "hello",); + let _ = writeln!(f, "hello {}", "world"); + let _ = writeln!(f, "hello {}", "world",); + } +} diff --git a/tests/ui/macros/macro-comma-support.rs b/tests/ui/macros/macro-comma-support.rs new file mode 100644 index 000000000..7df5b6233 --- /dev/null +++ b/tests/ui/macros/macro-comma-support.rs @@ -0,0 +1,10 @@ +// This is a companion to the similarly-named test in run-pass. +// +// It tests macros that unavoidably produce compile errors. + +fn compile_error() { + compile_error!("lel"); //~ ERROR lel + compile_error!("lel",); //~ ERROR lel +} + +fn main() {} diff --git a/tests/ui/macros/macro-comma-support.stderr b/tests/ui/macros/macro-comma-support.stderr new file mode 100644 index 000000000..874efccd3 --- /dev/null +++ b/tests/ui/macros/macro-comma-support.stderr @@ -0,0 +1,14 @@ +error: lel + --> $DIR/macro-comma-support.rs:6:5 + | +LL | compile_error!("lel"); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: lel + --> $DIR/macro-comma-support.rs:7:5 + | +LL | compile_error!("lel",); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs new file mode 100644 index 000000000..d09fdf118 --- /dev/null +++ b/tests/ui/macros/macro-context.rs @@ -0,0 +1,21 @@ +// (typeof used because it's surprisingly hard to find an unparsed token after a stmt) +macro_rules! m { + () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` + //~| ERROR macro expansion ignores token `typeof` + //~| ERROR macro expansion ignores token `;` + //~| ERROR macro expansion ignores token `;` + //~| ERROR cannot find type `i` in this scope + //~| ERROR cannot find value `i` in this scope + //~| WARN trailing semicolon in macro + //~| WARN this was previously +} + +fn main() { + let a: m!(); + let i = m!(); + match 0 { + m!() => {} + } + + m!(); +} diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr new file mode 100644 index 000000000..7785f4159 --- /dev/null +++ b/tests/ui/macros/macro-context.stderr @@ -0,0 +1,99 @@ +error: macro expansion ignores token `;` and any following + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | let a: m!(); + | ---- caused by the macro expansion here + | + = note: the usage of `m!` is likely invalid in type context + +error: macro expansion ignores token `typeof` and any following + --> $DIR/macro-context.rs:3:17 + | +LL | () => ( i ; typeof ); + | ^^^^^^ +... +LL | let i = m!(); + | ---- caused by the macro expansion here + | + = note: the usage of `m!` is likely invalid in expression context + +error: macro expansion ignores token `;` and any following + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | m!() => {} + | ---- caused by the macro expansion here + | + = note: the usage of `m!` is likely invalid in pattern context + +error: expected expression, found reserved keyword `typeof` + --> $DIR/macro-context.rs:3:17 + | +LL | () => ( i ; typeof ); + | ^^^^^^ expected expression +... +LL | m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0412]: cannot find type `i` in this scope + --> $DIR/macro-context.rs:3:13 + | +LL | () => ( i ; typeof ); + | ^ help: a builtin type with a similar name exists: `i8` +... +LL | let a: m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `i` in this scope + --> $DIR/macro-context.rs:3:13 + | +LL | () => ( i ; typeof ); + | ^ not found in this scope +... +LL | let i = m!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | let i = m!(); + | ---- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0412, E0425. +For more information about an error, try `rustc --explain E0412`. +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | let i = m!(); + | ---- in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/macro-crate-def-only.rs b/tests/ui/macros/macro-crate-def-only.rs new file mode 100644 index 000000000..514b33e38 --- /dev/null +++ b/tests/ui/macros/macro-crate-def-only.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:macro_crate_def_only.rs + + +#[macro_use] #[no_link] +extern crate macro_crate_def_only; + +pub fn main() { + assert_eq!(5, make_a_5!()); +} diff --git a/tests/ui/macros/macro-crate-nonterminal-non-root.rs b/tests/ui/macros/macro-crate-nonterminal-non-root.rs new file mode 100644 index 000000000..67899556f --- /dev/null +++ b/tests/ui/macros/macro-crate-nonterminal-non-root.rs @@ -0,0 +1,9 @@ +// aux-build:macro_crate_nonterminal.rs + +mod foo { + #[macro_use] + extern crate macro_crate_nonterminal; //~ ERROR must be at the crate root +} + +fn main() { +} diff --git a/tests/ui/macros/macro-crate-nonterminal-non-root.stderr b/tests/ui/macros/macro-crate-nonterminal-non-root.stderr new file mode 100644 index 000000000..1eca0186d --- /dev/null +++ b/tests/ui/macros/macro-crate-nonterminal-non-root.stderr @@ -0,0 +1,9 @@ +error[E0468]: an `extern crate` loading macros must be at the crate root + --> $DIR/macro-crate-nonterminal-non-root.rs:5:5 + | +LL | extern crate macro_crate_nonterminal; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0468`. diff --git a/tests/ui/macros/macro-crate-nonterminal-renamed.rs b/tests/ui/macros/macro-crate-nonterminal-renamed.rs new file mode 100644 index 000000000..87bd397f0 --- /dev/null +++ b/tests/ui/macros/macro-crate-nonterminal-renamed.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:macro_crate_nonterminal.rs + +#[macro_use] +extern crate macro_crate_nonterminal as new_name; + +pub fn main() { + new_name::check_local(); + assert_eq!(increment!(5), 6); +} diff --git a/tests/ui/macros/macro-crate-nonterminal.rs b/tests/ui/macros/macro-crate-nonterminal.rs new file mode 100644 index 000000000..4b1056fc7 --- /dev/null +++ b/tests/ui/macros/macro-crate-nonterminal.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:macro_crate_nonterminal.rs + +#[macro_use] +extern crate macro_crate_nonterminal; + +pub fn main() { + macro_crate_nonterminal::check_local(); + assert_eq!(increment!(5), 6); +} diff --git a/tests/ui/macros/macro-crate-use.rs b/tests/ui/macros/macro-crate-use.rs new file mode 100644 index 000000000..5c37cac96 --- /dev/null +++ b/tests/ui/macros/macro-crate-use.rs @@ -0,0 +1,17 @@ +// run-pass + +pub fn increment(x: usize) -> usize { + x + 1 +} + +#[macro_export] +macro_rules! increment { + ($x:expr) => ({ + use $crate::increment; + increment($x) + }) +} + +fn main() { + assert_eq!(increment!(3), 4); +} diff --git a/tests/ui/macros/macro-deep_expansion.rs b/tests/ui/macros/macro-deep_expansion.rs new file mode 100644 index 000000000..e13d8e1fc --- /dev/null +++ b/tests/ui/macros/macro-deep_expansion.rs @@ -0,0 +1,17 @@ +// run-pass + +macro_rules! foo2 { + () => { + "foo" + } +} + +macro_rules! foo { + () => { + foo2!() + } +} + +fn main() { + assert_eq!(concat!(foo!(), "bar"), "foobar") +} diff --git a/tests/ui/macros/macro-def-site-super.rs b/tests/ui/macros/macro-def-site-super.rs new file mode 100644 index 000000000..716a8ced5 --- /dev/null +++ b/tests/ui/macros/macro-def-site-super.rs @@ -0,0 +1,10 @@ +// `super` in a `macro` refers to the parent module of the macro itself and not its reexport. + +// check-pass +// aux-build:macro-def-site-super.rs + +extern crate macro_def_site_super; + +type A = macro_def_site_super::public::mac!(); + +fn main() {} diff --git a/tests/ui/macros/macro-delimiter-significance.rs b/tests/ui/macros/macro-delimiter-significance.rs new file mode 100644 index 000000000..89f222b05 --- /dev/null +++ b/tests/ui/macros/macro-delimiter-significance.rs @@ -0,0 +1,4 @@ +// run-pass +fn main() { + vec![1_usize, 2, 3].len(); +} diff --git a/tests/ui/macros/macro-deprecation.rs b/tests/ui/macros/macro-deprecation.rs new file mode 100644 index 000000000..a7f327cf5 --- /dev/null +++ b/tests/ui/macros/macro-deprecation.rs @@ -0,0 +1,13 @@ +// check-pass +// aux-build:deprecated-macros.rs + +#[macro_use] extern crate deprecated_macros; + +#[deprecated(since = "1.0.0", note = "local deprecation note")] +#[macro_export] +macro_rules! local_deprecated{ () => () } + +fn main() { + local_deprecated!(); //~ WARN use of deprecated macro `local_deprecated`: local deprecation note + deprecated_macro!(); //~ WARN use of deprecated macro `deprecated_macro`: deprecation note +} diff --git a/tests/ui/macros/macro-deprecation.stderr b/tests/ui/macros/macro-deprecation.stderr new file mode 100644 index 000000000..07849d7ce --- /dev/null +++ b/tests/ui/macros/macro-deprecation.stderr @@ -0,0 +1,16 @@ +warning: use of deprecated macro `local_deprecated`: local deprecation note + --> $DIR/macro-deprecation.rs:11:5 + | +LL | local_deprecated!(); + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated macro `deprecated_macro`: deprecation note + --> $DIR/macro-deprecation.rs:12:5 + | +LL | deprecated_macro!(); + | ^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/macros/macro-doc-comments.rs b/tests/ui/macros/macro-doc-comments.rs new file mode 100644 index 000000000..fcc64cc06 --- /dev/null +++ b/tests/ui/macros/macro-doc-comments.rs @@ -0,0 +1,26 @@ +// run-pass +#![allow(non_snake_case)] + +macro_rules! doc { + ( + $(#[$outer:meta])* + mod $i:ident { + $(#![$inner:meta])* + } + ) => + ( + $(#[$outer])* + pub mod $i { + $(#![$inner])* + } + ) +} + +doc! { + /// Outer doc + mod Foo { + //! Inner doc + } +} + +fn main() { } diff --git a/tests/ui/macros/macro-doc-escapes.rs b/tests/ui/macros/macro-doc-escapes.rs new file mode 100644 index 000000000..ff5a5793b --- /dev/null +++ b/tests/ui/macros/macro-doc-escapes.rs @@ -0,0 +1,16 @@ +// run-pass +// When expanding a macro, documentation attributes (including documentation comments) must be +// passed "as is" without being parsed. Otherwise, some text will be incorrectly interpreted as +// escape sequences, leading to an ICE. +// +// Related issues: #25929, #25943 + +macro_rules! homura { + (#[$x:meta]) => () +} + +homura! { + /// \madoka \x41 +} + +fn main() { } diff --git a/tests/ui/macros/macro-doc-raw-str-hashes.rs b/tests/ui/macros/macro-doc-raw-str-hashes.rs new file mode 100644 index 000000000..a003bff3c --- /dev/null +++ b/tests/ui/macros/macro-doc-raw-str-hashes.rs @@ -0,0 +1,30 @@ +// run-pass +// The number of `#`s used to wrap the documentation comment should differ regarding the content. +// +// Related issue: #27489 + +macro_rules! homura { + ($x:expr, #[$y:meta]) => (assert_eq!($x, stringify!($y))) +} + +fn main() { + homura! { + r#"doc = r" Madoka""#, + /// Madoka + }; + + homura! { + r##"doc = r#" One quote mark: ["]"#"##, + /// One quote mark: ["] + }; + + homura! { + r##"doc = r#" Two quote marks: [""]"#"##, + /// Two quote marks: [""] + }; + + homura! { + r#####"doc = r####" Raw string ending sequences: ["###]"####"#####, + /// Raw string ending sequences: ["###] + }; +} diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs new file mode 100644 index 000000000..59ed79e91 --- /dev/null +++ b/tests/ui/macros/macro-error.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + ($a:expr) => a; //~ ERROR macro rhs must be delimited +} + +fn main() { + foo!(0); // Check that we report errors at macro definition, not expansion. + + let _: cfg!(foo) = (); //~ ERROR non-type macro in type position +} diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr new file mode 100644 index 000000000..2539a6d51 --- /dev/null +++ b/tests/ui/macros/macro-error.stderr @@ -0,0 +1,14 @@ +error: macro rhs must be delimited + --> $DIR/macro-error.rs:2:18 + | +LL | ($a:expr) => a; + | ^ + +error: non-type macro in type position: cfg + --> $DIR/macro-error.rs:8:12 + | +LL | let _: cfg!(foo) = (); + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-expanded-include/file.txt b/tests/ui/macros/macro-expanded-include/file.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/ui/macros/macro-expanded-include/file.txt diff --git a/tests/ui/macros/macro-expanded-include/foo/mod.rs b/tests/ui/macros/macro-expanded-include/foo/mod.rs new file mode 100644 index 000000000..cff110470 --- /dev/null +++ b/tests/ui/macros/macro-expanded-include/foo/mod.rs @@ -0,0 +1,9 @@ +// ignore-test + +macro_rules! m { + () => { include!("file.txt"); } +} + +macro_rules! n { + () => { unsafe { core::arch::asm!(include_str!("file.txt")); } } +} diff --git a/tests/ui/macros/macro-expanded-include/test.rs b/tests/ui/macros/macro-expanded-include/test.rs new file mode 100644 index 000000000..20da58a7e --- /dev/null +++ b/tests/ui/macros/macro-expanded-include/test.rs @@ -0,0 +1,13 @@ +// needs-asm-support +// build-pass (FIXME(62277): could be check-pass?) +#![allow(unused)] + +#[macro_use] +mod foo; + +m!(); +fn f() { + n!(); +} + +fn main() {} diff --git a/tests/ui/macros/macro-expansion-tests.rs b/tests/ui/macros/macro-expansion-tests.rs new file mode 100644 index 000000000..38f4937c1 --- /dev/null +++ b/tests/ui/macros/macro-expansion-tests.rs @@ -0,0 +1,40 @@ +#![allow(unused_macros)] + +mod macros_cant_escape_fns { + fn f() { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } + //~^ ERROR cannot find macro +} + +mod macros_cant_escape_mods { + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } + //~^ ERROR cannot find macro +} + +mod macros_can_escape_flattened_mods_test { + #[macro_use] + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } +} + +fn macro_tokens_should_match() { + macro_rules! m { (a) => { 13 } } + m!(a); +} + +// should be able to use a bound identifier as a literal in a macro definition: +fn self_macro_parsing() { + macro_rules! foo { (zz) => { 287; } } + fn f(zz: i32) { + foo!(zz); + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-expansion-tests.stderr b/tests/ui/macros/macro-expansion-tests.stderr new file mode 100644 index 000000000..8b3f7ca88 --- /dev/null +++ b/tests/ui/macros/macro-expansion-tests.stderr @@ -0,0 +1,18 @@ +error: cannot find macro `m` in this scope + --> $DIR/macro-expansion-tests.rs:7:21 + | +LL | fn g() -> i32 { m!() } + | ^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `m` in this scope + --> $DIR/macro-expansion-tests.rs:15:21 + | +LL | fn g() -> i32 { m!() } + | ^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-export-inner-module.rs b/tests/ui/macros/macro-export-inner-module.rs new file mode 100644 index 000000000..1f23e90b6 --- /dev/null +++ b/tests/ui/macros/macro-export-inner-module.rs @@ -0,0 +1,9 @@ +// run-pass +//aux-build:macro_export_inner_module.rs + +#[macro_use] #[no_link] +extern crate macro_export_inner_module; + +pub fn main() { + assert_eq!(1, foo!()); +} diff --git a/tests/ui/macros/macro-first-set.rs b/tests/ui/macros/macro-first-set.rs new file mode 100644 index 000000000..eeb1ddd84 --- /dev/null +++ b/tests/ui/macros/macro-first-set.rs @@ -0,0 +1,272 @@ +// run-pass +#![allow(unused_macro_rules)] + +//{{{ issue 40569 ============================================================== + +macro_rules! my_struct { + ($(#[$meta:meta])* $ident:ident) => { + $(#[$meta])* struct $ident; + } +} + +my_struct!(#[derive(Debug, PartialEq)] Foo40569); + +fn test_40569() { + assert_eq!(Foo40569, Foo40569); +} + +//}}} + +//{{{ issue 26444 ============================================================== + +macro_rules! foo_26444 { + ($($beginning:ident),*; $middle:ident; $($end:ident),*) => { + stringify!($($beginning,)* $middle $(,$end)*) + } +} + +fn test_26444() { + assert_eq!("a, b, c, d, e", foo_26444!(a, b; c; d, e)); + assert_eq!("f", foo_26444!(; f ;)); +} + +macro_rules! pat_26444 { + ($fname:ident $($arg:pat)* =) => {} +} + +pat_26444!(foo 1 2 5...7 =); +pat_26444!(bar Some(ref x) Ok(ref mut y) &(w, z) =); + +//}}} + +//{{{ issue 40984 ============================================================== + +macro_rules! thread_local_40984 { + () => {}; + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => { + thread_local_40984!($($rest)*); + }; + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => {}; +} + +thread_local_40984! { + // no docs + #[allow(unused)] + static FOO: i32 = 42; + /// docs + pub static BAR: String = String::from("bar"); + + // look at these restrictions!! + pub(crate) static BAZ: usize = 0; + pub(in foo) static QUUX: usize = 0; +} + +//}}} + +//{{{ issue 35650 ============================================================== + +macro_rules! size { + ($ty:ty) => { + std::mem::size_of::<$ty>() + }; + ($size:tt) => { + $size + }; +} + +fn test_35650() { + assert_eq!(size!(u64), 8); + assert_eq!(size!(5), 5); +} + +//}}} + +//{{{ issue 27832 ============================================================== + +macro_rules! m { + ( $i:ident ) => (); + ( $t:tt $j:tt ) => (); +} + +m!(c); +m!(t 9); +m!(0 9); +m!(struct); +m!(struct Foo); + +macro_rules! m2 { + ( $b:expr ) => (); + ( $t:tt $u:tt ) => (); +} + +m2!(3); +m2!(1 2); +m2!(_ 1); +m2!(enum Foo); + +//}}} + +//{{{ issue 39964 ============================================================== + +macro_rules! foo_39964 { + ($a:ident) => {}; + (_) => {}; +} + +foo_39964!(_); + +//}}} + +//{{{ issue 34030 ============================================================== + +macro_rules! foo_34030 { + ($($t:ident),* /) => {}; +} + +foo_34030!(a, b/); +foo_34030!(a/); +foo_34030!(/); + +//}}} + +//{{{ issue 24189 ============================================================== + +macro_rules! foo_24189 { + ( + pub enum $name:ident { + $( #[$attr:meta] )* $var:ident + } + ) => { + pub enum $name { + $( #[$attr] )* $var + } + }; +} + +foo_24189! { + pub enum Foo24189 { + #[doc = "Bar"] Baz + } +} + +macro_rules! serializable { + ( + $(#[$struct_meta:meta])* + pub struct $name:ident { + $( + $(#[$field_meta:meta])* + $field:ident: $type_:ty + ),* , + } + ) => { + $(#[$struct_meta])* + pub struct $name { + $( + $(#[$field_meta])* + $field: $type_ + ),* , + } + } +} + +serializable! { + #[allow(dead_code)] + /// This is a test + pub struct Tester { + #[allow(dead_code)] + name: String, + } +} + +macro_rules! foo_24189_c { + ( $( > )* $x:ident ) => { }; +} +foo_24189_c!( > a ); + +fn test_24189() { + let _ = Foo24189::Baz; + let _ = Tester { name: "".to_owned() }; +} + +//}}} + +//{{{ issue 50903 ============================================================== + +macro_rules! foo_50903 { + ($($lif:lifetime ,)* #) => {}; +} + +foo_50903!('a, 'b, #); +foo_50903!('a, #); +foo_50903!(#); + +//}}} + +//{{{ issue 51477 ============================================================== + +macro_rules! foo_51477 { + ($lifetime:lifetime) => { + "last token is lifetime" + }; + ($other:tt) => { + "last token is other" + }; + ($first:tt $($rest:tt)*) => { + foo_51477!($($rest)*) + }; +} + +fn test_51477() { + assert_eq!("last token is lifetime", foo_51477!('a)); + assert_eq!("last token is other", foo_51477!(@)); + assert_eq!("last token is lifetime", foo_51477!(@ {} 'a)); +} + +//}}} + +//{{{ some more tests ========================================================== + +macro_rules! test_block { + (< $($b:block)* >) => {} +} + +test_block!(<>); +test_block!(<{}>); +test_block!(<{1}{2}>); + +macro_rules! test_ty { + ($($t:ty),* $(,)*) => {} +} + +test_ty!(); +test_ty!(,); +test_ty!(u8); +test_ty!(u8,); + +macro_rules! test_path { + ($($t:path),* $(,)*) => {} +} + +test_path!(); +test_path!(,); +test_path!(::std); +test_path!(std::ops,); +test_path!(any, super, super::super::self::path, X<Y>::Z<'a, T=U>); + +macro_rules! test_lifetime { + (1. $($l:lifetime)* $($b:block)*) => {}; + (2. $($b:block)* $($l:lifetime)*) => {}; +} + +test_lifetime!(1. 'a 'b {} {}); +test_lifetime!(2. {} {} 'a 'b); + +//}}} + +fn main() { + test_26444(); + test_40569(); + test_35650(); + test_24189(); + test_51477(); +} diff --git a/tests/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs new file mode 100644 index 000000000..ca9365563 --- /dev/null +++ b/tests/ui/macros/macro-follow-rpass.rs @@ -0,0 +1,183 @@ +// run-pass +#![allow(unused_macros)] +// Check the macro follow sets (see corresponding cfail test). + +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +macro_rules! follow_pat { + ($p:pat =>) => {}; + ($p:pat ,) => {}; + ($p:pat =) => {}; + ($p:pat |) => {}; + ($p:pat if) => {}; + ($p:pat in) => {}; +} +// FOLLOW(expr) = {FatArrow, Comma, Semicolon} +macro_rules! follow_expr { + ($e:expr =>) => {}; + ($e:expr ,) => {}; + ($e:expr ;) => {}; +} +// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, +// Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)} +macro_rules! follow_ty { + ($t:ty {}) => {}; + ($t:ty ,) => {}; + ($t:ty =>) => {}; + ($t:ty :) => {}; + ($t:ty =) => {}; + ($t:ty >) => {}; + ($t:ty ;) => {}; + ($t:ty |) => {}; + ($t:ty as) => {}; + ($t:ty where) => {}; + ($t:ty []) => {}; + ($t:ty $b:block) => {}; +} +// FOLLOW(stmt) = FOLLOW(expr) +macro_rules! follow_stmt { + ($s:stmt =>) => {}; + ($s:stmt ,) => {}; + ($s:stmt ;) => {}; +} +// FOLLOW(path) = FOLLOW(ty) +macro_rules! follow_path { + ($p:path {}) => {}; + ($p:path ,) => {}; + ($p:path =>) => {}; + ($p:path :) => {}; + ($p:path =) => {}; + ($p:path >) => {}; + ($p:path ;) => {}; + ($p:path |) => {}; + ($p:path as) => {}; + ($p:path where) => {}; + ($p:path []) => {}; + ($p:path $b:block) => {}; +} +// FOLLOW(block) = any token +macro_rules! follow_block { + ($b:block ()) => {}; + ($b:block []) => {}; + ($b:block {}) => {}; + ($b:block ,) => {}; + ($b:block =>) => {}; + ($b:block :) => {}; + ($b:block =) => {}; + ($b:block >) => {}; + ($b:block ;) => {}; + ($b:block |) => {}; + ($b:block +) => {}; + ($b:block ident) => {}; + ($b:block $p:pat) => {}; + ($b:block $e:expr) => {}; + ($b:block $t:ty) => {}; + ($b:block $s:stmt) => {}; + ($b:block $p:path) => {}; + ($b:block $c:block) => {}; + ($b:block $i:ident) => {}; + ($b:block $t:tt) => {}; + ($b:block $i:item) => {}; + ($b:block $m:meta) => {}; +} +// FOLLOW(ident) = any token +macro_rules! follow_ident { + ($i:ident ()) => {}; + ($i:ident []) => {}; + ($i:ident {}) => {}; + ($i:ident ,) => {}; + ($i:ident =>) => {}; + ($i:ident :) => {}; + ($i:ident =) => {}; + ($i:ident >) => {}; + ($i:ident ;) => {}; + ($i:ident |) => {}; + ($i:ident +) => {}; + ($i:ident ident) => {}; + ($i:ident $p:pat) => {}; + ($i:ident $e:expr) => {}; + ($i:ident $t:ty) => {}; + ($i:ident $s:stmt) => {}; + ($i:ident $p:path) => {}; + ($i:ident $b:block) => {}; + ($i:ident $j:ident) => {}; + ($i:ident $t:tt) => {}; + ($i:ident $j:item) => {}; + ($i:ident $m:meta) => {}; +} +// FOLLOW(tt) = any token +macro_rules! follow_tt { + ($t:tt ()) => {}; + ($t:tt []) => {}; + ($t:tt {}) => {}; + ($t:tt ,) => {}; + ($t:tt =>) => {}; + ($t:tt :) => {}; + ($t:tt =) => {}; + ($t:tt >) => {}; + ($t:tt ;) => {}; + ($t:tt |) => {}; + ($t:tt +) => {}; + ($t:tt ident) => {}; + ($t:tt $p:pat) => {}; + ($t:tt $e:expr) => {}; + ($t:tt $v:ty) => {}; + ($t:tt $s:stmt) => {}; + ($t:tt $p:path) => {}; + ($t:tt $b:block) => {}; + ($t:tt $i:ident) => {}; + ($t:tt $v:tt) => {}; + ($t:tt $i:item) => {}; + ($t:tt $m:meta) => {}; +} +// FOLLOW(item) = any token +macro_rules! follow_item { + ($i:item ()) => {}; + ($i:item []) => {}; + ($i:item {}) => {}; + ($i:item ,) => {}; + ($i:item =>) => {}; + ($i:item :) => {}; + ($i:item =) => {}; + ($i:item >) => {}; + ($i:item ;) => {}; + ($i:item |) => {}; + ($i:item +) => {}; + ($i:item ident) => {}; + ($i:item $p:pat) => {}; + ($i:item $e:expr) => {}; + ($i:item $t:ty) => {}; + ($i:item $s:stmt) => {}; + ($i:item $p:path) => {}; + ($i:item $b:block) => {}; + ($i:item $j:ident) => {}; + ($i:item $t:tt) => {}; + ($i:item $j:item) => {}; + ($i:item $m:meta) => {}; +} +// FOLLOW(meta) = any token +macro_rules! follow_meta { + ($m:meta ()) => {}; + ($m:meta []) => {}; + ($m:meta {}) => {}; + ($m:meta ,) => {}; + ($m:meta =>) => {}; + ($m:meta :) => {}; + ($m:meta =) => {}; + ($m:meta >) => {}; + ($m:meta ;) => {}; + ($m:meta |) => {}; + ($m:meta +) => {}; + ($m:meta ident) => {}; + ($m:meta $p:pat) => {}; + ($m:meta $e:expr) => {}; + ($m:meta $t:ty) => {}; + ($m:meta $s:stmt) => {}; + ($m:meta $p:path) => {}; + ($m:meta $b:block) => {}; + ($m:meta $i:ident) => {}; + ($m:meta $t:tt) => {}; + ($m:meta $i:item) => {}; + ($m:meta $n:meta) => {}; +} + +fn main() {} diff --git a/tests/ui/macros/macro-follow.rs b/tests/ui/macros/macro-follow.rs new file mode 100644 index 000000000..8054418d9 --- /dev/null +++ b/tests/ui/macros/macro-follow.rs @@ -0,0 +1,114 @@ +// +// Check the macro follow sets (see corresponding rpass test). + +#![allow(unused_macros)] + +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +macro_rules! follow_pat { + ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` + ($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[` + ($p:pat {}) => {}; //~ERROR `$p:pat` is followed by `{` + ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:` + ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>` + ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+` + ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident` + ($p:pat $q:pat) => {}; //~ERROR `$p:pat` is followed by `$q:pat` + ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr` + ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty` + ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt` + ($p:pat $q:path) => {}; //~ERROR `$p:pat` is followed by `$q:path` + ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block` + ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident` + ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt` + ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item` + ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta` +} +// FOLLOW(expr) = {FatArrow, Comma, Semicolon} +macro_rules! follow_expr { + ($e:expr ()) => {}; //~ERROR `$e:expr` is followed by `(` + ($e:expr []) => {}; //~ERROR `$e:expr` is followed by `[` + ($e:expr {}) => {}; //~ERROR `$e:expr` is followed by `{` + ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=` + ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|` + ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:` + ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>` + ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+` + ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident` + ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if` + ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in` + ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat` + ($e:expr $f:expr) => {}; //~ERROR `$e:expr` is followed by `$f:expr` + ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty` + ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt` + ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path` + ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block` + ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident` + ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` + ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` + ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` +} +// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, +// Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)} +macro_rules! follow_ty { + ($t:ty ()) => {}; //~ERROR `$t:ty` is followed by `(` + ($t:ty []) => {}; // ok (RFC 1462) + ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+` + ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident` + ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if` + ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat` + ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr` + ($t:ty $r:ty) => {}; //~ERROR `$t:ty` is followed by `$r:ty` + ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt` + ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path` + ($t:ty $b:block) => {}; // ok (RFC 1494) + ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident` + ($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt` + ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` + ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` +} +// FOLLOW(stmt) = FOLLOW(expr) +macro_rules! follow_stmt { + ($s:stmt ()) => {}; //~ERROR `$s:stmt` is followed by `(` + ($s:stmt []) => {}; //~ERROR `$s:stmt` is followed by `[` + ($s:stmt {}) => {}; //~ERROR `$s:stmt` is followed by `{` + ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=` + ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|` + ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:` + ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>` + ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+` + ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident` + ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if` + ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in` + ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat` + ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr` + ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty` + ($s:stmt $t:stmt) => {}; //~ERROR `$s:stmt` is followed by `$t:stmt` + ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path` + ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block` + ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident` + ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` + ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` + ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` +} +// FOLLOW(path) = FOLLOW(ty) +macro_rules! follow_path { + ($p:path ()) => {}; //~ERROR `$p:path` is followed by `(` + ($p:path []) => {}; // ok (RFC 1462) + ($p:path +) => {}; //~ERROR `$p:path` is followed by `+` + ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident` + ($p:path if) => {}; //~ERROR `$p:path` is followed by `if` + ($p:path $q:pat) => {}; //~ERROR `$p:path` is followed by `$q:pat` + ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr` + ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty` + ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt` + ($p:path $q:path) => {}; //~ERROR `$p:path` is followed by `$q:path` + ($p:path $b:block) => {}; // ok (RFC 1494) + ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident` + ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` + ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` + ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta` +} +// FOLLOW(block) = any token +// FOLLOW(ident) = any token + +fn main() {} diff --git a/tests/ui/macros/macro-follow.stderr b/tests/ui/macros/macro-follow.stderr new file mode 100644 index 000000000..61ae79d23 --- /dev/null +++ b/tests/ui/macros/macro-follow.stderr @@ -0,0 +1,682 @@ +error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:8:13 + | +LL | ($p:pat ()) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:9:13 + | +LL | ($p:pat []) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:10:13 + | +LL | ($p:pat {}) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:11:13 + | +LL | ($p:pat :) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:12:13 + | +LL | ($p:pat >) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:13:13 + | +LL | ($p:pat +) => {}; + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:14:13 + | +LL | ($p:pat ident) => {}; + | ^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:15:13 + | +LL | ($p:pat $q:pat) => {}; + | ^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:16:13 + | +LL | ($p:pat $e:expr) => {}; + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:17:13 + | +LL | ($p:pat $t:ty) => {}; + | ^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:18:13 + | +LL | ($p:pat $s:stmt) => {}; + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:19:13 + | +LL | ($p:pat $q:path) => {}; + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:20:13 + | +LL | ($p:pat $b:block) => {}; + | ^^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:21:13 + | +LL | ($p:pat $i:ident) => {}; + | ^^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:22:13 + | +LL | ($p:pat $t:tt) => {}; + | ^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:23:13 + | +LL | ($p:pat $i:item) => {}; + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments + --> $DIR/macro-follow.rs:24:13 + | +LL | ($p:pat $m:meta) => {}; + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:28:14 + | +LL | ($e:expr ()) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:29:14 + | +LL | ($e:expr []) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:30:14 + | +LL | ($e:expr {}) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:31:14 + | +LL | ($e:expr =) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:32:14 + | +LL | ($e:expr |) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:33:14 + | +LL | ($e:expr :) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:34:14 + | +LL | ($e:expr >) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:35:14 + | +LL | ($e:expr +) => {}; + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:36:14 + | +LL | ($e:expr ident) => {}; + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:37:14 + | +LL | ($e:expr if) => {}; + | ^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:38:14 + | +LL | ($e:expr in) => {}; + | ^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:39:14 + | +LL | ($e:expr $p:pat) => {}; + | ^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:40:14 + | +LL | ($e:expr $f:expr) => {}; + | ^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:41:14 + | +LL | ($e:expr $t:ty) => {}; + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:42:14 + | +LL | ($e:expr $s:stmt) => {}; + | ^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:43:14 + | +LL | ($e:expr $p:path) => {}; + | ^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:44:14 + | +LL | ($e:expr $b:block) => {}; + | ^^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:45:14 + | +LL | ($e:expr $i:ident) => {}; + | ^^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:46:14 + | +LL | ($e:expr $t:tt) => {}; + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:47:14 + | +LL | ($e:expr $i:item) => {}; + | ^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments + --> $DIR/macro-follow.rs:48:14 + | +LL | ($e:expr $m:meta) => {}; + | ^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:53:12 + | +LL | ($t:ty ()) => {}; + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:55:12 + | +LL | ($t:ty +) => {}; + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:56:12 + | +LL | ($t:ty ident) => {}; + | ^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:57:12 + | +LL | ($t:ty if) => {}; + | ^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:58:12 + | +LL | ($t:ty $p:pat) => {}; + | ^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:59:12 + | +LL | ($t:ty $e:expr) => {}; + | ^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:60:12 + | +LL | ($t:ty $r:ty) => {}; + | ^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:61:12 + | +LL | ($t:ty $s:stmt) => {}; + | ^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:62:12 + | +LL | ($t:ty $p:path) => {}; + | ^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:64:12 + | +LL | ($t:ty $i:ident) => {}; + | ^^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:65:12 + | +LL | ($t:ty $r:tt) => {}; + | ^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:66:12 + | +LL | ($t:ty $i:item) => {}; + | ^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments + --> $DIR/macro-follow.rs:67:12 + | +LL | ($t:ty $m:meta) => {}; + | ^^^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:71:14 + | +LL | ($s:stmt ()) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:72:14 + | +LL | ($s:stmt []) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:73:14 + | +LL | ($s:stmt {}) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:74:14 + | +LL | ($s:stmt =) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:75:14 + | +LL | ($s:stmt |) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:76:14 + | +LL | ($s:stmt :) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:77:14 + | +LL | ($s:stmt >) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:78:14 + | +LL | ($s:stmt +) => {}; + | ^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:79:14 + | +LL | ($s:stmt ident) => {}; + | ^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:80:14 + | +LL | ($s:stmt if) => {}; + | ^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:81:14 + | +LL | ($s:stmt in) => {}; + | ^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:82:14 + | +LL | ($s:stmt $p:pat) => {}; + | ^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:83:14 + | +LL | ($s:stmt $e:expr) => {}; + | ^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:84:14 + | +LL | ($s:stmt $t:ty) => {}; + | ^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:85:14 + | +LL | ($s:stmt $t:stmt) => {}; + | ^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:86:14 + | +LL | ($s:stmt $p:path) => {}; + | ^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:87:14 + | +LL | ($s:stmt $b:block) => {}; + | ^^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:88:14 + | +LL | ($s:stmt $i:ident) => {}; + | ^^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:89:14 + | +LL | ($s:stmt $t:tt) => {}; + | ^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:90:14 + | +LL | ($s:stmt $i:item) => {}; + | ^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments + --> $DIR/macro-follow.rs:91:14 + | +LL | ($s:stmt $m:meta) => {}; + | ^^^^^^^ not allowed after `stmt` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$p:path` is followed by `(`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:95:14 + | +LL | ($p:path ()) => {}; + | ^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `+`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:97:14 + | +LL | ($p:path +) => {}; + | ^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:98:14 + | +LL | ($p:path ident) => {}; + | ^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `if`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:99:14 + | +LL | ($p:path if) => {}; + | ^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:100:14 + | +LL | ($p:path $q:pat) => {}; + | ^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:101:14 + | +LL | ($p:path $e:expr) => {}; + | ^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:102:14 + | +LL | ($p:path $t:ty) => {}; + | ^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:103:14 + | +LL | ($p:path $s:stmt) => {}; + | ^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:104:14 + | +LL | ($p:path $q:path) => {}; + | ^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:106:14 + | +LL | ($p:path $i:ident) => {}; + | ^^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:107:14 + | +LL | ($p:path $t:tt) => {}; + | ^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:108:14 + | +LL | ($p:path $i:item) => {}; + | ^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments + --> $DIR/macro-follow.rs:109:14 + | +LL | ($p:path $m:meta) => {}; + | ^^^^^^^ not allowed after `path` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 85 previous errors + diff --git a/tests/ui/macros/macro-followed-by-seq-bad.rs b/tests/ui/macros/macro-followed-by-seq-bad.rs new file mode 100644 index 000000000..b73742f77 --- /dev/null +++ b/tests/ui/macros/macro-followed-by-seq-bad.rs @@ -0,0 +1,11 @@ +// Regression test for issue #25436: check that things which can be +// followed by any token also permit X* to come afterwards. + +#![allow(unused_macros)] + +macro_rules! foo { + ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments + ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments +} + +fn main() { } diff --git a/tests/ui/macros/macro-followed-by-seq-bad.stderr b/tests/ui/macros/macro-followed-by-seq-bad.stderr new file mode 100644 index 000000000..7097979ae --- /dev/null +++ b/tests/ui/macros/macro-followed-by-seq-bad.stderr @@ -0,0 +1,18 @@ +error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments + --> $DIR/macro-followed-by-seq-bad.rs:7:15 + | +LL | ( $a:expr $($b:tt)* ) => { }; + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments + --> $DIR/macro-followed-by-seq-bad.rs:8:13 + | +LL | ( $a:ty $($b:tt)* ) => { }; + | ^^^^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-followed-by-seq.rs b/tests/ui/macros/macro-followed-by-seq.rs new file mode 100644 index 000000000..71d59d8d3 --- /dev/null +++ b/tests/ui/macros/macro-followed-by-seq.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_macros)] +// Regression test for issue #25436: check that things which can be +// followed by any token also permit X* to come afterwards. + +macro_rules! foo { + ( $a:tt $($b:tt)* ) => { }; + ( $a:ident $($b:tt)* ) => { }; + ( $a:item $($b:tt)* ) => { }; + ( $a:block $($b:tt)* ) => { }; + ( $a:meta $($b:tt)* ) => { } +} + +fn main() { } diff --git a/tests/ui/macros/macro-in-expression-context-2.rs b/tests/ui/macros/macro-in-expression-context-2.rs new file mode 100644 index 000000000..9423f0a35 --- /dev/null +++ b/tests/ui/macros/macro-in-expression-context-2.rs @@ -0,0 +1,8 @@ +macro_rules! empty { () => () } + +fn main() { + match 42 { + _ => { empty!() } +//~^ ERROR macro expansion ends with an incomplete expression + }; +} diff --git a/tests/ui/macros/macro-in-expression-context-2.stderr b/tests/ui/macros/macro-in-expression-context-2.stderr new file mode 100644 index 000000000..d0312c485 --- /dev/null +++ b/tests/ui/macros/macro-in-expression-context-2.stderr @@ -0,0 +1,17 @@ +error: macro expansion ends with an incomplete expression: expected expression + --> $DIR/macro-in-expression-context-2.rs:5:16 + | +LL | macro_rules! empty { () => () } + | -- in this macro arm +... +LL | _ => { empty!() } + | ^^^^^^^^ expected expression + | + = note: the macro call doesn't expand to an expression, but it can expand to a statement +help: add `;` to interpret the expansion as a statement + | +LL | _ => { empty!(); } + | + + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed new file mode 100644 index 000000000..f22caf279 --- /dev/null +++ b/tests/ui/macros/macro-in-expression-context.fixed @@ -0,0 +1,27 @@ +// run-rustfix + +macro_rules! foo { + () => { + assert_eq!("A", "A"); + //~^ WARN trailing semicolon in macro + //~| WARN this was previously + //~| NOTE macro invocations at the end of a block + //~| NOTE to ignore the value produced by the macro + //~| NOTE for more information + //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default + assert_eq!("B", "B"); + } + //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~| NOTE the usage of `foo!` is likely invalid in expression context +} + +fn main() { + foo!(); + //~^ NOTE caused by the macro expansion here + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion +} diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs new file mode 100644 index 000000000..1a056e582 --- /dev/null +++ b/tests/ui/macros/macro-in-expression-context.rs @@ -0,0 +1,27 @@ +// run-rustfix + +macro_rules! foo { + () => { + assert_eq!("A", "A"); + //~^ WARN trailing semicolon in macro + //~| WARN this was previously + //~| NOTE macro invocations at the end of a block + //~| NOTE to ignore the value produced by the macro + //~| NOTE for more information + //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default + assert_eq!("B", "B"); + } + //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~| NOTE the usage of `foo!` is likely invalid in expression context +} + +fn main() { + foo!() + //~^ NOTE caused by the macro expansion here + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion +} diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr new file mode 100644 index 000000000..3f492b141 --- /dev/null +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -0,0 +1,50 @@ +error: macro expansion ignores token `assert_eq` and any following + --> $DIR/macro-in-expression-context.rs:12:9 + | +LL | assert_eq!("B", "B"); + | ^^^^^^^^^ +... +LL | foo!() + | ------ caused by the macro expansion here + | + = note: the usage of `foo!` is likely invalid in expression context +help: you might be missing a semicolon here + | +LL | foo!(); + | + + +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-in-expression-context.rs:5:29 + | +LL | assert_eq!("A", "A"); + | ^ +... +LL | foo!() + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-in-expression-context.rs:5:29 + | +LL | assert_eq!("A", "A"); + | ^ +... +LL | foo!() + | ------ in this macro invocation + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813> + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/tests/ui/macros/macro-in-fn.rs b/tests/ui/macros/macro-in-fn.rs new file mode 100644 index 000000000..d354fe4a7 --- /dev/null +++ b/tests/ui/macros/macro-in-fn.rs @@ -0,0 +1,8 @@ +// run-pass +#![feature(decl_macro)] + +pub fn moo() { + pub macro ABC() {{}} +} + +fn main() {} diff --git a/tests/ui/macros/macro-include-items.rs b/tests/ui/macros/macro-include-items.rs new file mode 100644 index 000000000..332bf59c9 --- /dev/null +++ b/tests/ui/macros/macro-include-items.rs @@ -0,0 +1,13 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-pretty issue #37195 + +fn bar() {} + +include!(concat!("", "", "auxiliary/", "macro-include-items-item.rs")); + +fn main() { + foo(); + assert_eq!(include!(concat!("", "auxiliary/", "macro-include-items-expr.rs")), 1_usize); +} diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs new file mode 100644 index 000000000..a8cda2307 --- /dev/null +++ b/tests/ui/macros/macro-inner-attributes.rs @@ -0,0 +1,20 @@ +#![feature(rustc_attrs)] + +macro_rules! test { ($nm:ident, + #[$a:meta], + $i:item) => (mod $nm { #![$a] $i }); } + +test!(a, + #[cfg(qux)], + pub fn bar() { }); + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }); + +#[rustc_dummy] +fn main() { + a::bar(); + //~^ ERROR failed to resolve: use of undeclared crate or module `a` + b::bar(); +} diff --git a/tests/ui/macros/macro-inner-attributes.stderr b/tests/ui/macros/macro-inner-attributes.stderr new file mode 100644 index 000000000..77b648615 --- /dev/null +++ b/tests/ui/macros/macro-inner-attributes.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `a` + --> $DIR/macro-inner-attributes.rs:17:5 + | +LL | a::bar(); + | ^ use of undeclared crate or module `a` + | +help: there is a crate or module with a similar name + | +LL | b::bar(); + | ~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/macro-input-future-proofing.rs b/tests/ui/macros/macro-input-future-proofing.rs new file mode 100644 index 000000000..9a5bdb08a --- /dev/null +++ b/tests/ui/macros/macro-input-future-proofing.rs @@ -0,0 +1,23 @@ +#![allow(unused_macros)] + +macro_rules! errors_everywhere { + ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` + ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` + ($ty:ty , ) => (); + ( ( $ty:ty ) ) => (); + ( { $ty:ty } ) => (); + ( [ $ty:ty ] ) => (); + ($bl:block < ) => (); + ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat` + ($pa:pat , ) => (); + ($pa:pat $pb:pat $ty:ty ,) => (); + //~^ ERROR `$pa:pat` is followed by `$pb:pat`, which is not allowed + //~^^ ERROR `$pb:pat` is followed by `$ty:ty`, which is not allowed + ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-` + ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-` + ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty` + ( $($a:expr)* $($b:tt)* ) => { }; + //~^ ERROR `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments +} + +fn main() { } diff --git a/tests/ui/macros/macro-input-future-proofing.stderr b/tests/ui/macros/macro-input-future-proofing.stderr new file mode 100644 index 000000000..542486927 --- /dev/null +++ b/tests/ui/macros/macro-input-future-proofing.stderr @@ -0,0 +1,74 @@ +error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments + --> $DIR/macro-input-future-proofing.rs:4:13 + | +LL | ($ty:ty <) => (); + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments + --> $DIR/macro-input-future-proofing.rs:5:13 + | +LL | ($ty:ty < foo ,) => (); + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments + --> $DIR/macro-input-future-proofing.rs:11:14 + | +LL | ($pa:pat >) => (); + | ^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments + --> $DIR/macro-input-future-proofing.rs:13:14 + | +LL | ($pa:pat $pb:pat $ty:ty ,) => (); + | ^^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments + --> $DIR/macro-input-future-proofing.rs:13:22 + | +LL | ($pa:pat $pb:pat $ty:ty ,) => (); + | ^^^^^^ not allowed after `pat` fragments + | + = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in` + +error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments + --> $DIR/macro-input-future-proofing.rs:16:17 + | +LL | ($($ty:ty)* -) => (); + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$b:ty` is followed by `-`, which is not allowed for `ty` fragments + --> $DIR/macro-input-future-proofing.rs:17:23 + | +LL | ($($a:ty, $b:ty)* -) => (); + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments + --> $DIR/macro-input-future-proofing.rs:18:15 + | +LL | ($($ty:ty)-+) => (); + | ^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments + --> $DIR/macro-input-future-proofing.rs:19:21 + | +LL | ( $($a:expr)* $($b:tt)* ) => { }; + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/macros/macro-interpolation.rs b/tests/ui/macros/macro-interpolation.rs new file mode 100644 index 000000000..35003a79a --- /dev/null +++ b/tests/ui/macros/macro-interpolation.rs @@ -0,0 +1,33 @@ +// run-pass + +macro_rules! overly_complicated { + ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) => + ({ + fn $fnname($arg: $ty) -> Option<$ty> $body + match $fnname($val) { + Some($pat) => { + $res + } + _ => { panic!(); } + } + }) + +} + +macro_rules! qpath { + (path, <$type:ty as $trait:path>::$name:ident) => { + <$type as $trait>::$name + }; + + (ty, <$type:ty as $trait:ty>::$name:ident) => { + <$type as $trait>::$name + }; +} + +pub fn main() { + let _: qpath!(path, <str as ToOwned>::Owned); + let _: qpath!(ty, <str as ToOwned>::Owned); + + assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); }, + Some(8), Some(y), y) == 8) +} diff --git a/tests/ui/macros/macro-invalid-fragment-spec.rs b/tests/ui/macros/macro-invalid-fragment-spec.rs new file mode 100644 index 000000000..dc4d75096 --- /dev/null +++ b/tests/ui/macros/macro-invalid-fragment-spec.rs @@ -0,0 +1,8 @@ +macro_rules! foo( + ($x:foo) => () + //~^ ERROR invalid fragment specifier +); + +fn main() { + foo!(foo); +} diff --git a/tests/ui/macros/macro-invalid-fragment-spec.stderr b/tests/ui/macros/macro-invalid-fragment-spec.stderr new file mode 100644 index 000000000..b04734482 --- /dev/null +++ b/tests/ui/macros/macro-invalid-fragment-spec.stderr @@ -0,0 +1,10 @@ +error: invalid fragment specifier `foo` + --> $DIR/macro-invalid-fragment-spec.rs:2:6 + | +LL | ($x:foo) => () + | ^^^^^^ + | + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs new file mode 100644 index 000000000..8f9dcb947 --- /dev/null +++ b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs @@ -0,0 +1,10 @@ +// run-pass +// pretty-expanded FIXME #23616 + +macro_rules! four { + () => (4) +} + +fn main() { + let _x: [u16; four!()]; +} diff --git a/tests/ui/macros/macro-lifetime-used-with-bound.rs b/tests/ui/macros/macro-lifetime-used-with-bound.rs new file mode 100644 index 000000000..ea3f74c9a --- /dev/null +++ b/tests/ui/macros/macro-lifetime-used-with-bound.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(unused_variables)] +macro_rules! foo { + ($l:lifetime, $l2:lifetime) => { + fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str { + arg + } + } +} + +pub fn main() { + foo!('a, 'b); + let x: &'static str = f("hi", "there"); + assert_eq!("hi", x); +} diff --git a/tests/ui/macros/macro-lifetime-used-with-labels.rs b/tests/ui/macros/macro-lifetime-used-with-labels.rs new file mode 100644 index 000000000..59017da3b --- /dev/null +++ b/tests/ui/macros/macro-lifetime-used-with-labels.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(stable_features)] +#![allow(unused_labels)] +#![allow(unreachable_code)] + +macro_rules! x { + ($a:lifetime) => { + $a: loop { + break $a; + panic!("failed"); + } + } +} +macro_rules! br { + ($a:lifetime) => { + break $a; + } +} +macro_rules! br2 { + ($b:lifetime) => { + 'b: loop { + break $b; // this $b should refer to the outer loop. + } + } +} +fn main() { + x!('a); + 'c: loop { + br!('c); + panic!("failed"); + } + 'b: loop { + br2!('b); + panic!("failed"); + } +} diff --git a/tests/ui/macros/macro-lifetime-used-with-static.rs b/tests/ui/macros/macro-lifetime-used-with-static.rs new file mode 100644 index 000000000..8552c4b81 --- /dev/null +++ b/tests/ui/macros/macro-lifetime-used-with-static.rs @@ -0,0 +1,14 @@ +// run-pass +macro_rules! foo { + ($l:lifetime) => { + fn f(arg: &$l str) -> &$l str { + arg + } + } +} + +pub fn main() { + foo!('static); + let x: &'static str = f("hi"); + assert_eq!("hi", x); +} diff --git a/tests/ui/macros/macro-lifetime.rs b/tests/ui/macros/macro-lifetime.rs new file mode 100644 index 000000000..5931fe009 --- /dev/null +++ b/tests/ui/macros/macro-lifetime.rs @@ -0,0 +1,14 @@ +// run-pass +macro_rules! foo { + ($l:lifetime) => { + fn f<$l>(arg: &$l str) -> &$l str { + arg + } + } +} + +pub fn main() { + foo!('a); + let x: &'static str = f("hi"); + assert_eq!("hi", x); +} diff --git a/tests/ui/macros/macro-literal.rs b/tests/ui/macros/macro-literal.rs new file mode 100644 index 000000000..3c2e71f9c --- /dev/null +++ b/tests/ui/macros/macro-literal.rs @@ -0,0 +1,134 @@ +// run-pass + +macro_rules! mtester { + ($l:literal) => { + &format!("macro caught literal: {}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +macro_rules! two_negative_literals { + ($l1:literal $l2:literal) => { + &format!("macro caught literals: {}, {}", $l1, $l2) + }; +} + +macro_rules! only_expr { + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +#[allow(unused_macro_rules)] +macro_rules! mtester_dbg { + ($l:literal) => { + &format!("macro caught literal: {:?}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {:?}", $e) + }; +} + +macro_rules! catch_range { + ($s:literal ..= $e:literal) => { + &format!("macro caught literal: {} ..= {}", $s, $e) + }; + (($s:expr) ..= ($e:expr)) => { // Must use ')' before '..=' + &format!("macro caught expr: {} ..= {}", $s, $e) + }; +} + +macro_rules! pat_match { + ($s:literal ..= $e:literal) => { + match 3 { + $s ..= $e => "literal, in range", + _ => "literal, other", + } + }; + ($s:pat) => { + match 3 { + $s => "pat, single", + _ => "pat, other", + } + }; +} + +macro_rules! match_attr { + (#[$attr:meta] $e:literal) => { + "attr matched literal" + }; + (#[$attr:meta] $e:expr) => { + "attr matched expr" + }; +} + +macro_rules! match_produced_attr { + ($lit: literal) => { + // Struct with doc comment passed via $literal + #[doc = $lit] + struct LiteralProduced; + }; + ($expr: expr) => { + struct ExprProduced; + }; +} + +macro_rules! test_user { + ($s:literal, $e:literal) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "literal" + } + }; + ($s:expr, $e: expr) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "expr" + } + }; +} + +pub fn main() { + // Cases where 'literal' catches + assert_eq!(mtester!("str"), "macro caught literal: str"); + assert_eq!(mtester!(2), "macro caught literal: 2"); + assert_eq!(mtester!(2.2), "macro caught literal: 2.2"); + assert_eq!(mtester!(1u32), "macro caught literal: 1"); + assert_eq!(mtester!(0x32), "macro caught literal: 50"); + assert_eq!(mtester!('c'), "macro caught literal: c"); + assert_eq!(mtester!(-1.2), "macro caught literal: -1.2"); + assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3"); + assert_eq!(catch_range!(2 ..= 3), "macro caught literal: 2 ..= 3"); + assert_eq!(match_attr!(#[attr] 1), "attr matched literal"); + assert_eq!(test_user!(10, 20), "literal"); + assert_eq!(mtester!(false), "macro caught literal: false"); + assert_eq!(mtester!(true), "macro caught literal: true"); + match_produced_attr!("a"); + let _a = LiteralProduced; + assert_eq!(pat_match!(1 ..= 3), "literal, in range"); + assert_eq!(pat_match!(4 ..= 6), "literal, other"); + + // Cases where 'expr' catches + assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2"); + assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2"); + assert_eq!(mtester!((1 + 3)), "macro caught expr: 4"); + assert_eq!(mtester_dbg!(()), "macro caught expr: ()"); + assert_eq!(catch_range!((1 + 1) ..= (2 + 2)), "macro caught expr: 2 ..= 4"); + assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr"); + assert_eq!(test_user!(10, (20 + 2)), "expr"); + + match_produced_attr!((3 + 2)); + let _b = ExprProduced; + + // Cases where 'pat' matched + assert_eq!(pat_match!(3), "pat, single"); + assert_eq!(pat_match!(6), "pat, other"); +} diff --git a/tests/ui/macros/macro-local-data-key-priv.rs b/tests/ui/macros/macro-local-data-key-priv.rs new file mode 100644 index 000000000..2e4f88f9a --- /dev/null +++ b/tests/ui/macros/macro-local-data-key-priv.rs @@ -0,0 +1,10 @@ +// check that the local data keys are private by default. + +mod bar { + thread_local!(static baz: f64 = 0.0); +} + +fn main() { + bar::baz.with(|_| ()); + //~^ ERROR `baz` is private +} diff --git a/tests/ui/macros/macro-local-data-key-priv.stderr b/tests/ui/macros/macro-local-data-key-priv.stderr new file mode 100644 index 000000000..fb8cab279 --- /dev/null +++ b/tests/ui/macros/macro-local-data-key-priv.stderr @@ -0,0 +1,16 @@ +error[E0603]: constant `baz` is private + --> $DIR/macro-local-data-key-priv.rs:8:10 + | +LL | bar::baz.with(|_| ()); + | ^^^ private constant + | +note: the constant `baz` is defined here + --> $DIR/macro-local-data-key-priv.rs:4:5 + | +LL | thread_local!(static baz: f64 = 0.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::__thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs new file mode 100644 index 000000000..5d9eb55fe --- /dev/null +++ b/tests/ui/macros/macro-match-nonterminal.rs @@ -0,0 +1,14 @@ +macro_rules! test { + ($a, $b) => { + //~^ ERROR missing fragment + //~| ERROR missing fragment + //~| ERROR missing fragment + //~| WARN this was previously accepted + //~| WARN this was previously accepted + () + }; +} + +fn main() { + test!() +} diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr new file mode 100644 index 000000000..ef7261c02 --- /dev/null +++ b/tests/ui/macros/macro-match-nonterminal.stderr @@ -0,0 +1,27 @@ +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:8 + | +LL | ($a, $b) => { + | ^ + +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:8 + | +LL | ($a, $b) => { + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + = note: `#[deny(missing_fragment_specifier)]` on by default + +error: missing fragment specifier + --> $DIR/macro-match-nonterminal.rs:2:10 + | +LL | ($a, $b) => { + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/macro-meta-items-modern.rs b/tests/ui/macros/macro-meta-items-modern.rs new file mode 100644 index 000000000..bc6938d4a --- /dev/null +++ b/tests/ui/macros/macro-meta-items-modern.rs @@ -0,0 +1,11 @@ +// check-pass + +macro_rules! check { ($meta:meta) => () } + +check!(meta(a b c d)); +check!(meta[a b c d]); +check!(meta { a b c d }); +check!(meta); +check!(meta = 0); + +fn main() {} diff --git a/tests/ui/macros/macro-meta-items.rs b/tests/ui/macros/macro-meta-items.rs new file mode 100644 index 000000000..4cbc252ae --- /dev/null +++ b/tests/ui/macros/macro-meta-items.rs @@ -0,0 +1,31 @@ +// run-pass +#![allow(dead_code)] +// compile-flags: --cfg foo + +macro_rules! compiles_fine { + ($at:meta) => { + #[cfg($at)] + static MISTYPED: () = "foo"; + } +} +macro_rules! emit { + ($at:meta) => { + #[cfg($at)] + static MISTYPED: &'static str = "foo"; + } +} + +// item +compiles_fine!(bar); +emit!(foo); + +fn foo() { + println!("{}", MISTYPED); +} + +pub fn main() { + // statement + compiles_fine!(baz); + emit!(baz); + println!("{}", MISTYPED); +} diff --git a/tests/ui/macros/macro-method-issue-4621.rs b/tests/ui/macros/macro-method-issue-4621.rs new file mode 100644 index 000000000..342fad5f6 --- /dev/null +++ b/tests/ui/macros/macro-method-issue-4621.rs @@ -0,0 +1,10 @@ +// run-pass + +struct A; + +macro_rules! make_thirteen_method {() => (fn thirteen(&self)->isize {13})} +impl A { make_thirteen_method!(); } + +fn main() { + assert_eq!(A.thirteen(),13); +} diff --git a/tests/ui/macros/macro-missing-delimiters.rs b/tests/ui/macros/macro-missing-delimiters.rs new file mode 100644 index 000000000..290d7615e --- /dev/null +++ b/tests/ui/macros/macro-missing-delimiters.rs @@ -0,0 +1,7 @@ +macro_rules! baz( + baz => () //~ ERROR invalid macro matcher; +); + +fn main() { + baz!(baz); +} diff --git a/tests/ui/macros/macro-missing-delimiters.stderr b/tests/ui/macros/macro-missing-delimiters.stderr new file mode 100644 index 000000000..e7c37c8dd --- /dev/null +++ b/tests/ui/macros/macro-missing-delimiters.stderr @@ -0,0 +1,8 @@ +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/macro-missing-delimiters.rs:2:5 + | +LL | baz => () + | ^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs new file mode 100644 index 000000000..c1e6ba746 --- /dev/null +++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zdeduplicate-diagnostics=yes + +macro_rules! m { + ($name) => {} + //~^ ERROR missing fragment + //~| ERROR missing fragment + //~| WARN this was previously accepted +} + +fn main() { + m!(); + m!(); + m!(); + m!(); +} diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr new file mode 100644 index 000000000..3b9e716e1 --- /dev/null +++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr @@ -0,0 +1,18 @@ +error: missing fragment specifier + --> $DIR/macro-missing-fragment-deduplication.rs:4:6 + | +LL | ($name) => {} + | ^^^^^ + +error: missing fragment specifier + --> $DIR/macro-missing-fragment-deduplication.rs:4:6 + | +LL | ($name) => {} + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs new file mode 100644 index 000000000..210c85ebb --- /dev/null +++ b/tests/ui/macros/macro-missing-fragment.rs @@ -0,0 +1,26 @@ +#![warn(missing_fragment_specifier)] + +macro_rules! used_arm { + ( $( any_token $field_rust_type )* ) => {}; + //~^ ERROR missing fragment + //~| WARN missing fragment + //~| WARN this was previously accepted +} + +macro_rules! used_macro_unused_arm { + () => {}; + ( $name ) => {}; + //~^ WARN missing fragment + //~| WARN this was previously accepted +} + +macro_rules! unused_macro { + ( $name ) => {}; + //~^ WARN missing fragment + //~| WARN this was previously accepted +} + +fn main() { + used_arm!(); + used_macro_unused_arm!(); +} diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr new file mode 100644 index 000000000..2aa1e58f6 --- /dev/null +++ b/tests/ui/macros/macro-missing-fragment.stderr @@ -0,0 +1,40 @@ +error: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:4:20 + | +LL | ( $( any_token $field_rust_type )* ) => {}; + | ^^^^^^^^^^^^^^^^ + +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:4:20 + | +LL | ( $( any_token $field_rust_type )* ) => {}; + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> +note: the lint level is defined here + --> $DIR/macro-missing-fragment.rs:1:9 + | +LL | #![warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:12:7 + | +LL | ( $name ) => {}; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + +warning: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:18:7 + | +LL | ( $name ) => {}; + | ^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + +error: aborting due to previous error; 3 warnings emitted + diff --git a/tests/ui/macros/macro-multiple-items.rs b/tests/ui/macros/macro-multiple-items.rs new file mode 100644 index 000000000..3b6dfd9bc --- /dev/null +++ b/tests/ui/macros/macro-multiple-items.rs @@ -0,0 +1,16 @@ +// run-pass +macro_rules! make_foo { + () => ( + struct Foo; + + impl Foo { + fn bar(&self) {} + } + ) +} + +make_foo!(); + +pub fn main() { + Foo.bar() +} diff --git a/tests/ui/macros/macro-multiple-matcher-bindings.rs b/tests/ui/macros/macro-multiple-matcher-bindings.rs new file mode 100644 index 000000000..7d39dc0a5 --- /dev/null +++ b/tests/ui/macros/macro-multiple-matcher-bindings.rs @@ -0,0 +1,21 @@ +// Test that duplicate matcher binding names are caught at declaration time, rather than at macro +// invocation time. + +#![allow(unused_macros)] + +macro_rules! foo1 { + ($a:ident, $a:ident) => {}; //~ERROR duplicate matcher binding + ($a:ident, $a:path) => {}; //~ERROR duplicate matcher binding +} + +macro_rules! foo2 { + ($a:ident) => {}; // OK + ($a:path) => {}; // OK +} + +macro_rules! foo3 { + ($a:ident, $($a:ident),*) => {}; //~ERROR duplicate matcher binding + ($($a:ident)+ # $($($a:path),+);*) => {}; //~ERROR duplicate matcher binding +} + +fn main() {} diff --git a/tests/ui/macros/macro-multiple-matcher-bindings.stderr b/tests/ui/macros/macro-multiple-matcher-bindings.stderr new file mode 100644 index 000000000..3ad1297ff --- /dev/null +++ b/tests/ui/macros/macro-multiple-matcher-bindings.stderr @@ -0,0 +1,34 @@ +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:7:16 + | +LL | ($a:ident, $a:ident) => {}; + | -------- ^^^^^^^^ duplicate binding + | | + | previous binding + +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:8:16 + | +LL | ($a:ident, $a:path) => {}; + | -------- ^^^^^^^ duplicate binding + | | + | previous binding + +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:17:18 + | +LL | ($a:ident, $($a:ident),*) => {}; + | -------- ^^^^^^^^ duplicate binding + | | + | previous binding + +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:18:25 + | +LL | ($($a:ident)+ # $($($a:path),+);*) => {}; + | -------- ^^^^^^^ duplicate binding + | | + | previous binding + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/macro-name-typo.rs b/tests/ui/macros/macro-name-typo.rs new file mode 100644 index 000000000..1ddc419d3 --- /dev/null +++ b/tests/ui/macros/macro-name-typo.rs @@ -0,0 +1,3 @@ +fn main() { + printlx!("oh noes!"); //~ ERROR cannot find +} diff --git a/tests/ui/macros/macro-name-typo.stderr b/tests/ui/macros/macro-name-typo.stderr new file mode 100644 index 000000000..d7c8aaae2 --- /dev/null +++ b/tests/ui/macros/macro-name-typo.stderr @@ -0,0 +1,11 @@ +error: cannot find macro `printlx` in this scope + --> $DIR/macro-name-typo.rs:2:5 + | +LL | printlx!("oh noes!"); + | ^^^^^^^ help: a macro with a similar name exists: `println` + --> $SRC_DIR/std/src/macros.rs:LL:COL + | + = note: similarly named macro `println` defined here + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-named-default.rs b/tests/ui/macros/macro-named-default.rs new file mode 100644 index 000000000..9b6cd1916 --- /dev/null +++ b/tests/ui/macros/macro-named-default.rs @@ -0,0 +1,18 @@ +// run-pass +macro_rules! default { + ($($x:tt)*) => { $($x)* } +} + +default! { + struct A; +} + +impl A { + default! { + fn foo(&self) {} + } +} + +fn main() { + A.foo(); +} diff --git a/tests/ui/macros/macro-nested_definition_issue-31946.rs b/tests/ui/macros/macro-nested_definition_issue-31946.rs new file mode 100644 index 000000000..a83c5b2e4 --- /dev/null +++ b/tests/ui/macros/macro-nested_definition_issue-31946.rs @@ -0,0 +1,9 @@ +// run-pass +fn main() { + println!("{}", { + macro_rules! foo { + ($name:expr) => { concat!("hello ", $name) } + } + foo!("rust") + }); +} diff --git a/tests/ui/macros/macro-nested_expr.rs b/tests/ui/macros/macro-nested_expr.rs new file mode 100644 index 000000000..f1433cbf4 --- /dev/null +++ b/tests/ui/macros/macro-nested_expr.rs @@ -0,0 +1,22 @@ +// run-pass +// #42164 + +#![feature(decl_macro)] +#![allow(dead_code)] + +pub macro m($inner_str:expr) { + #[doc = $inner_str] + struct S; +} + +macro_rules! define_f { + ($name:expr) => { + #[export_name = $name] + fn f() {} + } +} + +fn main() { + define_f!(concat!("exported_", "f")); + m!(stringify!(foo)); +} diff --git a/tests/ui/macros/macro-nested_stmt_macros.rs b/tests/ui/macros/macro-nested_stmt_macros.rs new file mode 100644 index 000000000..5d4758a0c --- /dev/null +++ b/tests/ui/macros/macro-nested_stmt_macros.rs @@ -0,0 +1,23 @@ +// run-pass +macro_rules! foo { + () => { + struct Bar; + struct Baz; + } +} + +macro_rules! grault { + () => { + foo!(); + struct Xyzzy; + } +} + +fn static_assert_exists<T>() { } + +fn main() { + grault!(); + static_assert_exists::<Bar>(); + static_assert_exists::<Baz>(); + static_assert_exists::<Xyzzy>(); +} diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs new file mode 100644 index 000000000..26e1f2afa --- /dev/null +++ b/tests/ui/macros/macro-non-lifetime.rs @@ -0,0 +1,8 @@ +// Test for issue #50381: non-lifetime passed to :lifetime. + +macro_rules! m { ($x:lifetime) => { } } + +fn main() { + m!(a); + //~^ ERROR no rules expected the token `a` +} diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr new file mode 100644 index 000000000..e1ed87f94 --- /dev/null +++ b/tests/ui/macros/macro-non-lifetime.stderr @@ -0,0 +1,17 @@ +error: no rules expected the token `a` + --> $DIR/macro-non-lifetime.rs:6:8 + | +LL | macro_rules! m { ($x:lifetime) => { } } + | -------------- when calling this macro +... +LL | m!(a); + | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$x:lifetime` + --> $DIR/macro-non-lifetime.rs:3:19 + | +LL | macro_rules! m { ($x:lifetime) => { } } + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-nt-list.rs b/tests/ui/macros/macro-nt-list.rs new file mode 100644 index 000000000..36aa74f08 --- /dev/null +++ b/tests/ui/macros/macro-nt-list.rs @@ -0,0 +1,21 @@ +// run-pass +// pretty-expanded FIXME #23616 + +macro_rules! list { + ( ($($id:ident),*) ) => (()); + ( [$($id:ident),*] ) => (()); + ( {$($id:ident),*} ) => (()); +} + +macro_rules! tt_list { + ( ($($tt:tt),*) ) => (()); +} + +pub fn main() { + list!( () ); + list!( [] ); + list!( {} ); + + tt_list!( (a, b, c) ); + tt_list!( () ); +} diff --git a/tests/ui/macros/macro-of-higher-order.rs b/tests/ui/macros/macro-of-higher-order.rs new file mode 100644 index 000000000..ec551d6cd --- /dev/null +++ b/tests/ui/macros/macro-of-higher-order.rs @@ -0,0 +1,22 @@ +// run-pass + +macro_rules! higher_order { + (subst $lhs:tt => $rhs:tt) => ({ + macro_rules! anon { $lhs => $rhs } + anon!(1_usize, 2_usize, "foo") + }); +} + +macro_rules! outer { + ($x:expr; $fragment:ident) => { + macro_rules! inner { ($y:$fragment) => { $x + $y } } + } +} + +fn main() { + let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo))); + assert_eq!(val, (3, "foo")); + + outer!(2; expr); + assert_eq!(inner!(3), 5); +} diff --git a/tests/ui/macros/macro-or-patterns-back-compat.fixed b/tests/ui/macros/macro-or-patterns-back-compat.fixed new file mode 100644 index 000000000..b0d56e9bb --- /dev/null +++ b/tests/ui/macros/macro-or-patterns-back-compat.fixed @@ -0,0 +1,39 @@ +// run-rustfix +// aux-build:or-pattern.rs + +#![deny(rust_2021_incompatible_or_patterns)] +#![allow(unused_macros)] + +#[macro_use] +extern crate or_pattern; + +macro_rules! foo { ($x:pat_param | $y:pat) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition +macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition + +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat_param )|+ => $expr_arm:expr ),+ ) => { + //~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + //~| WARN this is accepted in the current edition + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); + a!(1|); +} diff --git a/tests/ui/macros/macro-or-patterns-back-compat.rs b/tests/ui/macros/macro-or-patterns-back-compat.rs new file mode 100644 index 000000000..9e24b5106 --- /dev/null +++ b/tests/ui/macros/macro-or-patterns-back-compat.rs @@ -0,0 +1,39 @@ +// run-rustfix +// aux-build:or-pattern.rs + +#![deny(rust_2021_incompatible_or_patterns)] +#![allow(unused_macros)] + +#[macro_use] +extern crate or_pattern; + +macro_rules! foo { ($x:pat | $y:pat) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition +macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition + +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat | $y:pat_param) => {} } +//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +//~| WARN this is accepted in the current edition +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { + //~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + //~| WARN this is accepted in the current edition + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); + a!(1|); +} diff --git a/tests/ui/macros/macro-or-patterns-back-compat.stderr b/tests/ui/macros/macro-or-patterns-back-compat.stderr new file mode 100644 index 000000000..e04dfefa4 --- /dev/null +++ b/tests/ui/macros/macro-or-patterns-back-compat.stderr @@ -0,0 +1,43 @@ +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:10:21 + | +LL | macro_rules! foo { ($x:pat | $y:pat) => {} } + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html> +note: the lint level is defined here + --> $DIR/macro-or-patterns-back-compat.rs:4:9 + | +LL | #![deny(rust_2021_incompatible_or_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:13:23 + | +LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html> + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:19:21 + | +LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html> + +error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + --> $DIR/macro-or-patterns-back-compat.rs:23:26 + | +LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { + | ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html> + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs new file mode 100644 index 000000000..0752f7e31 --- /dev/null +++ b/tests/ui/macros/macro-outer-attributes.rs @@ -0,0 +1,20 @@ +#![feature(rustc_attrs)] + +macro_rules! test { ($nm:ident, + #[$a:meta], + $i:item) => (mod $nm { #[$a] $i }); } + +test!(a, + #[cfg(qux)], + pub fn bar() { }); + +test!(b, + #[cfg(not(qux))], + pub fn bar() { }); + +// test1!(#[bar]) +#[rustc_dummy] +fn main() { + a::bar(); //~ ERROR cannot find function `bar` in module `a` + b::bar(); +} diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr new file mode 100644 index 000000000..4ea760ab8 --- /dev/null +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -0,0 +1,19 @@ +error[E0425]: cannot find function `bar` in module `a` + --> $DIR/macro-outer-attributes.rs:18:8 + | +LL | a::bar(); + | ^^^ not found in `a` + | +help: consider importing this function + | +LL | use b::bar; + | +help: if you import `bar`, refer to it directly + | +LL - a::bar(); +LL + bar(); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-parameter-span.rs b/tests/ui/macros/macro-parameter-span.rs new file mode 100644 index 000000000..5609f84e1 --- /dev/null +++ b/tests/ui/macros/macro-parameter-span.rs @@ -0,0 +1,13 @@ +macro_rules! foo { + ($id: ident) => { + $id + } +} + +// Testing that the error span points to the parameter 'x' in the callsite, +// not to the macro variable '$id' +fn main() { + foo!( + x //~ ERROR cannot find value `x` in this scope + ); +} diff --git a/tests/ui/macros/macro-parameter-span.stderr b/tests/ui/macros/macro-parameter-span.stderr new file mode 100644 index 000000000..24e3e89ea --- /dev/null +++ b/tests/ui/macros/macro-parameter-span.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/macro-parameter-span.rs:11:9 + | +LL | x + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-pat-follow-2018.rs b/tests/ui/macros/macro-pat-follow-2018.rs new file mode 100644 index 000000000..ce2911de9 --- /dev/null +++ b/tests/ui/macros/macro-pat-follow-2018.rs @@ -0,0 +1,15 @@ +// run-pass +// edition:2018 + +macro_rules! pat_bar { + ($p:pat | $p2:pat) => {{ + match Some(1u8) { + $p | $p2 => {} + _ => {} + } + }}; +} + +fn main() { + pat_bar!(Some(1u8) | None); +} diff --git a/tests/ui/macros/macro-pat-follow.rs b/tests/ui/macros/macro-pat-follow.rs new file mode 100644 index 000000000..8e02789fd --- /dev/null +++ b/tests/ui/macros/macro-pat-follow.rs @@ -0,0 +1,21 @@ +// run-pass +macro_rules! pat_in { + ($p:pat in $e:expr) => {{ + let mut iter = $e.into_iter(); + while let $p = iter.next() {} + }}; +} + +macro_rules! pat_if { + ($p:pat if $e:expr) => {{ + match Some(1u8) { + $p if $e => {} + _ => {} + } + }}; +} + +fn main() { + pat_in!(Some(_) in 0..10); + pat_if!(Some(x) if x > 0); +} diff --git a/tests/ui/macros/macro-pat-neg-lit.rs b/tests/ui/macros/macro-pat-neg-lit.rs new file mode 100644 index 000000000..79c68fd25 --- /dev/null +++ b/tests/ui/macros/macro-pat-neg-lit.rs @@ -0,0 +1,25 @@ +// run-pass +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* + _ => None + } + } + } +} + +enum_number!(Change { + Down = -1, + None = 0, + Up = 1, +}); + +fn main() { + if let Some(Change::Down) = foo(-1) {} else { panic!() } +} diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs new file mode 100644 index 000000000..f5a97eca2 --- /dev/null +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs @@ -0,0 +1,20 @@ +// edition:2021 +#![allow(unused_macros)] +macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments +macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments +macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); +} diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr new file mode 100644 index 000000000..a06487be3 --- /dev/null +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr @@ -0,0 +1,32 @@ +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28 + | +LL | macro_rules! foo { ($x:pat | $y:pat) => {} } + | ------ ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$x:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32 + | +LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } + | ------ ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$x:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36 + | +LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { + | -------- ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs new file mode 100644 index 000000000..54bd13d7e --- /dev/null +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(unused_macros)] +macro_rules! foo { ($x:pat | $y:pat) => {} } // should be ok +macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } // should be ok +macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { // should be ok + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); +} diff --git a/tests/ui/macros/macro-pat.rs b/tests/ui/macros/macro-pat.rs new file mode 100644 index 000000000..baf816e53 --- /dev/null +++ b/tests/ui/macros/macro-pat.rs @@ -0,0 +1,65 @@ +// run-pass + +macro_rules! mypat { + () => ( + Some('y') + ) +} + +macro_rules! char_x { + () => ( + 'x' + ) +} + +macro_rules! some { + ($x:pat) => ( + Some($x) + ) +} + +macro_rules! indirect { + () => ( + some!(char_x!()) + ) +} + +macro_rules! ident_pat { + ($x:ident) => ( + $x + ) +} + +fn f(c: Option<char>) -> usize { + match c { + Some('x') => 1, + mypat!() => 2, + _ => 3, + } +} + +pub fn main() { + assert_eq!(1, f(Some('x'))); + assert_eq!(2, f(Some('y'))); + assert_eq!(3, f(None)); + + assert_eq!(1, match Some('x') { + Some(char_x!()) => 1, + _ => 2, + }); + + assert_eq!(1, match Some('x') { + some!(char_x!()) => 1, + _ => 2, + }); + + assert_eq!(1, match Some('x') { + indirect!() => 1, + _ => 2, + }); + + assert_eq!(3, { + let ident_pat!(x) = 2; + x+1 + }); +} diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs new file mode 100644 index 000000000..b4be03aad --- /dev/null +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs @@ -0,0 +1,22 @@ +// edition:2021 + +#![allow(unused_macros)] +macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments +macro_rules! match_any { + ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments + match $expr { + $( + $( $pat => $expr_arm, )+ + )+ + } + }; +} + +fn main() { + let result: Result<i64, i32> = Err(42); + let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into()); + assert_eq!(int, 42); +} diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr new file mode 100644 index 000000000..c3754dde0 --- /dev/null +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr @@ -0,0 +1,32 @@ +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28 + | +LL | macro_rules! foo { ($x:pat | $y:pat) => {} } + | ------ ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$x:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28 + | +LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } + | ------ ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$x:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35 + | +LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { + | -------- ^ not allowed after `pat` fragments + | | + | help: try a `pat_param` fragment specifier instead: `$pat:pat_param` + | + = note: allowed there are: `=>`, `,`, `=`, `if` or `in` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/macro-path-prelude-fail-1.rs b/tests/ui/macros/macro-path-prelude-fail-1.rs new file mode 100644 index 000000000..d93792bdf --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-1.rs @@ -0,0 +1,8 @@ +mod m { + fn check() { + Vec::clone!(); //~ ERROR failed to resolve: `Vec` is a struct, not a module + u8::clone!(); //~ ERROR failed to resolve: `u8` is a builtin type, not a module + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-fail-1.stderr b/tests/ui/macros/macro-path-prelude-fail-1.stderr new file mode 100644 index 000000000..f8377ffb3 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-1.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: `Vec` is a struct, not a module + --> $DIR/macro-path-prelude-fail-1.rs:3:9 + | +LL | Vec::clone!(); + | ^^^ `Vec` is a struct, not a module + +error[E0433]: failed to resolve: `u8` is a builtin type, not a module + --> $DIR/macro-path-prelude-fail-1.rs:4:9 + | +LL | u8::clone!(); + | ^^ `u8` is a builtin type, not a module + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/macro-path-prelude-fail-2.rs b/tests/ui/macros/macro-path-prelude-fail-2.rs new file mode 100644 index 000000000..816a3c4cc --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-2.rs @@ -0,0 +1,7 @@ +mod m { + fn check() { + Result::Ok!(); //~ ERROR failed to resolve: partially resolved path in a macro + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-fail-2.stderr b/tests/ui/macros/macro-path-prelude-fail-2.stderr new file mode 100644 index 000000000..9574b7a1e --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-2.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: partially resolved path in a macro + --> $DIR/macro-path-prelude-fail-2.rs:3:9 + | +LL | Result::Ok!(); + | ^^^^^^^^^^ partially resolved path in a macro + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/macro-path-prelude-fail-3.rs b/tests/ui/macros/macro-path-prelude-fail-3.rs new file mode 100644 index 000000000..68eb350a9 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-3.rs @@ -0,0 +1,3 @@ +fn main() { + inline!(); //~ ERROR cannot find macro `inline` in this scope +} diff --git a/tests/ui/macros/macro-path-prelude-fail-3.stderr b/tests/ui/macros/macro-path-prelude-fail-3.stderr new file mode 100644 index 000000000..f1c3512bc --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-3.stderr @@ -0,0 +1,13 @@ +error: cannot find macro `inline` in this scope + --> $DIR/macro-path-prelude-fail-3.rs:2:5 + | +LL | inline!(); + | ^^^^^^ help: a macro with a similar name exists: `line` + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | + = note: similarly named macro `line` defined here + | + = note: `inline` is in scope, but it is an attribute: `#[inline]` + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-path-prelude-fail-4.rs b/tests/ui/macros/macro-path-prelude-fail-4.rs new file mode 100644 index 000000000..0f93fcdaa --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-4.rs @@ -0,0 +1,4 @@ +#[derive(inline)] //~ ERROR expected derive macro, found built-in attribute `inline` +struct S; + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr new file mode 100644 index 000000000..dfd6818b6 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr @@ -0,0 +1,8 @@ +error: expected derive macro, found built-in attribute `inline` + --> $DIR/macro-path-prelude-fail-4.rs:1:10 + | +LL | #[derive(inline)] + | ^^^^^^ not a derive macro + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-path-prelude-pass.rs b/tests/ui/macros/macro-path-prelude-pass.rs new file mode 100644 index 000000000..7cf346286 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-pass.rs @@ -0,0 +1,9 @@ +// check-pass + +mod m { + fn check() { + std::panic!(); // OK + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-shadowing.rs b/tests/ui/macros/macro-path-prelude-shadowing.rs new file mode 100644 index 000000000..d71812000 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-shadowing.rs @@ -0,0 +1,33 @@ +// aux-build:macro-in-other-crate.rs + +#![feature(decl_macro)] + +macro_rules! add_macro_expanded_things_to_macro_prelude {() => { + #[macro_use] + extern crate macro_in_other_crate; +}} + +add_macro_expanded_things_to_macro_prelude!(); + +mod m1 { + fn check() { + inline!(); // OK. Theoretically ambiguous, but we do not consider built-in attributes + // as candidates for non-attribute macro invocations to avoid regressions + // on stable channel + } +} + +mod m2 { + pub mod std { + pub macro panic() {} + } +} + +mod m3 { + use m2::*; // glob-import user-defined `std` + fn check() { + std::panic!(); //~ ERROR `std` is ambiguous + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-path-prelude-shadowing.stderr b/tests/ui/macros/macro-path-prelude-shadowing.stderr new file mode 100644 index 000000000..4a864c2e9 --- /dev/null +++ b/tests/ui/macros/macro-path-prelude-shadowing.stderr @@ -0,0 +1,19 @@ +error[E0659]: `std` is ambiguous + --> $DIR/macro-path-prelude-shadowing.rs:29:9 + | +LL | std::panic!(); + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution + = note: `std` could refer to a built-in crate +note: `std` could also refer to the module imported here + --> $DIR/macro-path-prelude-shadowing.rs:27:9 + | +LL | use m2::*; // glob-import user-defined `std` + | ^^^^^ + = help: consider adding an explicit import of `std` to disambiguate + = help: or use `self::std` to refer to this module unambiguously + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/macro-path.rs b/tests/ui/macros/macro-path.rs new file mode 100644 index 000000000..6c011c897 --- /dev/null +++ b/tests/ui/macros/macro-path.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(non_camel_case_types)] + + +mod m { + pub type t = isize; +} + +macro_rules! foo { + ($p:path) => ({ + fn f() -> $p { 10 } + f() + }) +} + +pub fn main() { + assert_eq!(foo!(m::t), 10); +} diff --git a/tests/ui/macros/macro-pub-matcher.rs b/tests/ui/macros/macro-pub-matcher.rs new file mode 100644 index 000000000..7b02a70be --- /dev/null +++ b/tests/ui/macros/macro-pub-matcher.rs @@ -0,0 +1,117 @@ +// run-pass +#![allow(dead_code, unused_imports, unused_macro_rules)] + +/** +Ensure that `:vis` matches can be captured in existing positions, and passed +through without the need for reparse tricks. +*/ +macro_rules! vis_passthru { + ($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; }; + ($vis:vis enum $name:ident {}) => { $vis struct $name {} }; + ($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} }; + ($vis:vis fn $name:ident() {}) => { $vis fn $name() {} }; + ($vis:vis mod $name:ident {}) => { $vis mod $name {} }; + ($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; }; + ($vis:vis struct $name:ident;) => { $vis struct $name; }; + ($vis:vis trait $name:ident {}) => { $vis trait $name {} }; + ($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; }; + ($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; }; +} + +mod with_pub { + vis_passthru! { pub const A: i32 = 0; } + vis_passthru! { pub enum B {} } + vis_passthru! { pub extern "C" fn c() {} } + vis_passthru! { pub mod d {} } + vis_passthru! { pub static E: i32 = 0; } + vis_passthru! { pub struct F; } + vis_passthru! { pub trait G {} } + vis_passthru! { pub type H = i32; } + vis_passthru! { pub use A as I; } +} + +mod without_pub { + vis_passthru! { const A: i32 = 0; } + vis_passthru! { enum B {} } + vis_passthru! { extern "C" fn c() {} } + vis_passthru! { mod d {} } + vis_passthru! { static E: i32 = 0; } + vis_passthru! { struct F; } + vis_passthru! { trait G {} } + vis_passthru! { type H = i32; } + vis_passthru! { use A as I; } +} + +mod with_pub_restricted { + vis_passthru! { pub(crate) const A: i32 = 0; } + vis_passthru! { pub(crate) enum B {} } + vis_passthru! { pub(crate) extern "C" fn c() {} } + vis_passthru! { pub(crate) mod d {} } + vis_passthru! { pub(crate) static E: i32 = 0; } + vis_passthru! { pub(crate) struct F; } + vis_passthru! { pub(crate) trait G {} } + vis_passthru! { pub(crate) type H = i32; } + vis_passthru! { pub(crate) use A as I; } +} + +mod with_crate { + vis_passthru! { pub(crate) const A: i32 = 0; } + vis_passthru! { pub(crate) enum B {} } + vis_passthru! { pub(crate) extern "C" fn c() {} } + vis_passthru! { pub(crate) mod d {} } + vis_passthru! { pub(crate) static E: i32 = 0; } + vis_passthru! { pub(crate) struct F; } + vis_passthru! { pub(crate) trait G {} } + vis_passthru! { pub(crate) type H = i32; } + vis_passthru! { pub(crate) use A as I; } +} + +mod garden { + mod with_pub_restricted_path { + vis_passthru! { pub(in garden) const A: i32 = 0; } + vis_passthru! { pub(in garden) enum B {} } + vis_passthru! { pub(in garden) extern "C" fn c() {} } + vis_passthru! { pub(in garden) mod d {} } + vis_passthru! { pub(in garden) static E: i32 = 0; } + vis_passthru! { pub(in garden) struct F; } + vis_passthru! { pub(in garden) trait G {} } + vis_passthru! { pub(in garden) type H = i32; } + vis_passthru! { pub(in garden) use A as I; } + } +} + +/* +Ensure that the `:vis` matcher works in a more complex situation: parsing a +struct definition. +*/ +macro_rules! vis_parse_struct { + ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, $vis, $name, $($body)* } + }; + + ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, $vis, $name, $($body)* } + }; + + (@parse_fields + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* } + }; + + (@parse_tuple + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* ); + }; +} + +mod test_struct { + vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } } + vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } } + vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } } + + vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); } + vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); } + vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); } +} + +fn main() {} diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs new file mode 100644 index 000000000..874c94d08 --- /dev/null +++ b/tests/ui/macros/macro-reexport-removed.rs @@ -0,0 +1,8 @@ +// aux-build:two_macros.rs + +#![feature(macro_reexport)] //~ ERROR feature has been removed + +#[macro_reexport(macro_one)] //~ ERROR cannot find attribute `macro_reexport` in this scope +extern crate two_macros; + +fn main() {} diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr new file mode 100644 index 000000000..475a586dd --- /dev/null +++ b/tests/ui/macros/macro-reexport-removed.stderr @@ -0,0 +1,17 @@ +error[E0557]: feature has been removed + --> $DIR/macro-reexport-removed.rs:3:12 + | +LL | #![feature(macro_reexport)] + | ^^^^^^^^^^^^^^ feature has been removed + | + = note: subsumed by `pub use` + +error: cannot find attribute `macro_reexport` in this scope + --> $DIR/macro-reexport-removed.rs:5:3 + | +LL | #[macro_reexport(macro_one)] + | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0557`. diff --git a/tests/ui/macros/macro-seq-followed-by-seq.rs b/tests/ui/macros/macro-seq-followed-by-seq.rs new file mode 100644 index 000000000..8f0f4fd4a --- /dev/null +++ b/tests/ui/macros/macro-seq-followed-by-seq.rs @@ -0,0 +1,17 @@ +// run-pass +// Test of allowing two sequences repetitions in a row, +// functionality added as byproduct of RFC amendment #1384 +// https://github.com/rust-lang/rfcs/pull/1384 + +// Old version of Rust would reject this macro definition, even though +// there are no local ambiguities (the initial `banana` and `orange` +// tokens are enough for the expander to distinguish which case is +// intended). +macro_rules! foo { + ( $(banana $a:ident)* $(orange $b:tt)* ) => { }; +} + +fn main() { + foo!( banana id1 banana id2 + orange hi orange (hello world) ); +} diff --git a/tests/ui/macros/macro-shadowing-relaxed.rs b/tests/ui/macros/macro-shadowing-relaxed.rs new file mode 100644 index 000000000..b2a639218 --- /dev/null +++ b/tests/ui/macros/macro-shadowing-relaxed.rs @@ -0,0 +1,25 @@ +// build-pass (FIXME(62277): could be check-pass?) +// aux-build:macro-in-other-crate.rs + +#![feature(decl_macro)] + +macro_rules! my_include {() => { + // Outer + macro m() {} + #[macro_use(from_prelude)] extern crate macro_in_other_crate; + + fn inner() { + // Inner + macro m() {} + macro_rules! from_prelude { () => {} } + + // OK, both `m` and `from_prelude` are macro-expanded, + // but no more macro-expanded than their counterpart from outer scope. + m!(); + from_prelude!(); + } +}} + +my_include!(); + +fn main() {} diff --git a/tests/ui/macros/macro-shadowing.rs b/tests/ui/macros/macro-shadowing.rs new file mode 100644 index 000000000..7f956dd7d --- /dev/null +++ b/tests/ui/macros/macro-shadowing.rs @@ -0,0 +1,26 @@ +// aux-build:two_macros.rs + +#![allow(unused_macros)] + +macro_rules! foo { () => {} } +macro_rules! macro_one { () => {} } +#[macro_use(macro_two)] extern crate two_macros; + +macro_rules! m1 { () => { + macro_rules! foo { () => {} } + + #[macro_use] //~ ERROR `macro_two` is already in scope + extern crate two_macros as __; +}} +m1!(); + +foo!(); //~ ERROR `foo` is ambiguous + +macro_rules! m2 { () => { + macro_rules! foo { () => {} } + foo!(); +}} +m2!(); +//^ Since `foo` is not used outside this expansion, it is not a shadowing error. + +fn main() {} diff --git a/tests/ui/macros/macro-shadowing.stderr b/tests/ui/macros/macro-shadowing.stderr new file mode 100644 index 000000000..a052b43ac --- /dev/null +++ b/tests/ui/macros/macro-shadowing.stderr @@ -0,0 +1,37 @@ +error: `macro_two` is already in scope + --> $DIR/macro-shadowing.rs:12:5 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ +... +LL | m1!(); + | ----- in this macro invocation + | + = note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560) + = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `foo` is ambiguous + --> $DIR/macro-shadowing.rs:17:1 + | +LL | foo!(); + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `foo` could refer to the macro defined here + --> $DIR/macro-shadowing.rs:10:5 + | +LL | macro_rules! foo { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m1!(); + | ----- in this macro invocation +note: `foo` could also refer to the macro defined here + --> $DIR/macro-shadowing.rs:5:1 + | +LL | macro_rules! foo { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/macro-stability-rpass.rs b/tests/ui/macros/macro-stability-rpass.rs new file mode 100644 index 000000000..2d02b9528 --- /dev/null +++ b/tests/ui/macros/macro-stability-rpass.rs @@ -0,0 +1,15 @@ +// run-pass +// aux-build:unstable-macros.rs + +#![unstable(feature = "one_two_three_testing", issue = "none")] +#![feature(staged_api, unstable_macros, local_unstable)] + +#[macro_use] extern crate unstable_macros; + +#[unstable(feature = "local_unstable", issue = "none")] +macro_rules! local_unstable { () => () } + +fn main() { + unstable_macro!(); + local_unstable!(); +} diff --git a/tests/ui/macros/macro-stability.rs b/tests/ui/macros/macro-stability.rs new file mode 100644 index 000000000..ed7618a67 --- /dev/null +++ b/tests/ui/macros/macro-stability.rs @@ -0,0 +1,31 @@ +// aux-build:unstable-macros.rs + +#![feature(decl_macro)] +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[macro_use] +extern crate unstable_macros; + +#[unstable(feature = "local_unstable", issue = "none")] +macro_rules! local_unstable { () => () } + +#[unstable(feature = "local_unstable", issue = "none")] +macro local_unstable_modern() {} + +#[stable(feature = "deprecated_macros", since = "1.0.0")] +#[deprecated(since = "1.0.0", note = "local deprecation note")] +#[macro_export] +macro_rules! local_deprecated{ () => () } + +fn main() { + local_unstable!(); //~ ERROR use of unstable library feature 'local_unstable' + local_unstable_modern!(); //~ ERROR use of unstable library feature 'local_unstable' + unstable_macro!(); //~ ERROR use of unstable library feature 'unstable_macros' + // unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros' + + deprecated_macro!(); + //~^ WARN use of deprecated macro `deprecated_macro`: deprecation note + local_deprecated!(); + //~^ WARN use of deprecated macro `local_deprecated`: local deprecation note +} diff --git a/tests/ui/macros/macro-stability.stderr b/tests/ui/macros/macro-stability.stderr new file mode 100644 index 000000000..2cfdb52b1 --- /dev/null +++ b/tests/ui/macros/macro-stability.stderr @@ -0,0 +1,41 @@ +error[E0658]: use of unstable library feature 'local_unstable' + --> $DIR/macro-stability.rs:22:5 + | +LL | local_unstable!(); + | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(local_unstable)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'local_unstable' + --> $DIR/macro-stability.rs:23:5 + | +LL | local_unstable_modern!(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(local_unstable)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_macros' + --> $DIR/macro-stability.rs:24:5 + | +LL | unstable_macro!(); + | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(unstable_macros)]` to the crate attributes to enable + +warning: use of deprecated macro `deprecated_macro`: deprecation note + --> $DIR/macro-stability.rs:27:5 + | +LL | deprecated_macro!(); + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated macro `local_deprecated`: local deprecation note + --> $DIR/macro-stability.rs:29:5 + | +LL | local_deprecated!(); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/macro-stmt-matchers.rs b/tests/ui/macros/macro-stmt-matchers.rs new file mode 100644 index 000000000..a643e50e9 --- /dev/null +++ b/tests/ui/macros/macro-stmt-matchers.rs @@ -0,0 +1,7 @@ +// build-pass (FIXME(62277): could be check-pass?) + + +fn main() { + macro_rules! m { ($s:stmt;) => { $s } } + m!(vec![].push(0);); +} diff --git a/tests/ui/macros/macro-stmt.rs b/tests/ui/macros/macro-stmt.rs new file mode 100644 index 000000000..c9a0b879a --- /dev/null +++ b/tests/ui/macros/macro-stmt.rs @@ -0,0 +1,31 @@ +// run-pass +macro_rules! myfn { + ( $f:ident, ( $( $x:ident ),* ), $body:block ) => ( + fn $f( $( $x : isize),* ) -> isize $body + ) +} + +myfn!(add, (a,b), { return a+b; } ); + +pub fn main() { + + macro_rules! mylet { + ($x:ident, $val:expr) => ( + let $x = $val; + ) + } + + mylet!(y, 8*2); + assert_eq!(y, 16); + + myfn!(mult, (a,b), { a*b } ); + + assert_eq!(mult(2, add(4,4)), 16); + + macro_rules! actually_an_expr_macro { + () => ( 16 ) + } + + assert_eq!({ actually_an_expr_macro!() }, 16); + +} diff --git a/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs b/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs new file mode 100644 index 000000000..528d0b28b --- /dev/null +++ b/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] +macro_rules! foo { + () => { + struct Bar; + struct Baz; + } +} + +macro_rules! grault { + () => {{ + foo!(); + struct Xyzzy; + 0 + }} +} + +fn main() { + let x = grault!(); + assert_eq!(x, 0); +} diff --git a/tests/ui/macros/macro-tt-followed-by-seq.rs b/tests/ui/macros/macro-tt-followed-by-seq.rs new file mode 100644 index 000000000..080dbcfdd --- /dev/null +++ b/tests/ui/macros/macro-tt-followed-by-seq.rs @@ -0,0 +1,28 @@ +// run-pass +// Regression test for issue #25436: permit token-trees to be followed +// by sequences, enabling more general parsing. + +use self::Join::*; + +#[derive(Debug)] +#[allow(unused_tuple_struct_fields)] +enum Join<A,B> { + Keep(A,B), + Skip(A,B), +} + +macro_rules! parse_list { + ( < $a:expr; > $($b:tt)* ) => { Keep(parse_item!($a),parse_list!($($b)*)) }; + ( $a:tt $($b:tt)* ) => { Skip(parse_item!($a), parse_list!($($b)*)) }; + ( ) => { () }; +} + +macro_rules! parse_item { + ( $x:expr ) => { $x } +} + +fn main() { + let list = parse_list!(<1;> 2 <3;> 4); + assert_eq!("Keep(1, Skip(2, Keep(3, Skip(4, ()))))", + format!("{:?}", list)); +} diff --git a/tests/ui/macros/macro-tt-matchers.rs b/tests/ui/macros/macro-tt-matchers.rs new file mode 100644 index 000000000..2ee41b088 --- /dev/null +++ b/tests/ui/macros/macro-tt-matchers.rs @@ -0,0 +1,11 @@ +// build-pass (FIXME(62277): could be check-pass?) +#![allow(dead_code)] + +macro_rules! foo { + ($x:tt) => (type Alias = $x<i32>;) +} + +foo!(Box); + + +fn main() {} diff --git a/tests/ui/macros/macro-use-all-and-none.rs b/tests/ui/macros/macro-use-all-and-none.rs new file mode 100644 index 000000000..c8bd44008 --- /dev/null +++ b/tests/ui/macros/macro-use-all-and-none.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:two_macros-rpass.rs + +#![warn(unused_attributes)] + +#[macro_use] +#[macro_use()] //~ WARNING unused attribute +extern crate two_macros_rpass; + +pub fn main() { + macro_one!(); + macro_two!(); +} diff --git a/tests/ui/macros/macro-use-all-and-none.stderr b/tests/ui/macros/macro-use-all-and-none.stderr new file mode 100644 index 000000000..00b10dccd --- /dev/null +++ b/tests/ui/macros/macro-use-all-and-none.stderr @@ -0,0 +1,15 @@ +warning: unused attribute + --> $DIR/macro-use-all-and-none.rs:7:1 + | +LL | #[macro_use()] + | ^^^^^^^^^^^^^^ help: remove this attribute + | + = note: attribute `macro_use` with an empty list has no effect +note: the lint level is defined here + --> $DIR/macro-use-all-and-none.rs:4:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/macros/macro-use-all.rs b/tests/ui/macros/macro-use-all.rs new file mode 100644 index 000000000..48c7b77e5 --- /dev/null +++ b/tests/ui/macros/macro-use-all.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:two_macros.rs + +#[macro_use] +extern crate two_macros; + +pub fn main() { + macro_one!(); + macro_two!(); +} diff --git a/tests/ui/macros/macro-use-bad-args-1.rs b/tests/ui/macros/macro-use-bad-args-1.rs new file mode 100644 index 000000000..ec0b64a10 --- /dev/null +++ b/tests/ui/macros/macro-use-bad-args-1.rs @@ -0,0 +1,6 @@ +#![no_std] + +#[macro_use(foo(bar))] //~ ERROR bad macro import +extern crate std; + +fn main() {} diff --git a/tests/ui/macros/macro-use-bad-args-1.stderr b/tests/ui/macros/macro-use-bad-args-1.stderr new file mode 100644 index 000000000..4e5482a51 --- /dev/null +++ b/tests/ui/macros/macro-use-bad-args-1.stderr @@ -0,0 +1,9 @@ +error[E0466]: bad macro import + --> $DIR/macro-use-bad-args-1.rs:3:13 + | +LL | #[macro_use(foo(bar))] + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0466`. diff --git a/tests/ui/macros/macro-use-bad-args-2.rs b/tests/ui/macros/macro-use-bad-args-2.rs new file mode 100644 index 000000000..c5f8f62c1 --- /dev/null +++ b/tests/ui/macros/macro-use-bad-args-2.rs @@ -0,0 +1,6 @@ +#![no_std] + +#[macro_use(foo="bar")] //~ ERROR bad macro import +extern crate std; + +fn main() {} diff --git a/tests/ui/macros/macro-use-bad-args-2.stderr b/tests/ui/macros/macro-use-bad-args-2.stderr new file mode 100644 index 000000000..c958104ea --- /dev/null +++ b/tests/ui/macros/macro-use-bad-args-2.stderr @@ -0,0 +1,9 @@ +error[E0466]: bad macro import + --> $DIR/macro-use-bad-args-2.rs:3:13 + | +LL | #[macro_use(foo="bar")] + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0466`. diff --git a/tests/ui/macros/macro-use-both.rs b/tests/ui/macros/macro-use-both.rs new file mode 100644 index 000000000..ed5d1312f --- /dev/null +++ b/tests/ui/macros/macro-use-both.rs @@ -0,0 +1,10 @@ +// run-pass +// aux-build:two_macros.rs + +#[macro_use(macro_one, macro_two)] +extern crate two_macros; + +pub fn main() { + macro_one!(); + macro_two!(); +} diff --git a/tests/ui/macros/macro-use-one.rs b/tests/ui/macros/macro-use-one.rs new file mode 100644 index 000000000..f74795e68 --- /dev/null +++ b/tests/ui/macros/macro-use-one.rs @@ -0,0 +1,9 @@ +// run-pass +// aux-build:two_macros.rs + +#[macro_use(macro_two)] +extern crate two_macros; + +pub fn main() { + macro_two!(); +} diff --git a/tests/ui/macros/macro-use-scope.rs b/tests/ui/macros/macro-use-scope.rs new file mode 100644 index 000000000..5e58fc9c1 --- /dev/null +++ b/tests/ui/macros/macro-use-scope.rs @@ -0,0 +1,22 @@ +// aux-build:two_macros.rs + +// build-pass (FIXME(62277): could be check-pass?) +#![allow(unused)] + +fn f() { + let _ = macro_one!(); +} +#[macro_use(macro_one)] // Check that this macro is usable in the above function +extern crate two_macros; + +fn g() { + macro_two!(); +} +macro_rules! m { () => { + #[macro_use(macro_two)] // Check that this macro is usable in the above function + extern crate two_macros as _two_macros; +} } +m!(); + + +fn main() {} diff --git a/tests/ui/macros/macro-use-undef.rs b/tests/ui/macros/macro-use-undef.rs new file mode 100644 index 000000000..ae3054e7b --- /dev/null +++ b/tests/ui/macros/macro-use-undef.rs @@ -0,0 +1,8 @@ +// aux-build:two_macros.rs + +#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found +extern crate two_macros; + +pub fn main() { + macro_two!(); +} diff --git a/tests/ui/macros/macro-use-undef.stderr b/tests/ui/macros/macro-use-undef.stderr new file mode 100644 index 000000000..85b86e221 --- /dev/null +++ b/tests/ui/macros/macro-use-undef.stderr @@ -0,0 +1,9 @@ +error[E0469]: imported macro not found + --> $DIR/macro-use-undef.rs:3:24 + | +LL | #[macro_use(macro_two, no_way)] + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0469`. diff --git a/tests/ui/macros/macro-use-wrong-name.rs b/tests/ui/macros/macro-use-wrong-name.rs new file mode 100644 index 000000000..d142b5800 --- /dev/null +++ b/tests/ui/macros/macro-use-wrong-name.rs @@ -0,0 +1,9 @@ +// aux-build:two_macros.rs + +#[macro_use(macro_one)] +extern crate two_macros; + +pub fn main() { + macro_two!(); + //~^ ERROR cannot find macro +} diff --git a/tests/ui/macros/macro-use-wrong-name.stderr b/tests/ui/macros/macro-use-wrong-name.stderr new file mode 100644 index 000000000..ca5f0f190 --- /dev/null +++ b/tests/ui/macros/macro-use-wrong-name.stderr @@ -0,0 +1,16 @@ +error: cannot find macro `macro_two` in this scope + --> $DIR/macro-use-wrong-name.rs:7:5 + | +LL | macro_two!(); + | ^^^^^^^^^ help: a macro with a similar name exists: `macro_one` + | + ::: $DIR/auxiliary/two_macros.rs:2:1 + | +LL | macro_rules! macro_one { () => ("one") } + | ---------------------- similarly named macro `macro_one` defined here + | + = help: consider importing this macro: + two_macros::macro_two + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro-with-attrs1.rs b/tests/ui/macros/macro-with-attrs1.rs new file mode 100644 index 000000000..4e943b224 --- /dev/null +++ b/tests/ui/macros/macro-with-attrs1.rs @@ -0,0 +1,13 @@ +// run-pass +// compile-flags: --cfg foo + + +#[cfg(foo)] +macro_rules! foo { () => (1) } + +#[cfg(not(foo))] +macro_rules! foo { () => (2) } + +pub fn main() { + assert_eq!(foo!(), 1); +} diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs new file mode 100644 index 000000000..78c408102 --- /dev/null +++ b/tests/ui/macros/macro-with-attrs2.rs @@ -0,0 +1,11 @@ +// run-pass + +#[cfg(foo)] +macro_rules! foo { () => (1) } + +#[cfg(not(foo))] +macro_rules! foo { () => (2) } + +pub fn main() { + assert_eq!(foo!(), 2); +} diff --git a/tests/ui/macros/macro-with-braces-in-expr-position.rs b/tests/ui/macros/macro-with-braces-in-expr-position.rs new file mode 100644 index 000000000..f7d87434d --- /dev/null +++ b/tests/ui/macros/macro-with-braces-in-expr-position.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +macro_rules! expr { ($e: expr) => { $e } } + +macro_rules! spawn { + ($($code: tt)*) => { + expr!(thread::spawn(move|| {$($code)*}).join()) + } +} + +pub fn main() { + spawn! { + println!("stmt"); + }; + let _ = spawn! { + println!("expr"); + }; +} diff --git a/tests/ui/macros/macro_path_as_generic_bound.rs b/tests/ui/macros/macro_path_as_generic_bound.rs new file mode 100644 index 000000000..663f85688 --- /dev/null +++ b/tests/ui/macros/macro_path_as_generic_bound.rs @@ -0,0 +1,9 @@ +trait Foo {} + +macro_rules! foo(($t:path) => { + impl<T: $t> Foo for T {} +}); + +foo!(m::m2::A); //~ ERROR failed to resolve + +fn main() {} diff --git a/tests/ui/macros/macro_path_as_generic_bound.stderr b/tests/ui/macros/macro_path_as_generic_bound.stderr new file mode 100644 index 000000000..00d954d24 --- /dev/null +++ b/tests/ui/macros/macro_path_as_generic_bound.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `m` + --> $DIR/macro_path_as_generic_bound.rs:7:6 + | +LL | foo!(m::m2::A); + | ^ use of undeclared crate or module `m` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/macro_rules-unmatchable-literals.rs b/tests/ui/macros/macro_rules-unmatchable-literals.rs new file mode 100644 index 000000000..bde0fe1a0 --- /dev/null +++ b/tests/ui/macros/macro_rules-unmatchable-literals.rs @@ -0,0 +1,14 @@ +// Pinning tests for things that don't work to make sure we notice if that changes + +#![crate_type = "lib"] + +macro_rules! octal_with_bad_digit { + ( 0o1238 ) => {}; //~ ERROR invalid digit +} + +macro_rules! binary_with_bad_digit { + ( 0b012 ) => {}; //~ ERROR invalid digit +} + +// This can't happen for Hex and Decimal as things like `123A` and `0xFFG` +// get treated as unknown *suffixes*, rather than digits. diff --git a/tests/ui/macros/macro_rules-unmatchable-literals.stderr b/tests/ui/macros/macro_rules-unmatchable-literals.stderr new file mode 100644 index 000000000..956a66979 --- /dev/null +++ b/tests/ui/macros/macro_rules-unmatchable-literals.stderr @@ -0,0 +1,14 @@ +error: invalid digit for a base 8 literal + --> $DIR/macro_rules-unmatchable-literals.rs:6:12 + | +LL | ( 0o1238 ) => {}; + | ^ + +error: invalid digit for a base 2 literal + --> $DIR/macro_rules-unmatchable-literals.rs:10:11 + | +LL | ( 0b012 ) => {}; + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/macro_undefined.rs b/tests/ui/macros/macro_undefined.rs new file mode 100644 index 000000000..6ca1eb568 --- /dev/null +++ b/tests/ui/macros/macro_undefined.rs @@ -0,0 +1,13 @@ +// Test macro_undefined issue + +mod m { + #[macro_export] + macro_rules! kl { + () => () + } +} + +fn main() { + k!(); //~ ERROR cannot find + kl!(); +} diff --git a/tests/ui/macros/macro_undefined.stderr b/tests/ui/macros/macro_undefined.stderr new file mode 100644 index 000000000..4ab16bd10 --- /dev/null +++ b/tests/ui/macros/macro_undefined.stderr @@ -0,0 +1,11 @@ +error: cannot find macro `k` in this scope + --> $DIR/macro_undefined.rs:11:5 + | +LL | macro_rules! kl { + | --------------- similarly named macro `kl` defined here +... +LL | k!(); + | ^ help: a macro with a similar name exists: `kl` + +error: aborting due to previous error + diff --git a/tests/ui/macros/macro_with_super_2.rs b/tests/ui/macros/macro_with_super_2.rs new file mode 100644 index 000000000..2901a74f6 --- /dev/null +++ b/tests/ui/macros/macro_with_super_2.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:macro_with_super_1.rs + +// pretty-expanded FIXME #23616 + +#[macro_use] +extern crate macro_with_super_1; + +declare!(); + +fn main() { + bbb::ccc(); +} diff --git a/tests/ui/macros/macros-in-extern.rs b/tests/ui/macros/macros-in-extern.rs new file mode 100644 index 000000000..568ae3a85 --- /dev/null +++ b/tests/ui/macros/macros-in-extern.rs @@ -0,0 +1,51 @@ +// run-pass +// ignore-wasm32 + +#![feature(decl_macro)] + +macro_rules! returns_isize( + ($ident:ident) => ( + fn $ident() -> isize; + ) +); + +macro takes_u32_returns_u32($ident:ident) { + fn $ident(arg: u32) -> u32; +} + +macro_rules! emits_nothing( + () => () +); + +macro_rules! emits_multiple( + () => { + fn f1() -> u32; + fn f2() -> u32; + } +); + +mod defs { + #[no_mangle] + extern "C" fn f1() -> u32 { + 1 + } + #[no_mangle] + extern "C" fn f2() -> u32 { + 2 + } +} + +fn main() { + assert_eq!(unsafe { rust_get_test_int() }, 1); + assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32); + assert_eq!(unsafe { f1() }, 1); + assert_eq!(unsafe { f2() }, 2); +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + returns_isize!(rust_get_test_int); + takes_u32_returns_u32!(rust_dbg_extern_identity_u32); + emits_nothing!(); + emits_multiple!(); +} diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs new file mode 100644 index 000000000..ab14c3589 --- /dev/null +++ b/tests/ui/macros/macros-nonfatal-errors.rs @@ -0,0 +1,139 @@ +// normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG (" + +// test that errors in a (selection) of macros don't kill compilation +// immediately, so that we get more errors listed at a time. + +#![feature(trace_macros, concat_idents)] +#![feature(stmt_expr_attributes)] + +use std::arch::asm; + +#[derive(Default)] +struct DefaultInnerAttrStruct { + #[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants + foo: (), +} + +#[derive(Default)] +struct DefaultInnerAttrTupleStruct(#[default] ()); +//~^ ERROR the `#[default]` attribute may only be used on unit enum variants + +#[derive(Default)] +#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants +struct DefaultOuterAttrStruct {} + +#[derive(Default)] +#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants +enum DefaultOuterAttrEnum { + #[default] + Foo, +} + +#[rustfmt::skip] // needs some work to handle this case +#[repr(u8)] +#[derive(Default)] +enum AttrOnInnerExpression { + Foo = #[default] 0, //~ ERROR the `#[default]` attribute may only be used on unit enum variants + Bar([u8; #[default] 1]), //~ ERROR the `#[default]` attribute may only be used on unit enum variants + #[default] + Baz, +} + +#[derive(Default)] //~ ERROR no default declared +enum NoDeclaredDefault { + Foo, + Bar, +} + +#[derive(Default)] //~ ERROR multiple declared defaults +enum MultipleDefaults { + #[default] + Foo, + #[default] + Bar, + #[default] + Baz, +} + +#[derive(Default)] +enum ExtraDeriveTokens { + #[default = 1] //~ ERROR `#[default]` attribute does not accept a value + Foo, +} + +#[derive(Default)] +enum TwoDefaultAttrs { + #[default] + #[default] + Foo, //~ERROR multiple `#[default]` attributes + Bar, +} + +#[derive(Default)] +enum ManyDefaultAttrs { + #[default] + #[default] + #[default] + #[default] + Foo, //~ERROR multiple `#[default]` attributes + Bar, +} + +#[derive(Default)] +enum DefaultHasFields { + #[default] + Foo {}, //~ ERROR the `#[default]` attribute may only be used on unit enum variants + Bar, +} + +#[derive(Default)] +enum NonExhaustiveDefault { + #[default] + #[non_exhaustive] + Foo, //~ ERROR default variant must be exhaustive + Bar, +} + +fn main() { + asm!(invalid); //~ ERROR + llvm_asm!(invalid); //~ ERROR + + concat_idents!("not", "idents"); //~ ERROR + + option_env!(invalid); //~ ERROR + env!(invalid); //~ ERROR + env!(foo, abr, baz); //~ ERROR + env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR + + format!(invalid); //~ ERROR + + include!(invalid); //~ ERROR + + include_str!(invalid); //~ ERROR + include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR + include_bytes!(invalid); //~ ERROR + include_bytes!("i'd be quite surprised if a file with this name existed"); //~ ERROR + + trace_macros!(invalid); //~ ERROR +} + +/// Check that `#[derive(Default)]` does use a `T : Default` bound when the +/// `#[default]` variant is `#[non_exhaustive]` (should this end up allowed). +const _: () = { + #[derive(Default)] + enum NonExhaustiveDefaultGeneric<T> { + #[default] + #[non_exhaustive] + Foo, //~ ERROR default variant must be exhaustive + Bar(T), + } + + fn assert_impls_default<T: Default>() {} + + enum NotDefault {} + + // Note: the `derive(Default)` currently bails early enough for trait-checking + // not to happen. Should it bail late enough, or even pass, make sure to + // assert that the following line fails. + let _ = assert_impls_default::<NonExhaustiveDefaultGeneric<NotDefault>>; +}; diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr new file mode 100644 index 000000000..d42f6c179 --- /dev/null +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -0,0 +1,235 @@ +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:13:5 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:18:36 + | +LL | struct DefaultInnerAttrTupleStruct(#[default] ()); + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:22:1 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:26:1 + | +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:36:11 + | +LL | Foo = #[default] 0, + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:37:14 + | +LL | Bar([u8; #[default] 1]), + | ^^^^^^^^^^ + +error: no default declared + --> $DIR/macros-nonfatal-errors.rs:42:10 + | +LL | #[derive(Default)] + | ^^^^^^^ + | + = help: make a unit variant default by placing `#[default]` above it + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: multiple declared defaults + --> $DIR/macros-nonfatal-errors.rs:48:10 + | +LL | #[derive(Default)] + | ^^^^^^^ +... +LL | Foo, + | --- first default +LL | #[default] +LL | Bar, + | --- additional default +LL | #[default] +LL | Baz, + | --- additional default + | + = note: only one variant can be default + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `#[default]` attribute does not accept a value + --> $DIR/macros-nonfatal-errors.rs:60:5 + | +LL | #[default = 1] + | ^^^^^^^^^^^^^^ + | + = help: try using `#[default]` + +error: multiple `#[default]` attributes + --> $DIR/macros-nonfatal-errors.rs:68:5 + | +LL | #[default] + | ---------- `#[default]` used here +LL | #[default] + | ---------- `#[default]` used again here +LL | Foo, + | ^^^ + | + = note: only one `#[default]` attribute is needed +help: try removing this + --> $DIR/macros-nonfatal-errors.rs:67:5 + | +LL | #[default] + | ^^^^^^^^^^ + +error: multiple `#[default]` attributes + --> $DIR/macros-nonfatal-errors.rs:78:5 + | +LL | #[default] + | ---------- `#[default]` used here +LL | #[default] + | ---------- `#[default]` used again here +... +LL | Foo, + | ^^^ + | + = note: only one `#[default]` attribute is needed +help: try removing these + --> $DIR/macros-nonfatal-errors.rs:75:5 + | +LL | #[default] + | ^^^^^^^^^^ +LL | #[default] + | ^^^^^^^^^^ +LL | #[default] + | ^^^^^^^^^^ + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/macros-nonfatal-errors.rs:85:5 + | +LL | Foo {}, + | ^^^ + | + = help: consider a manual implementation of `Default` + +error: default variant must be exhaustive + --> $DIR/macros-nonfatal-errors.rs:93:5 + | +LL | #[non_exhaustive] + | ----------------- declared `#[non_exhaustive]` here +LL | Foo, + | ^^^ + | + = help: consider a manual implementation of `Default` + +error: asm template must be a string literal + --> $DIR/macros-nonfatal-errors.rs:98:10 + | +LL | asm!(invalid); + | ^^^^^^^ + +error: concat_idents! requires ident args + --> $DIR/macros-nonfatal-errors.rs:101:5 + | +LL | concat_idents!("not", "idents"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: argument must be a string literal + --> $DIR/macros-nonfatal-errors.rs:103:17 + | +LL | option_env!(invalid); + | ^^^^^^^ + +error: expected string literal + --> $DIR/macros-nonfatal-errors.rs:104:10 + | +LL | env!(invalid); + | ^^^^^^^ + +error: expected string literal + --> $DIR/macros-nonfatal-errors.rs:105:10 + | +LL | env!(foo, abr, baz); + | ^^^ + +error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined + --> $DIR/macros-nonfatal-errors.rs:106:5 + | +LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: format argument must be a string literal + --> $DIR/macros-nonfatal-errors.rs:108:13 + | +LL | format!(invalid); + | ^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | format!("{}", invalid); + | +++++ + +error: argument must be a string literal + --> $DIR/macros-nonfatal-errors.rs:110:14 + | +LL | include!(invalid); + | ^^^^^^^ + +error: argument must be a string literal + --> $DIR/macros-nonfatal-errors.rs:112:18 + | +LL | include_str!(invalid); + | ^^^^^^^ + +error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/macros-nonfatal-errors.rs:113:5 + | +LL | include_str!("i'd be quite surprised if a file with this name existed"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument must be a string literal + --> $DIR/macros-nonfatal-errors.rs:114:20 + | +LL | include_bytes!(invalid); + | ^^^^^^^ + +error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/macros-nonfatal-errors.rs:115:5 + | +LL | include_bytes!("i'd be quite surprised if a file with this name existed"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: trace_macros! accepts only `true` or `false` + --> $DIR/macros-nonfatal-errors.rs:117:5 + | +LL | trace_macros!(invalid); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: default variant must be exhaustive + --> $DIR/macros-nonfatal-errors.rs:127:9 + | +LL | #[non_exhaustive] + | ----------------- declared `#[non_exhaustive]` here +LL | Foo, + | ^^^ + | + = help: consider a manual implementation of `Default` + +error: cannot find macro `llvm_asm` in this scope + --> $DIR/macros-nonfatal-errors.rs:99:5 + | +LL | llvm_asm!(invalid); + | ^^^^^^^^ + +error: aborting due to 28 previous errors + diff --git a/tests/ui/macros/malformed_macro_lhs.rs b/tests/ui/macros/malformed_macro_lhs.rs new file mode 100644 index 000000000..f57d2fb4d --- /dev/null +++ b/tests/ui/macros/malformed_macro_lhs.rs @@ -0,0 +1,7 @@ +macro_rules! my_precioooous { + t => (1); //~ ERROR invalid macro matcher +} + +fn main() { + my_precioooous!(); +} diff --git a/tests/ui/macros/malformed_macro_lhs.stderr b/tests/ui/macros/malformed_macro_lhs.stderr new file mode 100644 index 000000000..adf64b089 --- /dev/null +++ b/tests/ui/macros/malformed_macro_lhs.stderr @@ -0,0 +1,8 @@ +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/malformed_macro_lhs.rs:2:5 + | +LL | t => (1); + | ^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/meta-item-absolute-path.rs b/tests/ui/macros/meta-item-absolute-path.rs new file mode 100644 index 000000000..8ed911cbc --- /dev/null +++ b/tests/ui/macros/meta-item-absolute-path.rs @@ -0,0 +1,5 @@ +#[derive(::Absolute)] //~ ERROR failed to resolve + //~| ERROR failed to resolve +struct S; + +fn main() {} diff --git a/tests/ui/macros/meta-item-absolute-path.stderr b/tests/ui/macros/meta-item-absolute-path.stderr new file mode 100644 index 000000000..c53971e24 --- /dev/null +++ b/tests/ui/macros/meta-item-absolute-path.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: maybe a missing crate `Absolute`? + --> $DIR/meta-item-absolute-path.rs:1:12 + | +LL | #[derive(::Absolute)] + | ^^^^^^^^ maybe a missing crate `Absolute`? + +error[E0433]: failed to resolve: maybe a missing crate `Absolute`? + --> $DIR/meta-item-absolute-path.rs:1:12 + | +LL | #[derive(::Absolute)] + | ^^^^^^^^ maybe a missing crate `Absolute`? + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.rs b/tests/ui/macros/meta-variable-depth-outside-repeat.rs new file mode 100644 index 000000000..b7fb94785 --- /dev/null +++ b/tests/ui/macros/meta-variable-depth-outside-repeat.rs @@ -0,0 +1,12 @@ +#![feature(macro_metavar_expr)] + +macro_rules! metavar { + ( $i:expr ) => { + ${length(0)} + //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition + }; +} + +const _: i32 = metavar!(0); + +fn main() {} diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.stderr b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr new file mode 100644 index 000000000..fad150cad --- /dev/null +++ b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr @@ -0,0 +1,8 @@ +error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition + --> $DIR/meta-variable-depth-outside-repeat.rs:5:10 + | +LL | ${length(0)} + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/macros/meta-variable-misuse.rs b/tests/ui/macros/meta-variable-misuse.rs new file mode 100644 index 000000000..99a2f9401 --- /dev/null +++ b/tests/ui/macros/meta-variable-misuse.rs @@ -0,0 +1,34 @@ +// run-pass +#![deny(meta_variable_misuse)] + +macro_rules! foo { + ($($m:ident $($f:ident $v:tt)+),*) => { + $($(macro_rules! $f { () => { $v } })+)* + $(macro_rules! $m { () => { $(fn $f() -> i32 { $v })+ } })* + } +} + +foo!(m a 1 b 2, n c 3); +m!(); +n!(); + +macro_rules! no_shadow { + ($x:tt) => { macro_rules! bar { ($x:tt) => { 42 }; } }; +} +no_shadow!(z); + +macro_rules! make_plus { + ($n: ident $x:expr) => { macro_rules! $n { ($y:expr) => { $x + $y }; } }; +} +make_plus!(add3 3); + +fn main() { + assert_eq!(a!(), 1); + assert_eq!(b!(), 2); + assert_eq!(c!(), 3); + assert_eq!(a(), 1); + assert_eq!(b(), 2); + assert_eq!(c(), 3); + assert_eq!(bar!(z:tt), 42); + assert_eq!(add3!(9), 12); +} diff --git a/tests/ui/macros/missing-bang-in-decl.fixed b/tests/ui/macros/missing-bang-in-decl.fixed new file mode 100644 index 000000000..b1aa3298b --- /dev/null +++ b/tests/ui/macros/missing-bang-in-decl.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_macros)] + +macro_rules! foo { + //~^ ERROR expected `!` after `macro_rules` + () => {}; +} + +macro_rules! bar { + //~^ ERROR expected `!` after `macro_rules` + //~^^ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/tests/ui/macros/missing-bang-in-decl.rs b/tests/ui/macros/missing-bang-in-decl.rs new file mode 100644 index 000000000..8393f15fc --- /dev/null +++ b/tests/ui/macros/missing-bang-in-decl.rs @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_macros)] + +macro_rules foo { + //~^ ERROR expected `!` after `macro_rules` + () => {}; +} + +macro_rules bar! { + //~^ ERROR expected `!` after `macro_rules` + //~^^ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/tests/ui/macros/missing-bang-in-decl.stderr b/tests/ui/macros/missing-bang-in-decl.stderr new file mode 100644 index 000000000..dfabafb0a --- /dev/null +++ b/tests/ui/macros/missing-bang-in-decl.stderr @@ -0,0 +1,20 @@ +error: expected `!` after `macro_rules` + --> $DIR/missing-bang-in-decl.rs:5:1 + | +LL | macro_rules foo { + | ^^^^^^^^^^^ help: add a `!`: `macro_rules!` + +error: expected `!` after `macro_rules` + --> $DIR/missing-bang-in-decl.rs:10:1 + | +LL | macro_rules bar! { + | ^^^^^^^^^^^ help: add a `!`: `macro_rules!` + +error: macro names aren't followed by a `!` + --> $DIR/missing-bang-in-decl.rs:10:16 + | +LL | macro_rules bar! { + | ^ help: remove the `!` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs new file mode 100644 index 000000000..92f8a7795 --- /dev/null +++ b/tests/ui/macros/missing-comma.rs @@ -0,0 +1,34 @@ +macro_rules! foo { + ($a:ident) => (); + ($a:ident, $b:ident) => (); + ($a:ident, $b:ident, $c:ident) => (); + ($a:ident, $b:ident, $c:ident, $d:ident) => (); + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => (); +} + +macro_rules! bar { + ($lvl:expr, $($arg:tt)+) => {} +} + +macro_rules! check { + ($ty:ty, $expected:expr) => {}; + ($ty_of:expr, $expected:expr) => {}; +} + +fn main() { + println!("{}" a); + //~^ ERROR expected `,`, found `a` + foo!(a b); + //~^ ERROR no rules expected the token `b` + foo!(a, b, c, d e); + //~^ ERROR no rules expected the token `e` + foo!(a, b, c d, e); + //~^ ERROR no rules expected the token `d` + foo!(a, b, c d e); + //~^ ERROR no rules expected the token `d` + bar!(Level::Error, ); + //~^ ERROR unexpected end of macro invocation + check!(<str as Debug>::fmt, "fmt"); + check!(<str as Debug>::fmt, "fmt",); + //~^ ERROR no rules expected the token `,` +} diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr new file mode 100644 index 000000000..81877a29e --- /dev/null +++ b/tests/ui/macros/missing-comma.stderr @@ -0,0 +1,104 @@ +error: expected `,`, found `a` + --> $DIR/missing-comma.rs:19:19 + | +LL | println!("{}" a); + | ^ expected `,` + +error: no rules expected the token `b` + --> $DIR/missing-comma.rs:21:12 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a b); + | -^ no rules expected this token in macro call + | | + | help: missing comma here + | +note: while trying to match meta-variable `$a:ident` + --> $DIR/missing-comma.rs:2:6 + | +LL | ($a:ident) => (); + | ^^^^^^^^ + +error: no rules expected the token `e` + --> $DIR/missing-comma.rs:23:21 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a, b, c, d e); + | -^ no rules expected this token in macro call + | | + | help: missing comma here + | +note: while trying to match meta-variable `$d:ident` + --> $DIR/missing-comma.rs:5:36 + | +LL | ($a:ident, $b:ident, $c:ident, $d:ident) => (); + | ^^^^^^^^ + +error: no rules expected the token `d` + --> $DIR/missing-comma.rs:25:18 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a, b, c d, e); + | -^ no rules expected this token in macro call + | | + | help: missing comma here + | +note: while trying to match meta-variable `$c:ident` + --> $DIR/missing-comma.rs:4:26 + | +LL | ($a:ident, $b:ident, $c:ident) => (); + | ^^^^^^^^ + +error: no rules expected the token `d` + --> $DIR/missing-comma.rs:27:18 + | +LL | macro_rules! foo { + | ---------------- when calling this macro +... +LL | foo!(a, b, c d e); + | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$c:ident` + --> $DIR/missing-comma.rs:4:26 + | +LL | ($a:ident, $b:ident, $c:ident) => (); + | ^^^^^^^^ + +error: unexpected end of macro invocation + --> $DIR/missing-comma.rs:29:23 + | +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | bar!(Level::Error, ); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$arg:tt` + --> $DIR/missing-comma.rs:10:19 + | +LL | ($lvl:expr, $($arg:tt)+) => {} + | ^^^^^^^ + +error: no rules expected the token `,` + --> $DIR/missing-comma.rs:32:38 + | +LL | macro_rules! check { + | ------------------ when calling this macro +... +LL | check!(<str as Debug>::fmt, "fmt",); + | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$expected:expr` + --> $DIR/missing-comma.rs:14:14 + | +LL | ($ty:ty, $expected:expr) => {}; + | ^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/macros/must-use-in-macro-55516.rs b/tests/ui/macros/must-use-in-macro-55516.rs new file mode 100644 index 000000000..e7c346286 --- /dev/null +++ b/tests/ui/macros/must-use-in-macro-55516.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags: -Wunused + +// make sure write!() can't hide its unused Result + +fn main() { + use std::fmt::Write; + let mut example = String::new(); + write!(&mut example, "{}", 42); //~WARN must be used +} diff --git a/tests/ui/macros/must-use-in-macro-55516.stderr b/tests/ui/macros/must-use-in-macro-55516.stderr new file mode 100644 index 000000000..8878b0eea --- /dev/null +++ b/tests/ui/macros/must-use-in-macro-55516.stderr @@ -0,0 +1,12 @@ +warning: unused `Result` that must be used + --> $DIR/must-use-in-macro-55516.rs:9:5 + | +LL | write!(&mut example, "{}", 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this `Result` may be an `Err` variant, which should be handled + = note: `-W unused-must-use` implied by `-W unused` + = note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/macros/no-std-macros.rs b/tests/ui/macros/no-std-macros.rs new file mode 100644 index 000000000..ada643c7a --- /dev/null +++ b/tests/ui/macros/no-std-macros.rs @@ -0,0 +1,13 @@ +// compile-flags: --crate-type=lib +// check-pass +// issue #55482 +#![no_std] + +macro_rules! foo { + ($e:expr) => { + $crate::core::assert!($e); + $crate::core::assert_eq!($e, true); + }; +} + +pub fn foo() { foo!(true); } diff --git a/tests/ui/macros/none-delim-lookahead.rs b/tests/ui/macros/none-delim-lookahead.rs new file mode 100644 index 000000000..bf4fddea1 --- /dev/null +++ b/tests/ui/macros/none-delim-lookahead.rs @@ -0,0 +1,15 @@ +// check-pass + +macro_rules! make_struct { + ($name:ident) => { + #[derive(Debug)] + struct Foo { + #[cfg(not(FALSE))] + field: fn($name: bool) + } + } +} + +make_struct!(param_name); + +fn main() {} diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs new file mode 100644 index 000000000..84fffe44d --- /dev/null +++ b/tests/ui/macros/nonterminal-matching.rs @@ -0,0 +1,26 @@ +// Check that we are refusing to match on complex nonterminals for which tokens are +// unavailable and we'd have to go through AST comparisons. + +#![feature(decl_macro)] + +macro simple_nonterminal($nt_ident: ident, $nt_lifetime: lifetime, $nt_tt: tt) { + macro n(a $nt_ident b $nt_lifetime c $nt_tt d) { + struct S; + } + + n!(a $nt_ident b $nt_lifetime c $nt_tt d); +} + +macro complex_nonterminal($nt_item: item) { + macro n(a $nt_item b) { + struct S; + } + + n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}` +} + +simple_nonterminal!(a, 'a, (x, y, z)); // OK + +complex_nonterminal!(enum E {}); + +fn main() {} diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr new file mode 100644 index 000000000..5bbd54390 --- /dev/null +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -0,0 +1,24 @@ +error: no rules expected the token `enum E {}` + --> $DIR/nonterminal-matching.rs:19:10 + | +LL | macro n(a $nt_item b) { + | --------------------- when calling this macro +... +LL | n!(a $nt_item b); + | ^^^^^^^^ no rules expected this token in macro call +... +LL | complex_nonterminal!(enum E {}); + | ------------------------------- in this macro invocation + | +note: while trying to match `enum E {}` + --> $DIR/nonterminal-matching.rs:15:15 + | +LL | macro n(a $nt_item b) { + | ^^^^^^^^ +... +LL | complex_nonterminal!(enum E {}); + | ------------------------------- in this macro invocation + = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/not-utf8.bin b/tests/ui/macros/not-utf8.bin Binary files differnew file mode 100644 index 000000000..4148e5b88 --- /dev/null +++ b/tests/ui/macros/not-utf8.bin diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs new file mode 100644 index 000000000..1cb1fdcb8 --- /dev/null +++ b/tests/ui/macros/not-utf8.rs @@ -0,0 +1,5 @@ +// error-pattern: did not contain valid UTF-8 + +fn foo() { + include!("not-utf8.bin") +} diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr new file mode 100644 index 000000000..7e1f2dcad --- /dev/null +++ b/tests/ui/macros/not-utf8.stderr @@ -0,0 +1,10 @@ +error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8 + --> $DIR/not-utf8.rs:4:5 + | +LL | include!("not-utf8.bin") + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/out-of-order-shadowing.rs b/tests/ui/macros/out-of-order-shadowing.rs new file mode 100644 index 000000000..a0d1a9737 --- /dev/null +++ b/tests/ui/macros/out-of-order-shadowing.rs @@ -0,0 +1,10 @@ +// aux-build:define-macro.rs + +macro_rules! bar { () => {} } +define_macro!(bar); +bar!(); //~ ERROR `bar` is ambiguous + +macro_rules! m { () => { #[macro_use] extern crate define_macro; } } +m!(); + +fn main() {} diff --git a/tests/ui/macros/out-of-order-shadowing.stderr b/tests/ui/macros/out-of-order-shadowing.stderr new file mode 100644 index 000000000..dedefac5c --- /dev/null +++ b/tests/ui/macros/out-of-order-shadowing.stderr @@ -0,0 +1,22 @@ +error[E0659]: `bar` is ambiguous + --> $DIR/out-of-order-shadowing.rs:5:1 + | +LL | bar!(); + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `bar` could refer to the macro defined here + --> $DIR/out-of-order-shadowing.rs:4:1 + | +LL | define_macro!(bar); + | ^^^^^^^^^^^^^^^^^^ +note: `bar` could also refer to the macro defined here + --> $DIR/out-of-order-shadowing.rs:3:1 + | +LL | macro_rules! bar { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `define_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs new file mode 100644 index 000000000..8fef9b0ed --- /dev/null +++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(dead_code)] +#![allow(unused_assignments)] +#![allow(unused_variables)] +#![allow(stable_features)] + +// Test parsing binary operators after macro invocations. + +// pretty-expanded FIXME #23616 + +#![feature(macro_rules)] + +macro_rules! id { + ($e: expr) => { $e } +} + +fn foo() { + id!(1) + 1; + id![1] - 1; + id!(1) * 1; + id![1] / 1; + id!(1) % 1; + + id!(1) & 1; + id![1] | 1; + id!(1) ^ 1; + + let mut x = 1; + id![x] = 2; + id!(x) += 1; + + id!(1f64).clone(); + + id!([1, 2, 3])[1]; + id![drop](1); + + id!(true) && true; + id![true] || true; +} + +fn main() {} diff --git a/tests/ui/macros/paths-in-macro-invocations.rs b/tests/ui/macros/paths-in-macro-invocations.rs new file mode 100644 index 000000000..622818a92 --- /dev/null +++ b/tests/ui/macros/paths-in-macro-invocations.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(dead_code)] +// aux-build:two_macros-rpass.rs + +extern crate two_macros_rpass as two_macros; + +::two_macros::macro_one!(); +two_macros::macro_one!(); + +mod foo { pub use two_macros::macro_one as bar; } + +trait T { + foo::bar!(); + ::foo::bar!(); +} + +struct S { + x: foo::bar!(i32), + y: ::foo::bar!(i32), +} + +impl S { + foo::bar!(); + ::foo::bar!(); +} + +fn main() { + foo::bar!(); + ::foo::bar!(); + + let _ = foo::bar!(0); + let _ = ::foo::bar!(0); + + let foo::bar!(_) = 0; + let ::foo::bar!(_) = 0; +} diff --git a/tests/ui/macros/proc_macro.rs b/tests/ui/macros/proc_macro.rs new file mode 100644 index 000000000..66f9cdc55 --- /dev/null +++ b/tests/ui/macros/proc_macro.rs @@ -0,0 +1,37 @@ +// run-pass +// aux-build:proc_macro_def.rs +// ignore-cross-compile + +extern crate proc_macro_def; + +use proc_macro_def::{attr_tru, attr_identity, identity, ret_tru, tru}; + +#[attr_tru] +fn f1() -> bool { + return false; +} + +#[attr_identity] +fn f2() -> bool { + return identity!(true); +} + +fn f3() -> identity!(bool) { + ret_tru!(); +} + +fn f4(x: bool) -> bool { + match x { + identity!(true) => false, + identity!(false) => true, + } +} + +fn main() { + assert!(f1()); + assert!(f2()); + assert!(tru!()); + assert!(f3()); + assert!(identity!(5 == 5)); + assert!(f4(false)); +} diff --git a/tests/ui/macros/pub-item-inside-macro.rs b/tests/ui/macros/pub-item-inside-macro.rs new file mode 100644 index 000000000..d07681453 --- /dev/null +++ b/tests/ui/macros/pub-item-inside-macro.rs @@ -0,0 +1,18 @@ +// run-pass +// Issue #14660 + +// pretty-expanded FIXME #23616 + +mod bleh { + macro_rules! foo { + () => { + pub fn bar() { } + } + } + + foo!(); +} + +fn main() { + bleh::bar(); +} diff --git a/tests/ui/macros/pub-method-inside-macro.rs b/tests/ui/macros/pub-method-inside-macro.rs new file mode 100644 index 000000000..bc918c7a4 --- /dev/null +++ b/tests/ui/macros/pub-method-inside-macro.rs @@ -0,0 +1,22 @@ +// run-pass +// Issue #17436 + +// pretty-expanded FIXME #23616 + +mod bleh { + macro_rules! foo { + () => { + pub fn bar(&self) { } + } + } + + pub struct S; + + impl S { + foo!(); + } +} + +fn main() { + bleh::S.bar(); +} diff --git a/tests/ui/macros/recovery-allowed.rs b/tests/ui/macros/recovery-allowed.rs new file mode 100644 index 000000000..ebf65f1cc --- /dev/null +++ b/tests/ui/macros/recovery-allowed.rs @@ -0,0 +1,8 @@ +macro_rules! please_recover { + ($a:expr) => {}; +} + +please_recover! { not 1 } +//~^ ERROR unexpected `1` after identifier + +fn main() {} diff --git a/tests/ui/macros/recovery-allowed.stderr b/tests/ui/macros/recovery-allowed.stderr new file mode 100644 index 000000000..ec036e8b1 --- /dev/null +++ b/tests/ui/macros/recovery-allowed.stderr @@ -0,0 +1,10 @@ +error: unexpected `1` after identifier + --> $DIR/recovery-allowed.rs:5:23 + | +LL | please_recover! { not 1 } + | ----^ + | | + | help: use `!` to perform bitwise not + +error: aborting due to previous error + diff --git a/tests/ui/macros/recovery-forbidden.rs b/tests/ui/macros/recovery-forbidden.rs new file mode 100644 index 000000000..5dd261933 --- /dev/null +++ b/tests/ui/macros/recovery-forbidden.rs @@ -0,0 +1,13 @@ +// check-pass + +macro_rules! dont_recover_here { + ($e:expr) => { + compile_error!("Must not recover to single !1 expr"); + }; + + (not $a:literal) => {}; +} + +dont_recover_here! { not 1 } + +fn main() {} diff --git a/tests/ui/macros/restricted-shadowing-legacy.rs b/tests/ui/macros/restricted-shadowing-legacy.rs new file mode 100644 index 000000000..f5cac2dfb --- /dev/null +++ b/tests/ui/macros/restricted-shadowing-legacy.rs @@ -0,0 +1,289 @@ +// Legend: +// `N` - number of combination, from 0 to 4*4*4=64 +// `Outer < Invoc` means that expansion that produced macro definition `Outer` +// is a strict ancestor of expansion that produced macro definition `Inner`. +// `>`, `=` and `Unordered` mean "strict descendant", "same" and +// "not in ordering relation" for parent expansions. +// `+` - possible configuration +// `-` - configuration impossible due to properties of partial ordering +// `-?` - configuration impossible due to block/scope syntax +// `+?` - configuration possible only with legacy scoping + +// N | Outer ~ Invoc | Invoc ~ Inner | Outer ~ Inner | Possible | +// 1 | < | < | < | + | +// 2 | < | < | = | - | +// 3 | < | < | > | - | +// 4 | < | < | Unordered | - | +// 5 | < | = | < | + | +// 6 | < | = | = | - | +// 7 | < | = | > | - | +// 8 | < | = | Unordered | - | +// 9 | < | > | < | + | +// 10 | < | > | = | + | +// 11 | < | > | > | -? | +// 12 | < | > | Unordered | -? | +// 13 | < | Unordered | < | + | +// 14 | < | Unordered | = | - | +// 15 | < | Unordered | > | - | +// 16 | < | Unordered | Unordered | -? | +// 17 | = | < | < | + | +// 18 | = | < | = | - | +// 19 | = | < | > | - | +// 20 | = | < | Unordered | - | +// 21 | = | = | < | - | +// 22 | = | = | = | + | +// 23 | = | = | > | - | +// 24 | = | = | Unordered | - | +// 25 | = | > | < | - | +// 26 | = | > | = | - | +// 27 | = | > | > | -? | +// 28 | = | > | Unordered | - | +// 29 | = | Unordered | < | - | +// 30 | = | Unordered | = | - | +// 31 | = | Unordered | > | - | +// 32 | = | Unordered | Unordered | -? | +// 33 | > | < | < | +? | +// 34 | > | < | = | +? | +// 35 | > | < | > | +? | +// 36 | > | < | Unordered | + | +// 37 | > | = | < | - | +// 38 | > | = | = | - | +// 39 | > | = | > | + | +// 40 | > | = | Unordered | - | +// 41 | > | > | < | - | +// 42 | > | > | = | - | +// 43 | > | > | > | -? | +// 44 | > | > | Unordered | - | +// 45 | > | Unordered | < | - | +// 46 | > | Unordered | = | - | +// 47 | > | Unordered | > | -? | +// 48 | > | Unordered | Unordered | -? | +// 49 | Unordered | < | < | -? | +// 50 | Unordered | < | = | - | +// 51 | Unordered | < | > | - | +// 52 | Unordered | < | Unordered | + | +// 53 | Unordered | = | < | - | +// 54 | Unordered | = | = | - | +// 55 | Unordered | = | > | - | +// 56 | Unordered | = | Unordered | + | +// 57 | Unordered | > | < | - | +// 58 | Unordered | > | = | - | +// 59 | Unordered | > | > | + | +// 60 | Unordered | > | Unordered | + | +// 61 | Unordered | Unordered | < | +? | +// 62 | Unordered | Unordered | = | +? | +// 63 | Unordered | Unordered | > | +? | +// 64 | Unordered | Unordered | Unordered | + | + +#![feature(decl_macro, rustc_attrs)] + +struct Right; +// struct Wrong; // not defined + +macro_rules! include { () => { + macro_rules! gen_outer { () => { + macro_rules! m { () => { Wrong } } + }} + macro_rules! gen_inner { () => { + macro_rules! m { () => { Right } } + }} + macro_rules! gen_invoc { () => { + m!() + }} + + // ----------------------------------------------------------- + + fn check1() { + macro_rules! m { () => {} } + + macro_rules! gen_gen_inner_invoc { () => { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + }} + gen_gen_inner_invoc!(); + } + + fn check5() { + macro_rules! m { () => { Wrong } } + + macro_rules! gen_inner_invoc { () => { + macro_rules! m { () => { Right } } + m!(); // OK + }} + gen_inner_invoc!(); + } + + fn check9() { + macro_rules! m { () => { Wrong } } + + macro_rules! gen_inner_gen_invoc { () => { + macro_rules! m { () => { Right } } + gen_invoc!(); // OK + }} + gen_inner_gen_invoc!(); + } + + fn check10() { + macro_rules! m { () => { Wrong } } + + macro_rules! m { () => { Right } } + + gen_invoc!(); // OK + } + + fn check13() { + macro_rules! m { () => {} } + + gen_inner!(); + + macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous + gen_invoc!(); + } + + fn check17() { + macro_rules! m { () => {} } + + gen_inner!(); + + m!(); //~ ERROR `m` is ambiguous + } + + fn check22() { + macro_rules! m { () => { Wrong } } + + macro_rules! m { () => { Right } } + + m!(); // OK + } + + fn check36() { + gen_outer!(); + + gen_inner!(); + + m!(); //~ ERROR `m` is ambiguous + } + + fn check39() { + gen_outer!(); + + macro_rules! m { () => { Right } } + + m!(); // OK + } + + fn check52() { + gen_outer!(); + + macro_rules! gen_gen_inner_invoc { () => { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + }} + gen_gen_inner_invoc!(); + } + + fn check56() { + gen_outer!(); + + macro_rules! gen_inner_invoc { () => { + macro_rules! m { () => { Right } } + m!(); // OK + }} + gen_inner_invoc!(); + } + + fn check59() { + gen_outer!(); + + macro_rules! m { () => { Right } } + + gen_invoc!(); // OK + } + + fn check60() { + gen_outer!(); + + macro_rules! gen_inner_gen_invoc { () => { + macro_rules! m { () => { Right } } + gen_invoc!(); // OK + }} + gen_inner_gen_invoc!(); + } + + fn check64() { + gen_outer!(); + + gen_inner!(); + + macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous + gen_invoc!(); + } + + // ----------------------------------------------------------- + // These configurations are only possible with legacy macro scoping + + fn check33() { + macro_rules! gen_outer_gen_inner { () => { + macro_rules! m { () => {} } + gen_inner!(); + }} + gen_outer_gen_inner!(); + + m!(); //~ ERROR `m` is ambiguous + } + + fn check34() { + macro_rules! gen_outer_inner { () => { + macro_rules! m { () => { Wrong } } + macro_rules! m { () => { Right } } + }} + gen_outer_inner!(); + + m!(); // OK + } + + fn check35() { + macro_rules! gen_gen_outer_inner { () => { + gen_outer!(); + macro_rules! m { () => { Right } } + }} + gen_gen_outer_inner!(); + + m!(); // OK + } + + fn check61() { + macro_rules! gen_outer_gen_inner { () => { + macro_rules! m { () => {} } + gen_inner!(); + }} + gen_outer_gen_inner!(); + + macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous + gen_invoc!(); + } + + fn check62() { + macro_rules! gen_outer_inner { () => { + macro_rules! m { () => { Wrong } } + macro_rules! m { () => { Right } } + }} + gen_outer_inner!(); + + gen_invoc!(); // OK + } + + fn check63() { + macro_rules! gen_gen_outer_inner { () => { + gen_outer!(); + macro_rules! m { () => { Right } } + }} + gen_gen_outer_inner!(); + + gen_invoc!(); // OK + } +}} + +include!(); + +fn main() {} diff --git a/tests/ui/macros/restricted-shadowing-legacy.stderr b/tests/ui/macros/restricted-shadowing-legacy.stderr new file mode 100644 index 000000000..b8865112e --- /dev/null +++ b/tests/ui/macros/restricted-shadowing-legacy.stderr @@ -0,0 +1,227 @@ +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:101:13 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:97:9 + | +LL | macro_rules! m { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:139:42 + | +LL | macro_rules! gen_invoc { () => { m!() } } + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:135:9 + | +LL | macro_rules! m { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:148:9 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:144:9 + | +LL | macro_rules! m { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:164:9 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:85:9 + | +LL | macro_rules! m { () => { Wrong } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:180:13 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:85:9 + | +LL | macro_rules! m { () => { Wrong } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:218:42 + | +LL | macro_rules! gen_invoc { () => { m!() } } + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:85:9 + | +LL | macro_rules! m { () => { Wrong } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:232:9 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:227:13 + | +LL | macro_rules! m { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-legacy.rs:262:42 + | +LL | macro_rules! gen_invoc { () => { m!() } } + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:88:9 + | +LL | macro_rules! m { () => { Right } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-legacy.rs:257:13 + | +LL | macro_rules! m { () => {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/restricted-shadowing-modern.rs b/tests/ui/macros/restricted-shadowing-modern.rs new file mode 100644 index 000000000..1151a829e --- /dev/null +++ b/tests/ui/macros/restricted-shadowing-modern.rs @@ -0,0 +1,241 @@ +// Legend: +// `N` - number of combination, from 0 to 4*4*4=64 +// `Outer < Invoc` means that expansion that produced macro definition `Outer` +// is a strict ancestor of expansion that produced macro definition `Inner`. +// `>`, `=` and `Unordered` mean "strict descendant", "same" and +// "not in ordering relation" for parent expansions. +// `+` - possible configuration +// `-` - configuration impossible due to properties of partial ordering +// `-?` - configuration impossible due to block/scope syntax +// `+?` - configuration possible only with legacy scoping + +// N | Outer ~ Invoc | Invoc ~ Inner | Outer ~ Inner | Possible | +// 1 | < | < | < | + | +// 2 | < | < | = | - | +// 3 | < | < | > | - | +// 4 | < | < | Unordered | - | +// 5 | < | = | < | + | +// 6 | < | = | = | - | +// 7 | < | = | > | - | +// 8 | < | = | Unordered | - | +// 9 | < | > | < | + | +// 10 | < | > | = | + | +// 11 | < | > | > | -? | +// 12 | < | > | Unordered | -? | +// 13 | < | Unordered | < | + | +// 14 | < | Unordered | = | - | +// 15 | < | Unordered | > | - | +// 16 | < | Unordered | Unordered | -? | +// 17 | = | < | < | + | +// 18 | = | < | = | - | +// 19 | = | < | > | - | +// 20 | = | < | Unordered | - | +// 21 | = | = | < | - | +// 22 | = | = | = | + | +// 23 | = | = | > | - | +// 24 | = | = | Unordered | - | +// 25 | = | > | < | - | +// 26 | = | > | = | - | +// 27 | = | > | > | -? | +// 28 | = | > | Unordered | - | +// 29 | = | Unordered | < | - | +// 30 | = | Unordered | = | - | +// 31 | = | Unordered | > | - | +// 32 | = | Unordered | Unordered | -? | +// 33 | > | < | < | -? | +// 34 | > | < | = | -? | +// 35 | > | < | > | -? | +// 36 | > | < | Unordered | + | +// 37 | > | = | < | - | +// 38 | > | = | = | - | +// 39 | > | = | > | + | +// 40 | > | = | Unordered | - | +// 41 | > | > | < | - | +// 42 | > | > | = | - | +// 43 | > | > | > | -? | +// 44 | > | > | Unordered | - | +// 45 | > | Unordered | < | - | +// 46 | > | Unordered | = | - | +// 47 | > | Unordered | > | -? | +// 48 | > | Unordered | Unordered | -? | +// 49 | Unordered | < | < | -? | +// 50 | Unordered | < | = | - | +// 51 | Unordered | < | > | - | +// 52 | Unordered | < | Unordered | + | +// 53 | Unordered | = | < | - | +// 54 | Unordered | = | = | - | +// 55 | Unordered | = | > | - | +// 56 | Unordered | = | Unordered | + | +// 57 | Unordered | > | < | - | +// 58 | Unordered | > | = | - | +// 59 | Unordered | > | > | + | +// 60 | Unordered | > | Unordered | + | +// 61 | Unordered | Unordered | < | -? | +// 62 | Unordered | Unordered | = | -? | +// 63 | Unordered | Unordered | > | -? | +// 64 | Unordered | Unordered | Unordered | + | + +#![feature(decl_macro, rustc_attrs)] + +struct Right; +// struct Wrong; // not defined + +#[rustc_macro_transparency = "transparent"] +macro include() { + #[rustc_macro_transparency = "transparent"] + macro gen_outer() { + macro m() { Wrong } + } + #[rustc_macro_transparency = "transparent"] + macro gen_inner() { + macro m() { Right } + } + #[rustc_macro_transparency = "transparent"] + macro gen_invoc() { + m!() + } + + fn check1() { + macro m() {} + { + #[rustc_macro_transparency = "transparent"] + macro gen_gen_inner_invoc() { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + } + gen_gen_inner_invoc!(); + } + } + + fn check5() { + macro m() { Wrong } + { + #[rustc_macro_transparency = "transparent"] + macro gen_inner_invoc() { + macro m() { Right } + m!(); // OK + } + gen_inner_invoc!(); + } + } + + fn check9() { + macro m() { Wrong } + { + #[rustc_macro_transparency = "transparent"] + macro gen_inner_gen_invoc() { + macro m() { Right } + gen_invoc!(); // OK + } + gen_inner_gen_invoc!(); + } + } + + fn check10() { + macro m() { Wrong } + { + macro m() { Right } + gen_invoc!(); // OK + } + } + + fn check13() { + macro m() {} + { + gen_inner!(); + #[rustc_macro_transparency = "transparent"] + macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous + gen_invoc!(); + } + } + + fn check17() { + macro m() {} + { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + } + } + + fn check22() { + macro m() { Wrong } + { + macro m() { Right } + m!(); // OK + } + } + + fn check36() { + gen_outer!(); + { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + } + } + + fn check39() { + gen_outer!(); + { + macro m() { Right } + m!(); // OK + } + } + + fn check52() { + gen_outer!(); + { + #[rustc_macro_transparency = "transparent"] + macro gen_gen_inner_invoc() { + gen_inner!(); + m!(); //~ ERROR `m` is ambiguous + } + gen_gen_inner_invoc!(); + } + } + + fn check56() { + gen_outer!(); + { + #[rustc_macro_transparency = "transparent"] + macro gen_inner_invoc() { + macro m() { Right } + m!(); // OK + } + gen_inner_invoc!(); + } + } + + fn check59() { + gen_outer!(); + { + macro m() { Right } + gen_invoc!(); // OK + } + } + + fn check60() { + gen_outer!(); + { + #[rustc_macro_transparency = "transparent"] + macro gen_inner_gen_invoc() { + macro m() { Right } + gen_invoc!(); // OK + } + gen_inner_gen_invoc!(); + } + } + + fn check64() { + gen_outer!(); + { + gen_inner!(); + #[rustc_macro_transparency = "transparent"] + macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous + gen_invoc!(); + } + } +} + +include!(); + +fn main() {} diff --git a/tests/ui/macros/restricted-shadowing-modern.stderr b/tests/ui/macros/restricted-shadowing-modern.stderr new file mode 100644 index 000000000..27665bfc3 --- /dev/null +++ b/tests/ui/macros/restricted-shadowing-modern.stderr @@ -0,0 +1,171 @@ +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:104:17 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:99:9 + | +LL | macro m() {} + | ^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:147:33 + | +LL | macro gen_invoc() { m!() } + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:143:9 + | +LL | macro m() {} + | ^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:156:13 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:153:9 + | +LL | macro m() {} + | ^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:172:13 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:87:9 + | +LL | macro m() { Wrong } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:190:17 + | +LL | m!(); + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:87:9 + | +LL | macro m() { Wrong } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `m` is ambiguous + --> $DIR/restricted-shadowing-modern.rs:233:33 + | +LL | macro gen_invoc() { m!() } + | ^ ambiguous name +... +LL | include!(); + | ---------- in this macro invocation + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:91:9 + | +LL | macro m() { Right } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation +note: `m` could also refer to the macro defined here + --> $DIR/restricted-shadowing-modern.rs:87:9 + | +LL | macro m() { Wrong } + | ^^^^^^^^^^^^^^^^^^^ +... +LL | include!(); + | ---------- in this macro invocation + = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs new file mode 100644 index 000000000..b8b6f0846 --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -0,0 +1,186 @@ +// edition:2021 +// ignore-tidy-linelength +// only-x86_64 +// run-pass +// needs-unwind Asserting on contents of error message + +#![allow(path_statements, unused_allocation)] +#![feature(box_syntax, core_intrinsics, generic_assert, generic_assert_internals)] + +macro_rules! test { + ( + let mut $elem_ident:ident = $elem_expr:expr; + [ $($assert:tt)* ] => $msg:literal + ) => { + { + #[allow(unused_assignments, unused_mut, unused_variables)] + let rslt = std::panic::catch_unwind(|| { + let mut $elem_ident = $elem_expr; + assert!($($assert)*); + }); + let err = rslt.unwrap_err(); + if let Some(elem) = err.downcast_ref::<String>() { + assert_eq!(elem, &$msg); + } + else if let Some(elem) = err.downcast_ref::<&str>() { + assert_eq!(elem, &$msg); + } + else { + panic!("assert!( ... ) should return a string"); + } + } + } +} + +macro_rules! tests { + ( + let mut $elem_ident:ident = $elem_expr:expr; + + $( + [ $($elem_assert:tt)* ] => $elem_msg:literal + )+ + ) => { + $( + test!( + let mut $elem_ident = $elem_expr; + [ $($elem_assert)* ] => $elem_msg + ); + )+ + } +} + +const FOO: Foo = Foo { bar: 1 }; + +#[derive(Clone, Copy, Debug, PartialEq)] +struct Foo { + bar: i32 +} + +impl Foo { + fn add(&self, a: i32, b: i32) -> i32 { a + b } +} + +fn add(a: i32, b: i32) -> i32 { a + b } + +fn main() { + // ***** Allowed ***** + + tests!( + let mut elem = 1i32; + + // addr of + [ &elem == &3 ] => "Assertion failed: &elem == &3\nWith captures:\n elem = 1\n" + + // array + [ [elem][0] == 3 ] => "Assertion failed: [elem][0] == 3\nWith captures:\n elem = 1\n" + + // binary + [ elem + 1 == 3 ] => "Assertion failed: elem + 1 == 3\nWith captures:\n elem = 1\n" + + // call + [ add(elem, elem) == 3 ] => "Assertion failed: add(elem, elem) == 3\nWith captures:\n elem = 1\n" + + // cast + [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n elem = 1\n" + + // index + [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n elem = 1\n" + + // method call + [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n elem = 1\n" + + // paren + [ (elem) == 3 ] => "Assertion failed: (elem) == 3\nWith captures:\n elem = 1\n" + + // range + [ (0..elem) == (0..3) ] => "Assertion failed: (0..elem) == (0..3)\nWith captures:\n elem = 1\n" + + // repeat + [ [elem; 1] == [3; 1] ] => "Assertion failed: [elem; 1] == [3; 1]\nWith captures:\n elem = 1\n" + + // struct + [ Foo { bar: elem } == Foo { bar: 3 } ] => "Assertion failed: Foo { bar: elem } == Foo { bar: 3 }\nWith captures:\n elem = 1\n" + + // tuple + [ (elem, 1) == (3, 3) ] => "Assertion failed: (elem, 1) == (3, 3)\nWith captures:\n elem = 1\n" + + // unary + [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n elem = 1\n" + ); + + // ***** Disallowed ***** + + tests!( + let mut elem = 1i32; + + // assign + [ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3" + + // assign op + [ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3" + + // async + [ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3" + + // await + + // block + [ { elem } == 3 ] => "Assertion failed: { elem } == 3" + + // box + [ box elem == box 3 ] => "Assertion failed: box elem == box 3" + + // break + [ loop { break elem; } == 3 ] => "Assertion failed: loop { break elem; } == 3" + + // closure + [(|| elem)() == 3 ] => "Assertion failed: (|| elem)() == 3" + + // const block + + // continue + + // err + + // field + [ FOO.bar == 3 ] => "Assertion failed: FOO.bar == 3" + + // for loop + [ { for _ in 0..elem { elem; } elem } == 3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3" + + // if + [ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3" + + // inline asm + + // let + [ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3" + + // lit + + // loop + [ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3" + + // mac call + + // match + [ match elem { _ => elem } == 3 ] => "Assertion failed: match elem { _ => elem, } == 3" + + // ret + [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3" + + // try + [ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)" + + // try block + + // underscore + + // while + [ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3" + + // yeet + + // yield + ); +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs new file mode 100644 index 000000000..d46f396ee --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs @@ -0,0 +1,44 @@ +// aux-build:common.rs +// ignore-tidy-linelength +// only-x86_64 +// run-pass +// needs-unwind Asserting on contents of error message + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +extern crate common; + +#[derive(Clone, Copy, PartialEq)] +struct CopyNoDebug(i32); + +#[derive(Debug, PartialEq)] +struct NoCopyDebug(i32); + +#[derive(PartialEq)] +struct NoCopyNoDebug(i32); + +fn main() { + // Has Copy but does not have Debug + common::test!( + let mut copy_no_debug = CopyNoDebug(1); + [ copy_no_debug == CopyNoDebug(3) ] => "Assertion failed: copy_no_debug == CopyNoDebug(3)\nWith captures:\n copy_no_debug = N/A\n" + ); + + // Does not have Copy but has Debug + common::test!( + let mut no_copy_debug = NoCopyDebug(1); + [ no_copy_debug == NoCopyDebug(3) ] => "Assertion failed: no_copy_debug == NoCopyDebug(3)\nWith captures:\n no_copy_debug = N/A\n" + ); + + // Does not have Copy and does not have Debug + common::test!( + let mut no_copy_no_debug = NoCopyNoDebug(1); + [ no_copy_no_debug == NoCopyNoDebug(3) ] => "Assertion failed: no_copy_no_debug == NoCopyNoDebug(3)\nWith captures:\n no_copy_no_debug = N/A\n" + ); + + // Unevaluated (Expression short-circuited) + common::test!( + let mut elem = true; + [ false && elem ] => "Assertion failed: false && elem\nWith captures:\n elem = N/A\n" + ); +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs new file mode 100644 index 000000000..6a1435f79 --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -0,0 +1,13 @@ +// compile-flags: --test +// run-pass + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +#[should_panic(expected = "Custom user message")] +#[test] +fn test() { + assert!(1 == 3, "Custom user message"); +} + +fn main() { +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs new file mode 100644 index 000000000..1f5a29ab5 --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -0,0 +1,15 @@ +// aux-build:common.rs +// only-x86_64 +// run-pass +// needs-unwind Asserting on contents of error message + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +extern crate common; + +fn main() { + common::test!( + let mut _nothing = (); + [ 1 == 3 ] => "Assertion failed: 1 == 3" + ); +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs new file mode 100644 index 000000000..903ed507c --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs @@ -0,0 +1,25 @@ +#[macro_export] +macro_rules! test { + ( + let mut $elem_ident:ident = $elem_expr:expr; + [ $($assert:tt)* ] => $msg:literal + ) => { + { + #[allow(unused_assignments, unused_mut, unused_variables)] + let rslt = std::panic::catch_unwind(|| { + let mut $elem_ident = $elem_expr; + assert!($($assert)*); + }); + let err = rslt.unwrap_err(); + if let Some(elem) = err.downcast_ref::<String>() { + assert_eq!(elem, &$msg); + } + else if let Some(elem) = err.downcast_ref::<&str>() { + assert_eq!(elem, &$msg); + } + else { + panic!("assert!( ... ) should return a string"); + } + } + } +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs new file mode 100644 index 000000000..01860adaa --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -0,0 +1,26 @@ +// compile-flags: --test +// ignore-tidy-linelength +// run-pass + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +use std::fmt::{Debug, Formatter}; + +#[derive(Clone, Copy, PartialEq)] +struct CopyDebug(i32); + +impl Debug for CopyDebug { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str("With great power comes great electricity bills") + } +} + +#[should_panic(expected = "Assertion failed: copy_debug == CopyDebug(3)\nWith captures:\n copy_debug = With great power comes great electricity bills\n")] +#[test] +fn test() { + let copy_debug = CopyDebug(1); + assert!(copy_debug == CopyDebug(3)); +} + +fn main() { +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs new file mode 100644 index 000000000..5ec84b08f --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + assert!(elem as usize); +} + +fn addr_of() { + let elem = 1i32; + assert!(&elem); +} + +fn binary() { + let elem = 1i32; + assert!(elem == 1); + assert!(elem >= 1); + assert!(elem > 0); + assert!(elem < 3); + assert!(elem <= 3); + assert!(elem != 3); +} + +fn unary() { + let elem = &1i32; + assert!(*elem); +} + +fn main() { +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout new file mode 100644 index 000000000..90f858f80 --- /dev/null +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -0,0 +1,147 @@ +#![feature(prelude_import)] +#![no_std] +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*{ + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + __local_bind0 + } as usize)) { + + + + + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn addr_of() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!&*__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn binary() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn unary() { + let elem = &1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!**__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn main() {} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs new file mode 100644 index 000000000..ab8d95a41 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs @@ -0,0 +1,271 @@ +// run-pass + +#![feature(macro_metavar_expr)] + +fn main() { + macro_rules! one_nested_count_and_length { + ( $( [ $( $l:literal ),* ] ),* ) => { + [ + // outer-most repetition + $( + // inner-most repetition + $( + ${ignore(l)} ${index()}, ${length()}, + )* + ${count(l)}, ${index()}, ${length()}, + )* + ${count(l)}, + ] + }; + } + assert_eq!( + one_nested_count_and_length!(["foo"], ["bar", "baz"]), + [ + // # ["foo"] + + // ## inner-most repetition (first iteration) + // + // `index` is 0 because this is the first inner-most iteration. + // `length` is 1 because there is only one inner-most repetition, "foo". + 0, 1, + + // ## outer-most repetition (first iteration) + // + // `count` is 1 because of "foo", i,e, `$l` has only one repetition, + // `index` is 0 because this is the first outer-most iteration. + // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"] + 1, 0, 2, + + // # ["bar", "baz"] + + // ## inner-most repetition (first iteration) + // + // `index` is 0 because this is the first inner-most iteration + // `length` is 2 because there are repetitions, "bar" and "baz" + 0, 2, + + // ## inner-most repetition (second iteration) + // + // `index` is 1 because this is the second inner-most iteration + // `length` is 2 because there are repetitions, "bar" and "baz" + 1, 2, + + // ## outer-most repetition (second iteration) + // + // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions, + // `index` is 1 because this is the second outer-most iteration + // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"] + 2, 1, 2, + + // # last count + + // Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz" + 3, + ] + ); + + // Based on the above explanation, the following macros should be straightforward + + // Grouped from the outer-most to the inner-most + macro_rules! three_nested_count { + ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => { + &[ + $( $( $( + &[ + ${ignore(i)} ${count(i, 0)}, + ][..], + )* )* )* + + $( $( + &[ + ${ignore(i)} ${count(i, 0)}, + ${ignore(i)} ${count(i, 1)}, + ][..], + )* )* + + $( + &[ + ${ignore(i)} ${count(i, 0)}, + ${ignore(i)} ${count(i, 1)}, + ${ignore(i)} ${count(i, 2)}, + ][..], + )* + + &[ + ${count(i, 0)}, + ${count(i, 1)}, + ${count(i, 2)}, + ${count(i, 3)}, + ][..] + ][..] + } + } + assert_eq!( + three_nested_count!( + { + [ (a b c) (d e f) ] + [ (g h) (i j k l m) ] + [ (n) ] + } + { + [ (o) (p q) (r s) ] + [ (t u v w x y z) ] + } + ), + &[ + // a b c + &[3][..], + // d e f + &[3][..], + // g h + &[2][..], + // i j k l m + &[5][..], + // n + &[1][..], + // o + &[1][..], + // p q + &[2][..], + // r s + &[2][..], + // t u v w x y z + &[7][..], + + // (a b c) (d e f) + &[2, 6][..], + // (g h) (i j k l m) + &[2, 7][..], + // (n) + &[1, 1][..], + // (o) (p q) (r s) + &[3, 5][..], + // (t u v w x y z) + &[1, 7][..], + + // [ (a b c) (d e f) ] + // [ (g h) (i j k l m) ] + // [ (n) ] + &[3, 5, 14][..], + // [ (o) (p q) (r s) ] + // [ (t u v w x y z) ] + &[2, 4, 12][..], + + // { + // [ (a b c) (d e f) ] + // [ (g h) (i j k l m) ] + // [ (n) ] + // } + // { + // [ (o) (p q) (r s) ] + // [ (t u v w x y z) ] + // } + &[2, 5, 9, 26][..] + ][..] + ); + + // Grouped from the outer-most to the inner-most + macro_rules! three_nested_length { + ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => { + &[ + $( $( $( $( + &[ + ${ignore(i)} ${length(3)}, + ${ignore(i)} ${length(2)}, + ${ignore(i)} ${length(1)}, + ${ignore(i)} ${length(0)}, + ][..], + )* )* )* )* + + $( $( $( + &[ + ${ignore(i)} ${length(2)}, + ${ignore(i)} ${length(1)}, + ${ignore(i)} ${length(0)}, + ][..], + )* )* )* + + $( $( + &[ + ${ignore(i)} ${length(1)}, + ${ignore(i)} ${length(0)}, + ][..], + )* )* + + $( + &[ + ${ignore(i)} ${length(0)}, + ][..], + )* + ][..] + } + } + assert_eq!( + three_nested_length!( + { + [ (a b c) (d e f) ] + [ (g h) (i j k l m) ] + [ (n) ] + } + { + [ (o) (p q) (r s) ] + [ (t u v w x y z) ] + } + ), + &[ + // a b c + &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], + // d e f + &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], + // g h + &[2, 3, 2, 2][..], &[2, 3, 2, 2][..], + // i j k l m + &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], + &[2, 3, 2, 5][..], + // n + &[2, 3, 1, 1][..], + // o + &[2, 2, 3, 1][..], + // p q + &[2, 2, 3, 2][..], &[2, 2, 3, 2][..], + // r s + &[2, 2, 3, 2][..], &[2, 2, 3, 2][..], + // t u v w x y z + &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], + &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], + + // (a b c) (d e f) + &[2, 3, 2][..], &[2, 3, 2][..], + // (g h) (i j k l m) + &[2, 3, 2][..], &[2, 3, 2][..], + // (n) + &[2, 3, 1][..], + // (o) (p q) (r s) + &[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..], + // (t u v w x y z) + &[2, 2, 1][..], + + // [ (a b c) (d e f) ] + // [ (g h) (i j k l m) ] + // [ (n) ] + &[2, 3][..], &[2, 3][..], &[2, 3,][..], + // [ (o) (p q) (r s) ] + // [ (t u v w x y z) ] + &[2, 2][..], &[2, 2][..], + + // { + // [ (a b c) (d e f) ] + // [ (g h) (i j k l m) ] + // [ (n) ] + // } + // { + // [ (o) (p q) (r s) ] + // [ (t u v w x y z) ] + // } + &[2][..], &[2][..] + ][..] + ); + + // It is possible to say, to some degree, that count is an "amalgamation" of length (see + // each length line result and compare them with the count results) +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs new file mode 100644 index 000000000..ed94c27cf --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs @@ -0,0 +1,28 @@ +// run-pass + +#![feature(macro_metavar_expr)] + +macro_rules! nested { + ( $a:ident ) => { + macro_rules! $a { + ( $$( $b:ident ),* ) => { + $$( + macro_rules! $b { + ( $$$$( $c:ident ),* ) => { + $$$$( + fn $c() -> &'static str { stringify!($c) } + ),* + }; + } + )* + }; + } + }; +} + +fn main() { + nested!(a); + a!(b); + b!(c); + assert_eq!(c(), "c"); +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs new file mode 100644 index 000000000..d05cd1b31 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs @@ -0,0 +1,148 @@ +// run-pass + +#![feature(macro_metavar_expr)] + +/// Count the number of idents in a macro repetition. +macro_rules! count_idents { + ( $( $i:ident ),* ) => { + ${count(i)} + }; +} + +/// Count the number of idents in a 2-dimensional macro repetition. +macro_rules! count_idents_2 { + ( $( [ $( $i:ident ),* ] ),* ) => { + ${count(i)} + }; +} + +/// Mostly counts the number of OUTER-MOST repetitions +macro_rules! count_depth_limits { + ( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => { + ( + ( + ${count(inner)}, + ${count(inner, 0)}, + ${count(inner, 1)}, + ${count(inner, 2)}, + ${count(inner, 3)}, + ), + ( + ${count(outer)}, + ${count(outer, 0)}, + ${count(outer, 1)}, + ${count(outer, 2)}, + ), + ) + }; +} + +/// Produce (index, length) pairs for literals in a macro repetition. +/// The literal is not included in the output, so this macro uses the +/// `ignore` meta-variable expression to create a non-expanding +/// repetition binding. +macro_rules! enumerate_literals { + ( $( ($l:stmt) ),* ) => { + [$( ${ignore(l)} (${index()}, ${length()}) ),*] + }; +} + +/// Produce index and length tuples for literals in a 2-dimensional +/// macro repetition. +macro_rules! enumerate_literals_2 { + ( $( [ $( ($l:literal) ),* ] ),* ) => { + [ + $( + $( + ( + ${index(1)}, + ${length(1)}, + ${index(0)}, + ${length(0)}, + $l + ), + )* + )* + ] + }; +} + +/// Generate macros that count idents and then add a constant number +/// to the count. +/// +/// This macro uses dollar escaping to make it unambiguous as to which +/// macro the repetition belongs to. +macro_rules! make_count_adders { + ( $( $i:ident, $b:literal );* ) => { + $( + macro_rules! $i { + ( $$( $$j:ident ),* ) => { + $b + $${count(j)} + }; + } + )* + }; +} + +make_count_adders! { plus_one, 1; plus_five, 5 } + +/// Generate a macro that allows selection of a particular literal +/// from a sequence of inputs by their identifier. +/// +/// This macro uses dollar escaping to make it unambiguous as to which +/// macro the repetition belongs to, and to allow expansion of an +/// identifier the name of which is not known in the definition +/// of `make_picker`. +macro_rules! make_picker { + ( $m:ident => $( $i:ident ),* ; $p:ident ) => { + macro_rules! $m { + ( $( $$ $i:literal ),* ) => { + $$ $p + }; + } + }; +} + +make_picker!(first => a, b; a); + +make_picker!(second => a, b; b); + +fn main() { + assert_eq!(count_idents!(a, b, c), 3); + assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6); + assert_eq!( + count_depth_limits! { + { + [ A: (a b c) D: (d e f) ] + [ G: (g h) I: (i j k l m) ] + [ N: (n) ] + } + { + [ O: (o) P: (p q) R: (r s) ] + [ T: (t u v w x y z) ] + } + }, + ((26, 2, 5, 9, 26), (9, 2, 5, 9)) + ); + assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]); + assert_eq!( + enumerate_literals_2![ + [("foo"), ("bar"), ("baz")], + [("qux"), ("quux"), ("quuz"), ("xyzzy")] + ], + [ + (0, 2, 0, 3, "foo"), + (0, 2, 1, 3, "bar"), + (0, 2, 2, 3, "baz"), + + (1, 2, 0, 4, "qux"), + (1, 2, 1, 4, "quux"), + (1, 2, 2, 4, "quuz"), + (1, 2, 3, 4, "xyzzy"), + ] + ); + assert_eq!(plus_one!(a, b, c), 4); + assert_eq!(plus_five!(a, b), 7); + assert_eq!(first!(1, 2), 1); + assert_eq!(second!(1, 2), 2); +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs new file mode 100644 index 000000000..b954967c4 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs @@ -0,0 +1,102 @@ +// run-pass + +#![feature(macro_metavar_expr)] + +#[derive(Debug)] +struct Example<'a> { + _indexes: &'a [(u32, u32)], + _counts: &'a [u32], + _nested: Vec<Example<'a>>, +} + +macro_rules! example { + ( $( [ $( ( $( $x:ident )* ) )* ] )* ) => { + Example { + _indexes: &[], + _counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}], + _nested: vec![ + $( + Example { + _indexes: &[(${index()}, ${length()})], + _counts: &[${count(x, 0)}, ${count(x, 1)}], + _nested: vec![ + $( + Example { + _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})], + _counts: &[${count(x)}], + _nested: vec![ + $( + Example { + _indexes: &[ + (${index(2)}, ${length(2)}), + (${index(1)}, ${length(1)}), + (${index()}, ${length()}) + ], + _counts: &[], + _nested: vec![], + ${ignore(x)} + } + ),* + ] + } + ),* + ] + } + ),* + ] + } + }; +} + +static EXPECTED: &str = concat!( + "Example { _indexes: [], _counts: [2, 4, 13], _nested: [", + concat!( + "Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [", + concat!( + "Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [", + concat!( + "Example { _indexes: [(0, 2), (0, 3), (0, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (0, 3), (1, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (0, 3), (2, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (0, 3), (3, 4)], _counts: [], _nested: [] }", + ), + "] }, ", + "Example { _indexes: [(0, 2), (1, 3)], _counts: [4], _nested: [", + concat!( + "Example { _indexes: [(0, 2), (1, 3), (0, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (1, 3), (1, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (1, 3), (2, 4)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (1, 3), (3, 4)], _counts: [], _nested: [] }", + ), + "] }, ", + "Example { _indexes: [(0, 2), (2, 3)], _counts: [2], _nested: [", + concat!( + "Example { _indexes: [(0, 2), (2, 3), (0, 2)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(0, 2), (2, 3), (1, 2)], _counts: [], _nested: [] }", + ), + "] }", + ), + "] }, ", + "Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [", + concat!( + "Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [", + concat!( + "Example { _indexes: [(1, 2), (0, 1), (0, 3)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(1, 2), (0, 1), (1, 3)], _counts: [], _nested: [] }, ", + "Example { _indexes: [(1, 2), (0, 1), (2, 3)], _counts: [], _nested: [] }", + ), + "] }", + ), + "] }", + ), + "] }", +); + +fn main() { + let e = example! { + [ ( A B C D ) ( E F G H ) ( I J ) ] + [ ( K L M ) ] + }; + let debug = format!("{:?}", e); + assert_eq!(debug, EXPECTED); +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs new file mode 100644 index 000000000..6a0d68bd6 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs @@ -0,0 +1,43 @@ +#![feature(macro_metavar_expr)] + +macro_rules! a { + ( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => { + ( + ${count(foo, 0)}, + ${count(foo, 10)}, + //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4 + ) + }; +} + +macro_rules! b { + ( $( { $( [ $( $foo:ident )* ] )* } )* ) => { + ( + $( $( $( + ${ignore(foo)} + ${index(0)}, + ${index(10)}, + //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3 + )* )* )* + ) + }; +} + +macro_rules! c { + ( $( { $( $foo:ident )* } )* ) => { + ( + $( $( + ${ignore(foo)} + ${length(0)} + ${length(10)} + //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2 + )* )* + ) + }; +} + +fn main() { + a!( { [ (a) ] [ (b c) ] } ); + b!( { [ a b ] } ); + c!({ a }); +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr new file mode 100644 index 000000000..236122b64 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr @@ -0,0 +1,20 @@ +error: depth parameter on meta-variable expression `count` must be less than 4 + --> $DIR/out-of-bounds-arguments.rs:7:14 + | +LL | ${count(foo, 10)}, + | ^^^^^^^^^^^^^^^^ + +error: depth parameter on meta-variable expression `index` must be less than 3 + --> $DIR/out-of-bounds-arguments.rs:19:18 + | +LL | ${index(10)}, + | ^^^^^^^^^^^ + +error: depth parameter on meta-variable expression `length` must be less than 2 + --> $DIR/out-of-bounds-arguments.rs:32:18 + | +LL | ${length(10)} + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs new file mode 100644 index 000000000..b4fef11f1 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs @@ -0,0 +1,44 @@ +macro_rules! count { + ( $( $e:stmt ),* ) => { + ${ count(e) } + //~^ ERROR meta-variable expressions are unstable + }; +} + +macro_rules! dollar_dollar { + () => { + macro_rules! bar { + ( $$( $$any:tt )* ) => { $$( $$any )* }; + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + } + }; +} + +macro_rules! index { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${index()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + +macro_rules! ignore { + ( $( $i:stmt ),* ) => {{ + 0 $( + 1 ${ignore(i)} )* + //~^ ERROR meta-variable expressions are unstable + }}; +} + +macro_rules! length { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${length()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + +fn main() { +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr new file mode 100644 index 000000000..ecf598b10 --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr @@ -0,0 +1,93 @@ +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:3:10 + | +LL | ${ count(e) } + | ^^^^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:16 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:20 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:39 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:43 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:13 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:26 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:30:19 + | +LL | 0 $( + 1 ${ignore(i)} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:13 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:26 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^ + | + = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs new file mode 100644 index 000000000..fdf16442d --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs @@ -0,0 +1,165 @@ +#![feature(macro_metavar_expr)] + +// `curly` = Right hand side curly brackets +// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function" +// `round` = Left hand side round brackets + +macro_rules! curly__no_rhs_dollar__round { + ( $( $i:ident ),* ) => { ${ count(i) } }; +} + +macro_rules! curly__no_rhs_dollar__no_round { + ( $i:ident ) => { ${ count(i) } }; + //~^ ERROR `count` can not be placed inside the inner-most repetition +} + +macro_rules! curly__rhs_dollar__round { + ( $( $i:ident ),* ) => { ${ count($i) } }; + //~^ ERROR expected identifier, found `$` + //~| ERROR expected expression, found `$` +} + +macro_rules! curly__rhs_dollar__no_round { + ( $i:ident ) => { ${ count($i) } }; + //~^ ERROR expected identifier, found `$` + //~| ERROR expected expression, found `$` +} + +macro_rules! no_curly__no_rhs_dollar__round { + ( $( $i:ident ),* ) => { count(i) }; + //~^ ERROR cannot find function `count` in this scope + //~| ERROR cannot find value `i` in this scope +} + +macro_rules! no_curly__no_rhs_dollar__no_round { + ( $i:ident ) => { count(i) }; + //~^ ERROR cannot find function `count` in this scope + //~| ERROR cannot find value `i` in this scope +} + +macro_rules! no_curly__rhs_dollar__round { + ( $( $i:ident ),* ) => { count($i) }; + //~^ ERROR variable 'i' is still repeating at this depth +} + +macro_rules! no_curly__rhs_dollar__no_round { + ( $i:ident ) => { count($i) }; + //~^ ERROR cannot find function `count` in this scope +} + +// Other scenarios + +macro_rules! dollar_dollar_in_the_lhs { + ( $$ $a:ident ) => { + //~^ ERROR unexpected token: $ + }; +} + +macro_rules! extra_garbage_after_metavar { + ( $( $i:ident ),* ) => { + ${count() a b c} + //~^ ERROR unexpected token: a + //~| ERROR expected expression, found `$` + ${count(i a b c)} + //~^ ERROR unexpected token: a + ${count(i, 1 a b c)} + //~^ ERROR unexpected token: a + ${count(i) a b c} + //~^ ERROR unexpected token: a + + ${ignore(i) a b c} + //~^ ERROR unexpected token: a + ${ignore(i a b c)} + //~^ ERROR unexpected token: a + + ${index() a b c} + //~^ ERROR unexpected token: a + ${index(1 a b c)} + //~^ ERROR unexpected token: a + + ${index() a b c} + //~^ ERROR unexpected token: a + ${index(1 a b c)} + //~^ ERROR unexpected token: a + }; +} + +const IDX: usize = 1; +macro_rules! metavar_depth_is_not_literal { + ( $( $i:ident ),* ) => { ${ index(IDX) } }; + //~^ ERROR meta-variable expression depth must be a literal + //~| ERROR expected expression, found `$` +} + +macro_rules! metavar_in_the_lhs { + ( ${ length() } ) => { + //~^ ERROR unexpected token: { + //~| ERROR expected one of: `*`, `+`, or `?` + }; +} + +macro_rules! metavar_token_without_ident { + ( $( $i:ident ),* ) => { ${ ignore() } }; + //~^ ERROR expected identifier + //~| ERROR expected expression, found `$` +} + +macro_rules! metavar_with_literal_suffix { + ( $( $i:ident ),* ) => { ${ index(1u32) } }; + //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions + //~| ERROR expected expression, found `$` +} + +macro_rules! metavar_without_parens { + ( $( $i:ident ),* ) => { ${ count{i} } }; + //~^ ERROR meta-variable expression parameter must be wrapped in parentheses + //~| ERROR expected expression, found `$` +} + +macro_rules! open_brackets_without_tokens { + ( $( $i:ident ),* ) => { ${ {} } }; + //~^ ERROR expected expression, found `$` + //~| ERROR expected identifier +} + +macro_rules! unknown_count_ident { + ( $( $i:ident )* ) => { + ${count(foo)} + //~^ ERROR variable `foo` is not recognized in meta-variable expression + }; +} + +macro_rules! unknown_ignore_ident { + ( $( $i:ident )* ) => { + ${ignore(bar)} + //~^ ERROR variable `bar` is not recognized in meta-variable expression + }; +} + +macro_rules! unknown_metavar { + ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; + //~^ ERROR unrecognized meta-variable expression + //~| ERROR expected expression +} + +fn main() { + curly__no_rhs_dollar__round!(a, b, c); + curly__no_rhs_dollar__no_round!(a); + curly__rhs_dollar__round!(a, b, c); + curly__rhs_dollar__no_round!(a); + no_curly__no_rhs_dollar__round!(a, b, c); + no_curly__no_rhs_dollar__no_round!(a); + no_curly__rhs_dollar__round!(a, b, c); + no_curly__rhs_dollar__no_round!(a); + //~^ ERROR cannot find value `a` in this scope + + extra_garbage_after_metavar!(a); + metavar_depth_is_not_literal!(a); + metavar_token_without_ident!(a); + metavar_with_literal_suffix!(a); + metavar_without_parens!(a); + open_brackets_without_tokens!(a); + unknown_count_ident!(a); + unknown_ignore_ident!(a); + unknown_metavar!(a); +} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr new file mode 100644 index 000000000..a6cff95fd --- /dev/null +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -0,0 +1,385 @@ +error: expected identifier, found `$` + --> $DIR/syntax-errors.rs:17:33 + | +LL | ( $( $i:ident ),* ) => { ${ count($i) } }; + | ^^^^^ - help: try removing `$` + +error: expected identifier, found `$` + --> $DIR/syntax-errors.rs:23:26 + | +LL | ( $i:ident ) => { ${ count($i) } }; + | ^^^^^ - help: try removing `$` + +error: unexpected token: $ + --> $DIR/syntax-errors.rs:53:8 + | +LL | ( $$ $a:ident ) => { + | ^ + +note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions + --> $DIR/syntax-errors.rs:53:8 + | +LL | ( $$ $a:ident ) => { + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:60:19 + | +LL | ${count() a b c} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:60:19 + | +LL | ${count() a b c} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:63:19 + | +LL | ${count(i a b c)} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:63:19 + | +LL | ${count(i a b c)} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:65:22 + | +LL | ${count(i, 1 a b c)} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:65:22 + | +LL | ${count(i, 1 a b c)} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:67:20 + | +LL | ${count(i) a b c} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:67:20 + | +LL | ${count(i) a b c} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:70:21 + | +LL | ${ignore(i) a b c} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:70:21 + | +LL | ${ignore(i) a b c} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:72:20 + | +LL | ${ignore(i a b c)} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:72:20 + | +LL | ${ignore(i a b c)} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:75:19 + | +LL | ${index() a b c} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:75:19 + | +LL | ${index() a b c} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:77:19 + | +LL | ${index(1 a b c)} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:77:19 + | +LL | ${index(1 a b c)} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:80:19 + | +LL | ${index() a b c} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:80:19 + | +LL | ${index() a b c} + | ^ + +error: unexpected token: a + --> $DIR/syntax-errors.rs:82:19 + | +LL | ${index(1 a b c)} + | ^ + | +note: meta-variable expression must not have trailing tokens + --> $DIR/syntax-errors.rs:82:19 + | +LL | ${index(1 a b c)} + | ^ + +error: meta-variable expression depth must be a literal + --> $DIR/syntax-errors.rs:89:33 + | +LL | ( $( $i:ident ),* ) => { ${ index(IDX) } }; + | ^^^^^ + +error: unexpected token: { + --> $DIR/syntax-errors.rs:95:8 + | +LL | ( ${ length() } ) => { + | ^^^^^^^^^^^^ + +note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions + --> $DIR/syntax-errors.rs:95:8 + | +LL | ( ${ length() } ) => { + | ^^^^^^^^^^^^ + +error: expected one of: `*`, `+`, or `?` + --> $DIR/syntax-errors.rs:95:8 + | +LL | ( ${ length() } ) => { + | ^^^^^^^^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:102:33 + | +LL | ( $( $i:ident ),* ) => { ${ ignore() } }; + | ^^^^^^ + +error: only unsuffixes integer literals are supported in meta-variable expressions + --> $DIR/syntax-errors.rs:108:33 + | +LL | ( $( $i:ident ),* ) => { ${ index(1u32) } }; + | ^^^^^ + +error: meta-variable expression parameter must be wrapped in parentheses + --> $DIR/syntax-errors.rs:114:33 + | +LL | ( $( $i:ident ),* ) => { ${ count{i} } }; + | ^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:120:31 + | +LL | ( $( $i:ident ),* ) => { ${ {} } }; + | ^^^^^^ + +error: unrecognized meta-variable expression + --> $DIR/syntax-errors.rs:140:33 + | +LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; + | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length + +error: `count` can not be placed inside the inner-most repetition + --> $DIR/syntax-errors.rs:12:24 + | +LL | ( $i:ident ) => { ${ count(i) } }; + | ^^^^^^^^^^^^ + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:17:30 + | +LL | ( $( $i:ident ),* ) => { ${ count($i) } }; + | ^ expected expression +... +LL | curly__rhs_dollar__round!(a, b, c); + | ---------------------------------- in this macro invocation + | + = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:23:23 + | +LL | ( $i:ident ) => { ${ count($i) } }; + | ^ expected expression +... +LL | curly__rhs_dollar__no_round!(a); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: variable 'i' is still repeating at this depth + --> $DIR/syntax-errors.rs:41:36 + | +LL | ( $( $i:ident ),* ) => { count($i) }; + | ^^ + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:60:9 + | +LL | ${count() a b c} + | ^ expected expression +... +LL | extra_garbage_after_metavar!(a); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:89:30 + | +LL | ( $( $i:ident ),* ) => { ${ index(IDX) } }; + | ^ expected expression +... +LL | metavar_depth_is_not_literal!(a); + | -------------------------------- in this macro invocation + | + = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:102:30 + | +LL | ( $( $i:ident ),* ) => { ${ ignore() } }; + | ^ expected expression +... +LL | metavar_token_without_ident!(a); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:108:30 + | +LL | ( $( $i:ident ),* ) => { ${ index(1u32) } }; + | ^ expected expression +... +LL | metavar_with_literal_suffix!(a); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:114:30 + | +LL | ( $( $i:ident ),* ) => { ${ count{i} } }; + | ^ expected expression +... +LL | metavar_without_parens!(a); + | -------------------------- in this macro invocation + | + = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:120:30 + | +LL | ( $( $i:ident ),* ) => { ${ {} } }; + | ^ expected expression +... +LL | open_brackets_without_tokens!(a); + | -------------------------------- in this macro invocation + | + = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: variable `foo` is not recognized in meta-variable expression + --> $DIR/syntax-errors.rs:127:17 + | +LL | ${count(foo)} + | ^^^ + +error: variable `bar` is not recognized in meta-variable expression + --> $DIR/syntax-errors.rs:134:18 + | +LL | ${ignore(bar)} + | ^^^ + +error: expected expression, found `$` + --> $DIR/syntax-errors.rs:140:30 + | +LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; + | ^ expected expression +... +LL | unknown_metavar!(a); + | ------------------- in this macro invocation + | + = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `i` in this scope + --> $DIR/syntax-errors.rs:29:36 + | +LL | ( $( $i:ident ),* ) => { count(i) }; + | ^ not found in this scope +... +LL | no_curly__no_rhs_dollar__round!(a, b, c); + | ---------------------------------------- in this macro invocation + | + = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `i` in this scope + --> $DIR/syntax-errors.rs:35:29 + | +LL | ( $i:ident ) => { count(i) }; + | ^ not found in this scope +... +LL | no_curly__no_rhs_dollar__no_round!(a); + | ------------------------------------- in this macro invocation + | + = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find value `a` in this scope + --> $DIR/syntax-errors.rs:153:37 + | +LL | no_curly__rhs_dollar__no_round!(a); + | ^ not found in this scope + +error[E0425]: cannot find function `count` in this scope + --> $DIR/syntax-errors.rs:29:30 + | +LL | ( $( $i:ident ),* ) => { count(i) }; + | ^^^^^ not found in this scope +... +LL | no_curly__no_rhs_dollar__round!(a, b, c); + | ---------------------------------------- in this macro invocation + | + = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `count` in this scope + --> $DIR/syntax-errors.rs:35:23 + | +LL | ( $i:ident ) => { count(i) }; + | ^^^^^ not found in this scope +... +LL | no_curly__no_rhs_dollar__no_round!(a); + | ------------------------------------- in this macro invocation + | + = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `count` in this scope + --> $DIR/syntax-errors.rs:46:23 + | +LL | ( $i:ident ) => { count($i) }; + | ^^^^^ not found in this scope +... +LL | no_curly__rhs_dollar__no_round!(a); + | ---------------------------------- in this macro invocation + | + = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 40 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/same-sequence-span.rs b/tests/ui/macros/same-sequence-span.rs new file mode 100644 index 000000000..e0bb4d985 --- /dev/null +++ b/tests/ui/macros/same-sequence-span.rs @@ -0,0 +1,22 @@ +// aux-build:proc_macro_sequence.rs + +// Regression test for issue #62831: Check that multiple sequences with the same span in the +// left-hand side of a macro definition behave as if they had unique spans, and in particular that +// they don't crash the compiler. + +#![allow(unused_macros)] + +extern crate proc_macro_sequence; + +// When ignoring spans, this macro has the same macro definition as `generated_foo` in +// `proc_macro_sequence.rs`. +macro_rules! manual_foo { + (1 $x:expr $($y:tt,)* //~ERROR `$x:expr` may be followed by `$y:tt` + $(= $z:tt)* //~ERROR `$x:expr` may be followed by `=` + ) => {}; +} + +proc_macro_sequence::make_foo!(); //~ERROR `$x:expr` may be followed by `$y:tt` + //~^ERROR `$x:expr` may be followed by `=` + +fn main() {} diff --git a/tests/ui/macros/same-sequence-span.stderr b/tests/ui/macros/same-sequence-span.stderr new file mode 100644 index 000000000..bdd191e8e --- /dev/null +++ b/tests/ui/macros/same-sequence-span.stderr @@ -0,0 +1,43 @@ +error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments + --> $DIR/same-sequence-span.rs:14:18 + | +LL | (1 $x:expr $($y:tt,)* + | ^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments + --> $DIR/same-sequence-span.rs:15:18 + | +LL | $(= $z:tt)* + | ^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + +error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments + --> $DIR/same-sequence-span.rs:19:1 + | +LL | proc_macro_sequence::make_foo!(); + | ^------------------------------- + | | + | _in this macro invocation + | | +LL | | +LL | | +LL | | fn main() {} + | |_________________________________^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments + --> $DIR/same-sequence-span.rs:19:1 + | +LL | proc_macro_sequence::make_foo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments + | + = note: allowed there are: `=>`, `,` or `;` + = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/semi-after-macro-ty.rs b/tests/ui/macros/semi-after-macro-ty.rs new file mode 100644 index 000000000..f83ace8fa --- /dev/null +++ b/tests/ui/macros/semi-after-macro-ty.rs @@ -0,0 +1,8 @@ +// run-pass +macro_rules! foo { + ($t:ty; $p:path;) => {} +} + +fn main() { + foo!(i32; i32;); +} diff --git a/tests/ui/macros/span-covering-argument-1.rs b/tests/ui/macros/span-covering-argument-1.rs new file mode 100644 index 000000000..9b9506c80 --- /dev/null +++ b/tests/ui/macros/span-covering-argument-1.rs @@ -0,0 +1,13 @@ +macro_rules! bad { + ($s:ident whatever) => { + { + let $s = 0; + *&mut $s = 0; + //~^ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable [E0596] + } + } +} + +fn main() { + bad!(foo whatever); +} diff --git a/tests/ui/macros/span-covering-argument-1.stderr b/tests/ui/macros/span-covering-argument-1.stderr new file mode 100644 index 000000000..e57347b36 --- /dev/null +++ b/tests/ui/macros/span-covering-argument-1.stderr @@ -0,0 +1,18 @@ +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable + --> $DIR/span-covering-argument-1.rs:5:14 + | +LL | *&mut $s = 0; + | ^^^^^^^ cannot borrow as mutable +... +LL | bad!(foo whatever); + | ------------------ in this macro invocation + | + = note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider changing this to be mutable + | +LL | let mut $s = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/macros/stmt_expr_attr_macro_parse.rs b/tests/ui/macros/stmt_expr_attr_macro_parse.rs new file mode 100644 index 000000000..570191d2c --- /dev/null +++ b/tests/ui/macros/stmt_expr_attr_macro_parse.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(unused_macro_rules)] + +macro_rules! m { + ($e:expr) => { + "expr includes attr" + }; + (#[$attr:meta] $e:expr) => { + "expr excludes attr" + } +} + +macro_rules! n { + (#[$attr:meta] $e:expr) => { + "expr excludes attr" + }; + ($e:expr) => { + "expr includes attr" + } +} + +fn main() { + assert_eq!(m!(#[attr] 1), "expr includes attr"); + assert_eq!(n!(#[attr] 1), "expr excludes attr"); +} diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs new file mode 100644 index 000000000..5cd217df6 --- /dev/null +++ b/tests/ui/macros/stringify.rs @@ -0,0 +1,889 @@ +// run-pass +// edition:2021 +// compile-flags: --test + +#![feature(async_closure)] +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(generators)] +#![feature(more_qualified_paths)] +#![feature(raw_ref_op)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(type_ascription)] +#![deny(unused_macros)] + +macro_rules! stringify_block { + ($block:block) => { + stringify!($block) + }; +} + +macro_rules! stringify_expr { + ($expr:expr) => { + stringify!($expr) + }; +} + +macro_rules! stringify_item { + ($item:item) => { + stringify!($item) + }; +} + +macro_rules! stringify_meta { + ($meta:meta) => { + stringify!($meta) + }; +} + +macro_rules! stringify_pat { + ($pat:pat) => { + stringify!($pat) + }; +} + +macro_rules! stringify_path { + ($path:path) => { + stringify!($path) + }; +} + +macro_rules! stringify_stmt { + ($stmt:stmt) => { + stringify!($stmt) + }; +} + +macro_rules! stringify_ty { + ($ty:ty) => { + stringify!($ty) + }; +} + +macro_rules! stringify_vis { + ($vis:vis) => { + stringify!($vis) + }; +} + +#[test] +fn test_block() { + assert_eq!(stringify_block!({}), "{}"); + assert_eq!(stringify_block!({ true }), "{ true }"); + assert_eq!(stringify_block!({ return }), "{ return }"); + assert_eq!( + stringify_block!({ + return; + }), + "{ return; }", + ); + assert_eq!( + stringify_block!({ + let _; + true + }), + "{ let _; true }", + ); +} + +#[test] +fn test_expr() { + // ExprKind::Box + assert_eq!(stringify_expr!(box expr), "box expr"); + + // ExprKind::Array + assert_eq!(stringify_expr!([]), "[]"); + assert_eq!(stringify_expr!([true]), "[true]"); + assert_eq!(stringify_expr!([true,]), "[true]"); + assert_eq!(stringify_expr!([true, true]), "[true, true]"); + + // ExprKind::Call + assert_eq!(stringify_expr!(f()), "f()"); + assert_eq!(stringify_expr!(f::<u8>()), "f::<u8>()"); + assert_eq!(stringify_expr!(f::<1>()), "f::<1>()"); + assert_eq!(stringify_expr!(f::<'a, u8, 1>()), "f::<'a, u8, 1>()"); + assert_eq!(stringify_expr!(f(true)), "f(true)"); + assert_eq!(stringify_expr!(f(true,)), "f(true)"); + assert_eq!(stringify_expr!(()()), "()()"); + + // ExprKind::MethodCall + assert_eq!(stringify_expr!(x.f()), "x.f()"); + assert_eq!(stringify_expr!(x.f::<u8>()), "x.f::<u8>()"); + + // ExprKind::Tup + assert_eq!(stringify_expr!(()), "()"); + assert_eq!(stringify_expr!((true,)), "(true,)"); + assert_eq!(stringify_expr!((true, false)), "(true, false)"); + assert_eq!(stringify_expr!((true, false,)), "(true, false)"); + + // ExprKind::Binary + assert_eq!(stringify_expr!(true || false), "true || false"); + assert_eq!(stringify_expr!(true || false && false), "true || false && false"); + + // ExprKind::Unary + assert_eq!(stringify_expr!(*expr), "*expr"); + assert_eq!(stringify_expr!(!expr), "!expr"); + assert_eq!(stringify_expr!(-expr), "-expr"); + + // ExprKind::Lit + assert_eq!(stringify_expr!('x'), "'x'"); + assert_eq!(stringify_expr!(1_000_i8), "1_000_i8"); + assert_eq!(stringify_expr!(1.00000000000000001), "1.00000000000000001"); + + // ExprKind::Cast + assert_eq!(stringify_expr!(expr as T), "expr as T"); + assert_eq!(stringify_expr!(expr as T<u8>), "expr as T<u8>"); + + // ExprKind::Type + assert_eq!(stringify_expr!(expr: T), "expr: T"); + assert_eq!(stringify_expr!(expr: T<u8>), "expr: T<u8>"); + + // ExprKind::If + assert_eq!(stringify_expr!(if true {}), "if true {}"); + assert_eq!( + stringify_expr!(if true { + } else { + }), + "if true {} else {}", + ); + assert_eq!( + stringify_expr!(if let true = true { + } else { + }), + "if let true = true {} else {}", + ); + assert_eq!( + stringify_expr!(if true { + } else if false { + }), + "if true {} else if false {}", + ); + assert_eq!( + stringify_expr!(if true { + } else if false { + } else { + }), + "if true {} else if false {} else {}", + ); + assert_eq!( + stringify_expr!(if true { + return; + } else if false { + 0 + } else { + 0 + }), + "if true { return; } else if false { 0 } else { 0 }", + ); + + // ExprKind::While + assert_eq!(stringify_expr!(while true {}), "while true {}"); + assert_eq!(stringify_expr!('a: while true {}), "'a: while true {}"); + assert_eq!(stringify_expr!(while let true = true {}), "while let true = true {}"); + + // ExprKind::ForLoop + assert_eq!(stringify_expr!(for _ in x {}), "for _ in x {}"); + assert_eq!(stringify_expr!('a: for _ in x {}), "'a: for _ in x {}"); + + // ExprKind::Loop + assert_eq!(stringify_expr!(loop {}), "loop {}"); + assert_eq!(stringify_expr!('a: loop {}), "'a: loop {}"); + + // ExprKind::Match + assert_eq!(stringify_expr!(match self {}), "match self {}"); + assert_eq!( + stringify_expr!(match self { + Ok => 1, + }), + "match self { Ok => 1, }", + ); + assert_eq!( + stringify_expr!(match self { + Ok => 1, + Err => 0, + }), + "match self { Ok => 1, Err => 0, }", + ); + + // ExprKind::Closure + assert_eq!(stringify_expr!(|| {}), "|| {}"); + assert_eq!(stringify_expr!(|x| {}), "|x| {}"); + assert_eq!(stringify_expr!(|x: u8| {}), "|x: u8| {}"); + assert_eq!(stringify_expr!(|| ()), "|| ()"); + assert_eq!(stringify_expr!(move || self), "move || self"); + assert_eq!(stringify_expr!(async || self), "async || self"); + assert_eq!(stringify_expr!(async move || self), "async move || self"); + assert_eq!(stringify_expr!(static || self), "static || self"); + assert_eq!(stringify_expr!(static move || self), "static move || self"); + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149 + assert_eq!( + stringify_expr!(static async || self), + "static async || self", + ); + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149 + assert_eq!( + stringify_expr!(static async move || self), + "static async move || self", + ); + assert_eq!(stringify_expr!(|| -> u8 { self }), "|| -> u8 { self }"); + assert_eq!(stringify_expr!(1 + || {}), "1 + (|| {})"); // ?? + + // ExprKind::Block + assert_eq!(stringify_expr!({}), "{}"); + assert_eq!(stringify_expr!(unsafe {}), "unsafe {}"); + assert_eq!(stringify_expr!('a: {}), "'a: {}"); + assert_eq!( + stringify_expr!( + #[attr] + {} + ), + "#[attr] {}", + ); + assert_eq!( + stringify_expr!( + { + #![attr] + } + ), + "{\n\ + \x20 #![attr]\n\ + }", + ); + + // ExprKind::Async + assert_eq!(stringify_expr!(async {}), "async {}"); + assert_eq!(stringify_expr!(async move {}), "async move {}"); + + // ExprKind::Await + assert_eq!(stringify_expr!(expr.await), "expr.await"); + + // ExprKind::TryBlock + assert_eq!(stringify_expr!(try {}), "try {}"); + + // ExprKind::Assign + assert_eq!(stringify_expr!(expr = true), "expr = true"); + + // ExprKind::AssignOp + assert_eq!(stringify_expr!(expr += true), "expr += true"); + + // ExprKind::Field + assert_eq!(stringify_expr!(expr.field), "expr.field"); + assert_eq!(stringify_expr!(expr.0), "expr.0"); + + // ExprKind::Index + assert_eq!(stringify_expr!(expr[true]), "expr[true]"); + + // ExprKind::Range + assert_eq!(stringify_expr!(..), ".."); + assert_eq!(stringify_expr!(..hi), "..hi"); + assert_eq!(stringify_expr!(lo..), "lo.."); + assert_eq!(stringify_expr!(lo..hi), "lo..hi"); + assert_eq!(stringify_expr!(..=hi), "..=hi"); + assert_eq!(stringify_expr!(lo..=hi), "lo..=hi"); + assert_eq!(stringify_expr!(-2..=-1), "-2..=-1"); + + // ExprKind::Path + assert_eq!(stringify_expr!(thing), "thing"); + assert_eq!(stringify_expr!(m::thing), "m::thing"); + assert_eq!(stringify_expr!(self::thing), "self::thing"); + assert_eq!(stringify_expr!(crate::thing), "crate::thing"); + assert_eq!(stringify_expr!(Self::thing), "Self::thing"); + assert_eq!(stringify_expr!(<Self as T>::thing), "<Self as T>::thing"); + assert_eq!(stringify_expr!(Self::<'static>), "Self::<'static>"); + + // ExprKind::AddrOf + assert_eq!(stringify_expr!(&expr), "&expr"); + assert_eq!(stringify_expr!(&mut expr), "&mut expr"); + assert_eq!(stringify_expr!(&raw const expr), "&raw const expr"); + assert_eq!(stringify_expr!(&raw mut expr), "&raw mut expr"); + + // ExprKind::Break + assert_eq!(stringify_expr!(break), "break"); + assert_eq!(stringify_expr!(break 'a), "break 'a"); + assert_eq!(stringify_expr!(break true), "break true"); + assert_eq!(stringify_expr!(break 'a true), "break 'a true"); + + // ExprKind::Continue + assert_eq!(stringify_expr!(continue), "continue"); + assert_eq!(stringify_expr!(continue 'a), "continue 'a"); + + // ExprKind::Ret + assert_eq!(stringify_expr!(return), "return"); + assert_eq!(stringify_expr!(return true), "return true"); + + // ExprKind::MacCall + assert_eq!(stringify_expr!(mac!(...)), "mac!(...)"); + assert_eq!(stringify_expr!(mac![...]), "mac![...]"); + assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }"); + + // ExprKind::Struct + assert_eq!(stringify_expr!(Struct {}), "Struct {}"); + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151 + assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}"); + assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }"); + assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }"); + assert_eq!(stringify_expr!(Struct { x }), "Struct { x }"); + assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }"); + assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }"); + assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }"); + assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }"); + assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }"); + + // ExprKind::Repeat + assert_eq!(stringify_expr!([(); 0]), "[(); 0]"); + + // ExprKind::Paren + assert_eq!(stringify_expr!((expr)), "(expr)"); + + // ExprKind::Try + assert_eq!(stringify_expr!(expr?), "expr?"); + + // ExprKind::Yield + assert_eq!(stringify_expr!(yield), "yield"); + assert_eq!(stringify_expr!(yield true), "yield true"); +} + +#[test] +fn test_item() { + // ItemKind::ExternCrate + assert_eq!( + stringify_item!( + extern crate std; + ), + "extern crate std;", + ); + assert_eq!( + stringify_item!( + pub extern crate self as std; + ), + "pub extern crate self as std;", + ); + + // ItemKind::Use + assert_eq!( + stringify_item!( + pub use crate::{a, b::c}; + ), + "pub use crate::{a, b::c};", + ); + + // ItemKind::Static + assert_eq!( + stringify_item!( + pub static S: () = {}; + ), + "pub static S: () = {};", + ); + assert_eq!( + stringify_item!( + static mut S: () = {}; + ), + "static mut S: () = {};", + ); + assert_eq!( + stringify_item!( + static S: (); + ), + "static S: ();", + ); + assert_eq!( + stringify_item!( + static mut S: (); + ), + "static mut S: ();", + ); + + // ItemKind::Const + assert_eq!( + stringify_item!( + pub const S: () = {}; + ), + "pub const S: () = {};", + ); + assert_eq!( + stringify_item!( + const S: (); + ), + "const S: ();", + ); + + // ItemKind::Fn + assert_eq!( + stringify_item!( + pub default const async unsafe extern "C" fn f() {} + ), + "pub default const async unsafe extern \"C\" fn f() {}", + ); + + // ItemKind::Mod + assert_eq!( + stringify_item!( + pub mod m; + ), + "pub mod m;", + ); + assert_eq!( + stringify_item!( + mod m {} + ), + "mod m {}", + ); + assert_eq!( + stringify_item!( + unsafe mod m; + ), + "unsafe mod m;", + ); + assert_eq!( + stringify_item!( + unsafe mod m {} + ), + "unsafe mod m {}", + ); + + // ItemKind::ForeignMod + assert_eq!( + stringify_item!( + extern "C" {} + ), + "extern \"C\" {}", + ); + #[rustfmt::skip] + assert_eq!( + stringify_item!( + pub extern "C" {} + ), + "extern \"C\" {}", + ); + assert_eq!( + stringify_item!( + unsafe extern "C++" {} + ), + "unsafe extern \"C++\" {}", + ); + + // ItemKind::TyAlias + #[rustfmt::skip] + assert_eq!( + stringify_item!( + pub default type Type<'a>: Bound + where + Self: 'a, + = T; + ), + "pub default type Type<'a>: Bound where Self: 'a = T;", + ); + + // ItemKind::Enum + assert_eq!( + stringify_item!( + pub enum Void {} + ), + "pub enum Void {}", + ); + assert_eq!( + stringify_item!( + enum Empty { + Unit, + Tuple(), + Struct {}, + } + ), + "enum Empty { Unit, Tuple(), Struct {}, }", + ); + assert_eq!( + stringify_item!( + enum Enum<T> + where + T: 'a, + { + Unit, + Tuple(T), + Struct { t: T }, + } + ), + "enum Enum<T> where T: 'a {\n\ + \x20 Unit,\n\ + \x20 Tuple(T),\n\ + \x20 Struct {\n\ + \x20 t: T,\n\ + \x20 },\n\ + }", + ); + + // ItemKind::Struct + assert_eq!( + stringify_item!( + pub struct Unit; + ), + "pub struct Unit;", + ); + assert_eq!( + stringify_item!( + struct Tuple(); + ), + "struct Tuple();", + ); + assert_eq!( + stringify_item!( + struct Tuple(T); + ), + "struct Tuple(T);", + ); + assert_eq!( + stringify_item!( + struct Struct {} + ), + "struct Struct {}", + ); + assert_eq!( + stringify_item!( + struct Struct<T> + where + T: 'a, + { + t: T, + } + ), + "struct Struct<T> where T: 'a {\n\ + \x20 t: T,\n\ + }", + ); + + // ItemKind::Union + assert_eq!( + stringify_item!( + pub union Union {} + ), + "pub union Union {}", + ); + assert_eq!( + stringify_item!( + union Union<T> where T: 'a { + t: T, + } + ), + "union Union<T> where T: 'a {\n\ + \x20 t: T,\n\ + }", + ); + + // ItemKind::Trait + assert_eq!( + stringify_item!( + pub unsafe auto trait Send {} + ), + "pub unsafe auto trait Send {}", + ); + assert_eq!( + stringify_item!( + trait Trait<'a>: Sized + where + Self: 'a, + { + } + ), + "trait Trait<'a>: Sized where Self: 'a {}", + ); + + // ItemKind::TraitAlias + assert_eq!( + stringify_item!( + pub trait Trait<T> = Sized where T: 'a; + ), + "pub trait Trait<T> = Sized where T: 'a;", + ); + + // ItemKind::Impl + assert_eq!( + stringify_item!( + pub impl Struct {} + ), + "pub impl Struct {}", + ); + assert_eq!( + stringify_item!( + impl<T> Struct<T> {} + ), + "impl<T> Struct<T> {}", + ); + assert_eq!( + stringify_item!( + pub impl Trait for Struct {} + ), + "pub impl Trait for Struct {}", + ); + assert_eq!( + stringify_item!( + impl<T> const Trait for T {} + ), + "impl<T> const Trait for T {}", + ); + assert_eq!( + stringify_item!( + impl ~const Struct {} + ), + "impl Struct {}", // FIXME + ); + + // ItemKind::MacCall + assert_eq!(stringify_item!(mac!(...);), "mac!(...);"); + assert_eq!(stringify_item!(mac![...];), "mac![...];"); + assert_eq!(stringify_item!(mac! { ... }), "mac! { ... }"); + + // ItemKind::MacroDef + assert_eq!( + stringify_item!( + macro_rules! stringify { + () => {}; + } + ), + "macro_rules! stringify { () => {} ; }", // FIXME + ); + assert_eq!( + stringify_item!( + pub macro stringify() {} + ), + "pub macro stringify { () => {} }", + ); +} + +#[test] +fn test_meta() { + assert_eq!(stringify_meta!(k), "k"); + assert_eq!(stringify_meta!(k = "v"), "k = \"v\""); + assert_eq!(stringify_meta!(list(k1, k2 = "v")), "list(k1, k2 = \"v\")"); + assert_eq!(stringify_meta!(serde::k), "serde::k"); +} + +#[test] +fn test_pat() { + // PatKind::Wild + assert_eq!(stringify_pat!(_), "_"); + + // PatKind::Ident + assert_eq!(stringify_pat!(_x), "_x"); + assert_eq!(stringify_pat!(ref _x), "ref _x"); + assert_eq!(stringify_pat!(mut _x), "mut _x"); + assert_eq!(stringify_pat!(ref mut _x), "ref mut _x"); + assert_eq!(stringify_pat!(ref mut _x @ _), "ref mut _x @ _"); + + // PatKind::Struct + assert_eq!(stringify_pat!(Struct {}), "Struct {}"); + assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {}"); + assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {}"); + assert_eq!(stringify_pat!(Struct { x }), "Struct { x }"); + assert_eq!(stringify_pat!(Struct { x: _x }), "Struct { x: _x }"); + assert_eq!(stringify_pat!(Struct { .. }), "Struct { .. }"); + assert_eq!(stringify_pat!(Struct { x, .. }), "Struct { x, .. }"); + assert_eq!(stringify_pat!(Struct { x: _x, .. }), "Struct { x: _x, .. }"); + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151 + assert_eq!( + stringify_pat!(<Struct as Trait>::Type {}), + "<Struct as Trait>::Type {}", + ); + + // PatKind::TupleStruct + assert_eq!(stringify_pat!(Tuple()), "Tuple()"); + assert_eq!(stringify_pat!(Tuple::<u8>()), "Tuple::<u8>()"); + assert_eq!(stringify_pat!(Tuple::<'static>()), "Tuple::<'static>()"); + assert_eq!(stringify_pat!(Tuple(x)), "Tuple(x)"); + assert_eq!(stringify_pat!(Tuple(..)), "Tuple(..)"); + assert_eq!(stringify_pat!(Tuple(x, ..)), "Tuple(x, ..)"); + assert_eq!(stringify_pat!(<Struct as Trait>::Type()), "<Struct as Trait>::Type()"); + + // PatKind::Or + assert_eq!(stringify_pat!(true | false), "true | false"); + assert_eq!(stringify_pat!(| true), "true"); + assert_eq!(stringify_pat!(|true| false), "true | false"); + + // PatKind::Path + assert_eq!(stringify_pat!(crate::Path), "crate::Path"); + assert_eq!(stringify_pat!(Path::<u8>), "Path::<u8>"); + assert_eq!(stringify_pat!(Path::<'static>), "Path::<'static>"); + assert_eq!(stringify_pat!(<Struct as Trait>::Type), "<Struct as Trait>::Type"); + + // PatKind::Tuple + assert_eq!(stringify_pat!(()), "()"); + assert_eq!(stringify_pat!((true,)), "(true,)"); + assert_eq!(stringify_pat!((true, false)), "(true, false)"); + + // PatKind::Box + assert_eq!(stringify_pat!(box pat), "box pat"); + + // PatKind::Ref + assert_eq!(stringify_pat!(&pat), "&pat"); + assert_eq!(stringify_pat!(&mut pat), "&mut pat"); + + // PatKind::Lit + assert_eq!(stringify_pat!(1_000_i8), "1_000_i8"); + + // PatKind::Range + assert_eq!(stringify_pat!(..1), "..1"); + assert_eq!(stringify_pat!(0..), "0.."); + assert_eq!(stringify_pat!(0..1), "0..1"); + assert_eq!(stringify_pat!(0..=1), "0..=1"); + assert_eq!(stringify_pat!(-2..=-1), "-2..=-1"); + + // PatKind::Slice + assert_eq!(stringify_pat!([]), "[]"); + assert_eq!(stringify_pat!([true]), "[true]"); + assert_eq!(stringify_pat!([true,]), "[true]"); + assert_eq!(stringify_pat!([true, false]), "[true, false]"); + + // PatKind::Rest + assert_eq!(stringify_pat!(..), ".."); + + // PatKind::Paren + assert_eq!(stringify_pat!((pat)), "(pat)"); + + // PatKind::MacCall + assert_eq!(stringify_pat!(mac!(...)), "mac!(...)"); + assert_eq!(stringify_pat!(mac![...]), "mac![...]"); + assert_eq!(stringify_pat!(mac! { ... }), "mac! { ... }"); +} + +#[test] +fn test_path() { + assert_eq!(stringify_path!(thing), "thing"); + assert_eq!(stringify_path!(m::thing), "m::thing"); + assert_eq!(stringify_path!(self::thing), "self::thing"); + assert_eq!(stringify_path!(crate::thing), "crate::thing"); + assert_eq!(stringify_path!(Self::thing), "Self::thing"); + assert_eq!(stringify_path!(Self<'static>), "Self<'static>"); + assert_eq!(stringify_path!(Self::<'static>), "Self<'static>"); + assert_eq!(stringify_path!(Self()), "Self()"); + assert_eq!(stringify_path!(Self() -> ()), "Self() -> ()"); +} + +#[test] +fn test_stmt() { + // StmtKind::Local + assert_eq!(stringify_stmt!(let _), "let _;"); + assert_eq!(stringify_stmt!(let x = true), "let x = true;"); + assert_eq!(stringify_stmt!(let x: bool = true), "let x: bool = true;"); + + // StmtKind::Item + assert_eq!( + stringify_stmt!( + struct S; + ), + "struct S;", + ); + + // StmtKind::Expr + assert_eq!(stringify_stmt!(loop {}), "loop {}"); + + // StmtKind::Semi + assert_eq!(stringify_stmt!(1 + 1), "1 + 1;"); + + // StmtKind::Empty + assert_eq!(stringify_stmt!(;), ";"); + + // StmtKind::MacCall + assert_eq!(stringify_stmt!(mac!(...)), "mac!(...)"); + assert_eq!(stringify_stmt!(mac![...]), "mac![...]"); + assert_eq!(stringify_stmt!(mac! { ... }), "mac! { ... }"); +} + +#[test] +fn test_ty() { + // TyKind::Slice + assert_eq!(stringify_ty!([T]), "[T]"); + + // TyKind::Array + assert_eq!(stringify_ty!([T; 0]), "[T; 0]"); + + // TyKind::Ptr + assert_eq!(stringify_ty!(*const T), "*const T"); + assert_eq!(stringify_ty!(*mut T), "*mut T"); + + // TyKind::Ref + assert_eq!(stringify_ty!(&T), "&T"); + assert_eq!(stringify_ty!(&mut T), "&mut T"); + assert_eq!(stringify_ty!(&'a T), "&'a T"); + assert_eq!(stringify_ty!(&'a mut T), "&'a mut T"); + + // TyKind::BareFn + assert_eq!(stringify_ty!(fn()), "fn()"); + assert_eq!(stringify_ty!(fn() -> ()), "fn() -> ()"); + assert_eq!(stringify_ty!(fn(u8)), "fn(u8)"); + assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)"); + #[rustfmt::skip] + assert_eq!(stringify_ty!(for<> fn()), "fn()"); + assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()"); + + // TyKind::Never + assert_eq!(stringify_ty!(!), "!"); + + // TyKind::Tup + assert_eq!(stringify_ty!(()), "()"); + assert_eq!(stringify_ty!((T,)), "(T,)"); + assert_eq!(stringify_ty!((T, U)), "(T, U)"); + + // TyKind::Path + assert_eq!(stringify_ty!(T), "T"); + assert_eq!(stringify_ty!(Ref<'a>), "Ref<'a>"); + assert_eq!(stringify_ty!(PhantomData<T>), "PhantomData<T>"); + assert_eq!(stringify_ty!(PhantomData::<T>), "PhantomData<T>"); + assert_eq!(stringify_ty!(Fn() -> !), "Fn() -> !"); + assert_eq!(stringify_ty!(Fn(u8) -> !), "Fn(u8) -> !"); + assert_eq!(stringify_ty!(<Struct as Trait>::Type), "<Struct as Trait>::Type"); + + // TyKind::TraitObject + assert_eq!(stringify_ty!(dyn Send), "dyn Send"); + assert_eq!(stringify_ty!(dyn Send + 'a), "dyn Send + 'a"); + assert_eq!(stringify_ty!(dyn 'a + Send), "dyn 'a + Send"); + assert_eq!(stringify_ty!(dyn ?Sized), "dyn ?Sized"); + assert_eq!(stringify_ty!(dyn ~const Clone), "dyn Clone"); // FIXME + assert_eq!(stringify_ty!(dyn for<'a> Send), "dyn for<'a> Send"); + + // TyKind::ImplTrait + assert_eq!(stringify_ty!(impl Send), "impl Send"); + assert_eq!(stringify_ty!(impl Send + 'a), "impl Send + 'a"); + assert_eq!(stringify_ty!(impl 'a + Send), "impl 'a + Send"); + assert_eq!(stringify_ty!(impl ?Sized), "impl ?Sized"); + assert_eq!(stringify_ty!(impl ~const Clone), "impl Clone"); // FIXME + assert_eq!(stringify_ty!(impl for<'a> Send), "impl for<'a> Send"); + + // TyKind::Paren + assert_eq!(stringify_ty!((T)), "(T)"); + + // TyKind::Infer + assert_eq!(stringify_ty!(_), "_"); + + // TyKind::MacCall + assert_eq!(stringify_ty!(mac!(...)), "mac!(...)"); + assert_eq!(stringify_ty!(mac![...]), "mac![...]"); + assert_eq!(stringify_ty!(mac! { ... }), "mac! { ... }"); +} + +#[test] +fn test_vis() { + // VisibilityKind::Public + assert_eq!(stringify_vis!(pub), "pub "); + + // VisibilityKind::Restricted + assert_eq!(stringify_vis!(pub(crate)), "pub(crate) "); + assert_eq!(stringify_vis!(pub(self)), "pub(self) "); + assert_eq!(stringify_vis!(pub(super)), "pub(super) "); + assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) "); + assert_eq!(stringify_vis!(pub(in self)), "pub(in self) "); + assert_eq!(stringify_vis!(pub(in super)), "pub(in super) "); + assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) "); + assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) "); + assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) "); + assert_eq!(stringify_vis!(pub(in super::path::to)), "pub(in super::path::to) "); + + // VisibilityKind::Inherited + // Directly calling `stringify_vis!()` does not work. + macro_rules! stringify_inherited_vis { + ($vis:vis struct) => { + stringify_vis!($vis) + }; + } + assert_eq!(stringify_inherited_vis!(struct), ""); +} diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs new file mode 100644 index 000000000..ae6de3c50 --- /dev/null +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -0,0 +1,18 @@ +macro_rules! values { + ($($token:ident($value:literal) $(as $inner:ty)? => $attr:meta,)*) => { + #[derive(Debug)] + pub enum TokenKind { + $( + #[$attr] + $token $($inner)? = $value, + )* + } + }; +} +//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)` +//~| ERROR macro expansion ignores token `(String)` and any following + +values!(STRING(1) as (String) => cfg(test),); +//~^ ERROR expected one of `!` or `::`, found `<eof>` + +fn main() {} diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr new file mode 100644 index 000000000..c42ee9b29 --- /dev/null +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -0,0 +1,31 @@ +error: expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)` + --> $DIR/syntax-error-recovery.rs:7:26 + | +LL | $token $($inner)? = $value, + | ^^^^^^ expected one of `(`, `,`, `=`, `{`, or `}` +... +LL | values!(STRING(1) as (String) => cfg(test),); + | -------------------------------------------- in this macro invocation + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: macro expansion ignores token `(String)` and any following + --> $DIR/syntax-error-recovery.rs:7:26 + | +LL | $token $($inner)? = $value, + | ^^^^^^ +... +LL | values!(STRING(1) as (String) => cfg(test),); + | -------------------------------------------- caused by the macro expansion here + | + = note: the usage of `values!` is likely invalid in item context + +error: expected one of `!` or `::`, found `<eof>` + --> $DIR/syntax-error-recovery.rs:15:9 + | +LL | values!(STRING(1) as (String) => cfg(test),); + | ^^^^^^ expected one of `!` or `::` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/syntax-extension-cfg.rs b/tests/ui/macros/syntax-extension-cfg.rs new file mode 100644 index 000000000..2e929fc1d --- /dev/null +++ b/tests/ui/macros/syntax-extension-cfg.rs @@ -0,0 +1,24 @@ +// run-pass +// compile-flags: --cfg foo --cfg qux="foo" + + +pub fn main() { + // check + if ! cfg!(foo) { panic!() } + if cfg!(not(foo)) { panic!() } + + if ! cfg!(qux="foo") { panic!() } + if cfg!(not(qux="foo")) { panic!() } + + if ! cfg!(all(foo, qux="foo")) { panic!() } + if cfg!(not(all(foo, qux="foo"))) { panic!() } + if cfg!(all(not(all(foo, qux="foo")))) { panic!() } + + if cfg!(not_a_cfg) { panic!() } + if cfg!(all(not_a_cfg, foo, qux="foo")) { panic!() } + if cfg!(all(not_a_cfg, foo, qux="foo")) { panic!() } + if ! cfg!(any(not_a_cfg, foo)) { panic!() } + + if ! cfg!(not(not_a_cfg)) { panic!() } + if ! cfg!(all(not(not_a_cfg), foo, qux="foo")) { panic!() } +} diff --git a/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment b/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment new file mode 100644 index 000000000..d752015a4 --- /dev/null +++ b/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment @@ -0,0 +1,7 @@ +/* this is for run-pass/syntax-extension-source-utils.rs */ + +{ + assert!(file!().ends_with("includeme.fragment")); + assert_eq!(line!(), 5u32); + format!("victory robot {}", line!()) +} diff --git a/tests/ui/macros/syntax-extension-source-utils.rs b/tests/ui/macros/syntax-extension-source-utils.rs new file mode 100644 index 000000000..7e46260d5 --- /dev/null +++ b/tests/ui/macros/syntax-extension-source-utils.rs @@ -0,0 +1,37 @@ +// run-pass +#![allow(stable_features)] + +// ignore-pretty issue #37195 + +pub mod m1 { + pub mod m2 { + pub fn where_am_i() -> String { + (module_path!()).to_string() + } + } +} + +macro_rules! indirect_line { () => ( line!() ) } + +pub fn main() { + assert_eq!(line!(), 17); + assert_eq!(column!(), 16); + assert_eq!(indirect_line!(), 19); + assert!((file!().ends_with("syntax-extension-source-utils.rs"))); + assert_eq!(stringify!((2*3) + 5).to_string(), "(2 * 3) + 5".to_string()); + assert!(include!("syntax-extension-source-utils-files/includeme.\ + fragment").to_string() + == "victory robot 6".to_string()); + + assert!( + include_str!("syntax-extension-source-utils-files/includeme.\ + fragment").to_string() + .starts_with("/* this is for ")); + assert!( + include_bytes!("syntax-extension-source-utils-files/includeme.fragment") + [1] == (42 as u8)); // '*' + // The Windows tests are wrapped in an extra module for some reason + assert!((m1::m2::where_am_i().ends_with("m1::m2"))); + + assert_eq!((36, "(2 * 3) + 5"), (line!(), stringify!((2*3) + 5))); +} diff --git a/tests/ui/macros/trace-macro.rs b/tests/ui/macros/trace-macro.rs new file mode 100644 index 000000000..576120811 --- /dev/null +++ b/tests/ui/macros/trace-macro.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z trace-macros +// build-pass (FIXME(62277): could be check-pass?) + +fn main() { + println!("Hello, World!"); +} diff --git a/tests/ui/macros/trace-macro.stderr b/tests/ui/macros/trace-macro.stderr new file mode 100644 index 000000000..43272248c --- /dev/null +++ b/tests/ui/macros/trace-macro.stderr @@ -0,0 +1,9 @@ +note: trace_macro + --> $DIR/trace-macro.rs:5:5 + | +LL | println!("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expanding `println! { "Hello, World!" }` + = note: to `{ $crate :: io :: _print($crate :: format_args_nl! ("Hello, World!")) ; }` + diff --git a/tests/ui/macros/trace_faulty_macros.rs b/tests/ui/macros/trace_faulty_macros.rs new file mode 100644 index 000000000..b2fdd2e19 --- /dev/null +++ b/tests/ui/macros/trace_faulty_macros.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z trace-macros + +#![recursion_limit = "4"] + +macro_rules! my_faulty_macro { + () => { + my_faulty_macro!(bcd); //~ ERROR no rules + }; +} + +macro_rules! pat_macro { + () => { + pat_macro!(A{a:a, b:0, c:_, ..}); + }; + ($a:pat) => { + $a //~ ERROR expected expression + }; +} + +macro_rules! my_recursive_macro { + () => { + my_recursive_macro!(); //~ ERROR recursion limit + }; +} + +macro_rules! my_macro { + () => {}; +} + +fn main() { + my_faulty_macro!(); + my_recursive_macro!(); + test!(); + non_exisiting!(); + derive!(Debug); + let a = pat_macro!(); +} + +#[my_macro] +fn use_bang_macro_as_attr() {} + +#[derive(Debug)] //~ ERROR `derive` may only be applied to `struct`s +fn use_derive_macro_as_attr() {} diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr new file mode 100644 index 000000000..21e47da07 --- /dev/null +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -0,0 +1,85 @@ +error: no rules expected the token `bcd` + --> $DIR/trace_faulty_macros.rs:7:26 + | +LL | macro_rules! my_faulty_macro { + | ---------------------------- when calling this macro +LL | () => { +LL | my_faulty_macro!(bcd); + | ^^^ no rules expected this token in macro call +... +LL | my_faulty_macro!(); + | ------------------ in this macro invocation + | + = note: while trying to match end of macro + = note: this error originates in the macro `my_faulty_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: trace_macro + --> $DIR/trace_faulty_macros.rs:31:5 + | +LL | my_faulty_macro!(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: expanding `my_faulty_macro! { }` + = note: to `my_faulty_macro! (bcd) ;` + = note: expanding `my_faulty_macro! { bcd }` + +error: recursion limit reached while expanding `my_recursive_macro!` + --> $DIR/trace_faulty_macros.rs:22:9 + | +LL | my_recursive_macro!(); + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | my_recursive_macro!(); + | --------------------- in this macro invocation + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`trace_faulty_macros`) + = note: this error originates in the macro `my_recursive_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: trace_macro + --> $DIR/trace_faulty_macros.rs:32:5 + | +LL | my_recursive_macro!(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: expanding `my_recursive_macro! { }` + = note: to `my_recursive_macro! () ;` + = note: expanding `my_recursive_macro! { }` + = note: to `my_recursive_macro! () ;` + = note: expanding `my_recursive_macro! { }` + = note: to `my_recursive_macro! () ;` + = note: expanding `my_recursive_macro! { }` + = note: to `my_recursive_macro! () ;` + +error: expected expression, found `A { a: a, b: 0, c: _, .. }` + --> $DIR/trace_faulty_macros.rs:16:9 + | +LL | $a + | ^^ expected expression +... +LL | let a = pat_macro!(); + | ------------ in this macro invocation + | + = note: this error originates in the macro `pat_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0774]: `derive` may only be applied to `struct`s, `enum`s and `union`s + --> $DIR/trace_faulty_macros.rs:42:1 + | +LL | #[derive(Debug)] + | ^^^^^^^^^^^^^^^^ not applicable here +LL | fn use_derive_macro_as_attr() {} + | -------------------------------- not a `struct`, `enum` or `union` + +note: trace_macro + --> $DIR/trace_faulty_macros.rs:36:13 + | +LL | let a = pat_macro!(); + | ^^^^^^^^^^^^ + | + = note: expanding `pat_macro! { }` + = note: to `pat_macro! (A { a : a, b : 0, c : _, .. }) ;` + = note: expanding `pat_macro! { A { a : a, b : 0, c : _, .. } }` + = note: to `A { a: a, b: 0, c: _, .. }` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0774`. diff --git a/tests/ui/macros/trace_macros-format.rs b/tests/ui/macros/trace_macros-format.rs new file mode 100644 index 000000000..afca45ca0 --- /dev/null +++ b/tests/ui/macros/trace_macros-format.rs @@ -0,0 +1,18 @@ +#![feature(trace_macros)] + +fn main() { + trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false` + trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false` + + + // should be fine: + macro_rules! expando { + ($x: ident) => { trace_macros!($x) } + } + + expando!(true); +} diff --git a/tests/ui/macros/trace_macros-format.stderr b/tests/ui/macros/trace_macros-format.stderr new file mode 100644 index 000000000..c32027086 --- /dev/null +++ b/tests/ui/macros/trace_macros-format.stderr @@ -0,0 +1,38 @@ +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:4:5 + | +LL | trace_macros!(); + | ^^^^^^^^^^^^^^^ + +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:5:5 + | +LL | trace_macros!(1); + | ^^^^^^^^^^^^^^^^ + +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:6:5 + | +LL | trace_macros!(ident); + | ^^^^^^^^^^^^^^^^^^^^ + +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:7:5 + | +LL | trace_macros!(for); + | ^^^^^^^^^^^^^^^^^^ + +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:8:5 + | +LL | trace_macros!(true,); + | ^^^^^^^^^^^^^^^^^^^^ + +error: trace_macros! accepts only `true` or `false` + --> $DIR/trace_macros-format.rs:9:5 + | +LL | trace_macros!(false 1); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/macros/try-macro.rs b/tests/ui/macros/try-macro.rs new file mode 100644 index 000000000..824c77d9d --- /dev/null +++ b/tests/ui/macros/try-macro.rs @@ -0,0 +1,49 @@ +// run-pass +#![allow(deprecated)] // for deprecated `try!()` macro +use std::num::{ParseFloatError, ParseIntError}; + +fn main() { + assert_eq!(simple(), Ok(1)); + assert_eq!(nested(), Ok(2)); + assert_eq!(merge_ok(), Ok(3.0)); + assert_eq!(merge_int_err(), Err(Error::Int)); + assert_eq!(merge_float_err(), Err(Error::Float)); +} + +fn simple() -> Result<i32, ParseIntError> { + Ok(try!("1".parse())) +} + +fn nested() -> Result<i32, ParseIntError> { + Ok(try!(try!("2".parse::<i32>()).to_string().parse::<i32>())) +} + +fn merge_ok() -> Result<f32, Error> { + Ok(try!("1".parse::<i32>()) as f32 + try!("2.0".parse::<f32>())) +} + +fn merge_int_err() -> Result<f32, Error> { + Ok(try!("a".parse::<i32>()) as f32 + try!("2.0".parse::<f32>())) +} + +fn merge_float_err() -> Result<f32, Error> { + Ok(try!("1".parse::<i32>()) as f32 + try!("b".parse::<f32>())) +} + +#[derive(Debug, PartialEq)] +enum Error { + Int, + Float, +} + +impl From<ParseIntError> for Error { + fn from(_: ParseIntError) -> Error { + Error::Int + } +} + +impl From<ParseFloatError> for Error { + fn from(_: ParseFloatError) -> Error { + Error::Float + } +} diff --git a/tests/ui/macros/two-macro-use.rs b/tests/ui/macros/two-macro-use.rs new file mode 100644 index 000000000..07022bb01 --- /dev/null +++ b/tests/ui/macros/two-macro-use.rs @@ -0,0 +1,11 @@ +// run-pass +// aux-build:two_macros.rs + +#[macro_use(macro_one)] +#[macro_use(macro_two)] +extern crate two_macros; + +pub fn main() { + macro_one!(); + macro_two!(); +} diff --git a/tests/ui/macros/type-macros-hlist.rs b/tests/ui/macros/type-macros-hlist.rs new file mode 100644 index 000000000..946b5bd5d --- /dev/null +++ b/tests/ui/macros/type-macros-hlist.rs @@ -0,0 +1,80 @@ +// run-pass +#![allow(unused_macro_rules)] + +use std::ops::*; + +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct Nil; + // empty HList +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct Cons<H, T: HList>(H, T); + // cons cell of HList + + // trait to classify valid HLists +trait HList { } +impl HList for Nil { } +impl <H, T: HList> HList for Cons<H, T> { } + +// term-level macro for HLists +macro_rules! hlist({ } => { Nil } ; { $ head : expr } => { + Cons ( $ head , Nil ) } ; { + $ head : expr , $ ( $ tail : expr ) , * } => { + Cons ( $ head , hlist ! ( $ ( $ tail ) , * ) ) } ;); + +// type-level macro for HLists +macro_rules! HList({ } => { Nil } ; { $ head : ty } => { + Cons < $ head , Nil > } ; { + $ head : ty , $ ( $ tail : ty ) , * } => { + Cons < $ head , HList ! ( $ ( $ tail ) , * ) > } ;); + +// nil case for HList append +impl <Ys: HList> Add<Ys> for Nil { + type + Output + = + Ys; + + fn add(self, rhs: Ys) -> Ys { rhs } +} + +// cons case for HList append +impl <Rec: HList + Sized, X, Xs: HList, Ys: HList> Add<Ys> for Cons<X, Xs> + where Xs: Add<Ys, Output = Rec> { + type + Output + = + Cons<X, Rec>; + + fn add(self, rhs: Ys) -> Cons<X, Rec> { Cons(self.0, self.1 + rhs) } +} + +// type macro Expr allows us to expand the + operator appropriately +macro_rules! Expr({ ( $ ( $ LHS : tt ) + ) } => { Expr ! ( $ ( $ LHS ) + ) } ; + { HList ! [ $ ( $ LHS : tt ) * ] + $ ( $ RHS : tt ) + } => { + < Expr ! ( HList ! [ $ ( $ LHS ) * ] ) as Add < Expr ! ( + $ ( $ RHS ) + ) >> :: Output } ; { + $ LHS : tt + $ ( $ RHS : tt ) + } => { + < Expr ! ( $ LHS ) as Add < Expr ! ( $ ( $ RHS ) + ) >> :: + Output } ; { $ LHS : ty } => { $ LHS } ;); + +// test demonstrating term level `xs + ys` and type level `Expr!(Xs + Ys)` +fn main() { + fn aux<Xs: HList, Ys: HList>(xs: Xs, ys: Ys) -> Expr!(Xs + Ys) where + Xs: Add<Ys> { + xs + ys + } + + let xs: HList!(& str , bool , Vec < u64 >) = + hlist!("foo" , false , vec ! [ ]); + let ys: HList!(u64 , [ u8 ; 3 ] , ( )) = + hlist!(0 , [ 0 , 1 , 2 ] , ( )); + + // demonstrate recursive expansion of Expr! + let zs: + Expr!(( + HList ! [ & str ] + HList ! [ bool ] + HList ! [ Vec < u64 > + ] ) + ( HList ! [ u64 ] + HList ! [ [ u8 ; 3 ] , ( ) ] ) + + HList ! [ ]) = aux(xs, ys); + assert_eq!(zs , hlist ! [ + "foo" , false , vec ! [ ] , 0 , [ 0 , 1 , 2 ] , ( ) ]) +} diff --git a/tests/ui/macros/type-macros-simple.rs b/tests/ui/macros/type-macros-simple.rs new file mode 100644 index 000000000..dd3ad2ef0 --- /dev/null +++ b/tests/ui/macros/type-macros-simple.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +macro_rules! Tuple { + { $A:ty,$B:ty } => { ($A, $B) } +} + +fn main() { + let x: Tuple!(i32, i32) = (1, 2); +} + +fn issue_36540() { + let i32 = 0; + macro_rules! m { () => { i32 } } + struct S<T = m!()>(m!(), T) where T: Trait<m!()>; + + let x: m!() = m!(); + std::cell::Cell::<m!()>::new(m!()); + impl<T> std::ops::Index<m!()> for dyn Trait<(m!(), T)> + where T: Trait<m!()> + { + type Output = m!(); + fn index(&self, i: m!()) -> &m!() { + unimplemented!() + } + } +} + +trait Trait<T> {} +impl Trait<i32> for i32 {} diff --git a/tests/ui/macros/typeck-macro-interaction-issue-8852.rs b/tests/ui/macros/typeck-macro-interaction-issue-8852.rs new file mode 100644 index 000000000..f2b089b74 --- /dev/null +++ b/tests/ui/macros/typeck-macro-interaction-issue-8852.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(dead_code)] + +enum T { + A(isize), + B(f64) +} + +// after fixing #9384 and implementing hygiene for match bindings, +// this now fails because the insertion of the 'y' into the match +// doesn't cause capture. Making this macro hygienic (as I've done) +// could very well make this test case completely pointless.... + +macro_rules! test { + ($id1:ident, $id2:ident, $e:expr) => ( + fn foo(a:T, b:T) -> T { + match (a, b) { + (T::A($id1), T::A($id2)) => T::A($e), + (T::B($id1), T::B($id2)) => T::B($e), + _ => panic!() + } + } + ) +} + +test!(x,y,x + y); + +pub fn main() { + foo(T::A(1), T::A(2)); +} diff --git a/tests/ui/macros/unimplemented-macro-panic.rs b/tests/ui/macros/unimplemented-macro-panic.rs new file mode 100644 index 000000000..e7169903f --- /dev/null +++ b/tests/ui/macros/unimplemented-macro-panic.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:not implemented +// ignore-emscripten no processes + +fn main() { + unimplemented!() +} diff --git a/tests/ui/macros/unknown-builtin.rs b/tests/ui/macros/unknown-builtin.rs new file mode 100644 index 000000000..16f9139e6 --- /dev/null +++ b/tests/ui/macros/unknown-builtin.rs @@ -0,0 +1,14 @@ +// error-pattern: attempted to define built-in macro more than once + +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` + +#[rustc_builtin_macro] +macro_rules! line { () => () } //~ NOTE previously defined here + +fn main() { + line!(); + std::prelude::v1::line!(); +} diff --git a/tests/ui/macros/unknown-builtin.stderr b/tests/ui/macros/unknown-builtin.stderr new file mode 100644 index 000000000..22f54e04e --- /dev/null +++ b/tests/ui/macros/unknown-builtin.stderr @@ -0,0 +1,18 @@ +error: cannot find a built-in macro with name `unknown` + --> $DIR/unknown-builtin.rs:6:1 + | +LL | macro_rules! unknown { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0773]: attempted to define built-in macro more than once + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0773`. diff --git a/tests/ui/macros/unreachable-arg.edition_2021.stderr b/tests/ui/macros/unreachable-arg.edition_2021.stderr new file mode 100644 index 000000000..d70ef31ee --- /dev/null +++ b/tests/ui/macros/unreachable-arg.edition_2021.stderr @@ -0,0 +1,13 @@ +error: format argument must be a string literal + --> $DIR/unreachable-arg.rs:15:18 + | +LL | unreachable!(a); + | ^ + | +help: you might be missing a string literal to format with + | +LL | unreachable!("{}", a); + | +++++ + +error: aborting due to previous error + diff --git a/tests/ui/macros/unreachable-arg.rs b/tests/ui/macros/unreachable-arg.rs new file mode 100644 index 000000000..4024bd20b --- /dev/null +++ b/tests/ui/macros/unreachable-arg.rs @@ -0,0 +1,16 @@ +// ignore-emscripten no processes + +// revisions: edition_2015 edition_2021 +// [edition_2015]edition:2015 +// [edition_2021]edition:2021 +// [edition_2015]run-fail +// [edition_2021]check-fail +// [edition_2015]error-pattern:internal error: entered unreachable code: hello +// [edition_2021]error-pattern:format argument must be a string literal + +#![allow(non_fmt_panics)] + +fn main() { + let a = "hello"; + unreachable!(a); +} diff --git a/tests/ui/macros/unreachable-fmt-msg.rs b/tests/ui/macros/unreachable-fmt-msg.rs new file mode 100644 index 000000000..eb17ed927 --- /dev/null +++ b/tests/ui/macros/unreachable-fmt-msg.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:internal error: entered unreachable code: 6 is not prime +// ignore-emscripten no processes + +fn main() { + unreachable!("{} is not {}", 6u32, "prime"); +} diff --git a/tests/ui/macros/unreachable-format-arg.rs b/tests/ui/macros/unreachable-format-arg.rs new file mode 100644 index 000000000..ff059ad9e --- /dev/null +++ b/tests/ui/macros/unreachable-format-arg.rs @@ -0,0 +1,15 @@ +// run-fail +// ignore-emscripten no processes + +// revisions: edition_2015 edition_2021 +// [edition_2015]edition:2015 +// [edition_2021]edition:2021 +// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x} +// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5 + +#![allow(non_fmt_panics)] + +fn main() { + let x = 5; + unreachable!("x is {x}"); +} diff --git a/tests/ui/macros/unreachable-format-args.edition_2015.stderr b/tests/ui/macros/unreachable-format-args.edition_2015.stderr new file mode 100644 index 000000000..2cc2e134b --- /dev/null +++ b/tests/ui/macros/unreachable-format-args.edition_2015.stderr @@ -0,0 +1,12 @@ +error: there is no argument named `x` + --> $DIR/unreachable-format-args.rs:13:5 + | +LL | unreachable!("x is {x} and y is {y}", y = 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: did you intend to capture a variable `x` from the surrounding scope? + = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro + = note: this error originates in the macro `$crate::concat` which comes from the expansion of the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/macros/unreachable-format-args.rs b/tests/ui/macros/unreachable-format-args.rs new file mode 100644 index 000000000..04a31fc1b --- /dev/null +++ b/tests/ui/macros/unreachable-format-args.rs @@ -0,0 +1,14 @@ +// ignore-emscripten no processes + +// revisions: edition_2015 edition_2021 +// [edition_2015]edition:2015 +// [edition_2021]edition:2021 +// [edition_2015]check-fail +// [edition_2021]run-fail +// [edition_2015]error-pattern:there is no argument named `x` +// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5 and y is 0 + +fn main() { + let x = 5; + unreachable!("x is {x} and y is {y}", y = 0); +} diff --git a/tests/ui/macros/unreachable-macro-panic.rs b/tests/ui/macros/unreachable-macro-panic.rs new file mode 100644 index 000000000..55e2102e2 --- /dev/null +++ b/tests/ui/macros/unreachable-macro-panic.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:internal error: entered unreachable code +// ignore-emscripten no processes + +fn main() { + unreachable!() +} diff --git a/tests/ui/macros/unreachable-static-msg.rs b/tests/ui/macros/unreachable-static-msg.rs new file mode 100644 index 000000000..55edf3af7 --- /dev/null +++ b/tests/ui/macros/unreachable-static-msg.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:internal error: entered unreachable code: uhoh +// ignore-emscripten no processes + +fn main() { + unreachable!("uhoh") +} diff --git a/tests/ui/macros/unreachable.rs b/tests/ui/macros/unreachable.rs new file mode 100644 index 000000000..55e2102e2 --- /dev/null +++ b/tests/ui/macros/unreachable.rs @@ -0,0 +1,7 @@ +// run-fail +// error-pattern:internal error: entered unreachable code +// ignore-emscripten no processes + +fn main() { + unreachable!() +} diff --git a/tests/ui/macros/use-macro-self.rs b/tests/ui/macros/use-macro-self.rs new file mode 100644 index 000000000..06464ab0b --- /dev/null +++ b/tests/ui/macros/use-macro-self.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(unused_imports)] +// aux-build:use-macro-self.rs + +#[macro_use] +extern crate use_macro_self; + +use use_macro_self::foobarius::{self}; + +fn main() { + let _: () = foobarius!(); // OK, the macro returns `()` +} diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs new file mode 100644 index 000000000..ce4298b8b --- /dev/null +++ b/tests/ui/macros/vec-macro-in-pattern.rs @@ -0,0 +1,10 @@ +// This is a regression test for #61933 +// Verify that the vec![] macro may not be used in patterns +// and that the resulting diagnostic is actually helpful. + +fn main() { + match Some(vec![42]) { + Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } +} diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr new file mode 100644 index 000000000..7060f5d8b --- /dev/null +++ b/tests/ui/macros/vec-macro-in-pattern.stderr @@ -0,0 +1,10 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/vec-macro-in-pattern.rs:7:14 + | +LL | Some(vec![43]) => {} + | ^^^^^^^^ + | + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + |