about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs13
-rw-r--r--src/librustc_resolve/lib.rs21
-rw-r--r--src/librustc_resolve/macros.rs200
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs6
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/expand.rs2
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs16
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs12
-rw-r--r--src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs10
-rw-r--r--src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr21
-rw-r--r--src/test/ui-fulldeps/proc-macro/issue-53481.rs22
11 files changed, 221 insertions, 106 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index d1a05964c8f..7d9139df415 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -13,7 +13,7 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
-use macros::{InvocationData, LegacyScope};
+use macros::{InvocationData, ParentScope, LegacyScope};
 use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
 use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
@@ -1061,8 +1061,15 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
 
     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
         if !attr.is_sugared_doc && is_builtin_attr(attr) {
-            self.resolver.current_module.builtin_attrs.borrow_mut().push((
-                attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
+            let parent_scope = ParentScope {
+                module: self.resolver.current_module.nearest_item_scope(),
+                expansion: self.expansion,
+                legacy: self.current_legacy_scope,
+                // Let's hope discerning built-in attributes from derive helpers is not necessary
+                derives: Vec::new(),
+            };
+            parent_scope.module.builtin_attrs.borrow_mut().push((
+                attr.path.segments[0].ident, parent_scope
             ));
         }
         visit::walk_attribute(self, attr);
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index c725d56d0cf..93f1c20661b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -80,7 +80,7 @@ use std::mem::replace;
 use rustc_data_structures::sync::Lrc;
 
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
-use macros::{InvocationData, LegacyBinding, LegacyScope};
+use macros::{InvocationData, LegacyBinding, ParentScope};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -1009,9 +1009,9 @@ pub struct ModuleData<'a> {
     normal_ancestor_id: DefId,
 
     resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
-    legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
+    legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>, Option<Def>)>>,
     macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
-    builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,
+    builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
 
     // Macro invocations that can expand into items in this module.
     unresolved_invocations: RefCell<FxHashSet<Mark>>,
@@ -3494,16 +3494,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         path_span: Span,
         crate_lint: CrateLint,
     ) -> PathResult<'a> {
-        self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(),
-                                                record_used, path_span, crate_lint)
+        let parent_scope = ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
+        self.resolve_path_with_parent_scope(base_module, path, opt_ns, &parent_scope,
+                                            record_used, path_span, crate_lint)
     }
 
-    fn resolve_path_with_parent_expansion(
+    fn resolve_path_with_parent_scope(
         &mut self,
         base_module: Option<ModuleOrUniformRoot<'a>>,
         path: &[Ident],
         opt_ns: Option<Namespace>, // `None` indicates a module path
-        parent_expansion: Mark,
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         path_span: Span,
         crate_lint: CrateLint,
@@ -3511,6 +3512,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         let mut module = base_module;
         let mut allow_super = true;
         let mut second_binding = None;
+        self.current_module = parent_scope.module;
 
         debug!(
             "resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \
@@ -3596,9 +3598,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
             } else if opt_ns == Some(MacroNS) {
                 assert!(ns == TypeNS);
-                self.resolve_lexical_macro_path_segment(ident, ns, None, parent_expansion,
-                                                        record_used, record_used, path_span)
-                                                        .map(|(binding, _)| binding)
+                self.resolve_lexical_macro_path_segment(ident, ns, None, parent_scope, record_used,
+                                                        record_used, path_span).map(|(b, _)| b)
             } else {
                 let record_used_id =
                     if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 7733ce475e3..f687e022a41 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -101,6 +101,15 @@ pub enum LegacyScope<'a> {
     Invocation(&'a InvocationData<'a>),
 }
 
+/// Everything you need to resolve a macro path.
+#[derive(Clone)]
+pub struct ParentScope<'a> {
+    crate module: Module<'a>,
+    crate expansion: Mark,
+    crate legacy: LegacyScope<'a>,
+    crate derives: Vec<ast::Path>,
+}
+
 pub struct ProcMacError {
     crate_name: Symbol,
     name: Symbol,
@@ -326,14 +335,15 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
             InvocationKind::Attr { attr: None, .. } =>
                 return Ok(None),
             InvocationKind::Attr { attr: Some(ref attr), ref traits, .. } =>
-                (&attr.path, MacroKind::Attr, &traits[..]),
+                (&attr.path, MacroKind::Attr, traits.clone()),
             InvocationKind::Bang { ref mac, .. } =>
-                (&mac.node.path, MacroKind::Bang, &[][..]),
+                (&mac.node.path, MacroKind::Bang, Vec::new()),
             InvocationKind::Derive { ref path, .. } =>
-                (path, MacroKind::Derive, &[][..]),
+                (path, MacroKind::Derive, Vec::new()),
         };
 
-        let (def, ext) = self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?;
+        let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
+        let (def, ext) = self.resolve_macro_to_def(path, kind, &parent_scope, force)?;
 
         if let Def::Macro(def_id, _) = def {
             self.macro_defs.insert(invoc.expansion_data.mark, def_id);
@@ -349,9 +359,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
     }
 
     fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
-                          derives_in_scope: &[ast::Path], force: bool)
+                          derives_in_scope: Vec<ast::Path>, force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy> {
-        Ok(self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?.1)
+        let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
+        Ok(self.resolve_macro_to_def(path, kind, &parent_scope, force)?.1)
     }
 
     fn check_unused_macros(&self) {
@@ -373,10 +384,28 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
 }
 
 impl<'a, 'cl> Resolver<'a, 'cl> {
-    fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
-                            derives_in_scope: &[ast::Path], force: bool)
-                            -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
-        let def = self.resolve_macro_to_def_inner(path, kind, invoc_id, derives_in_scope, force);
+    pub fn dummy_parent_scope(&mut self) -> ParentScope<'a> {
+        self.invoc_parent_scope(Mark::root(), Vec::new())
+    }
+
+    fn invoc_parent_scope(&mut self, invoc_id: Mark, derives: Vec<ast::Path>) -> ParentScope<'a> {
+        let invoc = self.invocations[&invoc_id];
+        ParentScope {
+            module: invoc.module.get().nearest_item_scope(),
+            expansion: invoc_id.parent(),
+            legacy: invoc.parent_legacy_scope.get(),
+            derives,
+        }
+    }
+
+    fn resolve_macro_to_def(
+        &mut self,
+        path: &ast::Path,
+        kind: MacroKind,
+        parent_scope: &ParentScope<'a>,
+        force: bool,
+    ) -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
+        let def = self.resolve_macro_to_def_inner(path, kind, parent_scope, force);
 
         // Report errors and enforce feature gates for the resolved macro.
         if def != Err(Determinacy::Undetermined) {
@@ -440,15 +469,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         Ok((def, self.get_macro(def)))
     }
 
-    pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
-                                      derives_in_scope: &[ast::Path], force: bool)
-                                      -> Result<Def, Determinacy> {
+    pub fn resolve_macro_to_def_inner(
+        &mut self,
+        path: &ast::Path,
+        kind: MacroKind,
+        parent_scope: &ParentScope<'a>,
+        force: bool,
+    ) -> Result<Def, Determinacy> {
         let ast::Path { ref segments, span } = *path;
         let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
-        let invocation = self.invocations[&invoc_id];
-        let parent_expansion = invoc_id.parent();
-        let parent_legacy_scope = invocation.parent_legacy_scope.get();
-        self.current_module = invocation.module.get().nearest_item_scope();
 
         // Possibly apply the macro helper hack
         if kind == MacroKind::Bang && path.len() == 1 &&
@@ -458,9 +487,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
 
         if path.len() > 1 {
-            let def = match self.resolve_path_with_parent_expansion(None, &path, Some(MacroNS),
-                                                                    parent_expansion, false, span,
-                                                                    CrateLint::No) {
+            let def = match self.resolve_path_with_parent_scope(None, &path, Some(MacroNS),
+                                                                parent_scope, false, span,
+                                                                CrateLint::No) {
                 PathResult::NonModule(path_res) => match path_res.base_def() {
                     Def::Err => Err(Determinacy::Determined),
                     def @ _ => {
@@ -480,19 +509,17 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     Err(Determinacy::Determined)
                 },
             };
-            self.current_module.macro_resolutions.borrow_mut()
+            parent_scope.module.macro_resolutions.borrow_mut()
                 .push((path.into_boxed_slice(), span));
             return def;
         }
 
-        let legacy_resolution = self.resolve_legacy_scope(
-            path[0], Some(kind), parent_expansion, parent_legacy_scope, false
-        );
-        let result = if let Some(legacy_binding) = legacy_resolution {
+        let result = if let Some(legacy_binding) = self.resolve_legacy_scope(path[0], Some(kind),
+                                                                             parent_scope, false) {
             Ok(legacy_binding.def())
         } else {
             match self.resolve_lexical_macro_path_segment(path[0], MacroNS, Some(kind),
-                                                          parent_expansion, false, force, span) {
+                                                          parent_scope, false, force, span) {
                 Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
                 Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
                 Err(Determinacy::Determined) => {
@@ -502,44 +529,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
         };
 
-        self.current_module.legacy_macro_resolutions.borrow_mut()
-            .push((path[0], kind, parent_expansion, parent_legacy_scope, result.ok()));
-
-        if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
-            return result;
-        }
+        parent_scope.module.legacy_macro_resolutions.borrow_mut()
+            .push((path[0], kind, parent_scope.clone(), result.ok()));
 
-        // At this point we've found that the `attr` is determinately unresolved and thus can be
-        // interpreted as a custom attribute. Normally custom attributes are feature gated, but
-        // it may be a custom attribute whitelisted by a derive macro and they do not require
-        // a feature gate.
-        //
-        // So here we look through all of the derive annotations in scope and try to resolve them.
-        // If they themselves successfully resolve *and* one of the resolved derive macros
-        // whitelists this attribute's name, then this is a registered attribute and we can convert
-        // it from a "generic custom attrite" into a "known derive helper attribute".
-        assert!(kind == MacroKind::Attr);
-        enum ConvertToDeriveHelper { Yes, No, DontKnow }
-        let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
-        for derive in derives_in_scope {
-            match self.resolve_macro_path(derive, MacroKind::Derive, invoc_id, &[], force) {
-                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
-                    if inert_attrs.contains(&path[0].name) {
-                        convert_to_derive_helper = ConvertToDeriveHelper::Yes;
-                        break
-                    }
-                },
-                Err(Determinacy::Undetermined) =>
-                    convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
-                Err(Determinacy::Determined) => {}
-            }
-        }
-
-        match convert_to_derive_helper {
-            ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
-            ConvertToDeriveHelper::No => result,
-            ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
-        }
+        result
     }
 
     // Resolve the initial segment of a non-global macro path
@@ -551,7 +544,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         mut ident: Ident,
         ns: Namespace,
         kind: Option<MacroKind>,
-        parent_expansion: Mark,
+        parent_scope: &ParentScope<'a>,
         record_used: bool,
         force: bool,
         path_span: Span,
@@ -580,6 +573,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         // 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
         // 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
         // 4. Language prelude: builtin attributes (closed, controlled).
+        // N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
+        //    are currently reported as errors. They should be higher in priority than preludes
+        //    and maybe even names in modules according to the "general principles" above. They
+        //    also should be subject to restricted shadowing because are effectively produced by
+        //    derives (you need to resolve the derive first to add helpers into scope), but they
+        //    should be available before the derive is expanded for compatibility.
+        //    It's mess in general, so we are being conservative for now.
 
         assert!(ns == TypeNS  || ns == MacroNS);
         assert!(force || !record_used); // `record_used` implies `force`
@@ -603,6 +603,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             MacroUsePrelude,
             BuiltinMacros,
             BuiltinAttrs,
+            DeriveHelpers,
             ExternPrelude,
             ToolPrelude,
             StdLibPrelude,
@@ -610,8 +611,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
 
         // Go through all the scopes and try to resolve the name.
-        let mut where_to_resolve = WhereToResolve::Module(self.current_module);
-        let mut use_prelude = !self.current_module.no_implicit_prelude;
+        let mut where_to_resolve = WhereToResolve::Module(parent_scope.module);
+        let mut use_prelude = !parent_scope.module.no_implicit_prelude;
         loop {
             let result = match where_to_resolve {
                 WhereToResolve::Module(module) => {
@@ -652,6 +653,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         Err(Determinacy::Determined)
                     }
                 }
+                WhereToResolve::DeriveHelpers => {
+                    let mut result = Err(Determinacy::Determined);
+                    for derive in &parent_scope.derives {
+                        let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
+                        if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
+                                                                        &parent_scope, force) {
+                            if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
+                                if helper_attrs.contains(&ident.name) {
+                                    let binding =
+                                        (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+                                        ty::Visibility::Public, derive.span, Mark::root())
+                                        .to_name_binding(self.arenas);
+                                    result = Ok((binding, FromPrelude(false)));
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    result
+                }
                 WhereToResolve::ExternPrelude => {
                     if use_prelude && self.extern_prelude.contains(&ident.name) {
                         if !self.session.features_untracked().extern_prelude &&
@@ -731,7 +752,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     }
                     WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
                     WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
-                    WhereToResolve::BuiltinAttrs => break, // nowhere else to search
+                    WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
+                    WhereToResolve::DeriveHelpers => break, // nowhere else to search
                     WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
                     WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
                     WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
@@ -753,9 +775,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
                     if let Some(innermost_result) = innermost_result {
                         // Found another solution, if the first one was "weak", report an error.
-                        if result.0.def() != innermost_result.0.def() &&
+                        let (def, innermost_def) = (result.0.def(), innermost_result.0.def());
+                        if def != innermost_def &&
                            (innermost_result.0.is_glob_import() ||
-                            innermost_result.0.may_appear_after(parent_expansion, result.0)) {
+                            innermost_result.0.may_appear_after(parent_scope.expansion, result.0) ||
+                            innermost_def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper) ||
+                            def == Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 ident,
                                 b1: innermost_result.0,
@@ -797,13 +822,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
     }
 
-    fn resolve_legacy_scope(&mut self,
-                            ident: Ident,
-                            kind: Option<MacroKind>,
-                            parent_expansion: Mark,
-                            parent_legacy_scope: LegacyScope<'a>,
-                            record_used: bool)
-                            -> Option<&'a NameBinding<'a>> {
+    fn resolve_legacy_scope(
+        &mut self,
+        ident: Ident,
+        kind: Option<MacroKind>,
+        parent_scope: &ParentScope<'a>,
+        record_used: bool,
+    ) -> Option<&'a NameBinding<'a>> {
         if macro_kind_mismatch(ident.name, kind, Some(MacroKind::Bang)) {
             return None;
         }
@@ -824,7 +849,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         let mut innermost_result: Option<&NameBinding> = None;
 
         // Go through all the scopes and try to resolve the name.
-        let mut where_to_resolve = parent_legacy_scope;
+        let mut where_to_resolve = parent_scope.legacy;
         loop {
             let result = match where_to_resolve {
                 LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
@@ -852,7 +877,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     if let Some(innermost_result) = innermost_result {
                         // Found another solution, if the first one was "weak", report an error.
                         if result.def() != innermost_result.def() &&
-                           innermost_result.may_appear_after(parent_expansion, result) {
+                           innermost_result.may_appear_after(parent_scope.expansion, result) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 ident,
                                 b1: innermost_result,
@@ -889,14 +914,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
         }
 
-        for &(ident, kind, parent_expansion, parent_legacy_scope, def)
-                in module.legacy_macro_resolutions.borrow().iter() {
+        let legacy_macro_resolutions =
+            mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
+        for (ident, kind, parent_scope, def) in legacy_macro_resolutions {
             let span = ident.span;
             let legacy_resolution = self.resolve_legacy_scope(
-                ident, Some(kind), parent_expansion, parent_legacy_scope, true
+                ident, Some(kind), &parent_scope, true
             );
             let resolution = self.resolve_lexical_macro_path_segment(
-                ident, MacroNS, Some(kind), parent_expansion, true, true, span
+                ident, MacroNS, Some(kind), &parent_scope, true, true, span
             );
 
             let check_consistency = |this: &Self, new_def: Def| {
@@ -932,7 +958,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 (Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
                         if legacy_binding.def() != binding.def_ignoring_ambiguity() &&
                            (!from_prelude ||
-                            legacy_binding.may_appear_after(parent_expansion, binding)) => {
+                            legacy_binding.may_appear_after(parent_scope.expansion, binding)) => {
                     self.report_ambiguity_error(ident, legacy_binding, binding);
                 },
                 // OK, non-macro-expanded legacy wins over prelude even if defs are different
@@ -953,13 +979,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             };
         }
 
-        for &(ident, parent_expansion, parent_legacy_scope)
-                in module.builtin_attrs.borrow().iter() {
+        let builtin_attrs = mem::replace(&mut *module.builtin_attrs.borrow_mut(), Vec::new());
+        for (ident, parent_scope) in builtin_attrs {
             let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope(
-                ident, Some(MacroKind::Attr), parent_expansion, parent_legacy_scope, true
+                ident, Some(MacroKind::Attr), &parent_scope, true
             );
             let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment(
-                ident, MacroNS, Some(MacroKind::Attr), parent_expansion, true, true, ident.span
+                ident, MacroNS, Some(MacroKind::Attr), &parent_scope, true, true, ident.span
             ).map(|(binding, _)| binding).ok();
 
             if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index cced30d1a0c..181fe379248 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -398,12 +398,12 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstor
 /// Resolve a string as a macro
 fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
     use syntax::ext::base::{MacroKind, SyntaxExtension};
-    use syntax::ext::hygiene::Mark;
     let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
     let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
     let mut resolver = cx.resolver.borrow_mut();
-    let mark = Mark::root();
-    if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, mark, &[], false) {
+    let parent_scope = resolver.dummy_parent_scope();
+    if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang,
+                                                         &parent_scope, false) {
         if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
             return Some(def);
         }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 07c3e578e5b..e42624bf41f 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -730,7 +730,7 @@ pub trait Resolver {
     fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
                                 -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
     fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
-                          derives_in_scope: &[ast::Path], force: bool)
+                          derives_in_scope: Vec<ast::Path>, force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy>;
 
     fn check_unused_macros(&self);
@@ -768,7 +768,7 @@ impl Resolver for DummyResolver {
         Err(Determinacy::Determined)
     }
     fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
-                          _derives_in_scope: &[ast::Path], _force: bool)
+                          _derives_in_scope: Vec<ast::Path>, _force: bool)
                           -> Result<Lrc<SyntaxExtension>, Determinacy> {
         Err(Determinacy::Determined)
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 7b4e1814a33..40903e8ad6c 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -384,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         let mark = Mark::fresh(self.cx.current_expansion.mark);
                         derives.push(mark);
                         let item = match self.cx.resolver.resolve_macro_path(
-                                path, MacroKind::Derive, Mark::root(), &[], false) {
+                                path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
                             Ok(ext) => match *ext {
                                 BuiltinDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs
new file mode 100644
index 00000000000..0fd8aa5638a
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/derive-helper-shadowing.rs
@@ -0,0 +1,16 @@
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn my_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+
+#[proc_macro_derive(MyTrait, attributes(my_attr))]
+pub fn derive(input: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
new file mode 100644
index 00000000000..9554cdde490
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/issue-53481.rs
@@ -0,0 +1,12 @@
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_derive(MyTrait, attributes(my_attr))]
+pub fn foo(_: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
new file mode 100644
index 00000000000..c2357d501ee
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.rs
@@ -0,0 +1,10 @@
+// aux-build:derive-helper-shadowing.rs
+
+extern crate derive_helper_shadowing;
+use derive_helper_shadowing::*;
+
+#[derive(MyTrait)]
+#[my_attr] //~ ERROR `my_attr` is ambiguous
+struct S;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr
new file mode 100644
index 00000000000..d597b577bb7
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/derive-helper-shadowing.stderr
@@ -0,0 +1,21 @@
+error[E0659]: `my_attr` is ambiguous
+  --> $DIR/derive-helper-shadowing.rs:7:3
+   |
+LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
+   |   ^^^^^^^ ambiguous name
+   |
+note: `my_attr` could refer to the name imported here
+  --> $DIR/derive-helper-shadowing.rs:4:5
+   |
+LL | use derive_helper_shadowing::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `my_attr` could also refer to the name defined here
+  --> $DIR/derive-helper-shadowing.rs:6:10
+   |
+LL | #[derive(MyTrait)]
+   |          ^^^^^^^
+   = note: consider adding an explicit import of `my_attr` to disambiguate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui-fulldeps/proc-macro/issue-53481.rs b/src/test/ui-fulldeps/proc-macro/issue-53481.rs
new file mode 100644
index 00000000000..479fd1db630
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/issue-53481.rs
@@ -0,0 +1,22 @@
+// compile-pass
+// aux-build:issue-53481.rs
+
+#[macro_use]
+extern crate issue_53481;
+
+mod m1 {
+    use m2::MyTrait;
+
+    #[derive(MyTrait)]
+    struct A {}
+}
+
+mod m2 {
+    pub type MyTrait = u8;
+
+    #[derive(MyTrait)]
+    #[my_attr]
+    struct B {}
+}
+
+fn main() {}