about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-08-21 20:33:31 +0000
committerbors <bors@rust-lang.org>2018-08-21 20:33:31 +0000
commitd0d81b7fc1421859ba0218e8a437af29ae3b0967 (patch)
treea9708466f9330e1ebc110f2e82a62905665de54b
parent2d6d3acf4f6f405af1fcf178300a0728496de138 (diff)
parent82619ea2bdb3e1107a1832a31aabcf1b3dd9126c (diff)
downloadrust-d0d81b7fc1421859ba0218e8a437af29ae3b0967.tar.gz
rust-d0d81b7fc1421859ba0218e8a437af29ae3b0967.zip
Auto merge of #53471 - petrochenkov:biattr2, r=oli-obk
resolve: Some macro resolution refactoring

Work towards completing https://github.com/rust-lang/rust/pull/50911#issuecomment-411605393

The last commit also fixes https://github.com/rust-lang/rust/issues/53269 by not using `def_id()` on `Def::Err` and also fixes https://github.com/rust-lang/rust/issues/53512.
-rw-r--r--src/librustc_resolve/lib.rs75
-rw-r--r--src/librustc_resolve/macros.rs474
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs4
-rw-r--r--src/libsyntax/ext/base.rs19
-rw-r--r--src/libsyntax/ext/expand.rs15
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs2
-rw-r--r--src/test/ui-fulldeps/proc-macro/macro-namespace-reserved-2.stderr18
-rw-r--r--src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr2
-rw-r--r--src/test/ui/custom_attribute.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_attribute.stderr52
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_derive.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-tool_attributes.stderr4
-rw-r--r--src/test/ui/imports/issue-53269.rs21
-rw-r--r--src/test/ui/imports/issue-53269.stderr27
-rw-r--r--src/test/ui/imports/issue-53512.rs17
-rw-r--r--src/test/ui/imports/issue-53512.stderr9
-rw-r--r--src/test/ui/imports/macros.stderr6
-rw-r--r--src/test/ui/imports/shadow_builtin_macros.rs4
-rw-r--r--src/test/ui/imports/shadow_builtin_macros.stderr14
-rw-r--r--src/test/ui/issues/issue-32655.stderr8
-rw-r--r--src/test/ui/issues/issue-49074.stderr4
-rw-r--r--src/test/ui/macros/macro-reexport-removed.stderr4
-rw-r--r--src/test/ui/reserved/reserved-attr-on-macro.stderr4
-rw-r--r--src/test/ui/span/issue-36530.stderr8
25 files changed, 423 insertions, 388 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 4a63311c48a..c79a4a93f27 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, MacroBinding};
+use macros::{InvocationData, LegacyBinding};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -1399,7 +1399,7 @@ pub struct Resolver<'a, 'b: 'a> {
     proc_mac_errors: Vec<macros::ProcMacError>,
     /// crate-local macro expanded `macro_export` referred to by a module-relative path
     macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
-
+    /// macro-expanded `macro_rules` shadowing existing macros
     disallowed_shadowing: Vec<&'a LegacyBinding<'a>>,
 
     arenas: &'a ResolverArenas<'a>,
@@ -3529,7 +3529,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             } else if opt_ns == Some(MacroNS) {
                 assert!(ns == TypeNS);
                 self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
-                                                        false, path_span).map(MacroBinding::binding)
+                                                        false, path_span).map(|(b, _)| b)
             } else {
                 let record_used_id =
                     if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
@@ -4431,6 +4431,42 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         vis.is_accessible_from(module.normal_ancestor_id, self)
     }
 
+    fn report_ambiguity_error(
+        &self, name: Name, span: Span, _lexical: bool,
+        def1: Def, is_import1: bool, is_glob1: bool, from_expansion1: bool, span1: Span,
+        def2: Def, is_import2: bool, _is_glob2: bool, _from_expansion2: bool, span2: Span,
+    ) {
+        let participle = |is_import: bool| if is_import { "imported" } else { "defined" };
+        let msg1 = format!("`{}` could refer to the name {} here", name, participle(is_import1));
+        let msg2 =
+            format!("`{}` could also refer to the name {} here", name, participle(is_import2));
+        let note = if from_expansion1 {
+            Some(if let Def::Macro(..) = def1 {
+                format!("macro-expanded {} do not shadow",
+                        if is_import1 { "macro imports" } else { "macros" })
+            } else {
+                format!("macro-expanded {} do not shadow when used in a macro invocation path",
+                        if is_import1 { "imports" } else { "items" })
+            })
+        } else if is_glob1 {
+            Some(format!("consider adding an explicit import of `{}` to disambiguate", name))
+        } else {
+            None
+        };
+
+        let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
+        err.span_note(span1, &msg1);
+        match def2 {
+            Def::Macro(..) if span2.is_dummy() =>
+                err.note(&format!("`{}` is also a builtin macro", name)),
+            _ => err.span_note(span2, &msg2),
+        };
+        if let Some(note) = note {
+            err.note(&note);
+        }
+        err.emit();
+    }
+
     fn report_errors(&mut self, krate: &Crate) {
         self.report_shadowing_errors();
         self.report_with_use_injections(krate);
@@ -4446,30 +4482,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         }
 
         for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
-            if !reported_spans.insert(span) { continue }
-            let participle = |binding: &NameBinding| {
-                if binding.is_import() { "imported" } else { "defined" }
-            };
-            let msg1 = format!("`{}` could refer to the name {} here", name, participle(b1));
-            let msg2 = format!("`{}` could also refer to the name {} here", name, participle(b2));
-            let note = if b1.expansion == Mark::root() || !lexical && b1.is_glob_import() {
-                format!("consider adding an explicit import of `{}` to disambiguate", name)
-            } else if let Def::Macro(..) = b1.def() {
-                format!("macro-expanded {} do not shadow",
-                        if b1.is_import() { "macro imports" } else { "macros" })
-            } else {
-                format!("macro-expanded {} do not shadow when used in a macro invocation path",
-                        if b1.is_import() { "imports" } else { "items" })
-            };
-
-            let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
-            err.span_note(b1.span, &msg1);
-            match b2.def() {
-                Def::Macro(..) if b2.span.is_dummy() =>
-                    err.note(&format!("`{}` is also a builtin macro", name)),
-                _ => err.span_note(b2.span, &msg2),
-            };
-            err.note(&note).emit();
+            if reported_spans.insert(span) {
+                self.report_ambiguity_error(
+                    name, span, lexical,
+                    b1.def(), b1.is_import(), b1.is_glob_import(),
+                    b1.expansion != Mark::root(), b1.span,
+                    b2.def(), b2.is_import(), b2.is_glob_import(),
+                    b2.expansion != Mark::root(), b2.span,
+                );
+            }
         }
 
         for &PrivacyError(span, name, binding) in &self.privacy_errors {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 8f2e76d8866..1161d57417b 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -43,6 +43,9 @@ use std::cell::Cell;
 use std::mem;
 use rustc_data_structures::sync::Lrc;
 
+crate struct FromPrelude(bool);
+crate struct FromExpansion(bool);
+
 #[derive(Clone)]
 pub struct InvocationData<'a> {
     pub module: Cell<Module<'a>>,
@@ -80,6 +83,12 @@ pub struct LegacyBinding<'a> {
     pub span: Span,
 }
 
+impl<'a> LegacyBinding<'a> {
+    fn def(&self) -> Def {
+        Def::Macro(self.def_id, MacroKind::Bang)
+    }
+}
+
 pub struct ProcMacError {
     crate_name: Symbol,
     name: Symbol,
@@ -88,37 +97,6 @@ pub struct ProcMacError {
     warn_msg: &'static str,
 }
 
-#[derive(Copy, Clone)]
-pub enum MacroBinding<'a> {
-    Legacy(&'a LegacyBinding<'a>),
-    Global(&'a NameBinding<'a>),
-    Modern(&'a NameBinding<'a>),
-}
-
-impl<'a> MacroBinding<'a> {
-    pub fn span(self) -> Span {
-        match self {
-            MacroBinding::Legacy(binding) => binding.span,
-            MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding.span,
-        }
-    }
-
-    pub fn binding(self) -> &'a NameBinding<'a> {
-        match self {
-            MacroBinding::Global(binding) | MacroBinding::Modern(binding) => binding,
-            MacroBinding::Legacy(_) => panic!("unexpected MacroBinding::Legacy"),
-        }
-    }
-
-    pub fn def_ignoring_ambiguity(self) -> Def {
-        match self {
-            MacroBinding::Legacy(binding) => Def::Macro(binding.def_id, MacroKind::Bang),
-            MacroBinding::Global(binding) | MacroBinding::Modern(binding) =>
-                binding.def_ignoring_ambiguity(),
-        }
-    }
-}
-
 impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -319,94 +297,38 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
         None
     }
 
-    fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool)
-                     -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
-        let def = match invoc.kind {
-            InvocationKind::Attr { attr: None, .. } => return Ok(None),
-            _ => self.resolve_invoc_to_def(invoc, scope, force)?,
+    fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
+                                -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
+        let (path, kind, derives_in_scope) = match invoc.kind {
+            InvocationKind::Attr { attr: None, .. } =>
+                return Ok(None),
+            InvocationKind::Attr { attr: Some(ref attr), ref traits, .. } =>
+                (&attr.path, MacroKind::Attr, &traits[..]),
+            InvocationKind::Bang { ref mac, .. } =>
+                (&mac.node.path, MacroKind::Bang, &[][..]),
+            InvocationKind::Derive { ref path, .. } =>
+                (path, MacroKind::Derive, &[][..]),
         };
-        if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
-            self.report_proc_macro_stub(invoc.span());
-            return Err(Determinacy::Determined);
-        } else if let Def::NonMacroAttr(attr_kind) = def {
-            // Note that not only attributes, but anything in macro namespace can result in a
-            // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report the error
-            // below for these cases.
-            let is_attr_invoc =
-                if let InvocationKind::Attr { .. } = invoc.kind { true } else { false };
-            let path = invoc.path().expect("no path for non-macro attr");
-            match attr_kind {
-                NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper |
-                NonMacroAttrKind::Custom if is_attr_invoc => {
-                    let features = self.session.features_untracked();
-                    if attr_kind == NonMacroAttrKind::Tool &&
-                       !features.tool_attributes {
-                        feature_err(&self.session.parse_sess, "tool_attributes",
-                                    invoc.span(), GateIssue::Language,
-                                    "tool attributes are unstable").emit();
-                    }
-                    if attr_kind == NonMacroAttrKind::Custom {
-                        assert!(path.segments.len() == 1);
-                        let name = path.segments[0].ident.name.as_str();
-                        if name.starts_with("rustc_") {
-                            if !features.rustc_attrs {
-                                let msg = "unless otherwise specified, attributes with the prefix \
-                                        `rustc_` are reserved for internal compiler diagnostics";
-                                feature_err(&self.session.parse_sess, "rustc_attrs", invoc.span(),
-                                            GateIssue::Language, &msg).emit();
-                            }
-                        } else if name.starts_with("derive_") {
-                            if !features.custom_derive {
-                                feature_err(&self.session.parse_sess, "custom_derive", invoc.span(),
-                                            GateIssue::Language, EXPLAIN_DERIVE_UNDERSCORE).emit();
-                            }
-                        } else if !features.custom_attribute {
-                            let msg = format!("The attribute `{}` is currently unknown to the \
-                                               compiler and may have meaning added to it in the \
-                                               future", path);
-                            feature_err(&self.session.parse_sess, "custom_attribute", invoc.span(),
-                                        GateIssue::Language, &msg).emit();
-                        }
-                    }
 
-                    return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr {
-                        mark_used: attr_kind == NonMacroAttrKind::Tool,
-                    })));
-                }
-                _ => {
-                    self.report_non_macro_attr(path.span, def);
-                    return Err(Determinacy::Determined);
-                }
-            }
+        let (def, ext) = self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?;
+
+        if let Def::Macro(def_id, _) = def {
+            self.macro_defs.insert(invoc.expansion_data.mark, def_id);
+            let normal_module_def_id =
+                self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
+            self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
+                                                            normal_module_def_id);
+            invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
+            invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE);
         }
-        let def_id = def.def_id();
-
-        self.macro_defs.insert(invoc.expansion_data.mark, def_id);
-        let normal_module_def_id =
-            self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
-        self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
-                                                        normal_module_def_id);
-
-        self.unused_macros.remove(&def_id);
-        let ext = self.get_macro(def);
-        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))
     }
 
-    fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-                     -> Result<Lrc<SyntaxExtension>, Determinacy> {
-        self.resolve_macro_to_def(scope, path, kind, force).and_then(|def| {
-            if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
-                self.report_proc_macro_stub(path.span);
-                return Err(Determinacy::Determined);
-            } else if let Def::NonMacroAttr(..) = def {
-                self.report_non_macro_attr(path.span, def);
-                return Err(Determinacy::Determined);
-            }
-            self.unused_macros.remove(&def.def_id());
-            Ok(self.get_macro(def))
-        })
+    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+                          derives_in_scope: &[ast::Path], force: bool)
+                          -> Result<Lrc<SyntaxExtension>, Determinacy> {
+        Ok(self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?.1)
     }
 
     fn check_unused_macros(&self) {
@@ -428,95 +350,91 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
 }
 
 impl<'a, 'cl> Resolver<'a, 'cl> {
-    fn report_proc_macro_stub(&self, span: Span) {
-        self.session.span_err(span,
-                              "can't use a procedural macro from the same crate that defines it");
-    }
+    fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+                            derives_in_scope: &[ast::Path], force: bool)
+                            -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> {
+        let def = self.resolve_macro_to_def_inner(path, kind, scope, derives_in_scope, force);
 
-    fn report_non_macro_attr(&self, span: Span, def: Def) {
-        self.session.span_err(span, &format!("expected a macro, found {}", def.kind_name()));
-    }
-
-    fn resolve_invoc_to_def(&mut self, invoc: &Invocation, scope: Mark, force: bool)
-                            -> Result<Def, Determinacy> {
-        let (attr, traits) = match invoc.kind {
-            InvocationKind::Attr { ref attr, ref traits, .. } => (attr, traits),
-            InvocationKind::Bang { ref mac, .. } => {
-                return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
-            }
-            InvocationKind::Derive { ref path, .. } => {
-                return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force);
+        // Report errors and enforce feature gates for the resolved macro.
+        if def != Err(Determinacy::Undetermined) {
+            // Do not report duplicated errors on every undetermined resolution.
+            for segment in &path.segments {
+                if let Some(args) = &segment.args {
+                    self.session.span_err(args.span(), "generic arguments in macro path");
+                }
             }
-        };
-
-        let path = attr.as_ref().unwrap().path.clone();
-        let def = self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force);
-        if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = def {} else {
-            return def;
         }
 
-        // 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".
-        enum ConvertToDeriveHelper { Yes, No, DontKnow }
-        let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
-        let attr_name = path.segments[0].ident.name;
-        for path in traits {
-            match self.resolve_macro(scope, path, MacroKind::Derive, force) {
-                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
-                    if inert_attrs.contains(&attr_name) {
-                        convert_to_derive_helper = ConvertToDeriveHelper::Yes;
-                        break
-                    }
-                },
-                Err(Determinacy::Undetermined) =>
-                    convert_to_derive_helper = ConvertToDeriveHelper::DontKnow,
-                Err(Determinacy::Determined) => {}
-            }
-        }
+        let def = def?;
 
-        match convert_to_derive_helper {
-            ConvertToDeriveHelper::Yes => Ok(Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper)),
-            ConvertToDeriveHelper::No => def,
-            ConvertToDeriveHelper::DontKnow => Err(Determinacy::determined(force)),
+        if path.segments.len() > 1 {
+            if kind != MacroKind::Bang {
+                if def != Def::NonMacroAttr(NonMacroAttrKind::Tool) &&
+                   !self.session.features_untracked().proc_macro_path_invoc {
+                    let msg = format!("non-ident {} paths are unstable", kind.descr());
+                    emit_feature_err(&self.session.parse_sess, "proc_macro_path_invoc",
+                                     path.span, GateIssue::Language, &msg);
+                }
+            }
         }
-    }
 
-    fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-                            -> Result<Def, Determinacy> {
-        let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
-        if def != Err(Determinacy::Undetermined) {
-            // Do not report duplicated errors on every undetermined resolution.
-            path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
-                self.session.span_err(segment.args.as_ref().unwrap().span(),
-                                      "generic arguments in macro path");
-            });
-        }
-        if kind != MacroKind::Bang && path.segments.len() > 1 &&
-           def != Ok(Def::NonMacroAttr(NonMacroAttrKind::Tool)) {
-            if !self.session.features_untracked().proc_macro_path_invoc {
-                emit_feature_err(
-                    &self.session.parse_sess,
-                    "proc_macro_path_invoc",
-                    path.span,
-                    GateIssue::Language,
-                    "paths of length greater than one in macro invocations are \
-                     currently unstable",
-                );
+        match def {
+            Def::Macro(def_id, macro_kind) => {
+                self.unused_macros.remove(&def_id);
+                if macro_kind == MacroKind::ProcMacroStub {
+                    let msg = "can't use a procedural macro from the same crate that defines it";
+                    self.session.span_err(path.span, msg);
+                    return Err(Determinacy::Determined);
+                }
+            }
+            Def::NonMacroAttr(attr_kind) => {
+                if kind == MacroKind::Attr {
+                    let features = self.session.features_untracked();
+                    if attr_kind == NonMacroAttrKind::Tool && !features.tool_attributes {
+                        feature_err(&self.session.parse_sess, "tool_attributes", path.span,
+                                    GateIssue::Language, "tool attributes are unstable").emit();
+                    }
+                    if attr_kind == NonMacroAttrKind::Custom {
+                        assert!(path.segments.len() == 1);
+                        let name = path.segments[0].ident.name.as_str();
+                        if name.starts_with("rustc_") {
+                            if !features.rustc_attrs {
+                                let msg = "unless otherwise specified, attributes with the prefix \
+                                           `rustc_` are reserved for internal compiler diagnostics";
+                                feature_err(&self.session.parse_sess, "rustc_attrs", path.span,
+                                            GateIssue::Language, &msg).emit();
+                            }
+                        } else if name.starts_with("derive_") {
+                            if !features.custom_derive {
+                                feature_err(&self.session.parse_sess, "custom_derive", path.span,
+                                            GateIssue::Language, EXPLAIN_DERIVE_UNDERSCORE).emit();
+                            }
+                        } else if !features.custom_attribute {
+                            let msg = format!("The attribute `{}` is currently unknown to the \
+                                               compiler and may have meaning added to it in the \
+                                               future", path);
+                            feature_err(&self.session.parse_sess, "custom_attribute", path.span,
+                                        GateIssue::Language, &msg).emit();
+                        }
+                    }
+                } else {
+                    // Not only attributes, but anything in macro namespace can result in
+                    // `Def::NonMacroAttr` definition (e.g. `inline!()`), so we must report
+                    // an error for those cases.
+                    let msg = format!("expected a macro, found {}", def.kind_name());
+                    self.session.span_err(path.span, &msg);
+                    return Err(Determinacy::Determined);
+                }
             }
+            _ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
         }
-        def
+
+        Ok((def, self.get_macro(def)))
     }
 
-    pub fn resolve_macro_to_def_inner(&mut self, scope: Mark, path: &ast::Path,
-                                  kind: MacroKind, force: bool)
-                                  -> Result<Def, Determinacy> {
+    pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+                                      derives_in_scope: &[ast::Path], 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[&scope];
@@ -558,12 +476,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         }
 
         let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
-        let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
-            Ok(Def::Macro(binding.def_id, MacroKind::Bang))
+        let result = if let Some((legacy_binding, _)) = legacy_resolution {
+            Ok(legacy_binding.def())
         } else {
             match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force,
                                                           kind == MacroKind::Attr, span) {
-                Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
+                Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
                 Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
                 Err(Determinacy::Determined) => {
                     self.found_unresolved_macro = true;
@@ -575,21 +493,56 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
             .push((scope, path[0], kind, result.ok()));
 
-        result
+        if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
+            return result;
+        }
+
+        // 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, scope, &[], 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)),
+        }
     }
 
     // Resolve the initial segment of a non-global macro path
     // (e.g. `foo` in `foo::bar!(); or `foo!();`).
     // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
     // expansion and import resolution (perhaps they can be merged in the future).
-    pub fn resolve_lexical_macro_path_segment(&mut self,
-                                              mut ident: Ident,
-                                              ns: Namespace,
-                                              record_used: bool,
-                                              force: bool,
-                                              is_attr: bool,
-                                              path_span: Span)
-                                              -> Result<MacroBinding<'a>, Determinacy> {
+    crate fn resolve_lexical_macro_path_segment(
+        &mut self,
+        mut ident: Ident,
+        ns: Namespace,
+        record_used: bool,
+        force: bool,
+        is_attr: bool,
+        path_span: Span
+    ) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
         // General principles:
         // 1. Not controlled (user-defined) names should have higher priority than controlled names
         //    built into the language or standard library. This way we can add new names into the
@@ -629,7 +582,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         //     m::mac!();
         // }
         // This includes names from globs and from macro expansions.
-        let mut potentially_ambiguous_result: Option<MacroBinding> = None;
+        let mut potentially_ambiguous_result: Option<(&NameBinding, FromPrelude)> = None;
 
         enum WhereToResolve<'a> {
             Module(Module<'a>),
@@ -657,11 +610,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         path_span,
                     );
                     self.current_module = orig_current_module;
-                    binding.map(MacroBinding::Modern)
+                    binding.map(|binding| (binding, FromPrelude(false)))
                 }
                 WhereToResolve::MacroPrelude => {
                     match self.macro_prelude.get(&ident.name).cloned() {
-                        Some(binding) => Ok(MacroBinding::Global(binding)),
+                        Some(binding) => Ok((binding, FromPrelude(true))),
                         None => Err(Determinacy::Determined),
                     }
                 }
@@ -673,7 +626,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
                                        ty::Visibility::Public, ident.span, Mark::root())
                                        .to_name_binding(self.arenas);
-                        Ok(MacroBinding::Global(binding))
+                        Ok((binding, FromPrelude(true)))
                     } else {
                         Err(Determinacy::Determined)
                     }
@@ -696,7 +649,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
                         let binding = (crate_root, ty::Visibility::Public,
                                        ident.span, Mark::root()).to_name_binding(self.arenas);
-                        Ok(MacroBinding::Global(binding))
+                        Ok((binding, FromPrelude(true)))
                     } else {
                         Err(Determinacy::Determined)
                     }
@@ -705,7 +658,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     if use_prelude && is_known_tool(ident.name) {
                         let binding = (Def::ToolMod, ty::Visibility::Public,
                                        ident.span, Mark::root()).to_name_binding(self.arenas);
-                        Ok(MacroBinding::Global(binding))
+                        Ok((binding, FromPrelude(true)))
                     } else {
                         Err(Determinacy::Determined)
                     }
@@ -722,7 +675,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                                 false,
                                 path_span,
                             ) {
-                                result = Ok(MacroBinding::Global(binding));
+                                result = Ok((binding, FromPrelude(true)));
                             }
                         }
                     }
@@ -733,7 +686,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                             self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
                         let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
                                        ident.span, Mark::root()).to_name_binding(self.arenas);
-                        Ok(MacroBinding::Global(binding))
+                        Ok((binding, FromPrelude(true)))
                     } else {
                         Err(Determinacy::Determined)
                     }
@@ -772,18 +725,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         return Ok(result);
                     }
 
-                    let binding = result.binding();
-
                     // Found a solution that is ambiguous with a previously found solution.
                     // Push an ambiguity error for later reporting and
                     // return something for better recovery.
                     if let Some(previous_result) = potentially_ambiguous_result {
-                        if binding.def() != previous_result.binding().def() {
+                        if result.0.def() != previous_result.0.def() {
                             self.ambiguity_errors.push(AmbiguityError {
                                 span: path_span,
                                 name: ident.name,
-                                b1: previous_result.binding(),
-                                b2: binding,
+                                b1: previous_result.0,
+                                b2: result.0,
                                 lexical: true,
                             });
                             return Ok(previous_result);
@@ -793,7 +744,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     // Found a solution that's not an ambiguity yet, but is "suspicious" and
                     // can participate in ambiguities later on.
                     // Remember it and go search for other solutions in outer scopes.
-                    if binding.is_glob_import() || binding.expansion != Mark::root() {
+                    if result.0.is_glob_import() || result.0.expansion != Mark::root() {
                         potentially_ambiguous_result = Some(result);
 
                         continue_search!();
@@ -823,20 +774,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             let binding = (Def::NonMacroAttr(NonMacroAttrKind::Custom),
                            ty::Visibility::Public, ident.span, Mark::root())
                            .to_name_binding(self.arenas);
-            Ok(MacroBinding::Global(binding))
+            Ok((binding, FromPrelude(true)))
         } else {
             Err(determinacy)
         }
     }
 
-    pub fn resolve_legacy_scope(&mut self,
-                                mut scope: &'a Cell<LegacyScope<'a>>,
-                                ident: Ident,
-                                record_used: bool)
-                                -> Option<MacroBinding<'a>> {
+    crate fn resolve_legacy_scope(&mut self,
+                                  mut scope: &'a Cell<LegacyScope<'a>>,
+                                  ident: Ident,
+                                  record_used: bool)
+                                  -> Option<(&'a LegacyBinding<'a>, FromExpansion)> {
         let ident = ident.modern();
         let mut relative_depth: u32 = 0;
-        let mut binding = None;
         loop {
             match scope.get() {
                 LegacyScope::Empty => break,
@@ -861,23 +811,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         if record_used && relative_depth > 0 {
                             self.disallowed_shadowing.push(potential_binding);
                         }
-                        binding = Some(potential_binding);
-                        break
+                        return Some((potential_binding, FromExpansion(relative_depth > 0)));
                     }
                     scope = &potential_binding.parent;
                 }
             };
         }
 
-        let binding = if let Some(binding) = binding {
-            MacroBinding::Legacy(binding)
-        } else if let Some(binding) = self.macro_prelude.get(&ident.name).cloned() {
-            MacroBinding::Global(binding)
-        } else {
-            return None;
-        };
-
-        Some(binding)
+        None
     }
 
     pub fn finalize_current_module_macro_resolutions(&mut self) {
@@ -899,10 +840,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true,
                                                                      kind == MacroKind::Attr, span);
 
-            let check_consistency = |this: &Self, binding: MacroBinding| {
+            let check_consistency = |this: &Self, new_def: Def| {
                 if let Some(def) = def {
                     if this.ambiguity_errors.is_empty() && this.disallowed_shadowing.is_empty() &&
-                       binding.def_ignoring_ambiguity() != def {
+                       new_def != def && new_def != Def::Err {
                         // Make sure compilation does not succeed if preferred macro resolution
                         // has changed after the macro had been expanded. In theory all such
                         // situations should be reported as ambiguity errors, so this is span-bug.
@@ -921,17 +862,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             };
 
             match (legacy_resolution, resolution) {
-                (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
-                    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());
                     let bang = if kind == MacroKind::Bang { "!" } else { "" };
@@ -941,26 +871,34 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                     self.suggest_macro_name(&ident.as_str(), kind, &mut err, span);
                     err.emit();
                 },
-                (Some(MacroBinding::Modern(_)), _) | (_, Ok(MacroBinding::Legacy(_))) => {
-                    span_bug!(span, "impossible macro resolution result");
-                }
+                (Some((legacy_binding, FromExpansion(from_expansion))),
+                 Ok((binding, FromPrelude(false)))) |
+                (Some((legacy_binding, FromExpansion(from_expansion @ true))),
+                 Ok((binding, FromPrelude(true)))) => {
+                    if legacy_binding.def() != binding.def_ignoring_ambiguity() {
+                        self.report_ambiguity_error(
+                            ident.name, span, true,
+                            legacy_binding.def(), false, false,
+                            from_expansion, legacy_binding.span,
+                            binding.def(), binding.is_import(), binding.is_glob_import(),
+                            binding.expansion != Mark::root(), binding.span,
+                        );
+                    }
+                },
+                // OK, non-macro-expanded legacy wins over macro prelude even if defs are different
+                (Some((legacy_binding, FromExpansion(false))), Ok((_, FromPrelude(true)))) |
                 // OK, unambiguous resolution
-                (Some(binding), Err(_)) | (None, Ok(binding)) |
-                // OK, legacy wins over global even if their definitions are different
-                (Some(binding @ MacroBinding::Legacy(_)), Ok(MacroBinding::Global(_))) |
-                // OK, modern wins over global even if their definitions are different
-                (Some(MacroBinding::Global(_)), Ok(binding @ MacroBinding::Modern(_))) => {
-                    check_consistency(self, binding);
+                (Some((legacy_binding, _)), Err(_)) => {
+                    check_consistency(self, legacy_binding.def());
                 }
-                (Some(MacroBinding::Global(binding1)), Ok(MacroBinding::Global(binding2))) => {
-                    if binding1.def() != binding2.def() {
-                        span_bug!(span, "mismatch between same global macro resolutions");
+                // OK, unambiguous resolution
+                (None, Ok((binding, FromPrelude(from_prelude)))) => {
+                    check_consistency(self, binding.def_ignoring_ambiguity());
+                    if from_prelude {
+                        self.record_use(ident, MacroNS, binding, span);
+                        self.err_if_macro_use_proc_macro(ident.name, span, binding);
                     }
-                    check_consistency(self, MacroBinding::Global(binding1));
-
-                    self.record_use(ident, MacroNS, binding1, span);
-                    self.err_if_macro_use_proc_macro(ident.name, span, binding1);
-                },
+                }
             };
         }
     }
@@ -1082,7 +1020,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
     /// Error if `ext` is a Macros 1.1 procedural macro being imported by `#[macro_use]`
     fn err_if_macro_use_proc_macro(&mut self, name: Name, use_span: Span,
                                    binding: &NameBinding<'a>) {
-        let krate = binding.def().def_id().krate;
+        let krate = match binding.def() {
+            Def::NonMacroAttr(..) | Def::Err => return,
+            Def::Macro(def_id, _) => def_id.krate,
+            _ => unreachable!(),
+        };
 
         // Plugin-based syntax extensions are exempt from this check
         if krate == BUILTIN_MACROS_CRATE { return; }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 28d504c2ee0..c00d67aaab6 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -403,9 +403,7 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
     let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
     let mut resolver = cx.resolver.borrow_mut();
     let mark = Mark::root();
-    let res = resolver
-        .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
-    if let Ok(def) = res {
+    if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, mark, &[], 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 154fe11dd35..c9925b41498 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -727,10 +727,12 @@ pub trait Resolver {
     fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool)
                               -> Option<Attribute>;
 
-    fn resolve_invoc(&mut self, invoc: &Invocation, scope: Mark, force: bool)
-                     -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
-    fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-                     -> Result<Lrc<SyntaxExtension>, Determinacy>;
+    fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
+                                -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
+    fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+                          derives_in_scope: &[ast::Path], force: bool)
+                          -> Result<Lrc<SyntaxExtension>, Determinacy>;
+
     fn check_unused_macros(&self);
 }
 
@@ -761,12 +763,13 @@ impl Resolver for DummyResolver {
     fn resolve_imports(&mut self) {}
     fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool)
                               -> Option<Attribute> { None }
-    fn resolve_invoc(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool)
-                     -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
+    fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool)
+                                -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
         Err(Determinacy::Determined)
     }
-    fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind,
-                     _force: bool) -> Result<Lrc<SyntaxExtension>, Determinacy> {
+    fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _scope: Mark,
+                          _derives_in_scope: &[ast::Path], _force: bool)
+                          -> Result<Lrc<SyntaxExtension>, Determinacy> {
         Err(Determinacy::Determined)
     }
     fn check_unused_macros(&self) {}
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 06e4087171a..97279e00869 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -243,15 +243,6 @@ impl Invocation {
             InvocationKind::Derive { ref path, .. } => path.span,
         }
     }
-
-    pub fn path(&self) -> Option<&Path> {
-        match self.kind {
-            InvocationKind::Bang { ref mac, .. } => Some(&mac.node.path),
-            InvocationKind::Attr { attr: Some(ref attr), .. } => Some(&attr.path),
-            InvocationKind::Attr { attr: None, .. } => None,
-            InvocationKind::Derive { ref path, .. } => Some(path),
-        }
-    }
 }
 
 pub struct MacroExpander<'a, 'b:'a> {
@@ -343,7 +334,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
             let scope =
                 if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
-            let ext = match self.cx.resolver.resolve_invoc(&invoc, scope, force) {
+            let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) {
                 Ok(ext) => Some(ext),
                 Err(Determinacy::Determined) => None,
                 Err(Determinacy::Undetermined) => {
@@ -393,8 +384,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     for path in &traits {
                         let mark = Mark::fresh(self.cx.current_expansion.mark);
                         derives.push(mark);
-                        let item = match self.cx.resolver.resolve_macro(
-                                Mark::root(), path, MacroKind::Derive, false) {
+                        let item = match self.cx.resolver.resolve_macro_path(
+                                path, MacroKind::Derive, Mark::root(), &[], false) {
                             Ok(ext) => match *ext {
                                 BuiltinDerive(..) => item_with_markers.clone(),
                                 _ => item.clone(),
diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
index 0798aa549f0..96f68341db7 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs
@@ -22,7 +22,7 @@ extern crate proc_macro_gates as foo;
 
 use foo::*;
 
-#[foo::a] //~ ERROR: paths of length greater than one
+#[foo::a] //~ ERROR: non-ident attribute macro paths are unstable
 fn _test() {}
 
 fn _test_inner() {
diff --git a/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved-2.stderr
index 342d7ddb36c..9def03e9450 100644
--- a/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved-2.stderr
+++ b/src/test/ui-fulldeps/proc-macro/macro-namespace-reserved-2.stderr
@@ -2,37 +2,37 @@ error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:34:5
    |
 LL |     my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:37:5
    |
 LL |     my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:40:5
    |
 LL |     MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:43:1
+  --> $DIR/macro-namespace-reserved-2.rs:43:3
    |
 LL | #[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
-   | ^^^^^^^^^^^
+   |   ^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:45:1
+  --> $DIR/macro-namespace-reserved-2.rs:45:3
    |
 LL | #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it
-   | ^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:47:1
+  --> $DIR/macro-namespace-reserved-2.rs:47:3
    |
 LL | #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it
-   | ^^^^^^^^^^
+   |   ^^^^^^^
 
 error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:50:10
diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr
index 33fe52366db..0f51c7d68c6 100644
--- a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr
+++ b/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr
@@ -2,7 +2,7 @@ error[E0658]: The attribute `unknown` is currently unknown to the compiler and m
   --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:13:27
    |
 LL |         #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
-   |                           ^^^^^^^^
+   |                           ^^^^^^^
 ...
 LL | foo!();
    | ------- in this macro invocation
diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr
index 4adfe1e450e..6ecad7d79b8 100644
--- a/src/test/ui/custom_attribute.stderr
+++ b/src/test/ui/custom_attribute.stderr
@@ -1,24 +1,24 @@
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/custom_attribute.rs:13:1
+  --> $DIR/custom_attribute.rs:13:3
    |
 LL | #[foo] //~ ERROR The attribute `foo`
-   | ^^^^^^
+   |   ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/custom_attribute.rs:15:5
+  --> $DIR/custom_attribute.rs:15:7
    |
 LL |     #[foo] //~ ERROR The attribute `foo`
-   |     ^^^^^^
+   |       ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/custom_attribute.rs:17:5
+  --> $DIR/custom_attribute.rs:17:7
    |
 LL |     #[foo] //~ ERROR The attribute `foo`
-   |     ^^^^^^
+   |       ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
index 36f5898f1c7..e60e9a342a9 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
@@ -1,104 +1,104 @@
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:17:1
+  --> $DIR/feature-gate-custom_attribute.rs:17:3
    |
 LL | #[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:18:1
+  --> $DIR/feature-gate-custom_attribute.rs:18:3
    |
 LL | #[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:19:1
+  --> $DIR/feature-gate-custom_attribute.rs:19:3
    |
 LL | #[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:20:1
+  --> $DIR/feature-gate-custom_attribute.rs:20:3
    |
 LL | #[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:21:1
+  --> $DIR/feature-gate-custom_attribute.rs:21:3
    |
 LL | #[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:22:1
+  --> $DIR/feature-gate-custom_attribute.rs:22:3
    |
 LL | #[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:23:1
+  --> $DIR/feature-gate-custom_attribute.rs:23:3
    |
 LL | #[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:24:1
+  --> $DIR/feature-gate-custom_attribute.rs:24:3
    |
 LL | #[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:25:1
+  --> $DIR/feature-gate-custom_attribute.rs:25:3
    |
 LL | #[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:26:1
+  --> $DIR/feature-gate-custom_attribute.rs:26:3
    |
 LL | #[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:27:1
+  --> $DIR/feature-gate-custom_attribute.rs:27:3
    |
 LL | #[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:28:1
+  --> $DIR/feature-gate-custom_attribute.rs:28:3
    |
 LL | #[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `fake_doc` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/feature-gate-custom_attribute.rs:29:1
+  --> $DIR/feature-gate-custom_attribute.rs:29:3
    |
 LL | #[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-custom_derive.stderr b/src/test/ui/feature-gates/feature-gate-custom_derive.stderr
index e633a5a9c99..0979372daea 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_derive.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_derive.stderr
@@ -1,8 +1,8 @@
 error[E0658]: attributes of the form `#[derive_*]` are reserved for the compiler (see issue #29644)
-  --> $DIR/feature-gate-custom_derive.rs:11:1
+  --> $DIR/feature-gate-custom_derive.rs:11:3
    |
 LL | #[derive_Clone]
-   | ^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^^^^
    |
    = help: add #![feature(custom_derive)] to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
index 52a4d3664ce..882549c1eaf 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -1,8 +1,8 @@
 error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642)
-  --> $DIR/feature-gate-rustc-attrs.rs:15:1
+  --> $DIR/feature-gate-rustc-attrs.rs:15:3
    |
 LL | #[rustc_foo]
-   | ^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(rustc_attrs)] to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-tool_attributes.stderr b/src/test/ui/feature-gates/feature-gate-tool_attributes.stderr
index ca9542dcc95..b024059d450 100644
--- a/src/test/ui/feature-gates/feature-gate-tool_attributes.stderr
+++ b/src/test/ui/feature-gates/feature-gate-tool_attributes.stderr
@@ -1,8 +1,8 @@
 error[E0658]: tool attributes are unstable (see issue #44690)
-  --> $DIR/feature-gate-tool_attributes.rs:12:5
+  --> $DIR/feature-gate-tool_attributes.rs:12:7
    |
 LL |     #[rustfmt::skip] //~ ERROR tool attributes are unstable
-   |     ^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^
    |
    = help: add #![feature(tool_attributes)] to the crate attributes to enable
 
diff --git a/src/test/ui/imports/issue-53269.rs b/src/test/ui/imports/issue-53269.rs
new file mode 100644
index 00000000000..1b21e3ba5f3
--- /dev/null
+++ b/src/test/ui/imports/issue-53269.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// Ambiguity between a `macro_rules` macro and a non-existent import recovered as `Def::Err`
+
+macro_rules! mac { () => () }
+
+mod m {
+    use nonexistent_module::mac; //~ ERROR unresolved import `nonexistent_module`
+
+    mac!(); //~ ERROR `mac` is ambiguous
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/issue-53269.stderr b/src/test/ui/imports/issue-53269.stderr
new file mode 100644
index 00000000000..0036d71107a
--- /dev/null
+++ b/src/test/ui/imports/issue-53269.stderr
@@ -0,0 +1,27 @@
+error[E0432]: unresolved import `nonexistent_module`
+  --> $DIR/issue-53269.rs:16:9
+   |
+LL |     use nonexistent_module::mac; //~ ERROR unresolved import `nonexistent_module`
+   |         ^^^^^^^^^^^^^^^^^^ Maybe a missing `extern crate nonexistent_module;`?
+
+error[E0659]: `mac` is ambiguous
+  --> $DIR/issue-53269.rs:18:5
+   |
+LL |     mac!(); //~ ERROR `mac` is ambiguous
+   |     ^^^
+   |
+note: `mac` could refer to the name defined here
+  --> $DIR/issue-53269.rs:13:1
+   |
+LL | macro_rules! mac { () => () }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `mac` could also refer to the name imported here
+  --> $DIR/issue-53269.rs:16:9
+   |
+LL |     use nonexistent_module::mac; //~ ERROR unresolved import `nonexistent_module`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0432, E0659.
+For more information about an error, try `rustc --explain E0432`.
diff --git a/src/test/ui/imports/issue-53512.rs b/src/test/ui/imports/issue-53512.rs
new file mode 100644
index 00000000000..82ae75e8198
--- /dev/null
+++ b/src/test/ui/imports/issue-53512.rs
@@ -0,0 +1,17 @@
+// 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 from prelude is shadowed by non-existent import recovered as `Def::Err`.
+
+use std::assert; //~ ERROR unresolved import `std::assert`
+
+fn main() {
+    assert!(true);
+}
diff --git a/src/test/ui/imports/issue-53512.stderr b/src/test/ui/imports/issue-53512.stderr
new file mode 100644
index 00000000000..e79e759f6c6
--- /dev/null
+++ b/src/test/ui/imports/issue-53512.stderr
@@ -0,0 +1,9 @@
+error[E0432]: unresolved import `std::assert`
+  --> $DIR/issue-53512.rs:13:5
+   |
+LL | use std::assert; //~ ERROR unresolved import `std::assert`
+   |     ^^^^^^^^^^^ no `assert` in the root
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/imports/macros.stderr b/src/test/ui/imports/macros.stderr
index 01d1f4fdfad..2c0c4642067 100644
--- a/src/test/ui/imports/macros.stderr
+++ b/src/test/ui/imports/macros.stderr
@@ -1,15 +1,15 @@
-error: `m` is ambiguous
+error[E0659]: `m` is ambiguous
   --> $DIR/macros.rs:48:5
    |
 LL |     m!(); //~ ERROR ambiguous
    |     ^
    |
-note: `m` could refer to the macro defined here
+note: `m` could refer to the name defined here
   --> $DIR/macros.rs:46:5
    |
 LL |     macro_rules! m { () => {} }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: `m` could also refer to the macro imported here
+note: `m` could also refer to the name imported here
   --> $DIR/macros.rs:47:9
    |
 LL |     use two_macros::m;
diff --git a/src/test/ui/imports/shadow_builtin_macros.rs b/src/test/ui/imports/shadow_builtin_macros.rs
index 90718abc37b..ec3f4107e38 100644
--- a/src/test/ui/imports/shadow_builtin_macros.rs
+++ b/src/test/ui/imports/shadow_builtin_macros.rs
@@ -37,10 +37,10 @@ mod m4 {
 
 mod m5 {
     macro_rules! m { () => {
-        macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope
+        macro_rules! panic { () => {} }
     } }
     m!();
-    panic!();
+    panic!(); //~ ERROR `panic` is ambiguous
 }
 
 #[macro_use(n)]
diff --git a/src/test/ui/imports/shadow_builtin_macros.stderr b/src/test/ui/imports/shadow_builtin_macros.stderr
index 693b7aadeca..5c7f15b6fe2 100644
--- a/src/test/ui/imports/shadow_builtin_macros.stderr
+++ b/src/test/ui/imports/shadow_builtin_macros.stderr
@@ -1,13 +1,19 @@
-error: `panic` is already in scope
+error[E0659]: `panic` is ambiguous
+  --> $DIR/shadow_builtin_macros.rs:43:5
+   |
+LL |     panic!(); //~ ERROR `panic` is ambiguous
+   |     ^^^^^
+   |
+note: `panic` could refer to the name defined here
   --> $DIR/shadow_builtin_macros.rs:40:9
    |
-LL |         macro_rules! panic { () => {} } //~ ERROR `panic` is already in scope
+LL |         macro_rules! panic { () => {} }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |     } }
 LL |     m!();
    |     ----- in this macro invocation
-   |
-   = note: macro-expanded `macro_rules!`s may not shadow existing macros (see RFC 1560)
+   = note: `panic` is also a builtin macro
+   = note: macro-expanded macros do not shadow
 
 error[E0659]: `panic` is ambiguous
   --> $DIR/shadow_builtin_macros.rs:25:14
diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr
index a1323808a91..f930217fe9e 100644
--- a/src/test/ui/issues/issue-32655.stderr
+++ b/src/test/ui/issues/issue-32655.stderr
@@ -1,8 +1,8 @@
 error[E0658]: attributes of the form `#[derive_*]` are reserved for the compiler (see issue #29644)
-  --> $DIR/issue-32655.rs:16:9
+  --> $DIR/issue-32655.rs:16:11
    |
 LL |         #[derive_Clone] //~ ERROR attributes of the form
-   |         ^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^
 ...
 LL | foo!();
    | ------- in this macro invocation
@@ -10,10 +10,10 @@ LL | foo!();
    = help: add #![feature(custom_derive)] to the crate attributes to enable
 
 error[E0658]: attributes of the form `#[derive_*]` are reserved for the compiler (see issue #29644)
-  --> $DIR/issue-32655.rs:28:5
+  --> $DIR/issue-32655.rs:28:7
    |
 LL |     #[derive_Clone] //~ ERROR attributes of the form
-   |     ^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^
    |
    = help: add #![feature(custom_derive)] to the crate attributes to enable
 
diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr
index 888222b69cc..6c9d1eac356 100644
--- a/src/test/ui/issues/issue-49074.stderr
+++ b/src/test/ui/issues/issue-49074.stderr
@@ -1,8 +1,8 @@
 error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/issue-49074.rs:13:1
+  --> $DIR/issue-49074.rs:13:3
    |
 LL | #[marco_use] // typo
-   | ^^^^^^^^^^^^
+   |   ^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr
index c93c7144f9e..8f954158a63 100644
--- a/src/test/ui/macros/macro-reexport-removed.stderr
+++ b/src/test/ui/macros/macro-reexport-removed.stderr
@@ -11,10 +11,10 @@ LL | #![feature(macro_reexport)] //~ ERROR feature has been removed
    |            ^^^^^^^^^^^^^^
 
 error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/macro-reexport-removed.rs:15:1
+  --> $DIR/macro-reexport-removed.rs:15:3
    |
 LL | #[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^^^^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr
index e8bfcc04f48..efcd1ec67d7 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.stderr
+++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr
@@ -1,8 +1,8 @@
 error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642)
-  --> $DIR/reserved-attr-on-macro.rs:11:1
+  --> $DIR/reserved-attr-on-macro.rs:11:3
    |
 LL | #[rustc_attribute_should_be_reserved] //~ ERROR attributes with the prefix `rustc_` are reserved
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(rustc_attrs)] to the crate attributes to enable
 
diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr
index cbec4f6b0a6..e7dd8e7aa8f 100644
--- a/src/test/ui/span/issue-36530.stderr
+++ b/src/test/ui/span/issue-36530.stderr
@@ -1,16 +1,16 @@
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/issue-36530.rs:11:1
+  --> $DIR/issue-36530.rs:11:3
    |
 LL | #[foo] //~ ERROR is currently unknown to the compiler
-   | ^^^^^^
+   |   ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable
 
 error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
-  --> $DIR/issue-36530.rs:13:5
+  --> $DIR/issue-36530.rs:13:8
    |
 LL |     #![foo] //~ ERROR is currently unknown to the compiler
-   |     ^^^^^^^
+   |        ^^^
    |
    = help: add #![feature(custom_attribute)] to the crate attributes to enable