about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2021-10-30 20:30:27 +0200
committerGitHub <noreply@github.com>2021-10-30 20:30:27 +0200
commit1a1f525bb0d9897673b2445122ffd6f7aa265c9e (patch)
tree6cf7640d023116647df7bb1ae3bb0fdbef1924f9
parent73494404e962f4d61e65e5e204432de5a5128101 (diff)
parenta76a2d4ef986ec69e4ffb81c35dfb8dc91effee9 (diff)
downloadrust-1a1f525bb0d9897673b2445122ffd6f7aa265c9e.tar.gz
rust-1a1f525bb0d9897673b2445122ffd6f7aa265c9e.zip
Rollup merge of #90202 - matthewjasper:xcrate-hygiene, r=petrochenkov
Improve and test cross-crate hygiene

- Decode the parent expansion for traits and enums in `rustc_resolve`, this was already being used for resolution in typeck
- Avoid suggesting importing names with def-site hygiene, since it's often not useful
- Add more tests

r? `@petrochenkov`
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs13
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs8
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs8
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--src/test/ui/hygiene/auxiliary/fields.rs73
-rw-r--r--src/test/ui/hygiene/auxiliary/methods.rs160
-rw-r--r--src/test/ui/hygiene/auxiliary/pub_hygiene.rs7
-rw-r--r--src/test/ui/hygiene/auxiliary/use_by_macro.rs15
-rw-r--r--src/test/ui/hygiene/auxiliary/variants.rs36
-rw-r--r--src/test/ui/hygiene/cross-crate-define-and-use.rs19
-rw-r--r--src/test/ui/hygiene/cross-crate-fields.rs24
-rw-r--r--src/test/ui/hygiene/cross-crate-glob-hygiene.rs23
-rw-r--r--src/test/ui/hygiene/cross-crate-glob-hygiene.stderr11
-rw-r--r--src/test/ui/hygiene/cross-crate-methods.rs33
-rw-r--r--src/test/ui/hygiene/cross-crate-name-collision.rs12
-rw-r--r--src/test/ui/hygiene/cross-crate-name-hiding-2.rs15
-rw-r--r--src/test/ui/hygiene/cross-crate-name-hiding-2.stderr9
-rw-r--r--src/test/ui/hygiene/cross-crate-name-hiding.rs13
-rw-r--r--src/test/ui/hygiene/cross-crate-name-hiding.stderr9
-rw-r--r--src/test/ui/hygiene/cross-crate-redefine.rs14
-rw-r--r--src/test/ui/hygiene/cross-crate-redefine.stderr15
-rw-r--r--src/test/ui/hygiene/cross-crate-variants.rs18
-rw-r--r--src/test/ui/hygiene/cross_crate_hygiene.rs8
-rw-r--r--src/test/ui/proc-macro/meta-macro-hygiene.stdout2
-rw-r--r--src/test/ui/proc-macro/nonterminal-token-hygiene.stdout2
27 files changed, 525 insertions, 32 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index ca9daa49aa2..5e90aec003e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1198,8 +1198,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             }
         }
 
-        if let EntryKind::Mod(data) = kind {
-            for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+        if let EntryKind::Mod(exports) = kind {
+            for exp in exports.decode((self, sess)) {
                 match exp.res {
                     Res::Def(DefKind::Macro(..), _) => {}
                     _ if macros_only => continue,
@@ -1219,10 +1219,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
-        if let EntryKind::Mod(m) = self.kind(id) {
-            m.decode((self, sess)).expansion
-        } else {
-            panic!("Expected module, found {:?}", self.local_def_id(id))
+        match self.kind(id) {
+            EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+                self.get_expn_that_defined(id, sess)
+            }
+            _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 20f7b059b56..0dbef66ac37 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1086,11 +1086,11 @@ impl EncodeContext<'a, 'tcx> {
             Lazy::empty()
         };
 
-        let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
-        record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+        record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
         if self.is_proc_macro {
             record!(self.tables.children[def_id] <- &[]);
+            // Encode this here because we don't do it in encode_def_ids.
+            record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
             record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
                 item_id.def_id.local_def_index
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 42855e9d9d1..4e09d23169a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -346,7 +346,7 @@ enum EntryKind {
     Union(Lazy<VariantData>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
-    Mod(Lazy<ModData>),
+    Mod(Lazy<[Export]>),
     MacroDef(Lazy<MacroDef>),
     ProcMacro(MacroKind),
     Closure,
@@ -365,12 +365,6 @@ enum EntryKind {
 struct RenderedConst(String);
 
 #[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
-    reexports: Lazy<[Export]>,
-    expansion: ExpnId,
-}
-
-#[derive(MetadataEncodable, MetadataDecodable)]
 struct FnData {
     asyncness: hir::IsAsync,
     constness: hir::Constness,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2a562a06cb3..33af9884cbb 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -145,17 +145,11 @@ impl<'a> Resolver<'a> {
                     } else {
                         def_key.disambiguated_data.data.get_opt_name().expect("module without name")
                     };
-                    let expn_id = if def_kind == DefKind::Mod {
-                        self.cstore().module_expansion_untracked(def_id, &self.session)
-                    } else {
-                        // FIXME: Parent expansions for enums and traits are not kept in metadata.
-                        ExpnId::root()
-                    };
 
                     Some(self.new_module(
                         parent,
                         ModuleKind::Def(def_kind, def_id, name),
-                        expn_id,
+                        self.cstore().module_expansion_untracked(def_id, &self.session),
                         self.cstore().get_span_untracked(def_id, &self.session),
                         // FIXME: Account for `#[no_implicit_prelude]` attributes.
                         parent.map_or(false, |module| module.no_implicit_prelude),
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ccfab263bd4..163acebccea 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -842,9 +842,11 @@ impl<'a> Resolver<'a> {
 
                 // collect results based on the filter function
                 // avoid suggesting anything from the same module in which we are resolving
+                // avoid suggesting anything with a hygienic name
                 if ident.name == lookup_ident.name
                     && ns == namespace
                     && !ptr::eq(in_module, parent_scope.module)
+                    && !ident.span.normalize_to_macros_2_0().from_expansion()
                 {
                     let res = name_binding.res();
                     if filter_fn(res) {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index aa15febe885..724d1904dc3 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -709,7 +709,7 @@ impl SyntaxContext {
     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
     ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
     ///     }
-    ///     n(f);
+    ///     n!(f);
     ///     macro n($j:ident) {
     ///         use foo::*;
     ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
diff --git a/src/test/ui/hygiene/auxiliary/fields.rs b/src/test/ui/hygiene/auxiliary/fields.rs
new file mode 100644
index 00000000000..733d11a9e82
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/auxiliary/methods.rs b/src/test/ui/hygiene/auxiliary/methods.rs
new file mode 100644
index 00000000000..23b9c61cfc0
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/auxiliary/pub_hygiene.rs b/src/test/ui/hygiene/auxiliary/pub_hygiene.rs
new file mode 100644
index 00000000000..47e76a629c8
--- /dev/null
+++ b/src/test/ui/hygiene/auxiliary/pub_hygiene.rs
@@ -0,0 +1,7 @@
+#![feature(decl_macro)]
+
+macro x() {
+    pub struct MyStruct;
+}
+
+x!();
diff --git a/src/test/ui/hygiene/auxiliary/use_by_macro.rs b/src/test/ui/hygiene/auxiliary/use_by_macro.rs
new file mode 100644
index 00000000000..791cf035895
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/auxiliary/variants.rs b/src/test/ui/hygiene/auxiliary/variants.rs
new file mode 100644
index 00000000000..dbfcce17d47
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-define-and-use.rs b/src/test/ui/hygiene/cross-crate-define-and-use.rs
new file mode 100644
index 00000000000..94f1adff626
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-fields.rs b/src/test/ui/hygiene/cross-crate-fields.rs
new file mode 100644
index 00000000000..1bcd64573ac
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-glob-hygiene.rs b/src/test/ui/hygiene/cross-crate-glob-hygiene.rs
new file mode 100644
index 00000000000..de5576682a6
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-glob-hygiene.stderr b/src/test/ui/hygiene/cross-crate-glob-hygiene.stderr
new file mode 100644
index 00000000000..7369e77d070
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-methods.rs b/src/test/ui/hygiene/cross-crate-methods.rs
new file mode 100644
index 00000000000..0e6f57c33f6
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-name-collision.rs b/src/test/ui/hygiene/cross-crate-name-collision.rs
new file mode 100644
index 00000000000..8f118782f23
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-name-hiding-2.rs b/src/test/ui/hygiene/cross-crate-name-hiding-2.rs
new file mode 100644
index 00000000000..3eacd775c9e
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-name-hiding-2.stderr b/src/test/ui/hygiene/cross-crate-name-hiding-2.stderr
new file mode 100644
index 00000000000..46314cdd5ab
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-name-hiding.rs b/src/test/ui/hygiene/cross-crate-name-hiding.rs
new file mode 100644
index 00000000000..dd76ecc5762
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-name-hiding.stderr b/src/test/ui/hygiene/cross-crate-name-hiding.stderr
new file mode 100644
index 00000000000..f8840c8f85a
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-redefine.rs b/src/test/ui/hygiene/cross-crate-redefine.rs
new file mode 100644
index 00000000000..3cb06b4bad8
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-redefine.stderr b/src/test/ui/hygiene/cross-crate-redefine.stderr
new file mode 100644
index 00000000000..4f1419de426
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross-crate-variants.rs b/src/test/ui/hygiene/cross-crate-variants.rs
new file mode 100644
index 00000000000..efc73a21f16
--- /dev/null
+++ b/src/test/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/src/test/ui/hygiene/cross_crate_hygiene.rs b/src/test/ui/hygiene/cross_crate_hygiene.rs
deleted file mode 100644
index 75742960b7e..00000000000
--- a/src/test/ui/hygiene/cross_crate_hygiene.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// check-pass
-// aux-build:needs_hygiene.rs
-
-extern crate needs_hygiene;
-
-use needs_hygiene::*;
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout
index 7f7a1009c90..5d04fe1e3de 100644
--- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout
@@ -49,6 +49,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
 crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
 
diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
index 07803863813..709b2a2169e 100644
--- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -73,6 +73,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
 crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)