diff options
Diffstat (limited to 'tests/ui/hygiene/auxiliary')
19 files changed, 488 insertions, 0 deletions
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() {} +} |