summaryrefslogtreecommitdiffstats
path: root/tests/ui/hygiene
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/hygiene')
-rw-r--r--tests/ui/hygiene/arguments.rs17
-rw-r--r--tests/ui/hygiene/arguments.stderr9
-rw-r--r--tests/ui/hygiene/assoc_item_ctxt.rs42
-rw-r--r--tests/ui/hygiene/assoc_item_ctxt.stderr32
-rw-r--r--tests/ui/hygiene/assoc_ty_bindings.rs38
-rw-r--r--tests/ui/hygiene/auxiliary/codegen-attrs.rs10
-rw-r--r--tests/ui/hygiene/auxiliary/def-site-async-await.rs7
-rw-r--r--tests/ui/hygiene/auxiliary/fields.rs73
-rw-r--r--tests/ui/hygiene/auxiliary/intercrate.rs46
-rw-r--r--tests/ui/hygiene/auxiliary/legacy_interaction.rs9
-rw-r--r--tests/ui/hygiene/auxiliary/local_inner_macros.rs19
-rw-r--r--tests/ui/hygiene/auxiliary/methods.rs160
-rw-r--r--tests/ui/hygiene/auxiliary/my_crate.rs1
-rw-r--r--tests/ui/hygiene/auxiliary/needs_hygiene.rs5
-rw-r--r--tests/ui/hygiene/auxiliary/nested-dollar-crate.rs14
-rw-r--r--tests/ui/hygiene/auxiliary/not-libstd.rs1
-rw-r--r--tests/ui/hygiene/auxiliary/opaque-hygiene.rs21
-rw-r--r--tests/ui/hygiene/auxiliary/pub_hygiene.rs7
-rw-r--r--tests/ui/hygiene/auxiliary/stdlib-prelude.rs3
-rw-r--r--tests/ui/hygiene/auxiliary/transparent-basic.rs6
-rw-r--r--tests/ui/hygiene/auxiliary/unhygienic_example.rs27
-rw-r--r--tests/ui/hygiene/auxiliary/use_by_macro.rs15
-rw-r--r--tests/ui/hygiene/auxiliary/variants.rs36
-rw-r--r--tests/ui/hygiene/auxiliary/xcrate.rs28
-rw-r--r--tests/ui/hygiene/cross-crate-codegen-attrs.rs12
-rw-r--r--tests/ui/hygiene/cross-crate-define-and-use.rs19
-rw-r--r--tests/ui/hygiene/cross-crate-fields.rs24
-rw-r--r--tests/ui/hygiene/cross-crate-glob-hygiene.rs23
-rw-r--r--tests/ui/hygiene/cross-crate-glob-hygiene.stderr11
-rw-r--r--tests/ui/hygiene/cross-crate-methods.rs33
-rw-r--r--tests/ui/hygiene/cross-crate-name-collision.rs12
-rw-r--r--tests/ui/hygiene/cross-crate-name-hiding-2.rs15
-rw-r--r--tests/ui/hygiene/cross-crate-name-hiding-2.stderr9
-rw-r--r--tests/ui/hygiene/cross-crate-name-hiding.rs13
-rw-r--r--tests/ui/hygiene/cross-crate-name-hiding.stderr9
-rw-r--r--tests/ui/hygiene/cross-crate-redefine.rs14
-rw-r--r--tests/ui/hygiene/cross-crate-redefine.stderr15
-rw-r--r--tests/ui/hygiene/cross-crate-variants.rs18
-rw-r--r--tests/ui/hygiene/dollar-crate-modern.rs25
-rw-r--r--tests/ui/hygiene/duplicate_lifetimes.rs19
-rw-r--r--tests/ui/hygiene/duplicate_lifetimes.stderr31
-rw-r--r--tests/ui/hygiene/eager-from-opaque-2.rs22
-rw-r--r--tests/ui/hygiene/eager-from-opaque.rs20
-rw-r--r--tests/ui/hygiene/expansion-info-reset.rs4
-rw-r--r--tests/ui/hygiene/expansion-info-reset.stderr13
-rw-r--r--tests/ui/hygiene/extern-prelude-from-opaque-fail.rs28
-rw-r--r--tests/ui/hygiene/extern-prelude-from-opaque-fail.stderr38
-rw-r--r--tests/ui/hygiene/fields-definition.rs22
-rw-r--r--tests/ui/hygiene/fields-definition.stderr16
-rw-r--r--tests/ui/hygiene/fields-move.rs30
-rw-r--r--tests/ui/hygiene/fields-move.stderr39
-rw-r--r--tests/ui/hygiene/fields-numeric-borrowck.rs13
-rw-r--r--tests/ui/hygiene/fields-numeric-borrowck.stderr14
-rw-r--r--tests/ui/hygiene/fields.rs30
-rw-r--r--tests/ui/hygiene/fields.stderr46
-rw-r--r--tests/ui/hygiene/for-loop.rs8
-rw-r--r--tests/ui/hygiene/for-loop.stderr9
-rw-r--r--tests/ui/hygiene/format-args.rs12
-rw-r--r--tests/ui/hygiene/generate-mod.rs49
-rw-r--r--tests/ui/hygiene/generate-mod.stderr59
-rw-r--r--tests/ui/hygiene/generic_params.rs104
-rw-r--r--tests/ui/hygiene/globs.rs72
-rw-r--r--tests/ui/hygiene/globs.stderr73
-rw-r--r--tests/ui/hygiene/hir-res-hygiene.rs18
-rw-r--r--tests/ui/hygiene/hygiene-dodging-1.rs14
-rw-r--r--tests/ui/hygiene/hygiene.rs114
-rw-r--r--tests/ui/hygiene/hygienic-label-1.rs7
-rw-r--r--tests/ui/hygiene/hygienic-label-1.stderr14
-rw-r--r--tests/ui/hygiene/hygienic-label-2.rs7
-rw-r--r--tests/ui/hygiene/hygienic-label-2.stderr9
-rw-r--r--tests/ui/hygiene/hygienic-label-3.rs9
-rw-r--r--tests/ui/hygiene/hygienic-label-3.stderr14
-rw-r--r--tests/ui/hygiene/hygienic-label-4.rs7
-rw-r--r--tests/ui/hygiene/hygienic-label-4.stderr9
-rw-r--r--tests/ui/hygiene/hygienic-labels-in-let.rs82
-rw-r--r--tests/ui/hygiene/hygienic-labels.rs60
-rw-r--r--tests/ui/hygiene/impl_items-2.rs26
-rw-r--r--tests/ui/hygiene/impl_items-2.stderr15
-rw-r--r--tests/ui/hygiene/impl_items.rs34
-rw-r--r--tests/ui/hygiene/impl_items.stderr13
-rw-r--r--tests/ui/hygiene/intercrate.rs12
-rw-r--r--tests/ui/hygiene/intercrate.stderr10
-rw-r--r--tests/ui/hygiene/issue-15221.rs16
-rw-r--r--tests/ui/hygiene/issue-32922.rs29
-rw-r--r--tests/ui/hygiene/issue-40847.rs17
-rw-r--r--tests/ui/hygiene/issue-44128.rs17
-rw-r--r--tests/ui/hygiene/issue-47311.rs17
-rw-r--r--tests/ui/hygiene/issue-47312.rs21
-rw-r--r--tests/ui/hygiene/issue-61574-const-parameters.rs30
-rw-r--r--tests/ui/hygiene/issue-77523-def-site-async-await.rs19
-rw-r--r--tests/ui/hygiene/items.rs27
-rw-r--r--tests/ui/hygiene/lambda-var-hygiene.rs12
-rw-r--r--tests/ui/hygiene/legacy_interaction.rs42
-rw-r--r--tests/ui/hygiene/lexical.rs24
-rw-r--r--tests/ui/hygiene/local_inner_macros.rs19
-rw-r--r--tests/ui/hygiene/macro-metavars-legacy.rs29
-rw-r--r--tests/ui/hygiene/macro-metavars-transparent.rs24
-rw-r--r--tests/ui/hygiene/missing-self-diag.rs23
-rw-r--r--tests/ui/hygiene/missing-self-diag.stderr17
-rw-r--r--tests/ui/hygiene/nested-dollar-crate.rs9
-rw-r--r--tests/ui/hygiene/nested_macro_privacy.rs17
-rw-r--r--tests/ui/hygiene/nested_macro_privacy.stderr9
-rw-r--r--tests/ui/hygiene/no_implicit_prelude-2018.rs11
-rw-r--r--tests/ui/hygiene/no_implicit_prelude-2018.stderr11
-rw-r--r--tests/ui/hygiene/no_implicit_prelude-2021.rs9
-rw-r--r--tests/ui/hygiene/no_implicit_prelude.rs20
-rw-r--r--tests/ui/hygiene/no_implicit_prelude.stderr35
-rw-r--r--tests/ui/hygiene/panic-location.rs10
-rw-r--r--tests/ui/hygiene/panic-location.run.stderr2
-rw-r--r--tests/ui/hygiene/pattern-macro.rs6
-rw-r--r--tests/ui/hygiene/pattern-macro.stderr9
-rw-r--r--tests/ui/hygiene/prelude-import-hygiene.rs29
-rw-r--r--tests/ui/hygiene/privacy-early.rs17
-rw-r--r--tests/ui/hygiene/privacy-early.stderr22
-rw-r--r--tests/ui/hygiene/privacy.rs18
-rw-r--r--tests/ui/hygiene/privacy.stderr15
-rw-r--r--tests/ui/hygiene/rustc-macro-transparency.rs31
-rw-r--r--tests/ui/hygiene/rustc-macro-transparency.stderr28
-rw-r--r--tests/ui/hygiene/specialization.rs25
-rw-r--r--tests/ui/hygiene/stdlib-prelude-from-opaque-early.rs21
-rw-r--r--tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs16
-rw-r--r--tests/ui/hygiene/thread-local-not-in-prelude.rs9
-rw-r--r--tests/ui/hygiene/trait_items-2.rs20
-rw-r--r--tests/ui/hygiene/trait_items.rs21
-rw-r--r--tests/ui/hygiene/trait_items.stderr22
-rw-r--r--tests/ui/hygiene/traits-in-scope.rs53
-rw-r--r--tests/ui/hygiene/transparent-basic.rs43
-rw-r--r--tests/ui/hygiene/unpretty-debug.rs20
-rw-r--r--tests/ui/hygiene/unpretty-debug.stdout28
-rw-r--r--tests/ui/hygiene/wrap_unhygienic_example.rs34
-rw-r--r--tests/ui/hygiene/xcrate.rs12
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!();
+}