about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libproc_macro/lib.rs19
-rw-r--r--src/librustc/hir/def.rs10
-rw-r--r--src/librustc/hir/map/definitions.rs36
-rw-r--r--src/librustc/lint/builtin.rs12
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_lint/lib.rs5
-rw-r--r--src/librustc_resolve/lib.rs91
-rw-r--r--src/librustc_resolve/macros.rs11
-rw-r--r--src/libsyntax/ext/base.rs18
-rw-r--r--src/libsyntax_pos/hygiene.rs140
-rw-r--r--src/libsyntax_pos/lib.rs2
-rw-r--r--src/libsyntax_pos/span_encoding.rs4
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs54
-rw-r--r--src/test/ui-fulldeps/proc-macro/generate-mod.rs34
-rw-r--r--src/test/ui-fulldeps/proc-macro/generate-mod.stderr46
-rw-r--r--src/test/ui/hygiene/arguments.rs (renamed from src/test/run-pass/hygiene/arguments.rs)2
-rw-r--r--src/test/ui/hygiene/arguments.stderr9
-rw-r--r--src/test/ui/hygiene/generate-mod.rs43
-rw-r--r--src/test/ui/hygiene/generate-mod.stderr53
-rw-r--r--src/test/ui/hygiene/globs.rs16
-rw-r--r--src/test/ui/hygiene/globs.stderr16
21 files changed, 450 insertions, 173 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index fb5cbf473a3..876cf295acc 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -1351,7 +1351,7 @@ pub mod __internal {
     use syntax::parse::token::{self, Token};
     use syntax::tokenstream;
     use syntax_pos::{BytePos, Loc, DUMMY_SP};
-    use syntax_pos::hygiene::{Mark, SyntaxContext, Transparency};
+    use syntax_pos::hygiene::{SyntaxContext, Transparency};
 
     use super::{TokenStream, LexError, Span};
 
@@ -1436,20 +1436,15 @@ pub mod __internal {
 
             // No way to determine def location for a proc macro right now, so use call location.
             let location = cx.current_expansion.mark.expn_info().unwrap().call_site;
-            // Opaque mark was already created by expansion, now create its transparent twin.
-            // We can't use the call-site span literally here, even if it appears to provide
-            // correct name resolution, because it has all the `ExpnInfo` wrong, so the edition
-            // checks, lint macro checks, macro backtraces will all break.
-            let opaque_mark = cx.current_expansion.mark;
-            let transparent_mark = Mark::fresh_cloned(opaque_mark);
-            transparent_mark.set_transparency(Transparency::Transparent);
-
-            let to_span = |mark| Span(location.with_ctxt(SyntaxContext::empty().apply_mark(mark)));
+            let to_span = |transparency| Span(location.with_ctxt(
+                SyntaxContext::empty().apply_mark_with_transparency(cx.current_expansion.mark,
+                                                                    transparency))
+            );
             p.set(ProcMacroSess {
                 parse_sess: cx.parse_sess,
                 data: ProcMacroData {
-                    def_site: to_span(opaque_mark),
-                    call_site: to_span(transparent_mark),
+                    def_site: to_span(Transparency::Opaque),
+                    call_site: to_span(Transparency::Transparent),
                 },
             });
             f()
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 7c10292061f..7a26a239aef 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -129,6 +129,16 @@ pub enum Namespace {
     MacroNS,
 }
 
+impl Namespace {
+    pub fn descr(self) -> &'static str {
+        match self {
+            TypeNS => "type",
+            ValueNS => "value",
+            MacroNS => "macro",
+        }
+    }
+}
+
 /// Just a helper ‒ separate structure for each namespace.
 #[derive(Copy, Clone, Default, Debug)]
 pub struct PerNS<T> {
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 328cb822547..49a4a1b78a1 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -153,6 +153,7 @@ impl Decodable for DefPathTable {
 /// The definition table containing node definitions.
 /// It holds the DefPathTable for local DefIds/DefPaths and it also stores a
 /// mapping from NodeIds to local DefIds.
+#[derive(Clone)]
 pub struct Definitions {
     table: DefPathTable,
     node_to_def_index: NodeMap<DefIndex>,
@@ -161,34 +162,12 @@ pub struct Definitions {
     /// If `Mark` is an ID of some macro expansion,
     /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
     parent_modules_of_macro_defs: FxHashMap<Mark, DefId>,
-    /// Item with a given `DefIndex` was defined during opaque macro expansion with ID `Mark`.
-    /// It can actually be defined during transparent macro expansions inside that opaque expansion,
-    /// but transparent expansions are ignored here.
-    opaque_expansions_that_defined: FxHashMap<DefIndex, Mark>,
+    /// Item with a given `DefIndex` was defined during macro expansion with ID `Mark`.
+    expansions_that_defined: FxHashMap<DefIndex, Mark>,
     next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
     def_index_to_span: FxHashMap<DefIndex, Span>,
 }
 
-// Unfortunately we have to provide a manual impl of Clone because of the
-// fixed-sized array field.
-impl Clone for Definitions {
-    fn clone(&self) -> Self {
-        Definitions {
-            table: self.table.clone(),
-            node_to_def_index: self.node_to_def_index.clone(),
-            def_index_to_node: [
-                self.def_index_to_node[0].clone(),
-                self.def_index_to_node[1].clone(),
-            ],
-            node_to_hir_id: self.node_to_hir_id.clone(),
-            parent_modules_of_macro_defs: self.parent_modules_of_macro_defs.clone(),
-            opaque_expansions_that_defined: self.opaque_expansions_that_defined.clone(),
-            next_disambiguator: self.next_disambiguator.clone(),
-            def_index_to_span: self.def_index_to_span.clone(),
-        }
-    }
-}
-
 /// A unique identifier that we can use to lookup a definition
 /// precisely. It combines the index of the definition's parent (if
 /// any) with a `DisambiguatedDefPathData`.
@@ -409,7 +388,7 @@ impl Definitions {
             def_index_to_node: [vec![], vec![]],
             node_to_hir_id: IndexVec::new(),
             parent_modules_of_macro_defs: FxHashMap(),
-            opaque_expansions_that_defined: FxHashMap(),
+            expansions_that_defined: FxHashMap(),
             next_disambiguator: FxHashMap(),
             def_index_to_span: FxHashMap(),
         }
@@ -584,9 +563,8 @@ impl Definitions {
             self.node_to_def_index.insert(node_id, index);
         }
 
-        let expansion = expansion.modern();
         if expansion != Mark::root() {
-            self.opaque_expansions_that_defined.insert(index, expansion);
+            self.expansions_that_defined.insert(index, expansion);
         }
 
         // The span is added if it isn't dummy
@@ -606,8 +584,8 @@ impl Definitions {
         self.node_to_hir_id = mapping;
     }
 
-    pub fn opaque_expansion_that_defined(&self, index: DefIndex) -> Mark {
-        self.opaque_expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root())
+    pub fn expansion_that_defined(&self, index: DefIndex) -> Mark {
+        self.expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root())
     }
 
     pub fn parent_module_of_macro_def(&self, mark: Mark) -> DefId {
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index a6bbd937505..efc2d9311c1 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -316,6 +316,12 @@ declare_lint! {
     "checks the object safety of where clauses"
 }
 
+declare_lint! {
+    pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+    Warn,
+    "detects proc macro derives using inaccessible names from parent modules"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -372,6 +378,7 @@ impl LintPass for HardwiredLints {
             DUPLICATE_MACRO_EXPORTS,
             INTRA_DOC_LINK_RESOLUTION_FAILURE,
             WHERE_CLAUSES_OBJECT_SAFETY,
+            PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         )
     }
 }
@@ -384,6 +391,7 @@ pub enum BuiltinLintDiagnostics {
     BareTraitObject(Span, /* is_global */ bool),
     AbsPathWithModule(Span),
     DuplicatedMacroExports(ast::Ident, Span, Span),
+    ProcMacroDeriveResolutionFallback(Span),
 }
 
 impl BuiltinLintDiagnostics {
@@ -420,6 +428,10 @@ impl BuiltinLintDiagnostics {
                 db.span_label(later_span, format!("`{}` already exported", ident));
                 db.span_note(earlier_span, "previous macro export is now shadowed");
             }
+            BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => {
+                db.span_label(span, "names from parent modules are not \
+                                     accessible without an explicit import");
+            }
         }
     }
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 98042f6389d..4a76cc683f6 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2724,7 +2724,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) {
         ident = ident.modern();
         let target_expansion = match scope.krate {
-            LOCAL_CRATE => self.hir.definitions().opaque_expansion_that_defined(scope.index),
+            LOCAL_CRATE => self.hir.definitions().expansion_that_defined(scope.index),
             _ => Mark::root(),
         };
         let scope = match ident.span.adjust(target_expansion) {
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 459f496c9fe..359b056b5a2 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -293,6 +293,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "issue #50589 <https://github.com/rust-lang/rust/issues/50589>",
             edition: None,
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK),
+            reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
+            edition: None,
+        },
         ]);
 
     // Register renamed and removed lints
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index ee2a1c3bdeb..8a47b8ea648 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 
 use syntax::visit::{self, FnKind, Visitor};
 use syntax::attr;
-use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
+use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
 use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
@@ -1891,7 +1891,12 @@ impl<'a> Resolver<'a> {
 
         ident.span = ident.span.modern();
         loop {
-            module = unwrap_or!(self.hygienic_lexical_parent(module, &mut ident.span), break);
+            let (opt_module, poisoned) = if record_used {
+                self.hygienic_lexical_parent_with_compatibility_fallback(module, &mut ident.span)
+            } else {
+                (self.hygienic_lexical_parent(module, &mut ident.span), false)
+            };
+            module = unwrap_or!(opt_module, break);
             let orig_current_module = self.current_module;
             self.current_module = module; // Lexical resolutions can never be a privacy error.
             let result = self.resolve_ident_in_module_unadjusted(
@@ -1900,7 +1905,19 @@ impl<'a> Resolver<'a> {
             self.current_module = orig_current_module;
 
             match result {
-                Ok(binding) => return Some(LexicalScopeBinding::Item(binding)),
+                Ok(binding) => {
+                    if poisoned {
+                        self.session.buffer_lint_with_diagnostic(
+                            lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+                            CRATE_NODE_ID, ident.span,
+                            &format!("cannot find {} `{}` in this scope", ns.descr(), ident),
+                            lint::builtin::BuiltinLintDiagnostics::
+                                ProcMacroDeriveResolutionFallback(ident.span),
+                        );
+                    }
+                    return Some(LexicalScopeBinding::Item(binding))
+                }
+                _ if poisoned => break,
                 Err(Undetermined) => return None,
                 Err(Determined) => {}
             }
@@ -1935,7 +1952,7 @@ impl<'a> Resolver<'a> {
         None
     }
 
-    fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span)
+    fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span)
                                -> Option<Module<'a>> {
         if !module.expansion.is_descendant_of(span.ctxt().outer()) {
             return Some(self.macro_def_scope(span.remove_mark()));
@@ -1945,22 +1962,41 @@ impl<'a> Resolver<'a> {
             return Some(module.parent.unwrap());
         }
 
-        let mut module_expansion = module.expansion.modern(); // for backward compatibility
-        while let Some(parent) = module.parent {
-            let parent_expansion = parent.expansion.modern();
-            if module_expansion.is_descendant_of(parent_expansion) &&
-               parent_expansion != module_expansion {
-                return if parent_expansion.is_descendant_of(span.ctxt().outer()) {
-                    Some(parent)
-                } else {
-                    None
-                };
+        None
+    }
+
+    fn hygienic_lexical_parent_with_compatibility_fallback(
+        &mut self, module: Module<'a>, span: &mut Span) -> (Option<Module<'a>>, /* poisoned */ bool
+    ) {
+        if let module @ Some(..) = self.hygienic_lexical_parent(module, span) {
+            return (module, false);
+        }
+
+        // We need to support the next case under a deprecation warning
+        // ```
+        // struct MyStruct;
+        // ---- begin: this comes from a proc macro derive
+        // mod implementation_details {
+        //     // Note that `MyStruct` is not in scope here.
+        //     impl SomeTrait for MyStruct { ... }
+        // }
+        // ---- end
+        // ```
+        // So we have to fall back to the module's parent during lexical resolution in this case.
+        if let Some(parent) = module.parent {
+            // Inner module is inside the macro, parent module is outside of the macro.
+            if module.expansion != parent.expansion &&
+            module.expansion.is_descendant_of(parent.expansion) {
+                // The macro is a proc macro derive
+                if module.expansion.looks_like_proc_macro_derive() {
+                    if parent.expansion.is_descendant_of(span.ctxt().outer()) {
+                        return (module.parent, true);
+                    }
+                }
             }
-            module = parent;
-            module_expansion = parent_expansion;
         }
 
-        None
+        (None, false)
     }
 
     fn resolve_ident_in_module(&mut self,
@@ -1996,8 +2032,8 @@ impl<'a> Resolver<'a> {
             let mut iter = ctxt.marks().into_iter().rev().peekable();
             let mut result = None;
             // Find the last modern mark from the end if it exists.
-            while let Some(&mark) = iter.peek() {
-                if mark.transparency() == Transparency::Opaque {
+            while let Some(&(mark, transparency)) = iter.peek() {
+                if transparency == Transparency::Opaque {
                     result = Some(mark);
                     iter.next();
                 } else {
@@ -2005,8 +2041,8 @@ impl<'a> Resolver<'a> {
                 }
             }
             // Then find the last legacy mark from the end if it exists.
-            for mark in iter {
-                if mark.transparency() == Transparency::SemiTransparent {
+            for (mark, transparency) in iter {
+                if transparency == Transparency::SemiTransparent {
                     result = Some(mark);
                 } else {
                     break;
@@ -4037,8 +4073,9 @@ impl<'a> Resolver<'a> {
         let mut search_module = self.current_module;
         loop {
             self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
-            search_module =
-                unwrap_or!(self.hygienic_lexical_parent(search_module, &mut ident.span), break);
+            search_module = unwrap_or!(
+                self.hygienic_lexical_parent(search_module, &mut ident.span), break
+            );
         }
 
         if let Some(prelude) = self.prelude {
@@ -4406,12 +4443,6 @@ impl<'a> Resolver<'a> {
             (TypeNS, _) => "type",
         };
 
-        let namespace = match ns {
-            ValueNS => "value",
-            MacroNS => "macro",
-            TypeNS => "type",
-        };
-
         let msg = format!("the name `{}` is defined multiple times", name);
 
         let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
@@ -4429,7 +4460,7 @@ impl<'a> Resolver<'a> {
 
         err.note(&format!("`{}` must be defined only once in the {} namespace of this {}",
                           name,
-                          namespace,
+                          ns.descr(),
                           container));
 
         err.span_label(span, format!("`{}` re{} here", name, new_participle));
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 0523765ea18..9ce1e21d0d0 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
 use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, InvocationKind};
-use syntax::ext::hygiene::{self, Mark, Transparency};
+use syntax::ext::hygiene::{self, Mark};
 use syntax::ext::placeholders::placeholder;
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{self, emit_feature_err, GateIssue};
@@ -331,13 +331,8 @@ impl<'a> base::Resolver for Resolver<'a> {
 
         self.unused_macros.remove(&def_id);
         let ext = self.get_macro(def);
-        if ext.is_modern() {
-            let transparency =
-                if ext.is_transparent() { Transparency::Transparent } else { Transparency::Opaque };
-            invoc.expansion_data.mark.set_transparency(transparency);
-        } else if def_id.krate == BUILTIN_MACROS_CRATE {
-            invoc.expansion_data.mark.set_is_builtin(true);
-        }
+        invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
+        invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
         Ok(Some(ext))
     }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index e2424de4d14..2e9c7d6f96c 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -17,7 +17,7 @@ use syntax_pos::{Span, MultiSpan, DUMMY_SP};
 use edition::Edition;
 use errors::{DiagnosticBuilder, DiagnosticId};
 use ext::expand::{self, AstFragment, Invocation};
-use ext::hygiene::{self, Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext, Transparency};
 use fold::{self, Folder};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
@@ -673,20 +673,14 @@ impl SyntaxExtension {
         }
     }
 
-    pub fn is_modern(&self) -> bool {
+    pub fn default_transparency(&self) -> Transparency {
         match *self {
-            SyntaxExtension::DeclMacro { .. } |
             SyntaxExtension::ProcMacro { .. } |
             SyntaxExtension::AttrProcMacro(..) |
-            SyntaxExtension::ProcMacroDerive(..) => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_transparent(&self) -> bool {
-        match *self {
-            SyntaxExtension::DeclMacro { is_transparent, .. } => is_transparent,
-            _ => false,
+            SyntaxExtension::ProcMacroDerive(..) |
+            SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque,
+            SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent,
+            _ => Transparency::SemiTransparent,
         }
     }
 
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 33d02d0b10a..c7076478332 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -27,16 +27,17 @@ use std::fmt;
 
 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
 #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
-pub struct SyntaxContext(pub(super) u32);
+pub struct SyntaxContext(u32);
 
 #[derive(Copy, Clone, Debug)]
-pub struct SyntaxContextData {
-    pub outer_mark: Mark,
-    pub prev_ctxt: SyntaxContext,
+struct SyntaxContextData {
+    outer_mark: Mark,
+    transparency: Transparency,
+    prev_ctxt: SyntaxContext,
     // This context, but with all transparent and semi-transparent marks filtered away.
-    pub opaque: SyntaxContext,
+    opaque: SyntaxContext,
     // This context, but with all transparent marks filtered away.
-    pub opaque_and_semitransparent: SyntaxContext,
+    opaque_and_semitransparent: SyntaxContext,
 }
 
 /// A mark is a unique id associated with a macro expansion.
@@ -46,14 +47,14 @@ pub struct Mark(u32);
 #[derive(Clone, Debug)]
 struct MarkData {
     parent: Mark,
-    transparency: Transparency,
+    default_transparency: Transparency,
     is_builtin: bool,
     expn_info: Option<ExpnInfo>,
 }
 
 /// A property of a macro expansion that determines how identifiers
 /// produced by that expansion are resolved.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
 pub enum Transparency {
     /// Identifier produced by a transparent expansion is always resolved at call-site.
     /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -71,26 +72,16 @@ pub enum Transparency {
 }
 
 impl Mark {
-    fn fresh_with_data(mark_data: MarkData, data: &mut HygieneData) -> Self {
-        data.marks.push(mark_data);
-        Mark(data.marks.len() as u32 - 1)
-    }
-
     pub fn fresh(parent: Mark) -> Self {
         HygieneData::with(|data| {
-            Mark::fresh_with_data(MarkData {
+            data.marks.push(MarkData {
                 parent,
                 // By default expansions behave like `macro_rules`.
-                transparency: Transparency::SemiTransparent,
+                default_transparency: Transparency::SemiTransparent,
                 is_builtin: false,
                 expn_info: None,
-            }, data)
-        })
-    }
-
-    pub fn fresh_cloned(clone_from: Mark) -> Self {
-        HygieneData::with(|data| {
-            Mark::fresh_with_data(data.marks[clone_from.0 as usize].clone(), data)
+            });
+            Mark(data.marks.len() as u32 - 1)
         })
     }
 
@@ -127,34 +118,21 @@ impl Mark {
         })
     }
 
-    pub fn modern(mut self) -> Mark {
-        HygieneData::with(|data| {
-            while data.marks[self.0 as usize].transparency != Transparency::Opaque {
-                self = data.marks[self.0 as usize].parent;
-            }
-            self
-        })
-    }
-
-    #[inline]
-    pub fn transparency(self) -> Transparency {
-        assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].transparency)
-    }
-
     #[inline]
-    pub fn set_transparency(self, transparency: Transparency) {
+    pub fn set_default_transparency(self, transparency: Transparency) {
         assert_ne!(self, Mark::root());
-        HygieneData::with(|data| data.marks[self.0 as usize].transparency = transparency)
+        HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
     }
 
     #[inline]
     pub fn is_builtin(self) -> bool {
+        assert_ne!(self, Mark::root());
         HygieneData::with(|data| data.marks[self.0 as usize].is_builtin)
     }
 
     #[inline]
     pub fn set_is_builtin(self, is_builtin: bool) {
+        assert_ne!(self, Mark::root());
         HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin)
     }
 
@@ -195,29 +173,48 @@ impl Mark {
             b
         })
     }
+
+    // Used for enabling some compatibility fallback in resolve.
+    #[inline]
+    pub fn looks_like_proc_macro_derive(self) -> bool {
+        HygieneData::with(|data| {
+            let mark_data = &data.marks[self.0 as usize];
+            if mark_data.default_transparency == Transparency::Opaque {
+                if let Some(expn_info) = &mark_data.expn_info {
+                    if let ExpnFormat::MacroAttribute(name) = expn_info.format {
+                        if name.as_str().starts_with("derive(") {
+                            return true;
+                        }
+                    }
+                }
+            }
+            false
+        })
+    }
 }
 
 #[derive(Debug)]
-pub struct HygieneData {
+crate struct HygieneData {
     marks: Vec<MarkData>,
     syntax_contexts: Vec<SyntaxContextData>,
-    markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
+    markings: HashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>,
     default_edition: Edition,
 }
 
 impl HygieneData {
-    pub fn new() -> Self {
+    crate fn new() -> Self {
         HygieneData {
             marks: vec![MarkData {
                 parent: Mark::root(),
                 // If the root is opaque, then loops searching for an opaque mark
                 // will automatically stop after reaching it.
-                transparency: Transparency::Opaque,
+                default_transparency: Transparency::Opaque,
                 is_builtin: true,
                 expn_info: None,
             }],
             syntax_contexts: vec![SyntaxContextData {
                 outer_mark: Mark::root(),
+                transparency: Transparency::Opaque,
                 prev_ctxt: SyntaxContext(0),
                 opaque: SyntaxContext(0),
                 opaque_and_semitransparent: SyntaxContext(0),
@@ -249,6 +246,14 @@ impl SyntaxContext {
         SyntaxContext(0)
     }
 
+    crate fn as_u32(self) -> u32 {
+        self.0
+    }
+
+    crate fn from_u32(raw: u32) -> SyntaxContext {
+        SyntaxContext(raw)
+    }
+
     // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
     // deserializing Spans from the incr. comp. cache.
     // FIXME(mw): This method does not restore MarkData::parent or
@@ -259,7 +264,7 @@ impl SyntaxContext {
         HygieneData::with(|data| {
             data.marks.push(MarkData {
                 parent: Mark::root(),
-                transparency: Transparency::SemiTransparent,
+                default_transparency: Transparency::SemiTransparent,
                 is_builtin: false,
                 expn_info: Some(expansion_info),
             });
@@ -268,6 +273,7 @@ impl SyntaxContext {
 
             data.syntax_contexts.push(SyntaxContextData {
                 outer_mark: mark,
+                transparency: Transparency::SemiTransparent,
                 prev_ctxt: SyntaxContext::empty(),
                 opaque: SyntaxContext::empty(),
                 opaque_and_semitransparent: SyntaxContext::empty(),
@@ -276,22 +282,32 @@ impl SyntaxContext {
         })
     }
 
-    /// Extend a syntax context with a given mark
+    /// Extend a syntax context with a given mark and default transparency for that mark.
     pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
-        if mark.transparency() == Transparency::Opaque {
-            return self.apply_mark_internal(mark);
+        assert_ne!(mark, Mark::root());
+        self.apply_mark_with_transparency(
+            mark, HygieneData::with(|data| data.marks[mark.0 as usize].default_transparency)
+        )
+    }
+
+    /// Extend a syntax context with a given mark and transparency
+    pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency)
+                                        -> SyntaxContext {
+        assert_ne!(mark, Mark::root());
+        if transparency == Transparency::Opaque {
+            return self.apply_mark_internal(mark, transparency);
         }
 
         let call_site_ctxt =
             mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt());
-        let call_site_ctxt = if mark.transparency() == Transparency::SemiTransparent {
+        let call_site_ctxt = if transparency == Transparency::SemiTransparent {
             call_site_ctxt.modern()
         } else {
             call_site_ctxt.modern_and_legacy()
         };
 
         if call_site_ctxt == SyntaxContext::empty() {
-            return self.apply_mark_internal(mark);
+            return self.apply_mark_internal(mark, transparency);
         }
 
         // Otherwise, `mark` is a macros 1.0 definition and the call site is in a
@@ -304,27 +320,26 @@ impl SyntaxContext {
         //
         // See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
         let mut ctxt = call_site_ctxt;
-        for mark in self.marks() {
-            ctxt = ctxt.apply_mark_internal(mark);
+        for (mark, transparency) in self.marks() {
+            ctxt = ctxt.apply_mark_internal(mark, transparency);
         }
-        ctxt.apply_mark_internal(mark)
+        ctxt.apply_mark_internal(mark, transparency)
     }
 
-    fn apply_mark_internal(self, mark: Mark) -> SyntaxContext {
+    fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxContext {
         HygieneData::with(|data| {
             let syntax_contexts = &mut data.syntax_contexts;
-            let transparency = data.marks[mark.0 as usize].transparency;
-
             let mut opaque = syntax_contexts[self.0 as usize].opaque;
             let mut opaque_and_semitransparent =
                 syntax_contexts[self.0 as usize].opaque_and_semitransparent;
 
             if transparency >= Transparency::Opaque {
                 let prev_ctxt = opaque;
-                opaque = *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| {
+                opaque = *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
                     let new_opaque = SyntaxContext(syntax_contexts.len() as u32);
                     syntax_contexts.push(SyntaxContextData {
                         outer_mark: mark,
+                        transparency,
                         prev_ctxt,
                         opaque: new_opaque,
                         opaque_and_semitransparent: new_opaque,
@@ -336,11 +351,12 @@ impl SyntaxContext {
             if transparency >= Transparency::SemiTransparent {
                 let prev_ctxt = opaque_and_semitransparent;
                 opaque_and_semitransparent =
-                        *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| {
+                        *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
                     let new_opaque_and_semitransparent =
                         SyntaxContext(syntax_contexts.len() as u32);
                     syntax_contexts.push(SyntaxContextData {
                         outer_mark: mark,
+                        transparency,
                         prev_ctxt,
                         opaque,
                         opaque_and_semitransparent: new_opaque_and_semitransparent,
@@ -350,11 +366,12 @@ impl SyntaxContext {
             }
 
             let prev_ctxt = self;
-            *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| {
+            *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
                 let new_opaque_and_semitransparent_and_transparent =
                     SyntaxContext(syntax_contexts.len() as u32);
                 syntax_contexts.push(SyntaxContextData {
                     outer_mark: mark,
+                    transparency,
                     prev_ctxt,
                     opaque,
                     opaque_and_semitransparent,
@@ -388,12 +405,13 @@ impl SyntaxContext {
         })
     }
 
-    pub fn marks(mut self) -> Vec<Mark> {
+    pub fn marks(mut self) -> Vec<(Mark, Transparency)> {
         HygieneData::with(|data| {
             let mut marks = Vec::new();
             while self != SyntaxContext::empty() {
-                marks.push(data.syntax_contexts[self.0 as usize].outer_mark);
-                self = data.syntax_contexts[self.0 as usize].prev_ctxt;
+                let ctxt_data = &data.syntax_contexts[self.0 as usize];
+                marks.push((ctxt_data.outer_mark, ctxt_data.transparency));
+                self = ctxt_data.prev_ctxt;
             }
             marks.reverse();
             marks
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 491ce720f36..61af70af47d 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -19,10 +19,10 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
 #![feature(const_fn)]
+#![feature(crate_visibility_modifier)]
 #![feature(custom_attribute)]
 #![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
-#![allow(unused_attributes)]
 #![feature(specialization)]
 #![feature(stdsimd)]
 
diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs
index 601a0273ae9..473aa1bd1b8 100644
--- a/src/libsyntax_pos/span_encoding.rs
+++ b/src/libsyntax_pos/span_encoding.rs
@@ -100,7 +100,7 @@ const INTERNED_INDEX_OFFSET: u32 = 1;
 
 #[inline]
 fn encode(sd: &SpanData) -> Span {
-    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0);
+    let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.as_u32());
 
     let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 &&
                  (len >> INLINE_SIZES[LEN_INDEX]) == 0 &&
@@ -132,7 +132,7 @@ fn decode(span: Span) -> SpanData {
         let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE);
         return with_span_interner(|interner| *interner.get(index));
     };
-    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) }
+    SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext::from_u32(ctxt) }
 }
 
 #[derive(Default)]
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs
new file mode 100644
index 00000000000..6a8d545db49
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs
@@ -0,0 +1,54 @@
+// 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.
+
+// run-pass
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn check(_: TokenStream) -> TokenStream {
+    "
+    type Alias = FromOutside; // OK
+    struct Outer;
+    mod inner {
+        type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+        type Inner = Outer; // `Outer` shouldn't be available from here
+    }
+    ".parse().unwrap()
+}
+
+#[proc_macro_attribute]
+pub fn check_attr(_: TokenStream, _: TokenStream) -> TokenStream {
+    "
+    type AliasAttr = FromOutside; // OK
+    struct OuterAttr;
+    mod inner_attr {
+        type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+        type Inner = OuterAttr; // `OuterAttr` shouldn't be available from here
+    }
+    ".parse().unwrap()
+}
+
+#[proc_macro_derive(CheckDerive)]
+pub fn check_derive(_: TokenStream) -> TokenStream {
+    "
+    type AliasDerive = FromOutside; // OK
+    struct OuterDerive;
+    mod inner_derive {
+        type Alias = FromOutside; // `FromOutside` shouldn't be available from here
+        type Inner = OuterDerive; // `OuterDerive` shouldn't be available from here
+    }
+    ".parse().unwrap()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/generate-mod.rs
new file mode 100644
index 00000000000..ff64421047f
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/generate-mod.rs
@@ -0,0 +1,34 @@
+// 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.
+
+// Modules generated by transparent proc macros still acts as barriers for names (issue #50504).
+
+// aux-build:generate-mod.rs
+
+#![feature(proc_macro, proc_macro_gen, proc_macro_path_invoc)]
+
+extern crate generate_mod;
+
+struct FromOutside;
+
+generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope
+                        //~| ERROR cannot find type `Outer` in this scope
+
+#[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope
+                            //~| ERROR cannot find type `OuterAttr` in this scope
+struct S;
+
+#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
+                                     //~| WARN cannot find type `OuterDerive` in this scope
+                                     //~| WARN this was previously accepted
+                                     //~| WARN this was previously accepted
+struct Z;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/proc-macro/generate-mod.stderr b/src/test/ui-fulldeps/proc-macro/generate-mod.stderr
new file mode 100644
index 00000000000..c024aeffbb0
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/generate-mod.stderr
@@ -0,0 +1,46 @@
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:21:1
+   |
+LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope
+   | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `Outer` in this scope
+  --> $DIR/generate-mod.rs:21:1
+   |
+LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope
+   | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:24:1
+   |
+LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `OuterAttr` in this scope
+  --> $DIR/generate-mod.rs:24:1
+   |
+LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+warning: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:28:10
+   |
+LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = note: #[warn(proc_macro_derive_resolution_fallback)] on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+
+warning: cannot find type `OuterDerive` in this scope
+  --> $DIR/generate-mod.rs:28:10
+   |
+LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/run-pass/hygiene/arguments.rs b/src/test/ui/hygiene/arguments.rs
index 5d9e1863847..958133e7ec5 100644
--- a/src/test/run-pass/hygiene/arguments.rs
+++ b/src/test/ui/hygiene/arguments.rs
@@ -23,5 +23,5 @@ macro m($t:ty, $e:expr) {
 
 fn main() {
     struct S;
-    m!(S, S);
+    m!(S, S); //~ ERROR cannot find type `S` in this scope
 }
diff --git a/src/test/ui/hygiene/arguments.stderr b/src/test/ui/hygiene/arguments.stderr
new file mode 100644
index 00000000000..1b0c23eff29
--- /dev/null
+++ b/src/test/ui/hygiene/arguments.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `S` in this scope
+  --> $DIR/arguments.rs:26:8
+   |
+LL |     m!(S, S); //~ ERROR cannot find type `S` in this scope
+   |        ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/hygiene/generate-mod.rs b/src/test/ui/hygiene/generate-mod.rs
index 90409857dea..2b2108558a0 100644
--- a/src/test/ui/hygiene/generate-mod.rs
+++ b/src/test/ui/hygiene/generate-mod.rs
@@ -12,13 +12,46 @@
 
 #![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_transparent_macro]
-macro genmod() {
-    mod m {
-        type A = S; //~ ERROR cannot find type `S` in this scope
+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
     }
 }
 
-struct S;
+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
+    }
+}}
 
-genmod!();
+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!();
+}
diff --git a/src/test/ui/hygiene/generate-mod.stderr b/src/test/ui/hygiene/generate-mod.stderr
index e79f8528c2c..0c5905c5acb 100644
--- a/src/test/ui/hygiene/generate-mod.stderr
+++ b/src/test/ui/hygiene/generate-mod.stderr
@@ -1,17 +1,56 @@
-error[E0412]: cannot find type `S` in this scope
-  --> $DIR/generate-mod.rs:18:18
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:45:13
    |
-LL |         type A = S; //~ ERROR cannot find type `S` in this scope
-   |                  ^ did you mean `A`?
+LL |     genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope
+   |             ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `Outer` in this scope
+  --> $DIR/generate-mod.rs:45:26
+   |
+LL |     genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope
+   |                          ^^^^^ not found in this scope
+
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:29:18
+   |
+LL |         type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope
+   |                  ^^^^^^^^^^^ not found in this scope
+...
+LL |     genmod_transparent!();
+   |     ---------------------- in this macro invocation
+
+error[E0412]: cannot find type `Outer` in this scope
+  --> $DIR/generate-mod.rs:30:22
+   |
+LL |         type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope
+   |                      ^^^^^ not found in this scope
+...
+LL |     genmod_transparent!();
+   |     ---------------------- in this macro invocation
+
+error[E0412]: cannot find type `FromOutside` in this scope
+  --> $DIR/generate-mod.rs:38:18
+   |
+LL |         type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope
+   |                  ^^^^^^^^^^^ not found in this scope
+...
+LL |     genmod_legacy!();
+   |     ----------------- in this macro invocation
+
+error[E0412]: cannot find type `Outer` in this scope
+  --> $DIR/generate-mod.rs:39:22
+   |
+LL |         type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope
+   |                      ^^^^^ not found in this scope
 ...
-LL | genmod!();
-   | ---------- in this macro invocation
+LL |     genmod_legacy!();
+   |     ----------------- in this macro invocation
 
 error[E0601]: `main` function not found in crate `generate_mod`
    |
    = note: consider adding a `main` function to `$DIR/generate-mod.rs`
 
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
 
 Some errors occurred: E0412, E0601.
 For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/hygiene/globs.rs b/src/test/ui/hygiene/globs.rs
index 7ba217061c6..9785ce6c004 100644
--- a/src/test/ui/hygiene/globs.rs
+++ b/src/test/ui/hygiene/globs.rs
@@ -57,12 +57,26 @@ macro n($i:ident) {
                 }
             }
         }
+        macro n_with_super($j:ident) {
+            mod test {
+                use super::*;
+                fn g() {
+                    let _: u32 = $i();
+                    let _: () = f();
+                    super::$j();
+                }
+            }
+        }
 
-        n!(f);
+        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/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr
index d77242e135d..7df2e31f9a7 100644
--- a/src/test/ui/hygiene/globs.stderr
+++ b/src/test/ui/hygiene/globs.stderr
@@ -30,13 +30,23 @@ LL | use bar::g;
    |
 LL | use foo::test2::test::g;
    |
-LL | use foo::test::g;
+LL | use foo::test2::test::g;
    |
 LL | use foo::test::g;
    |
+and 2 other candidates
+
+error[E0425]: cannot find function `f` in this scope
+  --> $DIR/globs.rs:71:12
+   |
+LL | n!(f);
+   | ------ in this macro invocation
+...
+LL |         n!(f); //~ ERROR cannot find function `f` in this scope
+   |            ^ not found in this scope
 
 error[E0425]: cannot find function `f` in this scope
-  --> $DIR/globs.rs:64:17
+  --> $DIR/globs.rs:75:17
    |
 LL | n!(f);
    | ------ in this macro invocation
@@ -44,6 +54,6 @@ LL | n!(f);
 LL |                 f //~ ERROR cannot find function `f` in this scope
    |                 ^ not found in this scope
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0425`.