diff options
Diffstat (limited to 'tests/ui/hygiene')
131 files changed, 3138 insertions, 0 deletions
diff --git a/tests/ui/hygiene/arguments.rs b/tests/ui/hygiene/arguments.rs new file mode 100644 index 000000000..f0f732f4c --- /dev/null +++ b/tests/ui/hygiene/arguments.rs @@ -0,0 +1,17 @@ +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +macro m($t:ty, $e:expr) { + mod foo { + #[allow(unused)] + struct S; + pub(super) fn f(_: $t) {} + } + foo::f($e); +} + +fn main() { + struct S; + m!(S, S); //~ ERROR cannot find type `S` in this scope +} diff --git a/tests/ui/hygiene/arguments.stderr b/tests/ui/hygiene/arguments.stderr new file mode 100644 index 000000000..d072086e0 --- /dev/null +++ b/tests/ui/hygiene/arguments.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `S` in this scope + --> $DIR/arguments.rs:16:8 + | +LL | m!(S, S); + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/hygiene/assoc_item_ctxt.rs b/tests/ui/hygiene/assoc_item_ctxt.rs new file mode 100644 index 000000000..65593d1d5 --- /dev/null +++ b/tests/ui/hygiene/assoc_item_ctxt.rs @@ -0,0 +1,42 @@ +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] +#![allow(unused)] + +mod ok { + macro mac_trait_item($method: ident) { + fn $method(); + } + + trait Tr { + mac_trait_item!(method); + } + + macro mac_trait_impl() { + impl Tr for u8 { // OK + fn method() {} // OK + } + } + + mac_trait_impl!(); +} + +mod error { + macro mac_trait_item() { + fn method(); + } + + trait Tr { + mac_trait_item!(); + } + + macro mac_trait_impl() { + impl Tr for u8 { //~ ERROR not all trait items implemented, missing: `method` + fn method() {} //~ ERROR method `method` is not a member of trait `Tr` + } + } + + mac_trait_impl!(); +} + +fn main() {} diff --git a/tests/ui/hygiene/assoc_item_ctxt.stderr b/tests/ui/hygiene/assoc_item_ctxt.stderr new file mode 100644 index 000000000..d65716ec2 --- /dev/null +++ b/tests/ui/hygiene/assoc_item_ctxt.stderr @@ -0,0 +1,32 @@ +error[E0407]: method `method` is not a member of trait `Tr` + --> $DIR/assoc_item_ctxt.rs:35:13 + | +LL | fn method() {} + | ^^^------^^^^^ + | | | + | | help: there is an associated function with a similar name: `method` + | not a member of trait `Tr` +... +LL | mac_trait_impl!(); + | ----------------- in this macro invocation + | + = note: this error originates in the macro `mac_trait_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0046]: not all trait items implemented, missing: `method` + --> $DIR/assoc_item_ctxt.rs:34:9 + | +LL | fn method(); + | ------------ `method` from trait +... +LL | impl Tr for u8 { + | ^^^^^^^^^^^^^^ missing `method` in implementation +... +LL | mac_trait_impl!(); + | ----------------- in this macro invocation + | + = note: this error originates in the macro `mac_trait_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0046, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/hygiene/assoc_ty_bindings.rs b/tests/ui/hygiene/assoc_ty_bindings.rs new file mode 100644 index 000000000..0567beab9 --- /dev/null +++ b/tests/ui/hygiene/assoc_ty_bindings.rs @@ -0,0 +1,38 @@ +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro, associated_type_defaults)] + +trait Base { + type AssocTy; + fn f(); +} +trait Derived: Base { + fn g(); +} + +macro mac() { + type A = dyn Base<AssocTy = u8>; + type B = dyn Derived<AssocTy = u8>; + + impl Base for u8 { + type AssocTy = u8; + fn f() { + let _: Self::AssocTy; + } + } + impl Derived for u8 { + fn g() { + let _: Self::AssocTy; + } + } + + fn h<T: Base, U: Derived>() { + let _: T::AssocTy; + let _: U::AssocTy; + } +} + +mac!(); + +fn main() {} diff --git a/tests/ui/hygiene/auxiliary/codegen-attrs.rs b/tests/ui/hygiene/auxiliary/codegen-attrs.rs new file mode 100644 index 000000000..74afedbeb --- /dev/null +++ b/tests/ui/hygiene/auxiliary/codegen-attrs.rs @@ -0,0 +1,10 @@ +#![feature(decl_macro)] + +macro m($f:ident) { + #[export_name = "export_function_name"] + pub fn $f() -> i32 { + 2 + } +} + +m!(rust_function_name); diff --git a/tests/ui/hygiene/auxiliary/def-site-async-await.rs b/tests/ui/hygiene/auxiliary/def-site-async-await.rs new file mode 100644 index 000000000..f7e9b8013 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/def-site-async-await.rs @@ -0,0 +1,7 @@ +// edition:2018 + +extern crate opaque_hygiene; + +pub async fn serve() { + opaque_hygiene::make_it!(); +} diff --git a/tests/ui/hygiene/auxiliary/fields.rs b/tests/ui/hygiene/auxiliary/fields.rs new file mode 100644 index 000000000..733d11a9e --- /dev/null +++ b/tests/ui/hygiene/auxiliary/fields.rs @@ -0,0 +1,73 @@ +#![feature(decl_macro)] + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Field { + RootCtxt, + MacroCtxt, +} + +#[rustfmt::skip] +macro x( + $macro_name:ident, + $macro2_name:ident, + $type_name:ident, + $field_name:ident, + $const_name:ident +) { + #[derive(Copy, Clone)] + pub struct $type_name { + pub field: Field, + pub $field_name: Field, + } + + pub const $const_name: $type_name = + $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }; + + #[macro_export] + macro_rules! $macro_name { + (check_fields_of $e:expr) => {{ + let e = $e; + assert_eq!(e.field, Field::MacroCtxt); + assert_eq!(e.$field_name, Field::RootCtxt); + }}; + (check_fields) => {{ + assert_eq!($const_name.field, Field::MacroCtxt); + assert_eq!($const_name.$field_name, Field::RootCtxt); + }}; + (construct) => { + $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt } + }; + } + + pub macro $macro2_name { + (check_fields_of $e:expr) => {{ + let e = $e; + assert_eq!(e.field, Field::MacroCtxt); + assert_eq!(e.$field_name, Field::RootCtxt); + }}, + (check_fields) => {{ + assert_eq!($const_name.field, Field::MacroCtxt); + assert_eq!($const_name.$field_name, Field::RootCtxt); + }}, + (construct) => { + $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt } + } + } +} + +x!(test_fields, test_fields2, MyStruct, field, MY_CONST); + +pub fn check_fields(s: MyStruct) { + test_fields!(check_fields_of s); +} + +pub fn check_fields_local() { + test_fields!(check_fields); + test_fields2!(check_fields); + + let s1 = test_fields!(construct); + test_fields!(check_fields_of s1); + + let s2 = test_fields2!(construct); + test_fields2!(check_fields_of s2); +} diff --git a/tests/ui/hygiene/auxiliary/intercrate.rs b/tests/ui/hygiene/auxiliary/intercrate.rs new file mode 100644 index 000000000..068535885 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/intercrate.rs @@ -0,0 +1,46 @@ +#![feature(decl_macro)] + +pub mod foo { + pub use self::bar::m; + mod bar { + fn f() -> u32 { 1 } + pub macro m() { + f() + } + } +} + +pub struct SomeType; + +// `$crate` +pub macro uses_dollar_crate_modern() { + type Alias = $crate::SomeType; +} + +pub macro define_uses_dollar_crate_modern_nested($uses_dollar_crate_modern_nested: ident) { + macro $uses_dollar_crate_modern_nested() { + type AliasCrateModernNested = $crate::SomeType; + } +} + +#[macro_export] +macro_rules! define_uses_dollar_crate_legacy_nested { + () => { + macro_rules! uses_dollar_crate_legacy_nested { + () => { + type AliasLegacyNested = $crate::SomeType; + } + } + } +} + +// `crate` +pub macro uses_crate_modern() { + type AliasCrate = crate::SomeType; +} + +pub macro define_uses_crate_modern_nested($uses_crate_modern_nested: ident) { + macro $uses_crate_modern_nested() { + type AliasCrateModernNested = crate::SomeType; + } +} diff --git a/tests/ui/hygiene/auxiliary/legacy_interaction.rs b/tests/ui/hygiene/auxiliary/legacy_interaction.rs new file mode 100644 index 000000000..90d5243b7 --- /dev/null +++ b/tests/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/tests/ui/hygiene/auxiliary/local_inner_macros.rs b/tests/ui/hygiene/auxiliary/local_inner_macros.rs new file mode 100644 index 000000000..4296ae2fd --- /dev/null +++ b/tests/ui/hygiene/auxiliary/local_inner_macros.rs @@ -0,0 +1,19 @@ +#[macro_export] +macro_rules! helper1 { + () => ( struct S; ) +} + +#[macro_export(local_inner_macros)] +macro_rules! helper2 { + () => ( helper1!(); ) +} + +#[macro_export(local_inner_macros)] +macro_rules! public_macro { + () => ( helper2!(); ) +} + +#[macro_export(local_inner_macros)] +macro_rules! public_macro_dynamic { + ($helper: ident) => ( $helper!(); ) +} diff --git a/tests/ui/hygiene/auxiliary/methods.rs b/tests/ui/hygiene/auxiliary/methods.rs new file mode 100644 index 000000000..23b9c61cf --- /dev/null +++ b/tests/ui/hygiene/auxiliary/methods.rs @@ -0,0 +1,160 @@ +#![feature(decl_macro)] + +#[derive(PartialEq, Eq, Debug)] +pub enum Method { + DefaultMacroCtxt, + DefaultRootCtxt, + OverrideMacroCtxt, + OverrideRootCtxt, +} + +#[rustfmt::skip] +macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) { + pub trait $trait_name { + fn method(&self) -> Method { + Method::DefaultMacroCtxt + } + + fn $method_name(&self) -> Method { + Method::DefaultRootCtxt + } + } + + impl $trait_name for () {} + impl $trait_name for bool { + fn method(&self) -> Method { + Method::OverrideMacroCtxt + } + + fn $method_name(&self) -> Method { + Method::OverrideRootCtxt + } + } + + #[macro_export] + macro_rules! $macro_name { + (check_resolutions) => { + assert_eq!(().method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt); + assert_eq!(().$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt); + + assert_eq!(false.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt); + assert_eq!(false.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt); + + assert_eq!('a'.method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt); + assert_eq!('a'.$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt); + + assert_eq!(1i32.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt); + assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt); + + assert_eq!(1i64.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt); + assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt); + }; + (assert_no_override $v:expr) => { + assert_eq!($v.method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt); + assert_eq!($v.$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt); + }; + (assert_override $v:expr) => { + assert_eq!($v.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt); + assert_eq!($v.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt); + }; + (impl for $t:ty) => { + impl $trait_name for $t { + fn method(&self) -> Method { + Method::OverrideMacroCtxt + } + + fn $method_name(&self) -> Method { + Method::OverrideRootCtxt + } + } + }; + } + + pub macro $macro2_name { + (check_resolutions) => { + assert_eq!(().method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt); + assert_eq!(().$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt); + + assert_eq!(false.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt); + assert_eq!(false.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt); + + assert_eq!('a'.method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt); + assert_eq!('a'.$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt); + + assert_eq!(1i32.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt); + assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt); + + assert_eq!(1i64.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt); + assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt); + }, + (assert_no_override $v:expr) => { + assert_eq!($v.method(), Method::DefaultMacroCtxt); + assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt); + assert_eq!($v.$method_name(), Method::DefaultRootCtxt); + assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt); + }, + (assert_override $v:expr) => { + assert_eq!($v.method(), Method::OverrideMacroCtxt); + assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt); + assert_eq!($v.$method_name(), Method::OverrideRootCtxt); + assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt); + }, + (impl for $t:ty) => { + impl $trait_name for $t { + fn method(&self) -> Method { + Method::OverrideMacroCtxt + } + + fn $method_name(&self) -> Method { + Method::OverrideRootCtxt + } + } + } + } +} + +x!(test_trait, test_trait2, MyTrait, method); + +impl MyTrait for char {} +test_trait!(impl for i32); +test_trait2!(impl for i64); + +pub fn check_crate_local() { + test_trait!(check_resolutions); + test_trait2!(check_resolutions); +} + +// Check that any comparison of idents at monomorphization time is correct +pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) { + test_trait!(check_resolutions); + test_trait2!(check_resolutions); + + test_trait!(assert_no_override t); + test_trait2!(assert_no_override t); + test_trait!(assert_override u); + test_trait2!(assert_override u); +} diff --git a/tests/ui/hygiene/auxiliary/my_crate.rs b/tests/ui/hygiene/auxiliary/my_crate.rs new file mode 100644 index 000000000..cdc6c27d8 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/my_crate.rs @@ -0,0 +1 @@ +pub fn f() {} diff --git a/tests/ui/hygiene/auxiliary/needs_hygiene.rs b/tests/ui/hygiene/auxiliary/needs_hygiene.rs new file mode 100644 index 000000000..3df6450fd --- /dev/null +++ b/tests/ui/hygiene/auxiliary/needs_hygiene.rs @@ -0,0 +1,5 @@ +#![feature(decl_macro)] +macro x() { struct MyStruct; } + +x!(); +x!(); diff --git a/tests/ui/hygiene/auxiliary/nested-dollar-crate.rs b/tests/ui/hygiene/auxiliary/nested-dollar-crate.rs new file mode 100644 index 000000000..e5caa0f9c --- /dev/null +++ b/tests/ui/hygiene/auxiliary/nested-dollar-crate.rs @@ -0,0 +1,14 @@ +pub const IN_DEF_CRATE: &str = "In def crate!"; + +macro_rules! make_it { + () => { + #[macro_export] + macro_rules! inner { + () => { + $crate::IN_DEF_CRATE + } + } + } +} + +make_it!(); diff --git a/tests/ui/hygiene/auxiliary/not-libstd.rs b/tests/ui/hygiene/auxiliary/not-libstd.rs new file mode 100644 index 000000000..babba293d --- /dev/null +++ b/tests/ui/hygiene/auxiliary/not-libstd.rs @@ -0,0 +1 @@ +pub fn not_in_lib_std() {} diff --git a/tests/ui/hygiene/auxiliary/opaque-hygiene.rs b/tests/ui/hygiene/auxiliary/opaque-hygiene.rs new file mode 100644 index 000000000..7730f91bd --- /dev/null +++ b/tests/ui/hygiene/auxiliary/opaque-hygiene.rs @@ -0,0 +1,21 @@ +// force-host +// no-prefer-dynamic + +#![feature(proc_macro_quote)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{TokenStream, quote}; + +#[proc_macro] +pub fn make_it(input: TokenStream) -> TokenStream { + // `quote!` applies def-site hygiene + quote! { + trait Foo { + fn my_fn(&self) {} + } + + impl<T> Foo for T {} + "a".my_fn(); + } +} diff --git a/tests/ui/hygiene/auxiliary/pub_hygiene.rs b/tests/ui/hygiene/auxiliary/pub_hygiene.rs new file mode 100644 index 000000000..47e76a629 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/pub_hygiene.rs @@ -0,0 +1,7 @@ +#![feature(decl_macro)] + +macro x() { + pub struct MyStruct; +} + +x!(); diff --git a/tests/ui/hygiene/auxiliary/stdlib-prelude.rs b/tests/ui/hygiene/auxiliary/stdlib-prelude.rs new file mode 100644 index 000000000..81b0b7faa --- /dev/null +++ b/tests/ui/hygiene/auxiliary/stdlib-prelude.rs @@ -0,0 +1,3 @@ +#![feature(decl_macro)] + +pub macro stdlib_macro() {} diff --git a/tests/ui/hygiene/auxiliary/transparent-basic.rs b/tests/ui/hygiene/auxiliary/transparent-basic.rs new file mode 100644 index 000000000..37de27ee8 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/transparent-basic.rs @@ -0,0 +1,6 @@ +#![feature(decl_macro, rustc_attrs)] + +#[rustc_macro_transparency = "transparent"] +pub macro dollar_crate() { + let s = $crate::S; +} diff --git a/tests/ui/hygiene/auxiliary/unhygienic_example.rs b/tests/ui/hygiene/auxiliary/unhygienic_example.rs new file mode 100644 index 000000000..8e6e8f9b3 --- /dev/null +++ b/tests/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/tests/ui/hygiene/auxiliary/use_by_macro.rs b/tests/ui/hygiene/auxiliary/use_by_macro.rs new file mode 100644 index 000000000..791cf0358 --- /dev/null +++ b/tests/ui/hygiene/auxiliary/use_by_macro.rs @@ -0,0 +1,15 @@ +#![feature(decl_macro)] + +macro x($macro_name:ident) { + #[macro_export] + macro_rules! $macro_name { + (define) => { + pub struct MyStruct; + }; + (create) => { + MyStruct {} + }; + } +} + +x!(my_struct); diff --git a/tests/ui/hygiene/auxiliary/variants.rs b/tests/ui/hygiene/auxiliary/variants.rs new file mode 100644 index 000000000..dbfcce17d --- /dev/null +++ b/tests/ui/hygiene/auxiliary/variants.rs @@ -0,0 +1,36 @@ +#![feature(decl_macro)] + +#[rustfmt::skip] +macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) { + #[repr(u8)] + pub enum $type_name { + Variant = 0, + $variant_name = 1, + } + + #[macro_export] + macro_rules! $macro_name { + () => {{ + assert_eq!($type_name::Variant as u8, 0); + assert_eq!($type_name::$variant_name as u8, 1); + assert_eq!(<$type_name>::Variant as u8, 0); + assert_eq!(<$type_name>::$variant_name as u8, 1); + }}; + } + + pub macro $macro2_name { + () => {{ + assert_eq!($type_name::Variant as u8, 0); + assert_eq!($type_name::$variant_name as u8, 1); + assert_eq!(<$type_name>::Variant as u8, 0); + assert_eq!(<$type_name>::$variant_name as u8, 1); + }}, + } +} + +x!(test_variants, test_variants2, MyEnum, Variant); + +pub fn check_variants() { + test_variants!(); + test_variants2!(); +} diff --git a/tests/ui/hygiene/auxiliary/xcrate.rs b/tests/ui/hygiene/auxiliary/xcrate.rs new file mode 100644 index 000000000..f5a911f57 --- /dev/null +++ b/tests/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/tests/ui/hygiene/cross-crate-codegen-attrs.rs b/tests/ui/hygiene/cross-crate-codegen-attrs.rs new file mode 100644 index 000000000..af6b13343 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-codegen-attrs.rs @@ -0,0 +1,12 @@ +// Make sure that macro expanded codegen attributes work across crates. +// We used to gensym the identifiers in attributes, which stopped dependent +// crates from seeing them, resulting in linker errors in cases like this one. + +// run-pass +// aux-build:codegen-attrs.rs + +extern crate codegen_attrs; + +fn main() { + assert_eq!(codegen_attrs::rust_function_name(), 2); +} diff --git a/tests/ui/hygiene/cross-crate-define-and-use.rs b/tests/ui/hygiene/cross-crate-define-and-use.rs new file mode 100644 index 000000000..94f1adff6 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-define-and-use.rs @@ -0,0 +1,19 @@ +// Check that a marco from another crate can define an item in one expansion +// and use it from another, without it being visible to everyone. +// This requires that the definition of `my_struct` preserves the hygiene +// information for the tokens in its definition. + +// check-pass +// aux-build:use_by_macro.rs + +#![feature(type_name_of_val)] +extern crate use_by_macro; + +use use_by_macro::*; + +enum MyStruct {} +my_struct!(define); + +fn main() { + let x = my_struct!(create); +} diff --git a/tests/ui/hygiene/cross-crate-fields.rs b/tests/ui/hygiene/cross-crate-fields.rs new file mode 100644 index 000000000..1bcd64573 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-fields.rs @@ -0,0 +1,24 @@ +// Test that fields on a struct defined in another crate are resolved correctly +// their names differ only in `SyntaxContext`. + +// run-pass +// aux-build:fields.rs + +extern crate fields; + +use fields::*; + +fn main() { + check_fields_local(); + + test_fields!(check_fields); + test_fields2!(check_fields); + + let s1 = test_fields!(construct); + check_fields(s1); + test_fields!(check_fields_of s1); + + let s2 = test_fields2!(construct); + check_fields(s2); + test_fields2!(check_fields_of s2); +} diff --git a/tests/ui/hygiene/cross-crate-glob-hygiene.rs b/tests/ui/hygiene/cross-crate-glob-hygiene.rs new file mode 100644 index 000000000..de5576682 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-glob-hygiene.rs @@ -0,0 +1,23 @@ +// Check that globs cannot import hygienic identifiers from a macro expansion +// in another crate. `my_struct` is a `macro_rules` macro, so the struct it +// defines is only not imported because `my_struct` is defined by a macros 2.0 +// macro. + +// aux-build:use_by_macro.rs + +extern crate use_by_macro; + +use use_by_macro::*; + +mod m { + use use_by_macro::*; + + my_struct!(define); +} + +use m::*; + +fn main() { + let x = my_struct!(create); + //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope +} diff --git a/tests/ui/hygiene/cross-crate-glob-hygiene.stderr b/tests/ui/hygiene/cross-crate-glob-hygiene.stderr new file mode 100644 index 000000000..7369e77d0 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-glob-hygiene.stderr @@ -0,0 +1,11 @@ +error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope + --> $DIR/cross-crate-glob-hygiene.rs:21:13 + | +LL | let x = my_struct!(create); + | ^^^^^^^^^^^^^^^^^^ not found in this scope + | + = note: this error originates in the macro `my_struct` (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 E0422`. diff --git a/tests/ui/hygiene/cross-crate-methods.rs b/tests/ui/hygiene/cross-crate-methods.rs new file mode 100644 index 000000000..0e6f57c33 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-methods.rs @@ -0,0 +1,33 @@ +// Test that methods defined in another crate are resolved correctly their +// names differ only in `SyntaxContext`. This also checks that any name +// resolution done when monomorphizing is correct. + +// run-pass +// aux-build:methods.rs + +extern crate methods; + +use methods::*; + +struct A; +struct B; +struct C; + +impl MyTrait for A {} +test_trait!(impl for B); +test_trait2!(impl for C); + +fn main() { + check_crate_local(); + check_crate_local_generic(A, B); + check_crate_local_generic(A, C); + + test_trait!(check_resolutions); + test_trait2!(check_resolutions); + test_trait!(assert_no_override A); + test_trait2!(assert_no_override A); + test_trait!(assert_override B); + test_trait2!(assert_override B); + test_trait!(assert_override C); + test_trait2!(assert_override C); +} diff --git a/tests/ui/hygiene/cross-crate-name-collision.rs b/tests/ui/hygiene/cross-crate-name-collision.rs new file mode 100644 index 000000000..8f118782f --- /dev/null +++ b/tests/ui/hygiene/cross-crate-name-collision.rs @@ -0,0 +1,12 @@ +// Check that two items defined in another crate that have identifiers that +// only differ by `SyntaxContext` do not cause name collisions when imported +// in another crate. + +// check-pass +// aux-build:needs_hygiene.rs + +extern crate needs_hygiene; + +use needs_hygiene::*; + +fn main() {} diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.rs b/tests/ui/hygiene/cross-crate-name-hiding-2.rs new file mode 100644 index 000000000..3eacd775c --- /dev/null +++ b/tests/ui/hygiene/cross-crate-name-hiding-2.rs @@ -0,0 +1,15 @@ +// Check that an identifier from a 2.0 macro in another crate cannot be +// resolved with an identifier that's not from a macro expansion. + +// aux-build:use_by_macro.rs + +extern crate use_by_macro; + +use use_by_macro::*; + +my_struct!(define); + +fn main() { + let x = MyStruct {}; + //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope +} diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr new file mode 100644 index 000000000..46314cdd5 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr @@ -0,0 +1,9 @@ +error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope + --> $DIR/cross-crate-name-hiding-2.rs:13:13 + | +LL | let x = MyStruct {}; + | ^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0422`. diff --git a/tests/ui/hygiene/cross-crate-name-hiding.rs b/tests/ui/hygiene/cross-crate-name-hiding.rs new file mode 100644 index 000000000..dd76ecc57 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-name-hiding.rs @@ -0,0 +1,13 @@ +// Check that an item defined by a 2.0 macro in another crate cannot be used in +// another crate. + +// aux-build:pub_hygiene.rs + +extern crate pub_hygiene; + +use pub_hygiene::*; + +fn main() { + let x = MyStruct {}; + //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope +} diff --git a/tests/ui/hygiene/cross-crate-name-hiding.stderr b/tests/ui/hygiene/cross-crate-name-hiding.stderr new file mode 100644 index 000000000..f8840c8f8 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-name-hiding.stderr @@ -0,0 +1,9 @@ +error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope + --> $DIR/cross-crate-name-hiding.rs:11:13 + | +LL | let x = MyStruct {}; + | ^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0422`. diff --git a/tests/ui/hygiene/cross-crate-redefine.rs b/tests/ui/hygiene/cross-crate-redefine.rs new file mode 100644 index 000000000..3cb06b4ba --- /dev/null +++ b/tests/ui/hygiene/cross-crate-redefine.rs @@ -0,0 +1,14 @@ +// Check that items with identical `SyntaxContext` conflict even when that +// context involves a mark from another crate. + +// aux-build:use_by_macro.rs + +extern crate use_by_macro; + +use use_by_macro::*; + +my_struct!(define); +//~^ ERROR the name `MyStruct` is defined multiple times +my_struct!(define); + +fn main() {} diff --git a/tests/ui/hygiene/cross-crate-redefine.stderr b/tests/ui/hygiene/cross-crate-redefine.stderr new file mode 100644 index 000000000..4f1419de4 --- /dev/null +++ b/tests/ui/hygiene/cross-crate-redefine.stderr @@ -0,0 +1,15 @@ +error[E0428]: the name `MyStruct` is defined multiple times + --> $DIR/cross-crate-redefine.rs:10:1 + | +LL | my_struct!(define); + | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here +LL | +LL | my_struct!(define); + | ------------------ previous definition of the type `MyStruct` here + | + = note: `MyStruct` must be defined only once in the type namespace of this module + = note: this error originates in the macro `my_struct` (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 E0428`. diff --git a/tests/ui/hygiene/cross-crate-variants.rs b/tests/ui/hygiene/cross-crate-variants.rs new file mode 100644 index 000000000..efc73a21f --- /dev/null +++ b/tests/ui/hygiene/cross-crate-variants.rs @@ -0,0 +1,18 @@ +// Test that variants of an enum defined in another crate are resolved +// correctly when their names differ only in `SyntaxContext`. + +// run-pass +// aux-build:variants.rs + +extern crate variants; + +use variants::*; + +fn main() { + check_variants(); + + test_variants!(); + test_variants2!(); + + assert_eq!(MyEnum::Variant as u8, 1); +} diff --git a/tests/ui/hygiene/dollar-crate-modern.rs b/tests/ui/hygiene/dollar-crate-modern.rs new file mode 100644 index 000000000..eb176fed8 --- /dev/null +++ b/tests/ui/hygiene/dollar-crate-modern.rs @@ -0,0 +1,25 @@ +// Make sure `$crate` and `crate` work in for basic cases of nested macros. + +// check-pass +// aux-build:intercrate.rs + +#![feature(decl_macro)] + +extern crate intercrate; + +// `$crate` +intercrate::uses_dollar_crate_modern!(); + +intercrate::define_uses_dollar_crate_modern_nested!(uses_dollar_crate_modern_nested); +uses_dollar_crate_modern_nested!(); + +intercrate::define_uses_dollar_crate_legacy_nested!(); +uses_dollar_crate_legacy_nested!(); + +// `crate` +intercrate::uses_crate_modern!(); + +intercrate::define_uses_crate_modern_nested!(uses_crate_modern_nested); +uses_crate_modern_nested!(); + +fn main() {} diff --git a/tests/ui/hygiene/duplicate_lifetimes.rs b/tests/ui/hygiene/duplicate_lifetimes.rs new file mode 100644 index 000000000..8971fb626 --- /dev/null +++ b/tests/ui/hygiene/duplicate_lifetimes.rs @@ -0,0 +1,19 @@ +// Ensure that lifetime parameter names are modernized before we check for +// duplicates. + +#![feature(decl_macro, rustc_attrs)] + +#[rustc_macro_transparency = "semitransparent"] +macro m($a:lifetime) { + fn g<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter +} + +#[rustc_macro_transparency = "transparent"] +macro n($a:lifetime) { + fn h<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter +} + +m!('a); +n!('a); + +fn main() {} diff --git a/tests/ui/hygiene/duplicate_lifetimes.stderr b/tests/ui/hygiene/duplicate_lifetimes.stderr new file mode 100644 index 000000000..9f1a75147 --- /dev/null +++ b/tests/ui/hygiene/duplicate_lifetimes.stderr @@ -0,0 +1,31 @@ +error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters + --> $DIR/duplicate_lifetimes.rs:8:14 + | +LL | fn g<$a, 'a>() {} + | ^^ already used +... +LL | m!('a); + | ------ + | | | + | | first use of `'a` + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters + --> $DIR/duplicate_lifetimes.rs:13:14 + | +LL | fn h<$a, 'a>() {} + | ^^ already used +... +LL | n!('a); + | ------ + | | | + | | first use of `'a` + | in this macro invocation + | + = note: this error originates in the macro `n` (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 E0403`. diff --git a/tests/ui/hygiene/eager-from-opaque-2.rs b/tests/ui/hygiene/eager-from-opaque-2.rs new file mode 100644 index 000000000..220e55267 --- /dev/null +++ b/tests/ui/hygiene/eager-from-opaque-2.rs @@ -0,0 +1,22 @@ +// Regression test for the issue #63460. + +// check-pass + +#[macro_export] +macro_rules! separator { + () => { "/" }; +} + +#[macro_export] +macro_rules! concat_separator { + ( $e:literal, $($other:literal),+ ) => { + concat!($e, $crate::separator!(), $crate::concat_separator!($($other),+)) + }; + ( $e:literal ) => { + $e + } +} + +fn main() { + println!("{}", concat_separator!(2, 3, 4)) +} diff --git a/tests/ui/hygiene/eager-from-opaque.rs b/tests/ui/hygiene/eager-from-opaque.rs new file mode 100644 index 000000000..6f3215dd6 --- /dev/null +++ b/tests/ui/hygiene/eager-from-opaque.rs @@ -0,0 +1,20 @@ +// Opaque macro can eagerly expand its input without breaking its resolution. +// Regression test for issue #63685. + +// check-pass + +macro_rules! foo { + () => { + "foo" + }; +} + +macro_rules! bar { + () => { + foo!() + }; +} + +fn main() { + format_args!(bar!()); +} diff --git a/tests/ui/hygiene/expansion-info-reset.rs b/tests/ui/hygiene/expansion-info-reset.rs new file mode 100644 index 000000000..fa5f71212 --- /dev/null +++ b/tests/ui/hygiene/expansion-info-reset.rs @@ -0,0 +1,4 @@ +fn main() { + format_args!({ #[derive(Clone)] struct S; }); + //~^ ERROR format argument must be a string literal +} diff --git a/tests/ui/hygiene/expansion-info-reset.stderr b/tests/ui/hygiene/expansion-info-reset.stderr new file mode 100644 index 000000000..64d27e064 --- /dev/null +++ b/tests/ui/hygiene/expansion-info-reset.stderr @@ -0,0 +1,13 @@ +error: format argument must be a string literal + --> $DIR/expansion-info-reset.rs:2:18 + | +LL | format_args!({ #[derive(Clone)] struct S; }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: you might be missing a string literal to format with + | +LL | format_args!("{}", { #[derive(Clone)] struct S; }); + | +++++ + +error: aborting due to previous error + diff --git a/tests/ui/hygiene/extern-prelude-from-opaque-fail.rs b/tests/ui/hygiene/extern-prelude-from-opaque-fail.rs new file mode 100644 index 000000000..571017df4 --- /dev/null +++ b/tests/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -0,0 +1,28 @@ +#![feature(decl_macro)] + +macro a() { + extern crate core as my_core; + mod v { + // Early resolution. + use my_core; //~ ERROR unresolved import `my_core` + } + mod u { + // Late resolution. + fn f() { my_core::mem::drop(0); } + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` + } +} + +a!(); + +mod v { + // Early resolution. + use my_core; //~ ERROR unresolved import `my_core` +} +mod u { + // Late resolution. + fn f() { my_core::mem::drop(0); } + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` +} + +fn main() {} diff --git a/tests/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/tests/ui/hygiene/extern-prelude-from-opaque-fail.stderr new file mode 100644 index 000000000..f1f4caee3 --- /dev/null +++ b/tests/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -0,0 +1,38 @@ +error[E0432]: unresolved import `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:20:9 + | +LL | use my_core; + | ^^^^^^^ no `my_core` in the root + +error[E0432]: unresolved import `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:7:13 + | +LL | use my_core; + | ^^^^^^^ no `my_core` in the root +... +LL | a!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 + | +LL | fn f() { my_core::mem::drop(0); } + | ^^^^^^^ use of undeclared crate or module `my_core` +... +LL | a!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 + | +LL | fn f() { my_core::mem::drop(0); } + | ^^^^^^^ use of undeclared crate or module `my_core` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/hygiene/fields-definition.rs b/tests/ui/hygiene/fields-definition.rs new file mode 100644 index 000000000..173c357bd --- /dev/null +++ b/tests/ui/hygiene/fields-definition.rs @@ -0,0 +1,22 @@ +#![feature(decl_macro)] + +macro modern($a: ident) { + struct Modern { + a: u8, + $a: u8, // OK + } +} + +macro_rules! legacy { + ($a: ident) => { + struct Legacy { + a: u8, + $a: u8, //~ ERROR field `a` is already declared + } + } +} + +modern!(a); +legacy!(a); + +fn main() {} diff --git a/tests/ui/hygiene/fields-definition.stderr b/tests/ui/hygiene/fields-definition.stderr new file mode 100644 index 000000000..9d091cedd --- /dev/null +++ b/tests/ui/hygiene/fields-definition.stderr @@ -0,0 +1,16 @@ +error[E0124]: field `a` is already declared + --> $DIR/fields-definition.rs:14:13 + | +LL | a: u8, + | ----- `a` first declared here +LL | $a: u8, + | ^^^^^^ field already declared +... +LL | legacy!(a); + | ---------- in this macro invocation + | + = note: this error originates in the macro `legacy` (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 E0124`. diff --git a/tests/ui/hygiene/fields-move.rs b/tests/ui/hygiene/fields-move.rs new file mode 100644 index 000000000..401ad97e3 --- /dev/null +++ b/tests/ui/hygiene/fields-move.rs @@ -0,0 +1,30 @@ +// issue #46314 + +#![feature(decl_macro)] + +#[derive(Debug)] +struct NonCopy(String); + +struct Foo { + x: NonCopy, +} + +macro copy_modern($foo: ident) { + $foo.x +} + +macro_rules! copy_legacy { + ($foo: ident) => { + $foo.x //~ ERROR use of moved value: `foo.x` + } +} + +fn assert_two_copies(a: NonCopy, b: NonCopy) { + println!("Got two copies: {:?}, {:?}", a, b); +} + +fn main() { + let foo = Foo { x: NonCopy("foo".into()) }; + assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` +} diff --git a/tests/ui/hygiene/fields-move.stderr b/tests/ui/hygiene/fields-move.stderr new file mode 100644 index 000000000..b5b507c7d --- /dev/null +++ b/tests/ui/hygiene/fields-move.stderr @@ -0,0 +1,39 @@ +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:18:9 + | +LL | $foo.x + | ^^^^^^ value used here after move +... +LL | assert_two_copies(copy_modern!(foo), foo.x); + | ----- value moved here +LL | assert_two_copies(copy_legacy!(foo), foo.x); + | ----------------- in this macro invocation + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + = note: this error originates in the macro `copy_legacy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:28:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_modern!(foo), foo.x); + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:29:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_legacy!(foo), foo.x); + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/hygiene/fields-numeric-borrowck.rs b/tests/ui/hygiene/fields-numeric-borrowck.rs new file mode 100644 index 000000000..9536babc2 --- /dev/null +++ b/tests/ui/hygiene/fields-numeric-borrowck.rs @@ -0,0 +1,13 @@ +struct S(u8); + +fn main() { + let mut s = S(0); + let borrow1 = &mut s.0; + let S { 0: ref mut borrow2 } = s; + //~^ ERROR cannot borrow `s.0` as mutable more than once at a time + borrow2.use_mut(); + borrow1.use_mut(); +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/hygiene/fields-numeric-borrowck.stderr b/tests/ui/hygiene/fields-numeric-borrowck.stderr new file mode 100644 index 000000000..bc13aa62f --- /dev/null +++ b/tests/ui/hygiene/fields-numeric-borrowck.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `s.0` as mutable more than once at a time + --> $DIR/fields-numeric-borrowck.rs:6:16 + | +LL | let borrow1 = &mut s.0; + | -------- first mutable borrow occurs here +LL | let S { 0: ref mut borrow2 } = s; + | ^^^^^^^^^^^^^^^ second mutable borrow occurs here +... +LL | borrow1.use_mut(); + | ----------------- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/hygiene/fields.rs b/tests/ui/hygiene/fields.rs new file mode 100644 index 000000000..7a417b46f --- /dev/null +++ b/tests/ui/hygiene/fields.rs @@ -0,0 +1,30 @@ +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +mod foo { + struct S { x: u32 } + struct T(u32); + + pub macro m($S:ident, $x:ident) {{ + struct $S { + $x: u32, + x: i32, + } + + let s = S { x: 0 }; //~ ERROR type `foo::S` is private + let _ = s.x; //~ ERROR type `foo::S` is private + + let t = T(0); //~ ERROR type `T` is private + let _ = t.0; //~ ERROR type `T` is private + + let s = $S { $x: 0, x: 1 }; + assert_eq!((s.$x, s.x), (0, 1)); + s + }} +} + +fn main() { + let s = foo::m!(S, x); + assert_eq!(s.x, 0); +} diff --git a/tests/ui/hygiene/fields.stderr b/tests/ui/hygiene/fields.stderr new file mode 100644 index 000000000..978120b1f --- /dev/null +++ b/tests/ui/hygiene/fields.stderr @@ -0,0 +1,46 @@ +error: type `foo::S` is private + --> $DIR/fields.rs:15:17 + | +LL | let s = S { x: 0 }; + | ^^^^^^^^^^ private type +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + | + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: type `foo::S` is private + --> $DIR/fields.rs:16:17 + | +LL | let _ = s.x; + | ^ private type +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + | + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: type `T` is private + --> $DIR/fields.rs:18:17 + | +LL | let t = T(0); + | ^^^^ private type +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + | + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: type `T` is private + --> $DIR/fields.rs:19:17 + | +LL | let _ = t.0; + | ^ private type +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + | + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/hygiene/for-loop.rs b/tests/ui/hygiene/for-loop.rs new file mode 100644 index 000000000..2e5ae43a9 --- /dev/null +++ b/tests/ui/hygiene/for-loop.rs @@ -0,0 +1,8 @@ +// for-loops are expanded in the front end, and use an `iter` ident in their expansion. Check that +// `iter` is not accessible inside the for loop. + +fn main() { + for _ in 0..10 { + iter.next(); //~ ERROR cannot find value `iter` in this scope + } +} diff --git a/tests/ui/hygiene/for-loop.stderr b/tests/ui/hygiene/for-loop.stderr new file mode 100644 index 000000000..932c951e7 --- /dev/null +++ b/tests/ui/hygiene/for-loop.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `iter` in this scope + --> $DIR/for-loop.rs:6:9 + | +LL | iter.next(); + | ^^^^ 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/hygiene/format-args.rs b/tests/ui/hygiene/format-args.rs new file mode 100644 index 000000000..d74889b95 --- /dev/null +++ b/tests/ui/hygiene/format-args.rs @@ -0,0 +1,12 @@ +// check-pass + +#![allow(non_upper_case_globals)] +#![feature(format_args_nl)] + +static arg0: () = (); + +fn main() { + static arg1: () = (); + format_args!("{} {:?}", 0, 1); + format_args_nl!("{} {:?}", 0, 1); +} diff --git a/tests/ui/hygiene/generate-mod.rs b/tests/ui/hygiene/generate-mod.rs new file mode 100644 index 000000000..882629354 --- /dev/null +++ b/tests/ui/hygiene/generate-mod.rs @@ -0,0 +1,49 @@ +// This is an equivalent of issue #50504, but for declarative macros. + +#![feature(decl_macro, rustc_attrs)] + +macro genmod($FromOutside: ident, $Outer: ident) { + type A = $FromOutside; + struct $Outer; + mod inner { + type A = $FromOutside; // `FromOutside` shouldn't be available from here + type Inner = $Outer; // `Outer` shouldn't be available from here + } +} + +#[rustc_macro_transparency = "transparent"] +macro genmod_transparent() { + type A = FromOutside; + struct Outer; + mod inner { + type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope + } +} + +macro_rules! genmod_legacy { () => { + type A = FromOutside; + struct Outer; + mod inner { + type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope + } +}} + +fn check() { + struct FromOutside; + genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `Outer` in this scope +} + +fn check_transparent() { + struct FromOutside; + genmod_transparent!(); +} + +fn check_legacy() { + struct FromOutside; + genmod_legacy!(); +} + +fn main() {} diff --git a/tests/ui/hygiene/generate-mod.stderr b/tests/ui/hygiene/generate-mod.stderr new file mode 100644 index 000000000..32a2e145c --- /dev/null +++ b/tests/ui/hygiene/generate-mod.stderr @@ -0,0 +1,59 @@ +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:35:13 + | +LL | genmod!(FromOutside, Outer); + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:35:26 + | +LL | genmod!(FromOutside, Outer); + | ^^^^^ not found in this scope + +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:19:18 + | +LL | type A = FromOutside; + | ^^^^^^^^^^^ not found in this scope +... +LL | genmod_transparent!(); + | --------------------- in this macro invocation + | + = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:20:22 + | +LL | type Inner = Outer; + | ^^^^^ not found in this scope +... +LL | genmod_transparent!(); + | --------------------- in this macro invocation + | + = note: this error originates in the macro `genmod_transparent` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:28:18 + | +LL | type A = FromOutside; + | ^^^^^^^^^^^ not found in this scope +... +LL | genmod_legacy!(); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `genmod_legacy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:29:22 + | +LL | type Inner = Outer; + | ^^^^^ not found in this scope +... +LL | genmod_legacy!(); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `genmod_legacy` (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 E0412`. diff --git a/tests/ui/hygiene/generic_params.rs b/tests/ui/hygiene/generic_params.rs new file mode 100644 index 000000000..3b6216c3e --- /dev/null +++ b/tests/ui/hygiene/generic_params.rs @@ -0,0 +1,104 @@ +// Ensure that generic parameters always have modern hygiene. + +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro, rustc_attrs)] + +mod type_params { + macro m($T:ident) { + fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) { + (t1.clone(), t2 == t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($T:ident) { + fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn h<T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($T:ident) { + fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn k<T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + m!(T); + n!(T); + p!(T); +} + +mod lifetime_params { + macro m($a:lifetime) { + fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($a:lifetime) { + fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($a:lifetime) { + fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + m!('a); + n!('a); + p!('a); +} + +mod const_params { + macro m($C:ident) { + fn f<const $C: usize, const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($C:ident) { + fn g<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn h<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($C:ident) { + fn j<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn k<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + m!(C); + n!(C); + p!(C); +} + +fn main() {} diff --git a/tests/ui/hygiene/globs.rs b/tests/ui/hygiene/globs.rs new file mode 100644 index 000000000..a3f466ef4 --- /dev/null +++ b/tests/ui/hygiene/globs.rs @@ -0,0 +1,72 @@ +#![feature(decl_macro)] + +mod foo { + pub fn f() {} +} + +mod bar { + pub fn g() {} +} + +macro m($($t:tt)*) { + $($t)* + use foo::*; + f(); + g(); //~ ERROR cannot find function `g` in this scope +} + +fn main() { + m! { + use bar::*; + g(); + f(); //~ ERROR cannot find function `f` in this scope + } +} + +n!(f); +macro n($i:ident) { + mod foo { + pub fn $i() -> u32 { 0 } + pub fn f() {} + + mod test { + use super::*; + fn g() { + let _: u32 = $i(); + let _: () = f(); + } + } + + macro n($j:ident) { + mod test { + use super::*; + fn g() { + let _: u32 = $i(); + let _: () = f(); + $j(); + } + } + } + macro n_with_super($j:ident) { + mod test { + use super::*; + fn g() { + let _: u32 = $i(); + let _: () = f(); + super::$j(); + } + } + } + + n!(f); //~ ERROR cannot find function `f` in this scope + n_with_super!(f); + mod test2 { + super::n! { + f //~ ERROR cannot find function `f` in this scope + } + super::n_with_super! { + f + } + } + } +} diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr new file mode 100644 index 000000000..c01901be5 --- /dev/null +++ b/tests/ui/hygiene/globs.stderr @@ -0,0 +1,73 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:22:9 + | +LL | pub fn g() {} + | ---------- similarly named function `g` defined here +... +LL | f(); + | ^ + | +help: a function with a similar name exists + | +LL | g(); + | ~ +help: consider importing this function + | +LL | use foo::f; + | + +error[E0425]: cannot find function `g` in this scope + --> $DIR/globs.rs:15:5 + | +LL | pub fn f() {} + | ---------- similarly named function `f` defined here +... +LL | g(); + | ^ +... +LL | / m! { +LL | | use bar::*; +LL | | g(); +LL | | f(); +LL | | } + | |_____- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: a function with a similar name exists + | +LL | f(); + | ~ +help: consider importing this function + | +LL | use bar::g; + | + +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:61:12 + | +LL | n!(f); + | ----- in this macro invocation +... +LL | n!(f); + | ^ not found in this scope + | + = help: consider importing this function: + foo::f + = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:65:17 + | +LL | n!(f); + | ----- in this macro invocation +... +LL | f + | ^ not found in this scope + | + = help: consider importing this function: + foo::f + = note: this error originates in the macro `n` (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 E0425`. diff --git a/tests/ui/hygiene/hir-res-hygiene.rs b/tests/ui/hygiene/hir-res-hygiene.rs new file mode 100644 index 000000000..c26cf5fdb --- /dev/null +++ b/tests/ui/hygiene/hir-res-hygiene.rs @@ -0,0 +1,18 @@ +// check-pass +// edition:2018 +// aux-build:not-libstd.rs + +// Check that paths created in HIR are not affected by in scope names. + +extern crate not_libstd as std; + +async fn the_future() { + async {}.await; +} + +fn main() -> Result<(), ()> { + for i in 0..10 {} + for j in 0..=10 {} + Ok(())?; + Ok(()) +} diff --git a/tests/ui/hygiene/hygiene-dodging-1.rs b/tests/ui/hygiene/hygiene-dodging-1.rs new file mode 100644 index 000000000..69e47e82b --- /dev/null +++ b/tests/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/tests/ui/hygiene/hygiene.rs b/tests/ui/hygiene/hygiene.rs new file mode 100644 index 000000000..fb351cf0f --- /dev/null +++ b/tests/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/tests/ui/hygiene/hygienic-label-1.rs b/tests/ui/hygiene/hygienic-label-1.rs new file mode 100644 index 000000000..a06d9255a --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-1.rs @@ -0,0 +1,7 @@ +macro_rules! foo { + () => { break 'x; } //~ ERROR use of undeclared label `'x` +} + +pub fn main() { + 'x: loop { foo!(); } +} diff --git a/tests/ui/hygiene/hygienic-label-1.stderr b/tests/ui/hygiene/hygienic-label-1.stderr new file mode 100644 index 000000000..deb6a2059 --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-1.stderr @@ -0,0 +1,14 @@ +error[E0426]: use of undeclared label `'x` + --> $DIR/hygienic-label-1.rs:2:19 + | +LL | () => { break 'x; } + | ^^ undeclared label `'x` +... +LL | 'x: loop { foo!(); } + | ------ 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 E0426`. diff --git a/tests/ui/hygiene/hygienic-label-2.rs b/tests/ui/hygiene/hygienic-label-2.rs new file mode 100644 index 000000000..43e01a934 --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-2.rs @@ -0,0 +1,7 @@ +macro_rules! foo { + ($e: expr) => { 'x: loop { $e } } +} + +pub fn main() { + foo!(break 'x); //~ ERROR use of undeclared label `'x` +} diff --git a/tests/ui/hygiene/hygienic-label-2.stderr b/tests/ui/hygiene/hygienic-label-2.stderr new file mode 100644 index 000000000..f23e741de --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-2.stderr @@ -0,0 +1,9 @@ +error[E0426]: use of undeclared label `'x` + --> $DIR/hygienic-label-2.rs:6:16 + | +LL | foo!(break 'x); + | ^^ undeclared label `'x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0426`. diff --git a/tests/ui/hygiene/hygienic-label-3.rs b/tests/ui/hygiene/hygienic-label-3.rs new file mode 100644 index 000000000..ab0559e1b --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-3.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + () => { break 'x; } //~ ERROR use of undeclared label `'x` +} + +pub fn main() { + 'x: for _ in 0..1 { + foo!(); + }; +} diff --git a/tests/ui/hygiene/hygienic-label-3.stderr b/tests/ui/hygiene/hygienic-label-3.stderr new file mode 100644 index 000000000..cf7f78a99 --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-3.stderr @@ -0,0 +1,14 @@ +error[E0426]: use of undeclared label `'x` + --> $DIR/hygienic-label-3.rs:2:19 + | +LL | () => { break 'x; } + | ^^ undeclared label `'x` +... +LL | foo!(); + | ------ 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 E0426`. diff --git a/tests/ui/hygiene/hygienic-label-4.rs b/tests/ui/hygiene/hygienic-label-4.rs new file mode 100644 index 000000000..a7e1f0e78 --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-4.rs @@ -0,0 +1,7 @@ +macro_rules! foo { + ($e: expr) => { 'x: for _ in 0..1 { $e } } +} + +pub fn main() { + foo!(break 'x); //~ ERROR use of undeclared label `'x` +} diff --git a/tests/ui/hygiene/hygienic-label-4.stderr b/tests/ui/hygiene/hygienic-label-4.stderr new file mode 100644 index 000000000..1c93da02f --- /dev/null +++ b/tests/ui/hygiene/hygienic-label-4.stderr @@ -0,0 +1,9 @@ +error[E0426]: use of undeclared label `'x` + --> $DIR/hygienic-label-4.rs:6:16 + | +LL | foo!(break 'x); + | ^^ undeclared label `'x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0426`. diff --git a/tests/ui/hygiene/hygienic-labels-in-let.rs b/tests/ui/hygiene/hygienic-labels-in-let.rs new file mode 100644 index 000000000..8cf66f31a --- /dev/null +++ b/tests/ui/hygiene/hygienic-labels-in-let.rs @@ -0,0 +1,82 @@ +// run-pass +#![allow(unreachable_code)] +#![allow(unused_labels)] + +// 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/tests/ui/hygiene/hygienic-labels.rs b/tests/ui/hygiene/hygienic-labels.rs new file mode 100644 index 000000000..6a7d81f04 --- /dev/null +++ b/tests/ui/hygiene/hygienic-labels.rs @@ -0,0 +1,60 @@ +// run-pass +#![allow(unreachable_code)] +#![allow(unused_labels)] +// 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/tests/ui/hygiene/impl_items-2.rs b/tests/ui/hygiene/impl_items-2.rs new file mode 100644 index 000000000..465e444ae --- /dev/null +++ b/tests/ui/hygiene/impl_items-2.rs @@ -0,0 +1,26 @@ +#![feature(decl_macro)] + +trait Trait { + fn foo() {} +} + +macro trait_impl() { + fn foo() {} +} + +// Check that we error on multiple impl items that resolve to the same trait item. +impl Trait for i32 { + trait_impl!(); + fn foo() {} + //~^ ERROR duplicate definitions with name `foo`: [E0201] +} + +struct Type; + +// Check that we do not error with inherent impls. +impl Type { + trait_impl!(); + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/hygiene/impl_items-2.stderr b/tests/ui/hygiene/impl_items-2.stderr new file mode 100644 index 000000000..3c0ffeb10 --- /dev/null +++ b/tests/ui/hygiene/impl_items-2.stderr @@ -0,0 +1,15 @@ +error[E0201]: duplicate definitions with name `foo`: + --> $DIR/impl_items-2.rs:14:5 + | +LL | fn foo() {} + | ----------- item in trait +... +LL | fn foo() {} + | ----------- previous definition here +... +LL | fn foo() {} + | ^^^^^^^^^^^ duplicate definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0201`. diff --git a/tests/ui/hygiene/impl_items.rs b/tests/ui/hygiene/impl_items.rs new file mode 100644 index 000000000..ddb25c06b --- /dev/null +++ b/tests/ui/hygiene/impl_items.rs @@ -0,0 +1,34 @@ +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] + +mod foo { + struct S; + impl S { + fn f(&self) {} + } + + pub macro m() { + let _: () = S.f(); //~ ERROR type `for<'a> fn(&'a foo::S) {foo::S::f}` is private + } +} + +struct S; + +macro m($f:ident) { + impl S { + fn f(&self) -> u32 { 0 } + fn $f(&self) -> i32 { 0 } + } + fn f() { + let _: u32 = S.f(); + let _: i32 = S.$f(); + } +} + +m!(f); + +fn main() { + let _: i32 = S.f(); + foo::m!(); +} diff --git a/tests/ui/hygiene/impl_items.stderr b/tests/ui/hygiene/impl_items.stderr new file mode 100644 index 000000000..46a250038 --- /dev/null +++ b/tests/ui/hygiene/impl_items.stderr @@ -0,0 +1,13 @@ +error: type `for<'a> fn(&'a foo::S) {foo::S::f}` is private + --> $DIR/impl_items.rs:12:23 + | +LL | let _: () = S.f(); + | ^ private type +... +LL | foo::m!(); + | --------- in this macro invocation + | + = note: this error originates in the macro `foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/hygiene/intercrate.rs b/tests/ui/hygiene/intercrate.rs new file mode 100644 index 000000000..d9b5b789e --- /dev/null +++ b/tests/ui/hygiene/intercrate.rs @@ -0,0 +1,12 @@ +// ignore-pretty pretty-printing is unhygienic + +// aux-build:intercrate.rs + +#![feature(decl_macro)] + +extern crate intercrate; + +fn main() { + assert_eq!(intercrate::foo::m!(), 1); + //~^ ERROR type `fn() -> u32 {foo::bar::f}` is private +} diff --git a/tests/ui/hygiene/intercrate.stderr b/tests/ui/hygiene/intercrate.stderr new file mode 100644 index 000000000..91358b279 --- /dev/null +++ b/tests/ui/hygiene/intercrate.stderr @@ -0,0 +1,10 @@ +error: type `fn() -> u32 {foo::bar::f}` is private + --> $DIR/intercrate.rs:10:16 + | +LL | assert_eq!(intercrate::foo::m!(), 1); + | ^^^^^^^^^^^^^^^^^^^^^ private type + | + = note: this error originates in the macro `intercrate::foo::m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/hygiene/issue-15221.rs b/tests/ui/hygiene/issue-15221.rs new file mode 100644 index 000000000..4b8319a83 --- /dev/null +++ b/tests/ui/hygiene/issue-15221.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(path_statements)] +// pretty-expanded FIXME #23616 + +macro_rules! inner { + ($e:pat ) => ($e) +} + +macro_rules! outer { + ($e:pat ) => (inner!($e)) +} + +fn main() { + let outer!(g1) = 13; + g1; +} diff --git a/tests/ui/hygiene/issue-32922.rs b/tests/ui/hygiene/issue-32922.rs new file mode 100644 index 000000000..54ec44a1c --- /dev/null +++ b/tests/ui/hygiene/issue-32922.rs @@ -0,0 +1,29 @@ +// check-pass + +macro_rules! foo { () => { + let x = 1; + macro_rules! bar { () => {x} } + let _ = bar!(); +}} + +macro_rules! m { // test issue #31856 + ($n:ident) => ( + let a = 1; + let $n = a; + ) +} + +macro_rules! baz { + ($i:ident) => { + let mut $i = 2; + $i = $i + 1; + } +} + +fn main() { + foo! {}; + bar! {}; + + let mut a = true; + baz!(a); +} diff --git a/tests/ui/hygiene/issue-40847.rs b/tests/ui/hygiene/issue-40847.rs new file mode 100644 index 000000000..087b40ad6 --- /dev/null +++ b/tests/ui/hygiene/issue-40847.rs @@ -0,0 +1,17 @@ +// run-pass +macro_rules! gen { + ($name:ident ( $($dol:tt $var:ident)* ) $($body:tt)*) => { + macro_rules! $name { + ($($dol $var:ident)*) => { + $($body)* + } + } + } +} + +gen!(m($var) $var); + +fn main() { + let x = 1; + assert_eq!(m!(x), 1); +} diff --git a/tests/ui/hygiene/issue-44128.rs b/tests/ui/hygiene/issue-44128.rs new file mode 100644 index 000000000..5e03bdb8c --- /dev/null +++ b/tests/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/tests/ui/hygiene/issue-47311.rs b/tests/ui/hygiene/issue-47311.rs new file mode 100644 index 000000000..5c2379a8a --- /dev/null +++ b/tests/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/tests/ui/hygiene/issue-47312.rs b/tests/ui/hygiene/issue-47312.rs new file mode 100644 index 000000000..bbcb3a7f3 --- /dev/null +++ b/tests/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/tests/ui/hygiene/issue-61574-const-parameters.rs b/tests/ui/hygiene/issue-61574-const-parameters.rs new file mode 100644 index 000000000..3634ee004 --- /dev/null +++ b/tests/ui/hygiene/issue-61574-const-parameters.rs @@ -0,0 +1,30 @@ +// A more comprehensive test that const parameters have correctly implemented +// hygiene + +// check-pass + +use std::ops::Add; + +struct VectorLike<T, const SIZE: usize>([T; {SIZE}]); + +macro_rules! impl_operator_overload { + ($trait_ident:ident, $method_ident:ident) => { + + impl<T, const SIZE: usize> $trait_ident for VectorLike<T, {SIZE}> + where + T: $trait_ident, + { + type Output = VectorLike<T, {SIZE}>; + + fn $method_ident(self, _: VectorLike<T, {SIZE}>) -> VectorLike<T, {SIZE}> { + let _ = SIZE; + unimplemented!() + } + } + + } +} + +impl_operator_overload!(Add, add); + +fn main() {} diff --git a/tests/ui/hygiene/issue-77523-def-site-async-await.rs b/tests/ui/hygiene/issue-77523-def-site-async-await.rs new file mode 100644 index 000000000..2af60ff6f --- /dev/null +++ b/tests/ui/hygiene/issue-77523-def-site-async-await.rs @@ -0,0 +1,19 @@ +// build-pass +// aux-build:opaque-hygiene.rs +// aux-build:def-site-async-await.rs + +// Regression test for issue #77523 +// Tests that we don't ICE when an unusual combination +// of def-site hygiene and cross-crate monomorphization occurs. + +extern crate def_site_async_await; + +use std::future::Future; + +fn mk_ctxt() -> std::task::Context<'static> { + panic!() +} + +fn main() { + Box::pin(def_site_async_await::serve()).as_mut().poll(&mut mk_ctxt()); +} diff --git a/tests/ui/hygiene/items.rs b/tests/ui/hygiene/items.rs new file mode 100644 index 000000000..1c625a972 --- /dev/null +++ b/tests/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/tests/ui/hygiene/lambda-var-hygiene.rs b/tests/ui/hygiene/lambda-var-hygiene.rs new file mode 100644 index 000000000..bf06765e5 --- /dev/null +++ b/tests/ui/hygiene/lambda-var-hygiene.rs @@ -0,0 +1,12 @@ +// run-pass +// shouldn't affect evaluation of $ex: +macro_rules! bad_macro { + ($ex:expr) => ({(|_x| { $ex }) (9) }) +} + +fn takes_x(_x : isize) { + assert_eq!(bad_macro!(_x),8); +} +fn main() { + takes_x(8); +} diff --git a/tests/ui/hygiene/legacy_interaction.rs b/tests/ui/hygiene/legacy_interaction.rs new file mode 100644 index 000000000..52008eed5 --- /dev/null +++ b/tests/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/tests/ui/hygiene/lexical.rs b/tests/ui/hygiene/lexical.rs new file mode 100644 index 000000000..3d25c7209 --- /dev/null +++ b/tests/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/tests/ui/hygiene/local_inner_macros.rs b/tests/ui/hygiene/local_inner_macros.rs new file mode 100644 index 000000000..71ffcac40 --- /dev/null +++ b/tests/ui/hygiene/local_inner_macros.rs @@ -0,0 +1,19 @@ +// check-pass +// aux-build:local_inner_macros.rs + +extern crate local_inner_macros; + +use local_inner_macros::{public_macro, public_macro_dynamic}; + +public_macro!(); + +macro_rules! local_helper { + () => ( struct Z; ) +} + +public_macro_dynamic!(local_helper); + +fn main() { + let s = S; + let z = Z; +} diff --git a/tests/ui/hygiene/macro-metavars-legacy.rs b/tests/ui/hygiene/macro-metavars-legacy.rs new file mode 100644 index 000000000..09070f0f5 --- /dev/null +++ b/tests/ui/hygiene/macro-metavars-legacy.rs @@ -0,0 +1,29 @@ +// Ensure macro metavariables are compared with legacy hygiene + +#![feature(rustc_attrs)] + +// run-pass + +macro_rules! make_mac { + ( $($dollar:tt $arg:ident),+ ) => { + macro_rules! mac { + ( $($dollar $arg : ident),+ ) => { + $( $dollar $arg )-+ + } + } + } +} + +macro_rules! show_hygiene { + ( $dollar:tt $arg:ident ) => { + make_mac!($dollar $arg, $dollar arg); + } +} + +show_hygiene!( $arg ); + +fn main() { + let x = 5; + let y = 3; + assert_eq!(2, mac!(x, y)); +} diff --git a/tests/ui/hygiene/macro-metavars-transparent.rs b/tests/ui/hygiene/macro-metavars-transparent.rs new file mode 100644 index 000000000..e475b5728 --- /dev/null +++ b/tests/ui/hygiene/macro-metavars-transparent.rs @@ -0,0 +1,24 @@ +// Ensure macro metavariables are not compared without removing transparent +// marks. + +#![feature(rustc_attrs)] + +// run-pass + +#[rustc_macro_transparency = "transparent"] +macro_rules! k { + ($($s:tt)*) => { + macro_rules! m { + ($y:tt) => { + $($s)* + } + } + } +} + +k!(1 + $y); + +fn main() { + let x = 2; + assert_eq!(3, m!(x)); +} diff --git a/tests/ui/hygiene/missing-self-diag.rs b/tests/ui/hygiene/missing-self-diag.rs new file mode 100644 index 000000000..f934f793c --- /dev/null +++ b/tests/ui/hygiene/missing-self-diag.rs @@ -0,0 +1,23 @@ +// Regression test for issue #66898 +// Tests that we don't emit a nonsensical error message +// when a macro invocation tries to access `self` from a function +// that has a 'self' parameter + +pub struct Foo; + +macro_rules! call_bar { + () => { + self.bar(); //~ ERROR expected value + } +} + +impl Foo { + pub fn foo(&self) { + call_bar!(); + } + + pub fn bar(&self) { + } +} + +fn main() {} diff --git a/tests/ui/hygiene/missing-self-diag.stderr b/tests/ui/hygiene/missing-self-diag.stderr new file mode 100644 index 000000000..690bcd032 --- /dev/null +++ b/tests/ui/hygiene/missing-self-diag.stderr @@ -0,0 +1,17 @@ +error[E0424]: expected value, found module `self` + --> $DIR/missing-self-diag.rs:10:9 + | +LL | self.bar(); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / pub fn foo(&self) { +LL | | call_bar!(); + | | ----------- in this macro invocation +LL | | } + | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in the macro `call_bar` (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 E0424`. diff --git a/tests/ui/hygiene/nested-dollar-crate.rs b/tests/ui/hygiene/nested-dollar-crate.rs new file mode 100644 index 000000000..e8703bc77 --- /dev/null +++ b/tests/ui/hygiene/nested-dollar-crate.rs @@ -0,0 +1,9 @@ +// aux-build:nested-dollar-crate.rs +// edition:2018 +// run-pass + +extern crate nested_dollar_crate; + +fn main() { + assert_eq!(nested_dollar_crate::inner!(), "In def crate!"); +} diff --git a/tests/ui/hygiene/nested_macro_privacy.rs b/tests/ui/hygiene/nested_macro_privacy.rs new file mode 100644 index 000000000..dea9101ee --- /dev/null +++ b/tests/ui/hygiene/nested_macro_privacy.rs @@ -0,0 +1,17 @@ +#![feature(decl_macro)] + +macro n($foo:ident, $S:ident, $i:ident, $m:ident) { + mod $foo { + #[derive(Default)] + pub struct $S { $i: u32 } + pub macro $m($e:expr) { $e.$i } + } +} + +n!(foo, S, i, m); + +fn main() { + use foo::{S, m}; + S::default().i; //~ ERROR field `i` of struct `S` is private + m!(S::default()); // ok +} diff --git a/tests/ui/hygiene/nested_macro_privacy.stderr b/tests/ui/hygiene/nested_macro_privacy.stderr new file mode 100644 index 000000000..1d11cd0f5 --- /dev/null +++ b/tests/ui/hygiene/nested_macro_privacy.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `i` of struct `S` is private + --> $DIR/nested_macro_privacy.rs:15:18 + | +LL | S::default().i; + | ^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/tests/ui/hygiene/no_implicit_prelude-2018.rs b/tests/ui/hygiene/no_implicit_prelude-2018.rs new file mode 100644 index 000000000..83ca28167 --- /dev/null +++ b/tests/ui/hygiene/no_implicit_prelude-2018.rs @@ -0,0 +1,11 @@ +// edition:2018 + +#[no_implicit_prelude] +mod bar { + fn f() { + ::std::print!(""); // OK + print!(); //~ ERROR cannot find macro `print` in this scope + } +} + +fn main() {} diff --git a/tests/ui/hygiene/no_implicit_prelude-2018.stderr b/tests/ui/hygiene/no_implicit_prelude-2018.stderr new file mode 100644 index 000000000..3f31b041b --- /dev/null +++ b/tests/ui/hygiene/no_implicit_prelude-2018.stderr @@ -0,0 +1,11 @@ +error: cannot find macro `print` in this scope + --> $DIR/no_implicit_prelude-2018.rs:7:9 + | +LL | print!(); + | ^^^^^ + | + = help: consider importing this macro: + std::print + +error: aborting due to previous error + diff --git a/tests/ui/hygiene/no_implicit_prelude-2021.rs b/tests/ui/hygiene/no_implicit_prelude-2021.rs new file mode 100644 index 000000000..0fe9ae56c --- /dev/null +++ b/tests/ui/hygiene/no_implicit_prelude-2021.rs @@ -0,0 +1,9 @@ +// check-pass +// edition:2021 + +#![no_implicit_prelude] + +fn main() { + assert!(true, "hoi"); + assert!(false, "hoi {}", 123); +} diff --git a/tests/ui/hygiene/no_implicit_prelude.rs b/tests/ui/hygiene/no_implicit_prelude.rs new file mode 100644 index 000000000..e23826e9d --- /dev/null +++ b/tests/ui/hygiene/no_implicit_prelude.rs @@ -0,0 +1,20 @@ +#![feature(decl_macro)] + +mod foo { + pub macro m() { Vec::<i32>::new(); ().clone() } + fn f() { ::bar::m!(); } +} + +#[no_implicit_prelude] +mod bar { + pub macro m() { + Vec::new(); //~ ERROR failed to resolve + ().clone() //~ ERROR no method named `clone` found + } + fn f() { + ::foo::m!(); + assert!(true); + } +} + +fn main() {} diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr new file mode 100644 index 000000000..c48c84035 --- /dev/null +++ b/tests/ui/hygiene/no_implicit_prelude.stderr @@ -0,0 +1,35 @@ +error[E0433]: failed to resolve: use of undeclared type `Vec` + --> $DIR/no_implicit_prelude.rs:11:9 + | +LL | fn f() { ::bar::m!(); } + | ----------- in this macro invocation +... +LL | Vec::new(); + | ^^^ use of undeclared type `Vec` + | + = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider importing this struct + | +LL | use std::vec::Vec; + | + +error[E0599]: no method named `clone` found for unit type `()` in the current scope + --> $DIR/no_implicit_prelude.rs:12:12 + | +LL | fn f() { ::bar::m!(); } + | ----------- in this macro invocation +... +LL | ().clone() + | ^^^^^ method not found in `()` + | + = help: items from traits can only be used if the trait is in scope + = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::clone::Clone; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0433, E0599. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/hygiene/panic-location.rs b/tests/ui/hygiene/panic-location.rs new file mode 100644 index 000000000..5cf169dfb --- /dev/null +++ b/tests/ui/hygiene/panic-location.rs @@ -0,0 +1,10 @@ +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=0 +// +// Regression test for issue #70963 +// The captured stderr from this test reports a location +// inside `VecDeque::with_capacity`, instead of `<::core::macros::panic macros>` +fn main() { + std::collections::VecDeque::<String>::with_capacity(!0); +} diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr new file mode 100644 index 000000000..0b23b1cc2 --- /dev/null +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:518:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/hygiene/pattern-macro.rs b/tests/ui/hygiene/pattern-macro.rs new file mode 100644 index 000000000..e5d6a3aa1 --- /dev/null +++ b/tests/ui/hygiene/pattern-macro.rs @@ -0,0 +1,6 @@ +macro_rules! foo { () => ( x ) } + +fn main() { + let foo!() = 2; + x + 1; //~ ERROR cannot find value `x` in this scope +} diff --git a/tests/ui/hygiene/pattern-macro.stderr b/tests/ui/hygiene/pattern-macro.stderr new file mode 100644 index 000000000..edd05916e --- /dev/null +++ b/tests/ui/hygiene/pattern-macro.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/pattern-macro.rs:5:5 + | +LL | x + 1; + | ^ 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/hygiene/prelude-import-hygiene.rs b/tests/ui/hygiene/prelude-import-hygiene.rs new file mode 100644 index 000000000..51e7bed65 --- /dev/null +++ b/tests/ui/hygiene/prelude-import-hygiene.rs @@ -0,0 +1,29 @@ +// Make sure that attribute used when injecting the prelude are resolved +// hygienically. + +// check-pass +// aux-build:not-libstd.rs + +//revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +// The prelude import shouldn't see these as candidates for when it's trying to +// use the built-in macros. +extern crate core; +use core::prelude::v1::test as prelude_import; +use core::prelude::v1::test as macro_use; + +// Should not be used for the prelude import - not a concern in the 2015 edition +// because `std` is already declared in the crate root. +#[cfg(rust2018)] +extern crate not_libstd as std; + +#[cfg(rust2018)] +mod x { + // The extern crate item should override `std` in the extern prelude. + fn f() { + std::not_in_lib_std(); + } +} + +fn main() {} diff --git a/tests/ui/hygiene/privacy-early.rs b/tests/ui/hygiene/privacy-early.rs new file mode 100644 index 000000000..58fc74d65 --- /dev/null +++ b/tests/ui/hygiene/privacy-early.rs @@ -0,0 +1,17 @@ +// edition:2018 + +#![feature(decl_macro)] + +mod foo { + fn f() {} + macro f() {} + + pub macro m() { + use f as g; //~ ERROR `f` is private, and cannot be re-exported + f!(); + } +} + +fn main() { + foo::m!(); +} diff --git a/tests/ui/hygiene/privacy-early.stderr b/tests/ui/hygiene/privacy-early.stderr new file mode 100644 index 000000000..0375ed56d --- /dev/null +++ b/tests/ui/hygiene/privacy-early.stderr @@ -0,0 +1,22 @@ +error[E0364]: `f` is private, and cannot be re-exported + --> $DIR/privacy-early.rs:10:13 + | +LL | use f as g; + | ^^^^^^ +... +LL | foo::m!(); + | --------- in this macro invocation + | +note: consider marking `f` as `pub` in the imported module + --> $DIR/privacy-early.rs:10:13 + | +LL | use f as g; + | ^^^^^^ +... +LL | foo::m!(); + | --------- in this macro invocation + = note: this error originates in the macro `foo::m` (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 E0364`. diff --git a/tests/ui/hygiene/privacy.rs b/tests/ui/hygiene/privacy.rs new file mode 100644 index 000000000..78d255553 --- /dev/null +++ b/tests/ui/hygiene/privacy.rs @@ -0,0 +1,18 @@ +#![feature(decl_macro)] + +mod foo { + fn f() {} + + pub macro m($e:expr) { + f(); + self::f(); + ::foo::f(); + $e + } +} + +fn main() { + foo::m!( + foo::f() //~ ERROR `f` is private + ); +} diff --git a/tests/ui/hygiene/privacy.stderr b/tests/ui/hygiene/privacy.stderr new file mode 100644 index 000000000..70a24304d --- /dev/null +++ b/tests/ui/hygiene/privacy.stderr @@ -0,0 +1,15 @@ +error[E0603]: function `f` is private + --> $DIR/privacy.rs:16:14 + | +LL | foo::f() + | ^ private function + | +note: the function `f` is defined here + --> $DIR/privacy.rs:4:5 + | +LL | fn f() {} + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs new file mode 100644 index 000000000..5f36993af --- /dev/null +++ b/tests/ui/hygiene/rustc-macro-transparency.rs @@ -0,0 +1,31 @@ +#![feature(decl_macro, rustc_attrs)] + +#[rustc_macro_transparency = "transparent"] +macro transparent() { + struct Transparent; + let transparent = 0; +} +#[rustc_macro_transparency = "semitransparent"] +macro semitransparent() { + struct SemiTransparent; + let semitransparent = 0; +} +#[rustc_macro_transparency = "opaque"] +macro opaque() { + struct Opaque; + let opaque = 0; +} + +fn main() { + transparent!(); + semitransparent!(); + opaque!(); + + Transparent; // OK + SemiTransparent; // OK + Opaque; //~ ERROR cannot find value `Opaque` in this scope + + transparent; // OK + semitransparent; //~ ERROR expected value, found macro `semitransparent` + opaque; //~ ERROR expected value, found macro `opaque` +} diff --git a/tests/ui/hygiene/rustc-macro-transparency.stderr b/tests/ui/hygiene/rustc-macro-transparency.stderr new file mode 100644 index 000000000..1d2a1e124 --- /dev/null +++ b/tests/ui/hygiene/rustc-macro-transparency.stderr @@ -0,0 +1,28 @@ +error[E0425]: cannot find value `Opaque` in this scope + --> $DIR/rustc-macro-transparency.rs:26:5 + | +LL | Opaque; + | ^^^^^^ not found in this scope + +error[E0423]: expected value, found macro `semitransparent` + --> $DIR/rustc-macro-transparency.rs:29:5 + | +LL | struct SemiTransparent; + | ----------------------- similarly named unit struct `SemiTransparent` defined here +... +LL | semitransparent; + | ^^^^^^^^^^^^^^^ + | | + | not a value + | help: a unit struct with a similar name exists: `SemiTransparent` + +error[E0423]: expected value, found macro `opaque` + --> $DIR/rustc-macro-transparency.rs:30:5 + | +LL | opaque; + | ^^^^^^ not a value + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0423, E0425. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/hygiene/specialization.rs b/tests/ui/hygiene/specialization.rs new file mode 100644 index 000000000..656aa880a --- /dev/null +++ b/tests/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/tests/ui/hygiene/stdlib-prelude-from-opaque-early.rs b/tests/ui/hygiene/stdlib-prelude-from-opaque-early.rs new file mode 100644 index 000000000..c8c5c72bf --- /dev/null +++ b/tests/ui/hygiene/stdlib-prelude-from-opaque-early.rs @@ -0,0 +1,21 @@ +// check-pass +// aux-build:stdlib-prelude.rs + +#![feature(decl_macro)] +#![feature(prelude_import)] + +extern crate stdlib_prelude; + +#[prelude_import] +use stdlib_prelude::*; + +macro mac() { + mod m { + use std::mem; // OK (extern prelude) + stdlib_macro!(); // OK (stdlib prelude) + } +} + +mac!(); + +fn main() {} diff --git a/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs new file mode 100644 index 000000000..cf65de2bc --- /dev/null +++ b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(decl_macro)] + +macro mac() { + mod m { + fn f() { + std::mem::drop(0); // OK (extern prelude) + drop(0); // OK (stdlib prelude) + } + } +} + +mac!(); + +fn main() {} diff --git a/tests/ui/hygiene/thread-local-not-in-prelude.rs b/tests/ui/hygiene/thread-local-not-in-prelude.rs new file mode 100644 index 000000000..e5ed09c60 --- /dev/null +++ b/tests/ui/hygiene/thread-local-not-in-prelude.rs @@ -0,0 +1,9 @@ +// run-pass +#![no_std] + +extern crate std; + +std::thread_local!(static A: usize = 30); + +fn main() { +} diff --git a/tests/ui/hygiene/trait_items-2.rs b/tests/ui/hygiene/trait_items-2.rs new file mode 100644 index 000000000..39edfc37d --- /dev/null +++ b/tests/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/tests/ui/hygiene/trait_items.rs b/tests/ui/hygiene/trait_items.rs new file mode 100644 index 000000000..15c4acbc9 --- /dev/null +++ b/tests/ui/hygiene/trait_items.rs @@ -0,0 +1,21 @@ +#![feature(decl_macro)] + +mod foo { + pub trait T { + fn f(&self) {} + } + impl T for () {} +} + +mod bar { + use foo::*; + pub macro m() { ().f() } + fn f() { ::baz::m!(); } +} + +mod baz { + pub macro m() { ().f() } //~ ERROR no method named `f` found + fn f() { ::bar::m!(); } +} + +fn main() {} diff --git a/tests/ui/hygiene/trait_items.stderr b/tests/ui/hygiene/trait_items.stderr new file mode 100644 index 000000000..80bdbe0e2 --- /dev/null +++ b/tests/ui/hygiene/trait_items.stderr @@ -0,0 +1,22 @@ +error[E0599]: no method named `f` found for unit type `()` in the current scope + --> $DIR/trait_items.rs:17:24 + | +LL | fn f(&self) {} + | - the method is available for `()` here +... +LL | fn f() { ::baz::m!(); } + | ----------- in this macro invocation +... +LL | pub macro m() { ().f() } + | ^ method not found in `()` + | + = help: items from traits can only be used if the trait is in scope + = note: this error originates in the macro `::baz::m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use foo::T; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/hygiene/traits-in-scope.rs b/tests/ui/hygiene/traits-in-scope.rs new file mode 100644 index 000000000..548bb226b --- /dev/null +++ b/tests/ui/hygiene/traits-in-scope.rs @@ -0,0 +1,53 @@ +// Macros with def-site hygiene still bring traits into scope. +// It is not clear whether this is desirable behavior or not. +// It is also not clear how to prevent it if it is not desirable. + +// check-pass + +#![feature(decl_macro)] +#![feature(trait_alias)] + +mod traits { + pub trait Trait1 { + fn simple_import(&self) {} + } + pub trait Trait2 { + fn renamed_import(&self) {} + } + pub trait Trait3 { + fn underscore_import(&self) {} + } + pub trait Trait4 { + fn trait_alias(&self) {} + } + + impl Trait1 for () {} + impl Trait2 for () {} + impl Trait3 for () {} + impl Trait4 for () {} +} + +macro m1() { + use traits::Trait1; +} +macro m2() { + use traits::Trait2 as Alias; +} +macro m3() { + use traits::Trait3 as _; +} +macro m4() { + trait Alias = traits::Trait4; +} + +fn main() { + m1!(); + m2!(); + m3!(); + m4!(); + + ().simple_import(); + ().renamed_import(); + ().underscore_import(); + ().trait_alias(); +} diff --git a/tests/ui/hygiene/transparent-basic.rs b/tests/ui/hygiene/transparent-basic.rs new file mode 100644 index 000000000..bfa1713e4 --- /dev/null +++ b/tests/ui/hygiene/transparent-basic.rs @@ -0,0 +1,43 @@ +// check-pass +// aux-build:transparent-basic.rs + +#![feature(decl_macro, rustc_attrs)] + +extern crate transparent_basic; + +#[rustc_macro_transparency = "transparent"] +macro binding() { + let x = 10; +} + +#[rustc_macro_transparency = "transparent"] +macro label() { + break 'label +} + +macro_rules! legacy { + () => { + binding!(); + let y = x; + } +} + +fn legacy_interaction1() { + legacy!(); +} + +struct S; + +fn check_dollar_crate() { + // `$crate::S` inside the macro resolves to `S` from this crate. + transparent_basic::dollar_crate!(); +} + +fn main() { + binding!(); + let y = x; + + 'label: loop { + label!(); + } +} diff --git a/tests/ui/hygiene/unpretty-debug.rs b/tests/ui/hygiene/unpretty-debug.rs new file mode 100644 index 000000000..6e936bb3d --- /dev/null +++ b/tests/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/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout new file mode 100644 index 000000000..51c21043d --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug.stdout @@ -0,0 +1,28 @@ +// 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 */() {} + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent) +*/ diff --git a/tests/ui/hygiene/wrap_unhygienic_example.rs b/tests/ui/hygiene/wrap_unhygienic_example.rs new file mode 100644 index 000000000..50c6b35ab --- /dev/null +++ b/tests/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/tests/ui/hygiene/xcrate.rs b/tests/ui/hygiene/xcrate.rs new file mode 100644 index 000000000..6981ce3f6 --- /dev/null +++ b/tests/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!(); +} |