diff options
| author | Mark Rousskov <mark.simulacrum@gmail.com> | 2019-07-18 11:29:43 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-07-18 11:29:43 -0400 |
| commit | aa31ca71283f783b20ee3b460620e0907f4a4a31 (patch) | |
| tree | 13ea0f69c0dc60a4edb69aacee289bf802e58513 /src/test/ui | |
| parent | 831d33b8b0108c808d5148d434295c4c94f7102b (diff) | |
| parent | a4a7bb9a3f72505efb6ca9856af45287c8685d5e (diff) | |
Rollup merge of #62730 - matthewjasper:hygiene-tests, r=petrochenkov
Consolidate hygiene tests Some general clean-up extracted out from another PR
Diffstat (limited to 'src/test/ui')
28 files changed, 1212 insertions, 7 deletions
diff --git a/src/test/ui/hygiene/auxiliary/legacy_interaction.rs b/src/test/ui/hygiene/auxiliary/legacy_interaction.rs new file mode 100644 index 00000000000..90d5243b74b --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/legacy_interaction.rs @@ -0,0 +1,9 @@ +// ignore-pretty pretty-printing is unhygienic + +#[macro_export] +macro_rules! m { + () => { + fn f() {} // (2) + g(); // (1) + } +} diff --git a/src/test/ui/hygiene/auxiliary/my_crate.rs b/src/test/ui/hygiene/auxiliary/my_crate.rs new file mode 100644 index 00000000000..cdc6c27d800 --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/my_crate.rs @@ -0,0 +1 @@ +pub fn f() {} diff --git a/src/test/ui/hygiene/auxiliary/unhygienic_example.rs b/src/test/ui/hygiene/auxiliary/unhygienic_example.rs new file mode 100644 index 00000000000..8e6e8f9b32f --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/unhygienic_example.rs @@ -0,0 +1,27 @@ +#![crate_type = "lib"] + +extern crate my_crate; + +pub fn g() {} // (a) + +#[macro_export] +macro_rules! unhygienic_macro { + () => { + // (1) unhygienic: depends on `my_crate` in the crate root at the invocation site. + ::my_crate::f(); + + // (2) unhygienic: defines `f` at the invocation site (in addition to the above point). + use my_crate::f; + f(); + + g(); // (3) unhygienic: `g` needs to be in scope at use site. + + $crate::g(); // (4) hygienic: this always resolves to (a) + } +} + +#[allow(unused)] +fn test_unhygienic() { + unhygienic_macro!(); + f(); // `f` was defined at the use site +} diff --git a/src/test/ui/hygiene/auxiliary/xcrate.rs b/src/test/ui/hygiene/auxiliary/xcrate.rs new file mode 100644 index 00000000000..f5a911f57df --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/xcrate.rs @@ -0,0 +1,28 @@ +#![feature(decl_macro)] +#![allow(unused)] + +pub use bar::test; + +extern crate std as foo; + +pub fn f() {} +use f as f2; + +mod bar { + pub fn g() {} + use baz::h; + + pub macro test() { + use std::mem; + use foo::cell; + ::f(); + ::f2(); + g(); + h(); + ::bar::h(); + } +} + +mod baz { + pub fn h() {} +} diff --git a/src/test/ui/hygiene/dollar-crate-modern.rs b/src/test/ui/hygiene/dollar-crate-modern.rs index 9c25e138d2c..a432fb6eee1 100644 --- a/src/test/ui/hygiene/dollar-crate-modern.rs +++ b/src/test/ui/hygiene/dollar-crate-modern.rs @@ -1,6 +1,6 @@ // Make sure `$crate` and `crate` work in for basic cases of nested macros. -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // aux-build:intercrate.rs #![feature(decl_macro, crate_in_paths)] diff --git a/src/test/ui/hygiene/expansion-info-reset.rs b/src/test/ui/hygiene/expansion-info-reset.rs index 5c384c4ada9..fa5f712121d 100644 --- a/src/test/ui/hygiene/expansion-info-reset.rs +++ b/src/test/ui/hygiene/expansion-info-reset.rs @@ -1,6 +1,3 @@ -// FIXME: Investigate why expansion info for a single expansion id is reset from -// `MacroBang(format_args)` to `MacroAttribute(derive(Clone))` (issue #52363). - fn main() { format_args!({ #[derive(Clone)] struct S; }); //~^ ERROR format argument must be a string literal diff --git a/src/test/ui/hygiene/expansion-info-reset.stderr b/src/test/ui/hygiene/expansion-info-reset.stderr index 9dd954b16cd..d8b602ce1c6 100644 --- a/src/test/ui/hygiene/expansion-info-reset.stderr +++ b/src/test/ui/hygiene/expansion-info-reset.stderr @@ -1,5 +1,5 @@ error: format argument must be a string literal - --> $DIR/expansion-info-reset.rs:5:18 + --> $DIR/expansion-info-reset.rs:2:18 | LL | format_args!({ #[derive(Clone)] struct S; }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/hygiene/hygiene-dodging-1.rs b/src/test/ui/hygiene/hygiene-dodging-1.rs new file mode 100644 index 00000000000..69e47e82ba5 --- /dev/null +++ b/src/test/ui/hygiene/hygiene-dodging-1.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_must_use)] + +mod x { + pub fn g() -> usize {14} +} + +pub fn main(){ + // should *not* shadow the module x: + let x = 9; + // use it to avoid warnings: + x+3; + assert_eq!(x::g(),14); +} diff --git a/src/test/ui/hygiene/hygiene.rs b/src/test/ui/hygiene/hygiene.rs new file mode 100644 index 00000000000..fb351cf0faf --- /dev/null +++ b/src/test/ui/hygiene/hygiene.rs @@ -0,0 +1,114 @@ +// run-pass +#![allow(unused)] + +fn f() { + let x = 0; + macro_rules! foo { () => { + assert_eq!(x, 0); + } } + + let x = 1; + foo!(); +} + +fn g() { + let x = 0; + macro_rules! m { ($m1:ident, $m2:ident, $x:ident) => { + macro_rules! $m1 { () => { ($x, x) } } + let x = 1; + macro_rules! $m2 { () => { ($x, x) } } + } } + + let x = 2; + m!(m2, m3, x); + + let x = 3; + assert_eq!(m2!(), (2, 0)); + assert_eq!(m3!(), (2, 1)); + + let x = 4; + m!(m4, m5, x); + assert_eq!(m4!(), (4, 0)); + assert_eq!(m5!(), (4, 1)); +} + +mod foo { + macro_rules! m { + ($f:ident : |$x:ident| $e:expr) => { + pub fn $f() -> (i32, i32) { + let x = 0; + let $x = 1; + (x, $e) + } + } + } + + m!(f: |x| x + 10); +} + +fn interpolated_pattern() { + let x = 0; + macro_rules! m { + ($p:pat, $e:expr) => { + let $p = 1; + assert_eq!((x, $e), (0, 1)); + } + } + + m!(x, x); +} + +fn patterns_in_macro_generated_macros() { + let x = 0; + macro_rules! m { + ($a:expr, $b:expr) => { + assert_eq!(x, 0); + let x = $a; + macro_rules! n { + () => { + (x, $b) + } + } + } + } + + let x = 1; + m!(2, x); + + let x = 3; + assert_eq!(n!(), (2, 1)); +} + +fn match_hygiene() { + let x = 0; + + macro_rules! m { + ($p:pat, $e:expr) => { + for result in &[Ok(1), Err(1)] { + match *result { + $p => { assert_eq!(($e, x), (1, 0)); } + Err(x) => { assert_eq!(($e, x), (2, 1)); } + } + } + } + } + + let x = 2; + m!(Ok(x), x); +} + +fn label_hygiene() { + 'a: loop { + macro_rules! m { () => { break 'a; } } + m!(); + } +} + +fn main() { + f(); + g(); + assert_eq!(foo::f(), (0, 11)); + interpolated_pattern(); + patterns_in_macro_generated_macros(); + match_hygiene(); +} diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.rs b/src/test/ui/hygiene/hygienic-labels-in-let.rs new file mode 100644 index 00000000000..fb9523b547d --- /dev/null +++ b/src/test/ui/hygiene/hygienic-labels-in-let.rs @@ -0,0 +1,75 @@ +// run-pass +#![allow(unreachable_code)] + +// Test that labels injected by macros do not break hygiene. This +// checks cases where the macros invocations are under the rhs of a +// let statement. + +// Issue #24278: The label/lifetime shadowing checker from #24162 +// conservatively ignores hygiene, and thus issues warnings that are +// both true- and false-positives for this test. + +macro_rules! loop_x { + ($e: expr) => { + // $e shouldn't be able to interact with this 'x + 'x: loop { $e } + } +} + +macro_rules! while_true { + ($e: expr) => { + // $e shouldn't be able to interact with this 'x + 'x: while 1 + 1 == 2 { $e } + } +} + +macro_rules! run_once { + ($e: expr) => { + // ditto + 'x: for _ in 0..1 { $e } + } +} + +pub fn main() { + let mut i = 0; + + let j: isize = { + 'x: loop { + // this 'x should refer to the outer loop, lexically + loop_x!(break 'x); + i += 1; + } + i + 1 + }; + assert_eq!(j, 1); + + let k: isize = { + 'x: for _ in 0..1 { + // ditto + loop_x!(break 'x); + i += 1; + } + i + 1 + }; + assert_eq!(k, 1); + + let l: isize = { + 'x: for _ in 0..1 { + // ditto + while_true!(break 'x); + i += 1; + } + i + 1 + }; + assert_eq!(l, 1); + + let n: isize = { + 'x: for _ in 0..1 { + // ditto + run_once!(continue 'x); + i += 1; + } + i + 1 + }; + assert_eq!(n, 1); +} diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr new file mode 100644 index 00000000000..9c906749f8c --- /dev/null +++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr @@ -0,0 +1,300 @@ +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:15:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +LL | // this 'x should refer to the outer loop, lexically +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:47:9 + | +LL | 'x: loop { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:47:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:15:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +... +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:15:9 + | +LL | 'x: loop { $e } + | ^^ + | | + | first declared here + | lifetime 'x already in scope +... +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:15:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +LL | // ditto +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:57:9 + | +LL | 'x: loop { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:57:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:57:9 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:57:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:22:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +... +LL | while_true!(break 'x); + | ---------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:22:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | while_true!(break 'x); + | ---------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:22:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | while_true!(break 'x); + | ---------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:22:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | while_true!(break 'x); + | ---------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:22:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +LL | // ditto +LL | while_true!(break 'x); + | ---------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: loop { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:67:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels-in-let.rs:29:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +LL | // ditto +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + diff --git a/src/test/ui/hygiene/hygienic-labels.rs b/src/test/ui/hygiene/hygienic-labels.rs new file mode 100644 index 00000000000..a364dd9c887 --- /dev/null +++ b/src/test/ui/hygiene/hygienic-labels.rs @@ -0,0 +1,53 @@ +// run-pass +#![allow(unreachable_code)] +// Test that labels injected by macros do not break hygiene. + +// Issue #24278: The label/lifetime shadowing checker from #24162 +// conservatively ignores hygiene, and thus issues warnings that are +// both true- and false-positives for this test. + +macro_rules! loop_x { + ($e: expr) => { + // $e shouldn't be able to interact with this 'x + 'x: loop { $e } + } +} + +macro_rules! run_once { + ($e: expr) => { + // ditto + 'x: for _ in 0..1 { $e } + } +} + +macro_rules! while_x { + ($e: expr) => { + // ditto + 'x: while 1 + 1 == 2 { $e } + } +} + +pub fn main() { + 'x: for _ in 0..1 { + // this 'x should refer to the outer loop, lexically + loop_x!(break 'x); + panic!("break doesn't act hygienically inside for loop"); + } + + 'x: loop { + // ditto + loop_x!(break 'x); + panic!("break doesn't act hygienically inside infinite loop"); + } + + 'x: while 1 + 1 == 2 { + while_x!(break 'x); + panic!("break doesn't act hygienically inside infinite while loop"); + } + + 'x: for _ in 0..1 { + // ditto + run_once!(continue 'x); + panic!("continue doesn't act hygienically inside for loop"); + } +} diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr new file mode 100644 index 00000000000..d88dfce540e --- /dev/null +++ b/src/test/ui/hygiene/hygienic-labels.stderr @@ -0,0 +1,299 @@ +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:12:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +LL | // this 'x should refer to the outer loop, lexically +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:37:5 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: loop { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:37:5 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: loop { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:12:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:12:9 + | +LL | 'x: loop { $e } + | ^^ + | | + | first declared here + | lifetime 'x already in scope +... +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:12:9 + | +LL | 'x: loop { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +LL | // ditto +LL | loop_x!(break 'x); + | ------------------ in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:43:5 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:43:5 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:43:5 + | +LL | 'x: loop { + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:43:5 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:26:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | while_x!(break 'x); + | ------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:26:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | while_x!(break 'x); + | ------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:26:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +... +LL | while_x!(break 'x); + | ------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:26:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | while_x!(break 'x); + | ------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:26:9 + | +LL | 'x: while 1 + 1 == 2 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: while 1 + 1 == 2 { + | -- first declared here +LL | while_x!(break 'x); + | ------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: loop { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: while 1 + 1 == 2 { + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:48:5 + | +LL | 'x: while 1 + 1 == 2 { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { + | ^^ lifetime 'x already in scope + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: loop { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: loop { $e } + | -- first declared here +... +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: while 1 + 1 == 2 { + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: while 1 + 1 == 2 { $e } + | -- first declared here +... +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + +warning: label name `'x` shadows a label name that is already in scope + --> $DIR/hygienic-labels.rs:19:9 + | +LL | 'x: for _ in 0..1 { $e } + | ^^ lifetime 'x already in scope +... +LL | 'x: for _ in 0..1 { + | -- first declared here +LL | // ditto +LL | run_once!(continue 'x); + | ----------------------- in this macro invocation + diff --git a/src/test/ui/hygiene/issue-44128.rs b/src/test/ui/hygiene/issue-44128.rs new file mode 100644 index 00000000000..5e03bdb8c5b --- /dev/null +++ b/src/test/ui/hygiene/issue-44128.rs @@ -0,0 +1,17 @@ +// check-pass +#![allow(unused_must_use)] +#![feature(decl_macro)] + +pub macro create_struct($a:ident) { + struct $a; + impl Clone for $a { + fn clone(&self) -> Self { + $a + } + } +} + +fn main() { + create_struct!(Test); + Test.clone(); +} diff --git a/src/test/ui/hygiene/issue-47311.rs b/src/test/ui/hygiene/issue-47311.rs new file mode 100644 index 00000000000..5c2379a8aba --- /dev/null +++ b/src/test/ui/hygiene/issue-47311.rs @@ -0,0 +1,17 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] +#![allow(unused)] + +macro m($S:ident, $x:ident) { + $S { $x: 0 } +} + +mod foo { + struct S { x: i32 } + + fn f() { ::m!(S, x); } +} + +fn main() {} diff --git a/src/test/ui/hygiene/issue-47312.rs b/src/test/ui/hygiene/issue-47312.rs new file mode 100644 index 00000000000..bbcb3a7f393 --- /dev/null +++ b/src/test/ui/hygiene/issue-47312.rs @@ -0,0 +1,21 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] +#![allow(unused)] + +mod foo { + pub macro m($s:tt, $i:tt) { + $s.$i + } +} + +mod bar { + struct S(i32); + fn f() { + let s = S(0); + ::foo::m!(s, 0); + } +} + +fn main() {} diff --git a/src/test/ui/hygiene/items.rs b/src/test/ui/hygiene/items.rs new file mode 100644 index 00000000000..1c625a9728c --- /dev/null +++ b/src/test/ui/hygiene/items.rs @@ -0,0 +1,27 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +pub macro m($foo:ident, $f:ident, $e:expr) { + mod foo { + pub fn f() -> u32 { 0 } + pub fn $f() -> u64 { 0 } + } + + mod $foo { + pub fn f() -> i32 { 0 } + pub fn $f() -> i64 { 0 } + } + + let _: u32 = foo::f(); + let _: u64 = foo::$f(); + let _: i32 = $foo::f(); + let _: i64 = $foo::$f(); + let _: i64 = $e; +} + +fn main() { + m!(foo, f, foo::f()); + let _: i64 = foo::f(); +} diff --git a/src/test/ui/hygiene/legacy_interaction.rs b/src/test/ui/hygiene/legacy_interaction.rs new file mode 100644 index 00000000000..52008eed515 --- /dev/null +++ b/src/test/ui/hygiene/legacy_interaction.rs @@ -0,0 +1,42 @@ +// check-pass +#![allow(dead_code)] +// ignore-pretty pretty-printing is unhygienic + +// aux-build:legacy_interaction.rs + +#![feature(decl_macro)] +#[allow(unused)] + +extern crate legacy_interaction; +// ^ defines +// ```rust +// macro_rules! m { +// () => { +// fn f() {} // (1) +// g() // (2) +// } +// } +// ```rust + +mod def_site { + // Unless this macro opts out of hygiene, it should resolve the same wherever it is invoked. + pub macro m2() { + ::legacy_interaction::m!(); + f(); // This should resolve to (1) + fn g() {} // We want (2) resolve to this, not to (4) + } +} + +mod use_site { + fn test() { + fn f() -> bool { true } // (3) + fn g() -> bool { true } // (4) + + ::def_site::m2!(); + + let _: bool = f(); // This should resolve to (3) + let _: bool = g(); // This should resolve to (4) + } +} + +fn main() {} diff --git a/src/test/ui/hygiene/lexical.rs b/src/test/ui/hygiene/lexical.rs new file mode 100644 index 00000000000..3d25c720989 --- /dev/null +++ b/src/test/ui/hygiene/lexical.rs @@ -0,0 +1,24 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +mod bar { + mod baz { + pub fn f() {} + } + + pub macro m($f:ident) { + baz::f(); + let _: i32 = $f(); + { + fn $f() -> u32 { 0 } + let _: u32 = $f(); + } + } +} + +fn main() { + fn f() -> i32 { 0 } + bar::m!(f); +} diff --git a/src/test/ui/hygiene/local_inner_macros.rs b/src/test/ui/hygiene/local_inner_macros.rs index f361e3d5d49..71ffcac40d3 100644 --- a/src/test/ui/hygiene/local_inner_macros.rs +++ b/src/test/ui/hygiene/local_inner_macros.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // aux-build:local_inner_macros.rs extern crate local_inner_macros; diff --git a/src/test/ui/hygiene/specialization.rs b/src/test/ui/hygiene/specialization.rs new file mode 100644 index 00000000000..656aa880ad1 --- /dev/null +++ b/src/test/ui/hygiene/specialization.rs @@ -0,0 +1,25 @@ +// run-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +trait Tr { + fn f(&self) -> &'static str { + "This shouldn't happen" + } +} + +pub macro m($t:ty) { + impl Tr for $t { + fn f(&self) -> &'static str { + "Run me" + } + } +} + +struct S; +m!(S); + +fn main() { + assert_eq!(S.f(), "Run me"); +} diff --git a/src/test/ui/hygiene/trait_items-2.rs b/src/test/ui/hygiene/trait_items-2.rs new file mode 100644 index 00000000000..39edfc37d69 --- /dev/null +++ b/src/test/ui/hygiene/trait_items-2.rs @@ -0,0 +1,20 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +macro m($T:ident, $f:ident) { + pub trait $T { + fn f(&self) -> u32 { 0 } + fn $f(&self) -> i32 { 0 } + } + impl $T for () {} + + let _: u32 = ().f(); + let _: i32 = ().$f(); +} + +fn main() { + m!(T, f); + let _: i32 = ().f(); +} diff --git a/src/test/ui/hygiene/transparent-basic.rs b/src/test/ui/hygiene/transparent-basic.rs index 69dfc524989..bfa1713e4ed 100644 --- a/src/test/ui/hygiene/transparent-basic.rs +++ b/src/test/ui/hygiene/transparent-basic.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // aux-build:transparent-basic.rs #![feature(decl_macro, rustc_attrs)] diff --git a/src/test/ui/hygiene/ty_params.rs b/src/test/ui/hygiene/ty_params.rs new file mode 100644 index 00000000000..b296bfe5988 --- /dev/null +++ b/src/test/ui/hygiene/ty_params.rs @@ -0,0 +1,14 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +macro m($T:ident) { + fn f<T, $T>(t: T, t2: $T) -> (T, $T) { + (t, t2) + } +} + +m!(T); + +fn main() {} diff --git a/src/test/ui/hygiene/unpretty-debug.rs b/src/test/ui/hygiene/unpretty-debug.rs new file mode 100644 index 00000000000..6e936bb3d83 --- /dev/null +++ b/src/test/ui/hygiene/unpretty-debug.rs @@ -0,0 +1,20 @@ +// check-pass +// compile-flags: -Zunpretty=expanded,hygiene + +// Don't break whenever Symbol numbering changes +// normalize-stdout-test "\d+#" -> "0#" + +// minimal junk +#![feature(no_core)] +#![no_core] + +macro_rules! foo { + ($x: ident) => { y + $x } +} + +fn bar() { + let x = 1; + foo!(x) +} + +fn y() {} diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout new file mode 100644 index 00000000000..beac4c17abf --- /dev/null +++ b/src/test/ui/hygiene/unpretty-debug.stdout @@ -0,0 +1,15 @@ +// check-pass +// compile-flags: -Zunpretty=expanded,hygiene + +// Don't break whenever Symbol numbering changes +// normalize-stdout-test "\d+#" -> "0#" + +// minimal junk +#![feature /* 0#0 */(no_core)] +#![no_core /* 0#0 */] + +macro_rules! foo /* 0#0 */ { ($ x : ident) => { y + $ x } } + +fn bar /* 0#0 */() { let x /* 0#0 */ = 1; y /* 0#1 */ + x /* 0#0 */ } + +fn y /* 0#0 */() { } diff --git a/src/test/ui/hygiene/wrap_unhygienic_example.rs b/src/test/ui/hygiene/wrap_unhygienic_example.rs new file mode 100644 index 00000000000..50c6b35ab18 --- /dev/null +++ b/src/test/ui/hygiene/wrap_unhygienic_example.rs @@ -0,0 +1,34 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +// aux-build:my_crate.rs +// aux-build:unhygienic_example.rs + +#![feature(decl_macro)] + +extern crate unhygienic_example; +extern crate my_crate; // (b) + +// Hygienic version of `unhygienic_macro`. +pub macro hygienic_macro() { + fn g() {} // (c) + ::unhygienic_example::unhygienic_macro!(); + // ^ Even though we invoke an unhygienic macro, `hygienic_macro` remains hygienic. + // In the above expansion: + // (1) `my_crate` always resolves to (b) regardless of invocation site. + // (2) The defined function `f` is only usable inside this macro definition. + // (3) `g` always resolves to (c) regardless of invocation site. + // (4) `$crate::g` remains hygienic and continues to resolve to (a). + + f(); +} + +#[allow(unused)] +fn test_hygienic_macro() { + hygienic_macro!(); + + fn f() {} // (d) no conflict + f(); // resolves to (d) +} + +fn main() {} diff --git a/src/test/ui/hygiene/xcrate.rs b/src/test/ui/hygiene/xcrate.rs new file mode 100644 index 00000000000..6981ce3f687 --- /dev/null +++ b/src/test/ui/hygiene/xcrate.rs @@ -0,0 +1,12 @@ +// run-pass +// ignore-pretty pretty-printing is unhygienic + +// aux-build:xcrate.rs + +#![feature(decl_macro)] + +extern crate xcrate; + +fn main() { + xcrate::test!(); +} |
