about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-07-29 14:51:17 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-07-29 19:30:13 +0300
commit44422409a43544a1300506c83fbc2e8f3049d8a5 (patch)
treec7ffbf3091bea422e6b33ac774acabf702348be8
parent75af9df71b9eea84f281cf7de72c3e3cc2b02222 (diff)
downloadrust-44422409a43544a1300506c83fbc2e8f3049d8a5.tar.gz
rust-44422409a43544a1300506c83fbc2e8f3049d8a5.zip
resolve: Modularize crate-local `#[macro_export] macro_rules`
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs16
-rw-r--r--src/librustc_resolve/lib.rs18
-rw-r--r--src/librustc_resolve/macros.rs40
-rw-r--r--src/librustc_resolve/resolve_imports.rs18
-rw-r--r--src/test/run-pass/auxiliary/issue_38715-modern.rs18
-rw-r--r--src/test/run-pass/issue-38715.rs4
-rw-r--r--src/test/ui/duplicate-check-macro-exports.rs2
-rw-r--r--src/test/ui/duplicate-check-macro-exports.stderr18
-rw-r--r--src/test/ui/imports/local-modularized-tricky-fail-1.rs57
-rw-r--r--src/test/ui/imports/local-modularized-tricky-fail-1.stderr84
-rw-r--r--src/test/ui/imports/local-modularized-tricky-fail-2.rs58
-rw-r--r--src/test/ui/imports/local-modularized-tricky-fail-2.stderr36
-rw-r--r--src/test/ui/imports/local-modularized-tricky-pass.rs31
-rw-r--r--src/test/ui/imports/local-modularized.rs47
14 files changed, 415 insertions, 32 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index da2847dc557..4553a2ab577 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -59,7 +59,20 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
 impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Def(self.0),
+            kind: NameBindingKind::Def(self.0, false),
+            vis: self.1,
+            span: self.2,
+            expansion: self.3,
+        })
+    }
+}
+
+pub(crate) struct IsMacroExport;
+
+impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark, IsMacroExport) {
+    fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
+        arenas.alloc_name_binding(NameBinding {
+            kind: NameBindingKind::Def(self.0, true),
             vis: self.1,
             span: self.2,
             expansion: self.3,
@@ -772,6 +785,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
         let mark = id.placeholder_to_mark();
         self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
+        self.resolver.unresolved_invocations_macro_export.insert(mark);
         let invocation = self.resolver.invocations[&mark];
         invocation.module.set(self.resolver.current_module);
         invocation.legacy_scope.set(self.legacy_scope);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 725b3b4f150..77eb97b02ff 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1117,7 +1117,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> {
 
 #[derive(Clone, Debug)]
 enum NameBindingKind<'a> {
-    Def(Def),
+    Def(Def, /* is_macro_export */ bool),
     Module(Module<'a>),
     Import {
         binding: &'a NameBinding<'a>,
@@ -1161,7 +1161,7 @@ impl<'a> NameBinding<'a> {
 
     fn def(&self) -> Def {
         match self.kind {
-            NameBindingKind::Def(def) => def,
+            NameBindingKind::Def(def, _) => def,
             NameBindingKind::Module(module) => module.def().unwrap(),
             NameBindingKind::Import { binding, .. } => binding.def(),
             NameBindingKind::Ambiguity { .. } => Def::Err,
@@ -1191,8 +1191,8 @@ impl<'a> NameBinding<'a> {
 
     fn is_variant(&self) -> bool {
         match self.kind {
-            NameBindingKind::Def(Def::Variant(..)) |
-            NameBindingKind::Def(Def::VariantCtor(..)) => true,
+            NameBindingKind::Def(Def::Variant(..), _) |
+            NameBindingKind::Def(Def::VariantCtor(..), _) => true,
             _ => false,
         }
     }
@@ -1241,7 +1241,7 @@ impl<'a> NameBinding<'a> {
 
     fn is_macro_def(&self) -> bool {
         match self.kind {
-            NameBindingKind::Def(Def::Macro(..)) => true,
+            NameBindingKind::Def(Def::Macro(..), _) => true,
             _ => false,
         }
     }
@@ -1397,7 +1397,7 @@ pub struct Resolver<'a> {
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
     macro_defs: FxHashMap<Mark, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
-    macro_exports: Vec<Export>,
+    macro_exports: Vec<Export>, // FIXME: Remove when `use_extern_macros` is stabilized
     pub whitelisted_legacy_custom_derives: Vec<Name>,
     pub found_unresolved_macro: bool,
 
@@ -1427,6 +1427,9 @@ pub struct Resolver<'a> {
 
     /// Only supposed to be used by rustdoc, otherwise should be false.
     pub ignore_extern_prelude_feature: bool,
+
+    /// Macro invocations in the whole crate that can expand into a `#[macro_export] macro_rules`.
+    unresolved_invocations_macro_export: FxHashSet<Mark>,
 }
 
 /// Nothing really interesting here, it just provides memory for the rest of the crate.
@@ -1701,7 +1704,7 @@ impl<'a> Resolver<'a> {
 
             arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
-                kind: NameBindingKind::Def(Def::Err),
+                kind: NameBindingKind::Def(Def::Err, false),
                 expansion: Mark::root(),
                 span: DUMMY_SP,
                 vis: ty::Visibility::Public,
@@ -1731,6 +1734,7 @@ impl<'a> Resolver<'a> {
             current_type_ascription: Vec::new(),
             injected_crate: None,
             ignore_extern_prelude_feature: false,
+            unresolved_invocations_macro_export: FxHashSet(),
         }
     }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 29b6f958cc1..1d42ad4e490 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -11,7 +11,7 @@
 use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
 use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
 use Namespace::{self, MacroNS};
-use build_reduced_graph::BuildReducedGraphVisitor;
+use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
 use resolve_imports::ImportResolver;
 use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
                          DefIndexAddressSpace};
@@ -193,7 +193,9 @@ impl<'a> base::Resolver for Resolver<'a> {
 
         self.current_module = invocation.module.get();
         self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
+        self.unresolved_invocations_macro_export.remove(&mark);
         self.current_module.unresolved_invocations.borrow_mut().extend(derives);
+        self.unresolved_invocations_macro_export.extend(derives);
         for &derive in derives {
             self.invocations.insert(derive, invocation);
         }
@@ -215,7 +217,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         let kind = ext.kind();
         self.macro_map.insert(def_id, ext);
         let binding = self.arenas.alloc_name_binding(NameBinding {
-            kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
+            kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
             span: DUMMY_SP,
             vis: ty::Visibility::Invisible,
             expansion: Mark::root(),
@@ -711,12 +713,15 @@ impl<'a> Resolver<'a> {
 
             match (legacy_resolution, resolution) {
                 (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
-                    let msg1 = format!("`{}` could refer to the macro defined here", ident);
-                    let msg2 = format!("`{}` could also refer to the macro imported here", ident);
-                    self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
-                        .span_note(legacy_binding.span, &msg1)
-                        .span_note(binding.span, &msg2)
-                        .emit();
+                    if legacy_binding.def_id != binding.def_ignoring_ambiguity().def_id() {
+                        let msg1 = format!("`{}` could refer to the macro defined here", ident);
+                        let msg2 =
+                            format!("`{}` could also refer to the macro imported here", ident);
+                        self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
+                            .span_note(legacy_binding.span, &msg1)
+                            .span_note(binding.span, &msg2)
+                            .emit();
+                    }
                 },
                 (None, Err(_)) => {
                     assert!(def.is_none());
@@ -850,12 +855,19 @@ impl<'a> Resolver<'a> {
             let def = Def::Macro(def_id, MacroKind::Bang);
             self.all_macros.insert(ident.name, def);
             if attr::contains_name(&item.attrs, "macro_export") {
-                self.macro_exports.push(Export {
-                    ident: ident.modern(),
-                    def: def,
-                    vis: ty::Visibility::Public,
-                    span: item.span,
-                });
+                if self.use_extern_macros {
+                    let module = self.graph_root;
+                    let vis = ty::Visibility::Public;
+                    self.define(module, ident, MacroNS,
+                                (def, vis, item.span, expansion, IsMacroExport));
+                } else {
+                    self.macro_exports.push(Export {
+                        ident: ident.modern(),
+                        def: def,
+                        vis: ty::Visibility::Public,
+                        span: item.span,
+                    });
+                }
             } else {
                 self.unused_macros.insert(def_id);
             }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 50eb89be690..c83fcf65c40 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -211,7 +211,9 @@ impl<'a> Resolver<'a> {
         // if it cannot be shadowed by some new item/import expanded from a macro.
         // This happens either if there are no unexpanded macros, or expanded names cannot
         // shadow globs (that happens in macro namespace or with restricted shadowing).
-        let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
+        let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty() ||
+                                (ns == MacroNS && ptr::eq(module, self.graph_root) &&
+                                 !self.unresolved_invocations_macro_export.is_empty());
         if let Some(binding) = resolution.binding {
             if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
                 return check_usable(self, binding);
@@ -363,6 +365,18 @@ impl<'a> Resolver<'a> {
                         resolution.binding = Some(binding);
                         resolution.shadowed_glob = Some(old_binding);
                     }
+                } else if let (&NameBindingKind::Def(_, true), &NameBindingKind::Def(_, true)) =
+                        (&old_binding.kind, &binding.kind) {
+
+                    this.session.buffer_lint_with_diagnostic(
+                        DUPLICATE_MACRO_EXPORTS,
+                        CRATE_NODE_ID,
+                        binding.span,
+                        &format!("a macro named `{}` has already been exported", ident),
+                        BuiltinLintDiagnostics::DuplicatedMacroExports(
+                            ident, old_binding.span, binding.span));
+
+                    resolution.binding = Some(binding);
                 } else {
                     return Err(old_binding);
                 }
@@ -766,7 +780,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                                     match binding.kind {
                                         // Never suggest the name that has binding error
                                         // i.e. the name that cannot be previously resolved
-                                        NameBindingKind::Def(Def::Err) => return None,
+                                        NameBindingKind::Def(Def::Err, _) => return None,
                                         _ => Some(&i.name),
                                     }
                                 },
diff --git a/src/test/run-pass/auxiliary/issue_38715-modern.rs b/src/test/run-pass/auxiliary/issue_38715-modern.rs
new file mode 100644
index 00000000000..68aced7f979
--- /dev/null
+++ b/src/test/run-pass/auxiliary/issue_38715-modern.rs
@@ -0,0 +1,18 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(use_extern_macros)]
+#![allow(duplicate_macro_exports)]
+
+#[macro_export]
+macro_rules! foo_modern { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo_modern { () => {} }
diff --git a/src/test/run-pass/issue-38715.rs b/src/test/run-pass/issue-38715.rs
index 054785e62b8..b158234eb11 100644
--- a/src/test/run-pass/issue-38715.rs
+++ b/src/test/run-pass/issue-38715.rs
@@ -9,12 +9,16 @@
 // except according to those terms.
 
 // aux-build:issue_38715.rs
+// aux-build:issue_38715-modern.rs
 
 // Test that `#[macro_export] macro_rules!` shadow earlier `#[macro_export] macro_rules!`
 
 #[macro_use]
 extern crate issue_38715;
+#[macro_use]
+extern crate issue_38715_modern;
 
 fn main() {
     foo!();
+    foo_modern!();
 }
diff --git a/src/test/ui/duplicate-check-macro-exports.rs b/src/test/ui/duplicate-check-macro-exports.rs
index d874a43d53d..d8159bff567 100644
--- a/src/test/ui/duplicate-check-macro-exports.rs
+++ b/src/test/ui/duplicate-check-macro-exports.rs
@@ -13,6 +13,6 @@
 pub use std::panic;
 
 #[macro_export]
-macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
+macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
 
 fn main() {}
diff --git a/src/test/ui/duplicate-check-macro-exports.stderr b/src/test/ui/duplicate-check-macro-exports.stderr
index 6d3bb669df9..651e984b274 100644
--- a/src/test/ui/duplicate-check-macro-exports.stderr
+++ b/src/test/ui/duplicate-check-macro-exports.stderr
@@ -1,14 +1,18 @@
-error: a macro named `panic` has already been exported
+error[E0255]: the name `panic` is defined multiple times
   --> $DIR/duplicate-check-macro-exports.rs:16:1
    |
-LL | macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `panic` already exported
+LL | pub use std::panic;
+   |         ---------- previous import of the macro `panic` here
+...
+LL | macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
+   | ^^^^^^^^^^^^^^^^^^ `panic` redefined here
    |
-note: previous macro export here
-  --> $DIR/duplicate-check-macro-exports.rs:13:9
+   = note: `panic` must be defined only once in the macro namespace of this module
+help: You can use `as` to change the binding name of the import
    |
-LL | pub use std::panic;
-   |         ^^^^^^^^^^
+LL | pub use std::panic as other_panic;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0255`.
diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.rs b/src/test/ui/imports/local-modularized-tricky-fail-1.rs
new file mode 100644
index 00000000000..445344732f7
--- /dev/null
+++ b/src/test/ui/imports/local-modularized-tricky-fail-1.rs
@@ -0,0 +1,57 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(decl_macro)]
+
+macro_rules! define_exported { () => {
+    #[macro_export]
+    macro_rules! exported {
+        () => ()
+    }
+}}
+macro_rules! define_panic { () => {
+    #[macro_export]
+    macro_rules! panic {
+        () => ()
+    }
+}}
+macro_rules! define_include { () => {
+    #[macro_export]
+    macro_rules! include {
+        () => ()
+    }
+}}
+
+use inner1::*;
+
+mod inner1 {
+    pub macro exported() {}
+}
+
+exported!(); //~ ERROR `exported` is ambiguous
+
+mod inner2 {
+    define_exported!();
+}
+
+fn main() {
+    panic!(); //~ ERROR `panic` is ambiguous
+              //~^ ERROR `panic` is ambiguous
+}
+
+mod inner3 {
+    define_panic!();
+}
+
+mod inner4 {
+    define_include!();
+}
+
+include!(); //~ ERROR `include` is ambiguous
diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.stderr b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr
new file mode 100644
index 00000000000..e9a81e7ae4c
--- /dev/null
+++ b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr
@@ -0,0 +1,84 @@
+error[E0659]: `exported` is ambiguous
+  --> $DIR/local-modularized-tricky-fail-1.rs:38:1
+   |
+LL | exported!(); //~ ERROR `exported` is ambiguous
+   | ^^^^^^^^
+   |
+note: `exported` could refer to the name defined here
+  --> $DIR/local-modularized-tricky-fail-1.rs:15:5
+   |
+LL | /     macro_rules! exported {
+LL | |         () => ()
+LL | |     }
+   | |_____^
+...
+LL |       define_exported!();
+   |       ------------------- in this macro invocation
+note: `exported` could also refer to the name imported here
+  --> $DIR/local-modularized-tricky-fail-1.rs:32:5
+   |
+LL | use inner1::*;
+   |     ^^^^^^^^^
+   = note: macro-expanded macros do not shadow
+
+error[E0659]: `include` is ambiguous
+  --> $DIR/local-modularized-tricky-fail-1.rs:57:1
+   |
+LL | include!(); //~ ERROR `include` is ambiguous
+   | ^^^^^^^
+   |
+note: `include` could refer to the name defined here
+  --> $DIR/local-modularized-tricky-fail-1.rs:27:5
+   |
+LL | /     macro_rules! include {
+LL | |         () => ()
+LL | |     }
+   | |_____^
+...
+LL |       define_include!();
+   |       ------------------ in this macro invocation
+   = note: `include` is also a builtin macro
+   = note: macro-expanded macros do not shadow
+
+error[E0659]: `panic` is ambiguous
+  --> $DIR/local-modularized-tricky-fail-1.rs:45:5
+   |
+LL |     panic!(); //~ ERROR `panic` is ambiguous
+   |     ^^^^^
+   |
+note: `panic` could refer to the name defined here
+  --> $DIR/local-modularized-tricky-fail-1.rs:21:5
+   |
+LL | /     macro_rules! panic {
+LL | |         () => ()
+LL | |     }
+   | |_____^
+...
+LL |       define_panic!();
+   |       ---------------- in this macro invocation
+   = note: `panic` is also a builtin macro
+   = note: macro-expanded macros do not shadow
+
+error[E0659]: `panic` is ambiguous
+  --> $DIR/local-modularized-tricky-fail-1.rs:45:5
+   |
+LL |     panic!(); //~ ERROR `panic` is ambiguous
+   |     ^^^^^^^^^
+   |
+note: `panic` could refer to the name defined here
+  --> $DIR/local-modularized-tricky-fail-1.rs:21:5
+   |
+LL | /     macro_rules! panic {
+LL | |         () => ()
+LL | |     }
+   | |_____^
+...
+LL |       define_panic!();
+   |       ---------------- in this macro invocation
+   = note: `panic` is also a builtin macro
+   = note: macro-expanded macros do not shadow
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/imports/local-modularized-tricky-fail-2.rs b/src/test/ui/imports/local-modularized-tricky-fail-2.rs
new file mode 100644
index 00000000000..afdebc4533f
--- /dev/null
+++ b/src/test/ui/imports/local-modularized-tricky-fail-2.rs
@@ -0,0 +1,58 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// `#[macro_export] macro_rules` that doen't originate from macro expansions can be placed
+// into the root module soon enough to act as usual items and shadow globs and preludes.
+
+#![feature(decl_macro)]
+
+// `macro_export` shadows globs
+use inner1::*;
+
+mod inner1 {
+    pub macro exported() {}
+}
+
+exported!();
+
+mod deep {
+    fn deep() {
+        type Deeper = [u8; {
+            #[macro_export]
+            macro_rules! exported {
+                () => ( struct Б; ) //~ ERROR non-ascii idents are not fully supported
+            }
+
+            0
+        }];
+    }
+}
+
+// `macro_export` shadows std prelude
+fn main() {
+    panic!();
+}
+
+mod inner3 {
+    #[macro_export]
+    macro_rules! panic {
+        () => ( struct Г; ) //~ ERROR non-ascii idents are not fully supported
+    }
+}
+
+// `macro_export` shadows builtin macros
+include!();
+
+mod inner4 {
+    #[macro_export]
+    macro_rules! include {
+        () => ( struct Д; ) //~ ERROR non-ascii idents are not fully supported
+    }
+}
diff --git a/src/test/ui/imports/local-modularized-tricky-fail-2.stderr b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr
new file mode 100644
index 00000000000..5681dd59628
--- /dev/null
+++ b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr
@@ -0,0 +1,36 @@
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+  --> $DIR/local-modularized-tricky-fail-2.rs:30:32
+   |
+LL | exported!();
+   | ------------ in this macro invocation
+...
+LL |                 () => ( struct Б; ) //~ ERROR non-ascii idents are not fully supported
+   |                                ^
+   |
+   = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+  --> $DIR/local-modularized-tricky-fail-2.rs:46:24
+   |
+LL |     panic!();
+   |     --------- in this macro invocation
+...
+LL |         () => ( struct Г; ) //~ ERROR non-ascii idents are not fully supported
+   |                        ^
+   |
+   = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+  --> $DIR/local-modularized-tricky-fail-2.rs:56:24
+   |
+LL | include!();
+   | ----------- in this macro invocation
+...
+LL |         () => ( struct Д; ) //~ ERROR non-ascii idents are not fully supported
+   |                        ^
+   |
+   = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/imports/local-modularized-tricky-pass.rs b/src/test/ui/imports/local-modularized-tricky-pass.rs
new file mode 100644
index 00000000000..04df357e106
--- /dev/null
+++ b/src/test/ui/imports/local-modularized-tricky-pass.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(use_extern_macros)]
+
+macro_rules! define_exported { () => {
+    #[macro_export]
+    macro_rules! exported {
+        () => ()
+    }
+}}
+
+mod inner1 {
+    use super::*;
+    exported!();
+}
+
+mod inner2 {
+    define_exported!();
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/local-modularized.rs b/src/test/ui/imports/local-modularized.rs
new file mode 100644
index 00000000000..a5297c54c9e
--- /dev/null
+++ b/src/test/ui/imports/local-modularized.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(use_extern_macros)]
+
+#[macro_export(local_inner_macros)]
+macro_rules! dollar_crate_exported {
+    (1) => { $crate::exported!(); };
+    (2) => { exported!(); };
+}
+
+// Before `exported` is defined
+exported!();
+
+mod inner {
+
+    ::exported!();
+    crate::exported!();
+    dollar_crate_exported!(1);
+    dollar_crate_exported!(2);
+
+    mod inner_inner {
+        #[macro_export]
+        macro_rules! exported {
+            () => ()
+        }
+    }
+
+    // After `exported` is defined
+    ::exported!();
+    crate::exported!();
+    dollar_crate_exported!(1);
+    dollar_crate_exported!(2);
+}
+
+exported!();
+
+fn main() {}