about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/def.rs8
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs4
-rw-r--r--src/librustc_resolve/diagnostics.rs673
-rw-r--r--src/librustc_resolve/lib.rs691
-rw-r--r--src/librustc_resolve/macros.rs495
-rw-r--r--src/librustc_resolve/resolve_imports.rs6
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs7
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/attributes/obsolete-attr.rs6
-rw-r--r--src/test/ui/attributes/obsolete-attr.stderr13
-rw-r--r--src/test/ui/attributes/unknown-attr.rs9
-rw-r--r--src/test/ui/attributes/unknown-attr.stderr20
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs3
-rw-r--r--src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr6
-rw-r--r--src/test/ui/custom_attribute.rs6
-rw-r--r--src/test/ui/custom_attribute.stderr16
-rw-r--r--src/test/ui/derives/deriving-meta-unknown-trait.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_attribute.rs35
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_attribute.stderr92
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc-attrs.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr5
-rw-r--r--src/test/ui/hygiene/no_implicit_prelude-2018.stderr2
-rw-r--r--src/test/ui/hygiene/no_implicit_prelude.stderr1
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.rs4
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr11
-rw-r--r--src/test/ui/impl-trait/universal_wrong_bounds.rs7
-rw-r--r--src/test/ui/impl-trait/universal_wrong_bounds.stderr14
-rw-r--r--src/test/ui/issues/issue-32655.rs7
-rw-r--r--src/test/ui/issues/issue-32655.stderr15
-rw-r--r--src/test/ui/issues/issue-37534.rs2
-rw-r--r--src/test/ui/issues/issue-37534.stderr8
-rw-r--r--src/test/ui/issues/issue-49074.rs2
-rw-r--r--src/test/ui/issues/issue-49074.stderr6
-rw-r--r--src/test/ui/macros/macro-name-typo.stderr2
-rw-r--r--src/test/ui/macros/macro-path-prelude-fail-3.stderr2
-rw-r--r--src/test/ui/macros/macro-reexport-removed.rs2
-rw-r--r--src/test/ui/macros/macro-reexport-removed.stderr8
-rw-r--r--src/test/ui/macros/macro-use-wrong-name.stderr2
-rw-r--r--src/test/ui/macros/macro_undefined.stderr2
-rw-r--r--src/test/ui/no-implicit-prelude-nested.rs6
-rw-r--r--src/test/ui/no-implicit-prelude-nested.stderr22
-rw-r--r--src/test/ui/no-implicit-prelude.rs2
-rw-r--r--src/test/ui/no-implicit-prelude.stderr10
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.rs2
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.stderr8
-rw-r--r--src/test/ui/proc-macro/derive-still-gated.rs2
-rw-r--r--src/test/ui/proc-macro/derive-still-gated.stderr6
-rw-r--r--src/test/ui/proc-macro/expand-to-unstable-2.rs3
-rw-r--r--src/test/ui/proc-macro/expand-to-unstable-2.stderr13
-rw-r--r--src/test/ui/proc-macro/issue-41211.rs4
-rw-r--r--src/test/ui/proc-macro/issue-41211.stderr14
-rw-r--r--src/test/ui/proc-macro/macro-namespace-reserved-2.rs2
-rw-r--r--src/test/ui/proc-macro/macro-namespace-reserved-2.stderr16
-rw-r--r--src/test/ui/proc-macro/proc-macro-attributes.rs2
-rw-r--r--src/test/ui/proc-macro/proc-macro-attributes.stderr10
-rw-r--r--src/test/ui/proc-macro/resolve-error.rs4
-rw-r--r--src/test/ui/proc-macro/resolve-error.stderr35
-rw-r--r--src/test/ui/reserved/reserved-attr-on-macro.rs2
-rw-r--r--src/test/ui/reserved/reserved-attr-on-macro.stderr5
-rw-r--r--src/test/ui/resolve/levenshtein.stderr2
-rw-r--r--src/test/ui/span/issue-36530.rs7
-rw-r--r--src/test/ui/span/issue-36530.stderr22
-rw-r--r--src/test/ui/suggestions/attribute-typos.rs6
-rw-r--r--src/test/ui/suggestions/attribute-typos.stderr19
-rw-r--r--src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs2
-rw-r--r--src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr18
66 files changed, 1170 insertions, 1271 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 131a910bebb..db568dbf9fb 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -398,4 +398,12 @@ impl<Id> Res<Id> {
             Res::Err => Res::Err,
         }
     }
+
+    pub fn macro_kind(self) -> Option<MacroKind> {
+        match self {
+            Res::Def(DefKind::Macro(kind), _) => Some(kind),
+            Res::NonMacroAttr(..) => Some(MacroKind::Attr),
+            _ => None,
+        }
+    }
 }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 16fd8cccc89..45549800712 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -3,11 +3,11 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
-use crate::macros::{InvocationData, ParentScope, LegacyScope};
+use crate::macros::{InvocationData, LegacyScope};
 use crate::resolve_imports::ImportDirective;
 use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
 use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
-use crate::{ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
+use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
 use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
 use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy};
 
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index e93a2315ca3..90a4107f773 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -2,21 +2,84 @@ use std::cmp::Reverse;
 
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use log::debug;
-use rustc::hir::def::{self, DefKind, CtorKind, Namespace::*};
+use rustc::hir::def::{self, DefKind, CtorKind, NonMacroAttrKind};
+use rustc::hir::def::Namespace::{self, *};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::PrimTy;
 use rustc::session::{Session, config::nightly_options};
-use syntax::ast::{self, Expr, ExprKind, Ident};
+use rustc::ty::{self, DefIdTree};
+use rustc::util::nodemap::FxHashSet;
+use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
 use syntax::ext::base::MacroKind;
+use syntax::feature_gate::BUILTIN_ATTRIBUTES;
 use syntax::symbol::{Symbol, kw};
+use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{BytePos, Span};
 
+use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
+use crate::{is_self_type, is_self_value, path_names_to_string, KNOWN_TOOLS};
+use crate::{CrateLint, LegacyScope, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{PathResult, PathSource, ParentScope, Resolver, RibKind, Scope, ScopeSet, Segment};
+
 type Res = def::Res<ast::NodeId>;
 
-use crate::macros::ParentScope;
-use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
-use crate::{import_candidate_to_enum_paths, is_self_type, is_self_value, path_names_to_string};
-use crate::{AssocSuggestion, CrateLint, ImportSuggestion, ModuleOrUniformRoot, PathResult,
-            PathSource, Resolver, Segment, Suggestion};
+/// A vector of spans and replacements, a message and applicability.
+crate type Suggestion = (Vec<(Span, String)>, String, Applicability);
+
+/// A field or associated item from self type suggested in case of resolution failure.
+enum AssocSuggestion {
+    Field,
+    MethodWithSelf,
+    AssocItem,
+}
+
+struct TypoSuggestion {
+    candidate: Symbol,
+
+    /// The kind of the binding ("crate", "module", etc.)
+    kind: &'static str,
+
+    /// An appropriate article to refer to the binding ("a", "an", etc.)
+    article: &'static str,
+}
+
+impl TypoSuggestion {
+    fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+        TypoSuggestion { candidate, kind: res.descr(), article: res.article() }
+    }
+}
+
+/// A free importable items suggested in case of resolution failure.
+crate struct ImportSuggestion {
+    did: Option<DefId>,
+    pub path: Path,
+}
+
+fn add_typo_suggestion(
+    err: &mut DiagnosticBuilder<'_>, suggestion: Option<TypoSuggestion>, span: Span
+) -> bool {
+    if let Some(suggestion) = suggestion {
+        let msg = format!("{} {} with a similar name exists", suggestion.article, suggestion.kind);
+        err.span_suggestion(
+            span, &msg, suggestion.candidate.to_string(), Applicability::MaybeIncorrect
+        );
+        return true;
+    }
+    false
+}
+
+fn add_module_candidates(
+    module: Module<'_>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool
+) {
+    for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
+        if let Some(binding) = resolution.borrow().binding {
+            let res = binding.res();
+            if filter_fn(res) {
+                names.push(TypoSuggestion::from_res(ident.name, res));
+            }
+        }
+    }
+}
 
 impl<'a> Resolver<'a> {
     /// Handles error reporting for `smart_resolve_path_fragment` function.
@@ -204,24 +267,10 @@ impl<'a> Resolver<'a> {
             }
         }
 
-        let mut levenshtein_worked = false;
-
         // Try Levenshtein algorithm.
-        let suggestion = self.lookup_typo_candidate(path, ns, is_expected, span);
-        if let Some(suggestion) = suggestion {
-            let msg = format!(
-                "{} {} with a similar name exists",
-                suggestion.article, suggestion.kind
-            );
-            err.span_suggestion(
-                ident_span,
-                &msg,
-                suggestion.candidate.to_string(),
-                Applicability::MaybeIncorrect,
-            );
-
-            levenshtein_worked = true;
-        }
+        let levenshtein_worked = add_typo_suggestion(
+            &mut err, self.lookup_typo_candidate(path, ns, is_expected, span), ident_span
+        );
 
         // Try context-dependent help if relaxed lookup didn't work.
         if let Some(res) = res {
@@ -365,7 +414,7 @@ impl<'a> Resolver<'a> {
         };
 
         match (res, source) {
-            (Res::Def(DefKind::Macro(..), _), _) => {
+            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
                 err.span_suggestion(
                     span,
                     "use `!` to invoke the macro",
@@ -439,6 +488,513 @@ impl<'a> Resolver<'a> {
         }
         true
     }
+
+    fn lookup_assoc_candidate<FilterFn>(&mut self,
+                                        ident: Ident,
+                                        ns: Namespace,
+                                        filter_fn: FilterFn)
+                                        -> Option<AssocSuggestion>
+        where FilterFn: Fn(Res) -> bool
+    {
+        fn extract_node_id(t: &Ty) -> Option<NodeId> {
+            match t.node {
+                TyKind::Path(None, _) => Some(t.id),
+                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
+                // This doesn't handle the remaining `Ty` variants as they are not
+                // that commonly the self_type, it might be interesting to provide
+                // support for those in future.
+                _ => None,
+            }
+        }
+
+        // Fields are generally expected in the same contexts as locals.
+        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
+            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
+                // Look for a field with the same name in the current self_type.
+                if let Some(resolution) = self.partial_res_map.get(&node_id) {
+                    match resolution.base_res() {
+                        Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did)
+                                if resolution.unresolved_segments() == 0 => {
+                            if let Some(field_names) = self.field_names.get(&did) {
+                                if field_names.iter().any(|&field_name| ident.name == field_name) {
+                                    return Some(AssocSuggestion::Field);
+                                }
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+        }
+
+        for assoc_type_ident in &self.current_trait_assoc_types {
+            if *assoc_type_ident == ident {
+                return Some(AssocSuggestion::AssocItem);
+            }
+        }
+
+        // Look for associated items in the current trait.
+        if let Some((module, _)) = self.current_trait_ref {
+            if let Ok(binding) = self.resolve_ident_in_module(
+                    ModuleOrUniformRoot::Module(module),
+                    ident,
+                    ns,
+                    None,
+                    false,
+                    module.span,
+                ) {
+                let res = binding.res();
+                if filter_fn(res) {
+                    return Some(if self.has_self.contains(&res.def_id()) {
+                        AssocSuggestion::MethodWithSelf
+                    } else {
+                        AssocSuggestion::AssocItem
+                    });
+                }
+            }
+        }
+
+        None
+    }
+
+    /// Lookup typo candidate in scope for a macro or import.
+    fn early_lookup_typo_candidate(
+        &mut self,
+        scope_set: ScopeSet,
+        parent_scope: &ParentScope<'a>,
+        ident: Ident,
+        filter_fn: &impl Fn(Res) -> bool,
+    ) -> Option<TypoSuggestion> {
+        let mut suggestions = Vec::new();
+        self.visit_scopes(scope_set, parent_scope, ident, |this, scope, _| {
+            match scope {
+                Scope::DeriveHelpers => {
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                    if filter_fn(res) {
+                        for derive in &parent_scope.derives {
+                            let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
+                            if let Ok((Some(ext), _)) = this.resolve_macro_path(
+                                derive, Some(MacroKind::Derive), &parent_scope, false, false
+                            ) {
+                                suggestions.extend(ext.helper_attrs.iter().map(|name| {
+                                    TypoSuggestion::from_res(*name, res)
+                                }));
+                            }
+                        }
+                    }
+                }
+                Scope::MacroRules(legacy_scope) => {
+                    if let LegacyScope::Binding(legacy_binding) = legacy_scope {
+                        let res = legacy_binding.binding.res();
+                        if filter_fn(res) {
+                            suggestions.push(
+                                TypoSuggestion::from_res(legacy_binding.ident.name, res)
+                            )
+                        }
+                    }
+                }
+                Scope::CrateRoot => {
+                    let root_ident = Ident::new(kw::PathRoot, ident.span);
+                    let root_module = this.resolve_crate_root(root_ident);
+                    add_module_candidates(root_module, &mut suggestions, filter_fn);
+                }
+                Scope::Module(module) => {
+                    add_module_candidates(module, &mut suggestions, filter_fn);
+                }
+                Scope::MacroUsePrelude => {
+                    suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
+                        let res = binding.res();
+                        if filter_fn(res) {
+                            Some(TypoSuggestion::from_res(*name, res))
+                        } else {
+                            None
+                        }
+                    }));
+                }
+                Scope::BuiltinMacros => {
+                    suggestions.extend(this.builtin_macros.iter().filter_map(|(name, binding)| {
+                        let res = binding.res();
+                        if filter_fn(res) {
+                            Some(TypoSuggestion::from_res(*name, res))
+                        } else {
+                            None
+                        }
+                    }));
+                }
+                Scope::BuiltinAttrs => {
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
+                    if filter_fn(res) {
+                        suggestions.extend(BUILTIN_ATTRIBUTES.iter().map(|(name, ..)| {
+                            TypoSuggestion::from_res(*name, res)
+                        }));
+                    }
+                }
+                Scope::LegacyPluginHelpers => {
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);
+                    if filter_fn(res) {
+                        let plugin_attributes = this.session.plugin_attributes.borrow();
+                        suggestions.extend(plugin_attributes.iter().map(|(name, _)| {
+                            TypoSuggestion::from_res(*name, res)
+                        }));
+                    }
+                }
+                Scope::ExternPrelude => {
+                    suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
+                        let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
+                        if filter_fn(res) {
+                            Some(TypoSuggestion::from_res(ident.name, res))
+                        } else {
+                            None
+                        }
+                    }));
+                }
+                Scope::ToolPrelude => {
+                    let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
+                    suggestions.extend(KNOWN_TOOLS.iter().map(|name| {
+                        TypoSuggestion::from_res(*name, res)
+                    }));
+                }
+                Scope::StdLibPrelude => {
+                    if let Some(prelude) = this.prelude {
+                        add_module_candidates(prelude, &mut suggestions, filter_fn);
+                    }
+                }
+                Scope::BuiltinTypes => {
+                    let primitive_types = &this.primitive_type_table.primitive_types;
+                    suggestions.extend(
+                        primitive_types.iter().flat_map(|(name, prim_ty)| {
+                            let res = Res::PrimTy(*prim_ty);
+                            if filter_fn(res) {
+                                Some(TypoSuggestion::from_res(*name, res))
+                            } else {
+                                None
+                            }
+                        })
+                    )
+                }
+            }
+
+            None::<()>
+        });
+
+        // Make sure error reporting is deterministic.
+        suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
+
+        match find_best_match_for_name(
+            suggestions.iter().map(|suggestion| &suggestion.candidate),
+            &ident.as_str(),
+            None,
+        ) {
+            Some(found) if found != ident.name => suggestions
+                .into_iter()
+                .find(|suggestion| suggestion.candidate == found),
+            _ => None,
+        }
+    }
+
+    fn lookup_typo_candidate(
+        &mut self,
+        path: &[Segment],
+        ns: Namespace,
+        filter_fn: &impl Fn(Res) -> bool,
+        span: Span,
+    ) -> Option<TypoSuggestion> {
+        let mut names = Vec::new();
+        if path.len() == 1 {
+            // Search in lexical scope.
+            // Walk backwards up the ribs in scope and collect candidates.
+            for rib in self.ribs[ns].iter().rev() {
+                // Locals and type parameters
+                for (ident, &res) in &rib.bindings {
+                    if filter_fn(res) {
+                        names.push(TypoSuggestion::from_res(ident.name, res));
+                    }
+                }
+                // Items in scope
+                if let RibKind::ModuleRibKind(module) = rib.kind {
+                    // Items from this module
+                    add_module_candidates(module, &mut names, &filter_fn);
+
+                    if let ModuleKind::Block(..) = module.kind {
+                        // We can see through blocks
+                    } else {
+                        // Items from the prelude
+                        if !module.no_implicit_prelude {
+                            names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| {
+                                self.crate_loader
+                                    .maybe_process_path_extern(ident.name, ident.span)
+                                    .and_then(|crate_id| {
+                                        let crate_mod = Res::Def(
+                                            DefKind::Mod,
+                                            DefId {
+                                                krate: crate_id,
+                                                index: CRATE_DEF_INDEX,
+                                            },
+                                        );
+
+                                        if filter_fn(crate_mod) {
+                                            Some(TypoSuggestion {
+                                                candidate: ident.name,
+                                                article: "a",
+                                                kind: "crate",
+                                            })
+                                        } else {
+                                            None
+                                        }
+                                    })
+                            }));
+
+                            if let Some(prelude) = self.prelude {
+                                add_module_candidates(prelude, &mut names, &filter_fn);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            // Add primitive types to the mix
+            if filter_fn(Res::PrimTy(PrimTy::Bool)) {
+                names.extend(
+                    self.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
+                        TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
+                    })
+                )
+            }
+        } else {
+            // Search in module.
+            let mod_path = &path[..path.len() - 1];
+            if let PathResult::Module(module) = self.resolve_path_without_parent_scope(
+                mod_path, Some(TypeNS), false, span, CrateLint::No
+            ) {
+                if let ModuleOrUniformRoot::Module(module) = module {
+                    add_module_candidates(module, &mut names, &filter_fn);
+                }
+            }
+        }
+
+        let name = path[path.len() - 1].ident.name;
+        // Make sure error reporting is deterministic.
+        names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
+
+        match find_best_match_for_name(
+            names.iter().map(|suggestion| &suggestion.candidate),
+            &name.as_str(),
+            None,
+        ) {
+            Some(found) if found != name => names
+                .into_iter()
+                .find(|suggestion| suggestion.candidate == found),
+            _ => None,
+        }
+    }
+
+    fn lookup_import_candidates_from_module<FilterFn>(&mut self,
+                                          lookup_ident: Ident,
+                                          namespace: Namespace,
+                                          start_module: Module<'a>,
+                                          crate_name: Ident,
+                                          filter_fn: FilterFn)
+                                          -> Vec<ImportSuggestion>
+        where FilterFn: Fn(Res) -> bool
+    {
+        let mut candidates = Vec::new();
+        let mut seen_modules = FxHashSet::default();
+        let not_local_module = crate_name.name != kw::Crate;
+        let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)];
+
+        while let Some((in_module,
+                        path_segments,
+                        in_module_is_extern)) = worklist.pop() {
+            self.populate_module_if_necessary(in_module);
+
+            // We have to visit module children in deterministic order to avoid
+            // instabilities in reported imports (#43552).
+            in_module.for_each_child_stable(|ident, ns, name_binding| {
+                // avoid imports entirely
+                if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
+                // avoid non-importable candidates as well
+                if !name_binding.is_importable() { return; }
+
+                // collect results based on the filter function
+                if ident.name == lookup_ident.name && ns == namespace {
+                    let res = name_binding.res();
+                    if filter_fn(res) {
+                        // create the path
+                        let mut segms = path_segments.clone();
+                        if lookup_ident.span.rust_2018() {
+                            // crate-local absolute paths start with `crate::` in edition 2018
+                            // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
+                            segms.insert(
+                                0, ast::PathSegment::from_ident(crate_name)
+                            );
+                        }
+
+                        segms.push(ast::PathSegment::from_ident(ident));
+                        let path = Path {
+                            span: name_binding.span,
+                            segments: segms,
+                        };
+                        // the entity is accessible in the following cases:
+                        // 1. if it's defined in the same crate, it's always
+                        // accessible (since private entities can be made public)
+                        // 2. if it's defined in another crate, it's accessible
+                        // only if both the module is public and the entity is
+                        // declared as public (due to pruning, we don't explore
+                        // outside crate private modules => no need to check this)
+                        if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
+                            let did = match res {
+                                Res::Def(DefKind::Ctor(..), did) => self.parent(did),
+                                _ => res.opt_def_id(),
+                            };
+                            candidates.push(ImportSuggestion { did, path });
+                        }
+                    }
+                }
+
+                // collect submodules to explore
+                if let Some(module) = name_binding.module() {
+                    // form the path
+                    let mut path_segments = path_segments.clone();
+                    path_segments.push(ast::PathSegment::from_ident(ident));
+
+                    let is_extern_crate_that_also_appears_in_prelude =
+                        name_binding.is_extern_crate() &&
+                        lookup_ident.span.rust_2018();
+
+                    let is_visible_to_user =
+                        !in_module_is_extern || name_binding.vis == ty::Visibility::Public;
+
+                    if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
+                        // add the module to the lookup
+                        let is_extern = in_module_is_extern || name_binding.is_extern_crate();
+                        if seen_modules.insert(module.def_id().unwrap()) {
+                            worklist.push((module, path_segments, is_extern));
+                        }
+                    }
+                }
+            })
+        }
+
+        candidates
+    }
+
+    /// When name resolution fails, this method can be used to look up candidate
+    /// entities with the expected name. It allows filtering them using the
+    /// supplied predicate (which should be used to only accept the types of
+    /// definitions expected, e.g., traits). The lookup spans across all crates.
+    ///
+    /// N.B., the method does not look into imports, but this is not a problem,
+    /// since we report the definitions (thus, the de-aliased imports).
+    crate fn lookup_import_candidates<FilterFn>(
+        &mut self, lookup_ident: Ident, namespace: Namespace, filter_fn: FilterFn
+    ) -> Vec<ImportSuggestion>
+        where FilterFn: Fn(Res) -> bool
+    {
+        let mut suggestions = self.lookup_import_candidates_from_module(
+            lookup_ident, namespace, self.graph_root, Ident::with_empty_ctxt(kw::Crate), &filter_fn
+        );
+
+        if lookup_ident.span.rust_2018() {
+            let extern_prelude_names = self.extern_prelude.clone();
+            for (ident, _) in extern_prelude_names.into_iter() {
+                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
+                                                                                    ident.span) {
+                    let crate_root = self.get_module(DefId {
+                        krate: crate_id,
+                        index: CRATE_DEF_INDEX,
+                    });
+                    self.populate_module_if_necessary(&crate_root);
+
+                    suggestions.extend(self.lookup_import_candidates_from_module(
+                        lookup_ident, namespace, crate_root, ident, &filter_fn));
+                }
+            }
+        }
+
+        suggestions
+    }
+
+    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
+        let mut result = None;
+        let mut seen_modules = FxHashSet::default();
+        let mut worklist = vec![(self.graph_root, Vec::new())];
+
+        while let Some((in_module, path_segments)) = worklist.pop() {
+            // abort if the module is already found
+            if result.is_some() { break; }
+
+            self.populate_module_if_necessary(in_module);
+
+            in_module.for_each_child_stable(|ident, _, name_binding| {
+                // abort if the module is already found or if name_binding is private external
+                if result.is_some() || !name_binding.vis.is_visible_locally() {
+                    return
+                }
+                if let Some(module) = name_binding.module() {
+                    // form the path
+                    let mut path_segments = path_segments.clone();
+                    path_segments.push(ast::PathSegment::from_ident(ident));
+                    let module_def_id = module.def_id().unwrap();
+                    if module_def_id == def_id {
+                        let path = Path {
+                            span: name_binding.span,
+                            segments: path_segments,
+                        };
+                        result = Some((module, ImportSuggestion { did: Some(def_id), path }));
+                    } else {
+                        // add the module to the lookup
+                        if seen_modules.insert(module_def_id) {
+                            worklist.push((module, path_segments));
+                        }
+                    }
+                }
+            });
+        }
+
+        result
+    }
+
+    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
+        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
+            self.populate_module_if_necessary(enum_module);
+
+            let mut variants = Vec::new();
+            enum_module.for_each_child_stable(|ident, _, name_binding| {
+                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
+                    let mut segms = enum_import_suggestion.path.segments.clone();
+                    segms.push(ast::PathSegment::from_ident(ident));
+                    variants.push(Path {
+                        span: name_binding.span,
+                        segments: segms,
+                    });
+                }
+            });
+            variants
+        })
+    }
+
+    crate fn unresolved_macro_suggestions(
+        &mut self,
+        err: &mut DiagnosticBuilder<'a>,
+        macro_kind: MacroKind,
+        parent_scope: &ParentScope<'a>,
+        ident: Ident,
+    ) {
+        let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
+        let suggestion = self.early_lookup_typo_candidate(
+            ScopeSet::Macro(macro_kind), &parent_scope, ident, is_expected
+        );
+        add_typo_suggestion(err, suggestion, ident.span);
+
+        if macro_kind == MacroKind::Derive &&
+           (ident.as_str() == "Send" || ident.as_str() == "Sync") {
+            let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
+            err.span_note(ident.span, &msg);
+        }
+        if self.macro_names.contains(&ident.modern()) {
+            err.help("have you added the `#[macro_use]` on the module/import?");
+        }
+    }
 }
 
 impl<'a, 'b> ImportResolver<'a, 'b> {
@@ -871,3 +1427,70 @@ fn find_span_immediately_after_crate_name(
 
     (next_left_bracket == after_second_colon, from_second_colon)
 }
+
+/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
+fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
+    let variant_path = &suggestion.path;
+    let variant_path_string = path_names_to_string(variant_path);
+
+    let path_len = suggestion.path.segments.len();
+    let enum_path = ast::Path {
+        span: suggestion.path.span,
+        segments: suggestion.path.segments[0..path_len - 1].to_vec(),
+    };
+    let enum_path_string = path_names_to_string(&enum_path);
+
+    (variant_path_string, enum_path_string)
+}
+
+/// When an entity with a given name is not available in scope, we search for
+/// entities with that name in all crates. This method allows outputting the
+/// results of this search in a programmer-friendly way
+crate fn show_candidates(
+    err: &mut DiagnosticBuilder<'_>,
+    // This is `None` if all placement locations are inside expansions
+    span: Option<Span>,
+    candidates: &[ImportSuggestion],
+    better: bool,
+    found_use: bool,
+) {
+    // we want consistent results across executions, but candidates are produced
+    // by iterating through a hash map, so make sure they are ordered:
+    let mut path_strings: Vec<_> =
+        candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
+    path_strings.sort();
+
+    let better = if better { "better " } else { "" };
+    let msg_diff = match path_strings.len() {
+        1 => " is found in another module, you can import it",
+        _ => "s are found in other modules, you can import them",
+    };
+    let msg = format!("possible {}candidate{} into scope", better, msg_diff);
+
+    if let Some(span) = span {
+        for candidate in &mut path_strings {
+            // produce an additional newline to separate the new use statement
+            // from the directly following item.
+            let additional_newline = if found_use {
+                ""
+            } else {
+                "\n"
+            };
+            *candidate = format!("use {};\n{}", candidate, additional_newline);
+        }
+
+        err.span_suggestions(
+            span,
+            &msg,
+            path_strings.into_iter(),
+            Applicability::Unspecified,
+        );
+    } else {
+        let mut msg = msg;
+        msg.push(':');
+        for candidate in path_strings {
+            msg.push('\n');
+            msg.push_str(&candidate);
+        }
+    }
+}
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index f867fb20785..ba8cfdcf535 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -31,7 +31,7 @@ use rustc::hir::def::{
 use rustc::hir::def::Namespace::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::hir::{TraitCandidate, TraitMap, GlobMap};
-use rustc::ty::{self, DefIdTree};
+use rustc::ty;
 use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
 use rustc::{bug, span_bug};
 
@@ -69,9 +69,10 @@ use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use smallvec::SmallVec;
 
+use diagnostics::{Suggestion, ImportSuggestion};
 use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
-use macros::{InvocationData, LegacyBinding, ParentScope};
+use macros::{InvocationData, LegacyBinding, LegacyScope};
 
 type Res = def::Res<NodeId>;
 
@@ -84,9 +85,7 @@ mod check_unused;
 mod build_reduced_graph;
 mod resolve_imports;
 
-fn is_known_tool(name: Name) -> bool {
-    ["clippy", "rustfmt"].contains(&&*name.as_str())
-}
+const KNOWN_TOOLS: &[Name] = &[sym::clippy, sym::rustfmt];
 
 enum Weak {
     Yes,
@@ -105,6 +104,29 @@ impl Determinacy {
     }
 }
 
+/// A specific scope in which a name can be looked up.
+/// This enum is currently used only for early resolution (imports and macros),
+/// but not for late resolution yet.
+#[derive(Clone, Copy)]
+enum Scope<'a> {
+    DeriveHelpers,
+    MacroRules(LegacyScope<'a>),
+    CrateRoot,
+    Module(Module<'a>),
+    MacroUsePrelude,
+    BuiltinMacros,
+    BuiltinAttrs,
+    LegacyPluginHelpers,
+    ExternPrelude,
+    ToolPrelude,
+    StdLibPrelude,
+    BuiltinTypes,
+}
+
+/// Names from different contexts may want to visit different subsets of all specific scopes
+/// with different restrictions when looking up the resolution.
+/// This enum is currently used only for early resolution (imports and macros),
+/// but not for late resolution yet.
 enum ScopeSet {
     Import(Namespace),
     AbsolutePath(Namespace),
@@ -112,17 +134,16 @@ enum ScopeSet {
     Module,
 }
 
-/// A free importable items suggested in case of resolution failure.
-struct ImportSuggestion {
-    did: Option<DefId>,
-    path: Path,
-}
-
-/// A field or associated item from self type suggested in case of resolution failure.
-enum AssocSuggestion {
-    Field,
-    MethodWithSelf,
-    AssocItem,
+/// Everything you need to know about a name's location to resolve it.
+/// Serves as a starting point for the scope visitor.
+/// This struct is currently used only for early resolution (imports and macros),
+/// but not for late resolution yet.
+#[derive(Clone, Debug)]
+pub struct ParentScope<'a> {
+    module: Module<'a>,
+    expansion: Mark,
+    legacy: LegacyScope<'a>,
+    derives: Vec<ast::Path>,
 }
 
 #[derive(Eq)]
@@ -132,16 +153,6 @@ struct BindingError {
     target: BTreeSet<Span>,
 }
 
-struct TypoSuggestion {
-    candidate: Symbol,
-
-    /// The kind of the binding ("crate", "module", etc.)
-    kind: &'static str,
-
-    /// An appropriate article to refer to the binding ("a", "an", etc.)
-    article: &'static str,
-}
-
 impl PartialOrd for BindingError {
     fn partial_cmp(&self, other: &BindingError) -> Option<cmp::Ordering> {
         Some(self.cmp(other))
@@ -160,9 +171,6 @@ impl Ord for BindingError {
     }
 }
 
-/// A vector of spans and replacements, a message and applicability.
-type Suggestion = (Vec<(Span, String)>, String, Applicability);
-
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer function.
     GenericParamsFromOuterFunction(Res),
@@ -1488,11 +1496,7 @@ impl<'a> NameBinding<'a> {
     }
 
     fn macro_kind(&self) -> Option<MacroKind> {
-        match self.res() {
-            Res::Def(DefKind::Macro(kind), _) => Some(kind),
-            Res::NonMacroAttr(..) => Some(MacroKind::Attr),
-            _ => None,
-        }
+        self.res().macro_kind()
     }
 
     fn descr(&self) -> &'static str {
@@ -2134,6 +2138,149 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    /// A generic scope visitor.
+    /// Visits scopes in order to resolve some identifier in them or perform other actions.
+    /// If the callback returns `Some` result, we stop visiting scopes and return it.
+    fn visit_scopes<T>(
+        &mut self,
+        scope_set: ScopeSet,
+        parent_scope: &ParentScope<'a>,
+        ident: Ident,
+        mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
+    ) -> Option<T> {
+        // 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
+        //    language or standard library without breaking user code.
+        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
+        // Places to search (in order of decreasing priority):
+        // (Type NS)
+        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Extern prelude (open, the open part is from macro expansions, not controlled).
+        // 4. Tool modules (closed, controlled right now, but not in the future).
+        // 5. Standard library prelude (de-facto closed, controlled).
+        // 6. Language prelude (closed, controlled).
+        // (Value NS)
+        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Standard library prelude (de-facto closed, controlled).
+        // (Macro NS)
+        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
+        //    are currently reported as errors. They should be higher in priority than preludes
+        //    and probably 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.
+        // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
+        //    priority than prelude macros, but create ambiguities with macros in modules.
+        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled). Have higher priority than prelude macros, but create
+        //    ambiguities with `macro_rules`.
+        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
+        // 4a. User-defined prelude from macro-use
+        //    (open, the open part is from macro expansions, not controlled).
+        // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
+        // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
+        // 6. Language prelude: builtin attributes (closed, controlled).
+        // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
+        //    but introduced by legacy plugins using `register_attribute`. Priority is somewhere
+        //    in prelude, not sure where exactly (creates ambiguities with any other prelude names).
+
+        let rust_2015 = ident.span.rust_2015();
+        let (ns, is_absolute_path) = match scope_set {
+            ScopeSet::Import(ns) => (ns, false),
+            ScopeSet::AbsolutePath(ns) => (ns, true),
+            ScopeSet::Macro(_) => (MacroNS, false),
+            ScopeSet::Module => (TypeNS, false),
+        };
+        let mut scope = match ns {
+            _ if is_absolute_path => Scope::CrateRoot,
+            TypeNS | ValueNS => Scope::Module(parent_scope.module),
+            MacroNS => Scope::DeriveHelpers,
+        };
+        let mut ident = ident.modern();
+        let mut use_prelude = !parent_scope.module.no_implicit_prelude;
+
+        loop {
+            let visit = match scope {
+                Scope::DeriveHelpers => true,
+                Scope::MacroRules(..) => true,
+                Scope::CrateRoot => true,
+                Scope::Module(..) => true,
+                Scope::MacroUsePrelude => use_prelude || rust_2015,
+                Scope::BuiltinMacros => true,
+                Scope::BuiltinAttrs => true,
+                Scope::LegacyPluginHelpers => use_prelude || rust_2015,
+                Scope::ExternPrelude => use_prelude || is_absolute_path,
+                Scope::ToolPrelude => use_prelude,
+                Scope::StdLibPrelude => use_prelude,
+                Scope::BuiltinTypes => true,
+            };
+
+            if visit {
+                if let break_result @ Some(..) = visitor(self, scope, ident) {
+                    return break_result;
+                }
+            }
+
+            scope = match scope {
+                Scope::DeriveHelpers =>
+                    Scope::MacroRules(parent_scope.legacy),
+                Scope::MacroRules(legacy_scope) => match legacy_scope {
+                    LegacyScope::Binding(binding) => Scope::MacroRules(
+                        binding.parent_legacy_scope
+                    ),
+                    LegacyScope::Invocation(invoc) => Scope::MacroRules(
+                        invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
+                    ),
+                    LegacyScope::Empty => Scope::Module(parent_scope.module),
+                }
+                Scope::CrateRoot => match ns {
+                    TypeNS => {
+                        ident.span.adjust(Mark::root());
+                        Scope::ExternPrelude
+                    }
+                    ValueNS | MacroNS => break,
+                }
+                Scope::Module(module) => {
+                    use_prelude = !module.no_implicit_prelude;
+                    match self.hygienic_lexical_parent(module, &mut ident.span) {
+                        Some(parent_module) => Scope::Module(parent_module),
+                        None => {
+                            ident.span.adjust(Mark::root());
+                            match ns {
+                                TypeNS => Scope::ExternPrelude,
+                                ValueNS => Scope::StdLibPrelude,
+                                MacroNS => Scope::MacroUsePrelude,
+                            }
+                        }
+                    }
+                }
+                Scope::MacroUsePrelude => Scope::StdLibPrelude,
+                Scope::BuiltinMacros => Scope::BuiltinAttrs,
+                Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
+                Scope::LegacyPluginHelpers => break, // nowhere else to search
+                Scope::ExternPrelude if is_absolute_path => break,
+                Scope::ExternPrelude => Scope::ToolPrelude,
+                Scope::ToolPrelude => Scope::StdLibPrelude,
+                Scope::StdLibPrelude => match ns {
+                    TypeNS => Scope::BuiltinTypes,
+                    ValueNS => break, // nowhere else to search
+                    MacroNS => Scope::BuiltinMacros,
+                }
+                Scope::BuiltinTypes => break, // nowhere else to search
+            };
+        }
+
+        None
+    }
+
     /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
     /// More specifically, we proceed up the hierarchy of scopes and return the binding for
     /// `ident` in the first scope that defines it (or None if no scopes define it).
@@ -2258,7 +2405,7 @@ impl<'a> Resolver<'a> {
                     return Some(LexicalScopeBinding::Item(binding));
                 }
             }
-            if ns == TypeNS && is_known_tool(ident.name) {
+            if ns == TypeNS && KNOWN_TOOLS.contains(&ident.name) {
                 let binding = (Res::ToolMod, ty::Visibility::Public,
                                DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
                 return Some(LexicalScopeBinding::Item(binding));
@@ -3517,9 +3664,7 @@ impl<'a> Resolver<'a> {
         crate_lint: CrateLint,
     ) -> Option<PartialRes> {
         let mut fin_res = None;
-        // FIXME: can't resolve paths in macro namespace yet, macros are
-        // processed by the little special hack below.
-        for (i, ns) in [primary_ns, TypeNS, ValueNS, /*MacroNS*/].iter().cloned().enumerate() {
+        for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
             if i == 0 || ns != primary_ns {
                 match self.resolve_qpath(id, qself, path, ns, span, global_by_default, crate_lint) {
                     // If defer_to_typeck, then resolution > no resolution,
@@ -3528,21 +3673,23 @@ impl<'a> Resolver<'a> {
                                          defer_to_typeck =>
                         return Some(partial_res),
                     partial_res => if fin_res.is_none() { fin_res = partial_res },
-                };
+                }
             }
         }
-        if primary_ns != MacroNS &&
-           (self.macro_names.contains(&path[0].ident.modern()) ||
-            self.builtin_macros.get(&path[0].ident.name).cloned()
-                               .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
-            self.macro_use_prelude.get(&path[0].ident.name).cloned()
-                                  .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
-            // Return some dummy definition, it's enough for error reporting.
-            return Some(PartialRes::new(Res::Def(
-                DefKind::Macro(MacroKind::Bang),
-                DefId::local(CRATE_DEF_INDEX),
-            )));
+
+        // `MacroNS`
+        assert!(primary_ns != MacroNS);
+        if qself.is_none() {
+            let path_seg = |seg: &Segment| ast::PathSegment::from_ident(seg.ident);
+            let path = Path { segments: path.iter().map(path_seg).collect(), span };
+            let parent_scope =
+                ParentScope { module: self.current_module, ..self.dummy_parent_scope() };
+            if let Ok((_, res)) =
+                    self.resolve_macro_path(&path, None, &parent_scope, false, false) {
+                return Some(PartialRes::new(res));
+            }
         }
+
         fin_res
     }
 
@@ -4124,195 +4271,6 @@ impl<'a> Resolver<'a> {
         res
     }
 
-    fn lookup_assoc_candidate<FilterFn: Fn(Res) -> bool>(
-        &mut self,
-        ident: Ident,
-        ns: Namespace,
-        filter_fn: FilterFn,
-    ) -> Option<AssocSuggestion> {
-        fn extract_node_id(t: &Ty) -> Option<NodeId> {
-            match t.node {
-                TyKind::Path(None, _) => Some(t.id),
-                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
-                // This doesn't handle the remaining `Ty` variants as they are not
-                // that commonly the self_type, it might be interesting to provide
-                // support for those in future.
-                _ => None,
-            }
-        }
-
-        // Fields are generally expected in the same contexts as locals.
-        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
-            if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
-                // Look for a field with the same name in the current self_type.
-                if let Some(resolution) = self.partial_res_map.get(&node_id) {
-                    match resolution.base_res() {
-                        Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did)
-                                if resolution.unresolved_segments() == 0 => {
-                            if let Some(field_names) = self.field_names.get(&did) {
-                                if field_names.iter().any(|&field_name| ident.name == field_name) {
-                                    return Some(AssocSuggestion::Field);
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
-        }
-
-        for assoc_type_ident in &self.current_trait_assoc_types {
-            if *assoc_type_ident == ident {
-                return Some(AssocSuggestion::AssocItem);
-            }
-        }
-
-        // Look for associated items in the current trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            if let Ok(binding) = self.resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    None,
-                    false,
-                    module.span,
-                ) {
-                let res = binding.res();
-                if filter_fn(res) {
-                    debug!("extract_node_id res not filtered");
-                    return Some(if self.has_self.contains(&res.def_id()) {
-                        AssocSuggestion::MethodWithSelf
-                    } else {
-                        AssocSuggestion::AssocItem
-                    });
-                }
-            }
-        }
-
-        None
-    }
-
-    fn lookup_typo_candidate<FilterFn>(
-        &mut self,
-        path: &[Segment],
-        ns: Namespace,
-        filter_fn: FilterFn,
-        span: Span,
-    ) -> Option<TypoSuggestion>
-    where
-        FilterFn: Fn(Res) -> bool,
-    {
-        let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
-            for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
-                if let Some(binding) = resolution.borrow().binding {
-                    if filter_fn(binding.res()) {
-                        names.push(TypoSuggestion {
-                            candidate: ident.name,
-                            article: binding.res().article(),
-                            kind: binding.res().descr(),
-                        });
-                    }
-                }
-            }
-        };
-
-        let mut names = Vec::new();
-        if path.len() == 1 {
-            // Search in lexical scope.
-            // Walk backwards up the ribs in scope and collect candidates.
-            for rib in self.ribs[ns].iter().rev() {
-                // Locals and type parameters
-                for (ident, &res) in &rib.bindings {
-                    if filter_fn(res) {
-                        names.push(TypoSuggestion {
-                            candidate: ident.name,
-                            article: res.article(),
-                            kind: res.descr(),
-                        });
-                    }
-                }
-                // Items in scope
-                if let ModuleRibKind(module) = rib.kind {
-                    // Items from this module
-                    add_module_candidates(module, &mut names);
-
-                    if let ModuleKind::Block(..) = module.kind {
-                        // We can see through blocks
-                    } else {
-                        // Items from the prelude
-                        if !module.no_implicit_prelude {
-                            names.extend(self.extern_prelude.clone().iter().flat_map(|(ident, _)| {
-                                self.crate_loader
-                                    .maybe_process_path_extern(ident.name, ident.span)
-                                    .and_then(|crate_id| {
-                                        let crate_mod = Res::Def(
-                                            DefKind::Mod,
-                                            DefId {
-                                                krate: crate_id,
-                                                index: CRATE_DEF_INDEX,
-                                            },
-                                        );
-
-                                        if filter_fn(crate_mod) {
-                                            Some(TypoSuggestion {
-                                                candidate: ident.name,
-                                                article: "a",
-                                                kind: "crate",
-                                            })
-                                        } else {
-                                            None
-                                        }
-                                    })
-                            }));
-
-                            if let Some(prelude) = self.prelude {
-                                add_module_candidates(prelude, &mut names);
-                            }
-                        }
-                        break;
-                    }
-                }
-            }
-            // Add primitive types to the mix
-            if filter_fn(Res::PrimTy(Bool)) {
-                names.extend(
-                    self.primitive_type_table.primitive_types.iter().map(|(name, _)| {
-                        TypoSuggestion {
-                            candidate: *name,
-                            article: "a",
-                            kind: "primitive type",
-                        }
-                    })
-                )
-            }
-        } else {
-            // Search in module.
-            let mod_path = &path[..path.len() - 1];
-            if let PathResult::Module(module) = self.resolve_path_without_parent_scope(
-                mod_path, Some(TypeNS), false, span, CrateLint::No
-            ) {
-                if let ModuleOrUniformRoot::Module(module) = module {
-                    add_module_candidates(module, &mut names);
-                }
-            }
-        }
-
-        let name = path[path.len() - 1].ident.name;
-        // Make sure error reporting is deterministic.
-        names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
-
-        match find_best_match_for_name(
-            names.iter().map(|suggestion| &suggestion.candidate),
-            &name.as_str(),
-            None,
-        ) {
-            Some(found) if found != name => names
-                .into_iter()
-                .find(|suggestion| suggestion.candidate == found),
-            _ => None,
-        }
-    }
-
     fn with_resolved_label<F>(&mut self, label: Option<Label>, id: NodeId, f: F)
         where F: FnOnce(&mut Resolver<'_>)
     {
@@ -4606,193 +4564,6 @@ impl<'a> Resolver<'a> {
         import_ids
     }
 
-    fn lookup_import_candidates_from_module<FilterFn>(&mut self,
-                                          lookup_ident: Ident,
-                                          namespace: Namespace,
-                                          start_module: &'a ModuleData<'a>,
-                                          crate_name: Ident,
-                                          filter_fn: FilterFn)
-                                          -> Vec<ImportSuggestion>
-        where FilterFn: Fn(Res) -> bool
-    {
-        let mut candidates = Vec::new();
-        let mut seen_modules = FxHashSet::default();
-        let not_local_module = crate_name.name != kw::Crate;
-        let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)];
-
-        while let Some((in_module,
-                        path_segments,
-                        in_module_is_extern)) = worklist.pop() {
-            self.populate_module_if_necessary(in_module);
-
-            // We have to visit module children in deterministic order to avoid
-            // instabilities in reported imports (#43552).
-            in_module.for_each_child_stable(|ident, ns, name_binding| {
-                // avoid imports entirely
-                if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
-                // avoid non-importable candidates as well
-                if !name_binding.is_importable() { return; }
-
-                // collect results based on the filter function
-                if ident.name == lookup_ident.name && ns == namespace {
-                    let res = name_binding.res();
-                    if filter_fn(res) {
-                        // create the path
-                        let mut segms = path_segments.clone();
-                        if lookup_ident.span.rust_2018() {
-                            // crate-local absolute paths start with `crate::` in edition 2018
-                            // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
-                            segms.insert(
-                                0, ast::PathSegment::from_ident(crate_name)
-                            );
-                        }
-
-                        segms.push(ast::PathSegment::from_ident(ident));
-                        let path = Path {
-                            span: name_binding.span,
-                            segments: segms,
-                        };
-                        // the entity is accessible in the following cases:
-                        // 1. if it's defined in the same crate, it's always
-                        // accessible (since private entities can be made public)
-                        // 2. if it's defined in another crate, it's accessible
-                        // only if both the module is public and the entity is
-                        // declared as public (due to pruning, we don't explore
-                        // outside crate private modules => no need to check this)
-                        if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
-                            let did = match res {
-                                Res::Def(DefKind::Ctor(..), did) => self.parent(did),
-                                _ => res.opt_def_id(),
-                            };
-                            candidates.push(ImportSuggestion { did, path });
-                        }
-                    }
-                }
-
-                // collect submodules to explore
-                if let Some(module) = name_binding.module() {
-                    // form the path
-                    let mut path_segments = path_segments.clone();
-                    path_segments.push(ast::PathSegment::from_ident(ident));
-
-                    let is_extern_crate_that_also_appears_in_prelude =
-                        name_binding.is_extern_crate() &&
-                        lookup_ident.span.rust_2018();
-
-                    let is_visible_to_user =
-                        !in_module_is_extern || name_binding.vis == ty::Visibility::Public;
-
-                    if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
-                        // add the module to the lookup
-                        let is_extern = in_module_is_extern || name_binding.is_extern_crate();
-                        if seen_modules.insert(module.def_id().unwrap()) {
-                            worklist.push((module, path_segments, is_extern));
-                        }
-                    }
-                }
-            })
-        }
-
-        candidates
-    }
-
-    /// When name resolution fails, this method can be used to look up candidate
-    /// entities with the expected name. It allows filtering them using the
-    /// supplied predicate (which should be used to only accept the types of
-    /// definitions expected, e.g., traits). The lookup spans across all crates.
-    ///
-    /// N.B., the method does not look into imports, but this is not a problem,
-    /// since we report the definitions (thus, the de-aliased imports).
-    fn lookup_import_candidates<FilterFn>(&mut self,
-                                          lookup_ident: Ident,
-                                          namespace: Namespace,
-                                          filter_fn: FilterFn)
-                                          -> Vec<ImportSuggestion>
-        where FilterFn: Fn(Res) -> bool
-    {
-        let mut suggestions = self.lookup_import_candidates_from_module(
-            lookup_ident, namespace, self.graph_root, Ident::with_empty_ctxt(kw::Crate), &filter_fn
-        );
-
-        if lookup_ident.span.rust_2018() {
-            let extern_prelude_names = self.extern_prelude.clone();
-            for (ident, _) in extern_prelude_names.into_iter() {
-                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
-                                                                                    ident.span) {
-                    let crate_root = self.get_module(DefId {
-                        krate: crate_id,
-                        index: CRATE_DEF_INDEX,
-                    });
-                    self.populate_module_if_necessary(&crate_root);
-
-                    suggestions.extend(self.lookup_import_candidates_from_module(
-                        lookup_ident, namespace, crate_root, ident, &filter_fn));
-                }
-            }
-        }
-
-        suggestions
-    }
-
-    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
-        let mut result = None;
-        let mut seen_modules = FxHashSet::default();
-        let mut worklist = vec![(self.graph_root, Vec::new())];
-
-        while let Some((in_module, path_segments)) = worklist.pop() {
-            // abort if the module is already found
-            if result.is_some() { break; }
-
-            self.populate_module_if_necessary(in_module);
-
-            in_module.for_each_child_stable(|ident, _, name_binding| {
-                // abort if the module is already found or if name_binding is private external
-                if result.is_some() || !name_binding.vis.is_visible_locally() {
-                    return
-                }
-                if let Some(module) = name_binding.module() {
-                    // form the path
-                    let mut path_segments = path_segments.clone();
-                    path_segments.push(ast::PathSegment::from_ident(ident));
-                    let module_def_id = module.def_id().unwrap();
-                    if module_def_id == def_id {
-                        let path = Path {
-                            span: name_binding.span,
-                            segments: path_segments,
-                        };
-                        result = Some((module, ImportSuggestion { did: Some(def_id), path }));
-                    } else {
-                        // add the module to the lookup
-                        if seen_modules.insert(module_def_id) {
-                            worklist.push((module, path_segments));
-                        }
-                    }
-                }
-            });
-        }
-
-        result
-    }
-
-    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
-        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
-            self.populate_module_if_necessary(enum_module);
-
-            let mut variants = Vec::new();
-            enum_module.for_each_child_stable(|ident, _, name_binding| {
-                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
-                    let mut segms = enum_import_suggestion.path.segments.clone();
-                    segms.push(ast::PathSegment::from_ident(ident));
-                    variants.push(Path {
-                        span: name_binding.span,
-                        segments: segms,
-                    });
-                }
-            });
-            variants
-        })
-    }
-
     fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         debug!("(recording res) recording {:?} for {}", resolution, node_id);
         if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
@@ -5010,7 +4781,7 @@ impl<'a> Resolver<'a> {
         for UseError { mut err, candidates, node_id, better } in self.use_injections.drain(..) {
             let (span, found_use) = UsePlacementFinder::check(krate, node_id);
             if !candidates.is_empty() {
-                show_candidates(&mut err, span, &candidates, better, found_use);
+                diagnostics::show_candidates(&mut err, span, &candidates, better, found_use);
             }
             err.emit();
         }
@@ -5326,72 +5097,6 @@ fn path_names_to_string(path: &Path) -> String {
                         .collect::<Vec<_>>())
 }
 
-/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
-fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
-    let variant_path = &suggestion.path;
-    let variant_path_string = path_names_to_string(variant_path);
-
-    let path_len = suggestion.path.segments.len();
-    let enum_path = ast::Path {
-        span: suggestion.path.span,
-        segments: suggestion.path.segments[0..path_len - 1].to_vec(),
-    };
-    let enum_path_string = path_names_to_string(&enum_path);
-
-    (variant_path_string, enum_path_string)
-}
-
-/// When an entity with a given name is not available in scope, we search for
-/// entities with that name in all crates. This method allows outputting the
-/// results of this search in a programmer-friendly way
-fn show_candidates(err: &mut DiagnosticBuilder<'_>,
-                   // This is `None` if all placement locations are inside expansions
-                   span: Option<Span>,
-                   candidates: &[ImportSuggestion],
-                   better: bool,
-                   found_use: bool) {
-
-    // we want consistent results across executions, but candidates are produced
-    // by iterating through a hash map, so make sure they are ordered:
-    let mut path_strings: Vec<_> =
-        candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
-    path_strings.sort();
-
-    let better = if better { "better " } else { "" };
-    let msg_diff = match path_strings.len() {
-        1 => " is found in another module, you can import it",
-        _ => "s are found in other modules, you can import them",
-    };
-    let msg = format!("possible {}candidate{} into scope", better, msg_diff);
-
-    if let Some(span) = span {
-        for candidate in &mut path_strings {
-            // produce an additional newline to separate the new use statement
-            // from the directly following item.
-            let additional_newline = if found_use {
-                ""
-            } else {
-                "\n"
-            };
-            *candidate = format!("use {};\n{}", candidate, additional_newline);
-        }
-
-        err.span_suggestions(
-            span,
-            &msg,
-            path_strings.into_iter(),
-            Applicability::Unspecified,
-        );
-    } else {
-        let mut msg = msg;
-        msg.push(':');
-        for candidate in path_strings {
-            msg.push('\n');
-            msg.push_str(&candidate);
-        }
-    }
-}
-
 /// A somewhat inefficient routine to obtain the name of a module.
 fn module_to_string(module: Module<'_>) -> Option<String> {
     let mut names = Vec::new();
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index fc1becfe309..34e85e1cf10 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1,7 +1,7 @@
 use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
-use crate::{CrateLint, Resolver, ResolutionError, ScopeSet, Weak};
+use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
 use crate::{Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
-use crate::{is_known_tool, resolve_error};
+use crate::{resolve_error, KNOWN_TOOLS};
 use crate::ModuleOrUniformRoot;
 use crate::Namespace::*;
 use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@@ -13,18 +13,15 @@ use rustc::middle::stability;
 use rustc::{ty, lint, span_bug};
 use syntax::ast::{self, Ident, ItemKind};
 use syntax::attr::{self, StabilityLevel};
-use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Indeterminate};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
 use syntax::ext::hygiene::{self, Mark, ExpnInfo, ExpnKind};
 use syntax::ext::tt::macro_rules;
-use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name};
-use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES};
+use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
+use syntax::feature_gate::GateIssue;
 use syntax::symbol::{Symbol, kw, sym};
-use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{Span, DUMMY_SP};
-use errors::Applicability;
 
 use std::cell::Cell;
 use std::{mem, ptr};
@@ -60,10 +57,10 @@ impl<'a> InvocationData<'a> {
 /// Not modularized, can shadow previous legacy bindings, etc.
 #[derive(Debug)]
 pub struct LegacyBinding<'a> {
-    binding: &'a NameBinding<'a>,
+    crate binding: &'a NameBinding<'a>,
     /// Legacy scope into which the `macro_rules` item was planted.
-    parent_legacy_scope: LegacyScope<'a>,
-    ident: Ident,
+    crate parent_legacy_scope: LegacyScope<'a>,
+    crate ident: Ident,
 }
 
 /// The scope introduced by a `macro_rules!` macro.
@@ -82,15 +79,6 @@ pub enum LegacyScope<'a> {
     Invocation(&'a InvocationData<'a>),
 }
 
-/// Everything you need to resolve a macro or import path.
-#[derive(Clone, Debug)]
-pub struct ParentScope<'a> {
-    crate module: Module<'a>,
-    crate expansion: Mark,
-    crate legacy: LegacyScope<'a>,
-    crate derives: Vec<ast::Path>,
-}
-
 // Macro namespace is separated into two sub-namespaces, one for bang macros and
 // one for attribute-like macros (attributes, derives).
 // We ignore resolutions from one sub-namespace when searching names in scope for another.
@@ -232,7 +220,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         };
 
         let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
-        let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, true, force)?;
+        let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, force)?;
 
         let span = invoc.span();
         invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, fast_print_path(path)));
@@ -281,10 +269,10 @@ impl<'a> Resolver<'a> {
         path: &ast::Path,
         kind: MacroKind,
         parent_scope: &ParentScope<'a>,
-        trace: bool,
         force: bool,
     ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
-        let (ext, res) = match self.resolve_macro_path(path, kind, parent_scope, trace, force) {
+        let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope,
+                                                       true, force) {
             Ok((Some(ext), res)) => (ext, res),
             // Use dummy syntax extensions for unresolved macros for better recovery.
             Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -324,23 +312,7 @@ impl<'a> Resolver<'a> {
                     }
                 }
             }
-            Res::NonMacroAttr(attr_kind) => {
-                if attr_kind == NonMacroAttrKind::Custom {
-                    assert!(path.segments.len() == 1);
-                    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);
-                        self.report_unknown_attribute(
-                            path.span,
-                            &path.segments[0].ident.as_str(),
-                            &msg,
-                            sym::custom_attribute,
-                        );
-                    }
-                }
-            }
-            Res::Err => {}
+            Res::NonMacroAttr(..) | Res::Err => {}
             _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
         };
 
@@ -359,64 +331,10 @@ impl<'a> Resolver<'a> {
         })
     }
 
-    fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) {
-        let mut err = feature_err(
-            &self.session.parse_sess,
-            feature,
-            span,
-            GateIssue::Language,
-            &msg,
-        );
-
-        let features = self.session.features_untracked();
-
-        let attr_candidates = BUILTIN_ATTRIBUTES
-            .iter()
-            .filter_map(|&(name, _, _, ref gate)| {
-                if name.as_str().starts_with("rustc_") && !features.rustc_attrs {
-                    return None;
-                }
-
-                match gate {
-                    AttributeGate::Gated(Stability::Unstable, ..)
-                        if self.session.opts.unstable_features.is_nightly_build() =>
-                    {
-                        Some(name)
-                    }
-                    AttributeGate::Gated(Stability::Deprecated(..), ..) => Some(name),
-                    AttributeGate::Ungated => Some(name),
-                    _ => None,
-                }
-            })
-            .chain(
-                // Add built-in macro attributes as well.
-                self.builtin_macros.iter().filter_map(|(name, binding)| {
-                    match binding.macro_kind() {
-                        Some(MacroKind::Attr) => Some(*name),
-                        _ => None,
-                    }
-                }),
-            )
-            .collect::<Vec<_>>();
-
-        let lev_suggestion = find_best_match_for_name(attr_candidates.iter(), &name, None);
-
-        if let Some(suggestion) = lev_suggestion {
-            err.span_suggestion(
-                span,
-                "a built-in attribute with a similar name exists",
-                suggestion.to_string(),
-                Applicability::MaybeIncorrect,
-            );
-        }
-
-        err.emit();
-    }
-
     pub fn resolve_macro_path(
         &mut self,
         path: &ast::Path,
-        kind: MacroKind,
+        kind: Option<MacroKind>,
         parent_scope: &ParentScope<'a>,
         trace: bool,
         force: bool,
@@ -425,7 +343,7 @@ impl<'a> Resolver<'a> {
         let mut path = Segment::from_path(path);
 
         // Possibly apply the macro helper hack
-        if kind == MacroKind::Bang && path.len() == 1 &&
+        if kind == Some(MacroKind::Bang) && path.len() == 1 &&
            path[0].ident.span.ctxt().outer_expn_info()
                .map_or(false, |info| info.local_inner_macros) {
             let root = Ident::new(kw::DollarCrate, path[0].ident.span);
@@ -446,6 +364,7 @@ impl<'a> Resolver<'a> {
             };
 
             if trace {
+                let kind = kind.expect("macro kind must be specified if tracing is enabled");
                 parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
                     .push((path, path_span, kind, parent_scope.clone(), res.ok()));
             }
@@ -453,14 +372,17 @@ impl<'a> Resolver<'a> {
             self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
             res
         } else {
+            // Macro without a specific kind restriction is equvalent to a macro import.
+            let scope_set = kind.map_or(ScopeSet::Import(MacroNS), ScopeSet::Macro);
             let binding = self.early_resolve_ident_in_lexical_scope(
-                path[0].ident, ScopeSet::Macro(kind), parent_scope, false, force, path_span
+                path[0].ident, scope_set, parent_scope, false, force, path_span
             );
             if let Err(Determinacy::Undetermined) = binding {
                 return Err(Determinacy::Undetermined);
             }
 
             if trace {
+                let kind = kind.expect("macro kind must be specified if tracing is enabled");
                 parent_scope.module.single_segment_macro_resolutions.borrow_mut()
                     .push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
             }
@@ -487,65 +409,6 @@ impl<'a> Resolver<'a> {
         force: bool,
         path_span: Span,
     ) -> Result<&'a NameBinding<'a>, 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
-        //    language or standard library without breaking user code.
-        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
-        // Places to search (in order of decreasing priority):
-        // (Type NS)
-        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Extern prelude (closed, not controlled).
-        // 4. Tool modules (closed, controlled right now, but not in the future).
-        // 5. Standard library prelude (de-facto closed, controlled).
-        // 6. Language prelude (closed, controlled).
-        // (Value NS)
-        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Standard library prelude (de-facto closed, controlled).
-        // (Macro NS)
-        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
-        //    are currently reported as errors. They should be higher in priority than preludes
-        //    and probably 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.
-        // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
-        //    priority than prelude macros, but create ambiguities with macros in modules.
-        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled). Have higher priority than prelude macros, but create
-        //    ambiguities with `macro_rules`.
-        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
-        // 4a. User-defined prelude from macro-use
-        //    (open, the open part is from macro expansions, not controlled).
-        // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
-        // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
-        // 6. Language prelude: builtin attributes (closed, controlled).
-        // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
-        //    but introduced by legacy plugins using `register_attribute`. Priority is somewhere
-        //    in prelude, not sure where exactly (creates ambiguities with any other prelude names).
-
-        enum WhereToResolve<'a> {
-            DeriveHelpers,
-            MacroRules(LegacyScope<'a>),
-            CrateRoot,
-            Module(Module<'a>),
-            MacroUsePrelude,
-            BuiltinMacros,
-            BuiltinAttrs,
-            LegacyPluginHelpers,
-            ExternPrelude,
-            ToolPrelude,
-            StdLibPrelude,
-            BuiltinTypes,
-        }
-
         bitflags::bitflags! {
             struct Flags: u8 {
                 const MACRO_RULES        = 1 << 0;
@@ -558,13 +421,19 @@ impl<'a> Resolver<'a> {
         }
 
         assert!(force || !record_used); // `record_used` implies `force`
-        let mut ident = orig_ident.modern();
 
         // Make sure `self`, `super` etc produce an error when passed to here.
-        if ident.is_path_segment_keyword() {
+        if orig_ident.is_path_segment_keyword() {
             return Err(Determinacy::Determined);
         }
 
+        let (ns, macro_kind, is_import) = match scope_set {
+            ScopeSet::Import(ns) => (ns, None, true),
+            ScopeSet::AbsolutePath(ns) => (ns, None, false),
+            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
+            ScopeSet::Module => (TypeNS, None, false),
+        };
+
         // This is *the* result, resolution from the scope closest to the resolved identifier.
         // However, sometimes this result is "weak" because it comes from a glob import or
         // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
@@ -577,34 +446,22 @@ impl<'a> Resolver<'a> {
         // So we have to save the innermost solution and continue searching in outer scopes
         // to detect potential ambiguities.
         let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
+        let mut determinacy = Determinacy::Determined;
 
         // Go through all the scopes and try to resolve the name.
-        let rust_2015 = orig_ident.span.rust_2015();
-        let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
-            ScopeSet::Import(ns) => (ns, None, true, false),
-            ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
-            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
-            ScopeSet::Module => (TypeNS, None, false, false),
-        };
-        let mut where_to_resolve = match ns {
-            _ if is_absolute_path => WhereToResolve::CrateRoot,
-            TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module),
-            MacroNS => WhereToResolve::DeriveHelpers,
-        };
-        let mut use_prelude = !parent_scope.module.no_implicit_prelude;
-        let mut determinacy = Determinacy::Determined;
-        loop {
-            let result = match where_to_resolve {
-                WhereToResolve::DeriveHelpers => {
+        let break_result =
+                self.visit_scopes(scope_set, parent_scope, orig_ident, |this, scope, ident| {
+            let result = match scope {
+                Scope::DeriveHelpers => {
                     let mut result = Err(Determinacy::Determined);
                     for derive in &parent_scope.derives {
                         let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
-                        match self.resolve_macro_path(derive, MacroKind::Derive,
+                        match this.resolve_macro_path(derive, Some(MacroKind::Derive),
                                                       &parent_scope, true, force) {
                             Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
                                 let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
                                                ty::Visibility::Public, derive.span, Mark::root())
-                                               .to_name_binding(self.arenas);
+                                               .to_name_binding(this.arenas);
                                 result = Ok((binding, Flags::empty()));
                                 break;
                             }
@@ -615,19 +472,19 @@ impl<'a> Resolver<'a> {
                     }
                     result
                 }
-                WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
+                Scope::MacroRules(legacy_scope) => match legacy_scope {
                     LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
                         Ok((legacy_binding.binding, Flags::MACRO_RULES)),
                     LegacyScope::Invocation(invoc) if invoc.output_legacy_scope.get().is_none() =>
                         Err(Determinacy::Undetermined),
                     _ => Err(Determinacy::Determined),
                 }
-                WhereToResolve::CrateRoot => {
-                    let root_ident = Ident::new(kw::PathRoot, orig_ident.span);
-                    let root_module = self.resolve_crate_root(root_ident);
-                    let binding = self.resolve_ident_in_module_ext(
+                Scope::CrateRoot => {
+                    let root_ident = Ident::new(kw::PathRoot, ident.span);
+                    let root_module = this.resolve_crate_root(root_ident);
+                    let binding = this.resolve_ident_in_module_ext(
                         ModuleOrUniformRoot::Module(root_module),
-                        orig_ident,
+                        ident,
                         ns,
                         None,
                         record_used,
@@ -636,15 +493,15 @@ impl<'a> Resolver<'a> {
                     match binding {
                         Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
                         Err((Determinacy::Undetermined, Weak::No)) =>
-                            return Err(Determinacy::determined(force)),
+                            return Some(Err(Determinacy::determined(force))),
                         Err((Determinacy::Undetermined, Weak::Yes)) =>
                             Err(Determinacy::Undetermined),
                         Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                     }
                 }
-                WhereToResolve::Module(module) => {
-                    let orig_current_module = mem::replace(&mut self.current_module, module);
-                    let binding = self.resolve_ident_in_module_unadjusted_ext(
+                Scope::Module(module) => {
+                    let orig_current_module = mem::replace(&mut this.current_module, module);
+                    let binding = this.resolve_ident_in_module_unadjusted_ext(
                         ModuleOrUniformRoot::Module(module),
                         ident,
                         ns,
@@ -653,10 +510,10 @@ impl<'a> Resolver<'a> {
                         record_used,
                         path_span,
                     );
-                    self.current_module = orig_current_module;
+                    this.current_module = orig_current_module;
                     match binding {
                         Ok(binding) => {
-                            let misc_flags = if ptr::eq(module, self.graph_root) {
+                            let misc_flags = if ptr::eq(module, this.graph_root) {
                                 Flags::MISC_SUGGEST_CRATE
                             } else if module.is_normal() {
                                 Flags::MISC_SUGGEST_SELF
@@ -666,107 +523,82 @@ impl<'a> Resolver<'a> {
                             Ok((binding, Flags::MODULE | misc_flags))
                         }
                         Err((Determinacy::Undetermined, Weak::No)) =>
-                            return Err(Determinacy::determined(force)),
+                            return Some(Err(Determinacy::determined(force))),
                         Err((Determinacy::Undetermined, Weak::Yes)) =>
                             Err(Determinacy::Undetermined),
                         Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                     }
                 }
-                WhereToResolve::MacroUsePrelude => {
-                    if use_prelude || rust_2015 {
-                        match self.macro_use_prelude.get(&ident.name).cloned() {
-                            Some(binding) =>
-                                Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
-                            None => Err(Determinacy::determined(
-                                self.graph_root.unresolved_invocations.borrow().is_empty()
-                            ))
-                        }
-                    } else {
-                        Err(Determinacy::Determined)
-                    }
-                }
-                WhereToResolve::BuiltinMacros => {
-                    match self.builtin_macros.get(&ident.name).cloned() {
-                        Some(binding) => Ok((binding, Flags::PRELUDE)),
-                        None => Err(Determinacy::Determined),
-                    }
-                }
-                WhereToResolve::BuiltinAttrs => {
-                    if is_builtin_attr_name(ident.name) {
-                        let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
-                                       ty::Visibility::Public, DUMMY_SP, Mark::root())
-                                       .to_name_binding(self.arenas);
-                        Ok((binding, Flags::PRELUDE))
-                    } else {
-                        Err(Determinacy::Determined)
-                    }
+                Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
+                    Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
+                    None => Err(Determinacy::determined(
+                        this.graph_root.unresolved_invocations.borrow().is_empty()
+                    ))
+                }
+                Scope::BuiltinMacros => match this.builtin_macros.get(&ident.name).cloned() {
+                    Some(binding) => Ok((binding, Flags::PRELUDE)),
+                    None => Err(Determinacy::Determined),
+                }
+                Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
+                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
+                                   ty::Visibility::Public, DUMMY_SP, Mark::root())
+                                   .to_name_binding(this.arenas);
+                    Ok((binding, Flags::PRELUDE))
+                } else {
+                    Err(Determinacy::Determined)
                 }
-                WhereToResolve::LegacyPluginHelpers => {
-                    if (use_prelude || rust_2015) &&
-                       self.session.plugin_attributes.borrow().iter()
+                Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
                                                      .any(|(name, _)| ident.name == *name) {
-                        let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
-                                       ty::Visibility::Public, DUMMY_SP, Mark::root())
-                                       .to_name_binding(self.arenas);
-                        Ok((binding, Flags::PRELUDE))
-                    } else {
-                        Err(Determinacy::Determined)
-                    }
-                }
-                WhereToResolve::ExternPrelude => {
-                    if use_prelude || is_absolute_path {
-                        match self.extern_prelude_get(ident, !record_used) {
-                            Some(binding) => Ok((binding, Flags::PRELUDE)),
-                            None => Err(Determinacy::determined(
-                                self.graph_root.unresolved_invocations.borrow().is_empty()
-                            )),
-                        }
-                    } else {
-                        Err(Determinacy::Determined)
-                    }
-                }
-                WhereToResolve::ToolPrelude => {
-                    if use_prelude && is_known_tool(ident.name) {
-                        let binding = (Res::ToolMod, ty::Visibility::Public,
-                                       DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
-                        Ok((binding, Flags::PRELUDE))
-                    } else {
-                        Err(Determinacy::Determined)
-                    }
+                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
+                                   ty::Visibility::Public, DUMMY_SP, Mark::root())
+                                   .to_name_binding(this.arenas);
+                    Ok((binding, Flags::PRELUDE))
+                } else {
+                    Err(Determinacy::Determined)
+                }
+                Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
+                    Some(binding) => Ok((binding, Flags::PRELUDE)),
+                    None => Err(Determinacy::determined(
+                        this.graph_root.unresolved_invocations.borrow().is_empty()
+                    )),
+                }
+                Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
+                    let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, Mark::root())
+                                   .to_name_binding(this.arenas);
+                    Ok((binding, Flags::PRELUDE))
+                } else {
+                    Err(Determinacy::Determined)
                 }
-                WhereToResolve::StdLibPrelude => {
+                Scope::StdLibPrelude => {
                     let mut result = Err(Determinacy::Determined);
-                    if use_prelude {
-                        if let Some(prelude) = self.prelude {
-                            if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
-                                ModuleOrUniformRoot::Module(prelude),
-                                ident,
-                                ns,
-                                false,
-                                path_span,
-                            ) {
-                                result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
-                            }
+                    if let Some(prelude) = this.prelude {
+                        if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
+                            ModuleOrUniformRoot::Module(prelude),
+                            ident,
+                            ns,
+                            false,
+                            path_span,
+                        ) {
+                            result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
                         }
                     }
                     result
                 }
-                WhereToResolve::BuiltinTypes => {
-                    match self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
-                        Some(prim_ty) => {
-                            let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
-                                           DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
-                            Ok((binding, Flags::PRELUDE))
-                        }
-                        None => Err(Determinacy::Determined)
+                Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
+                                                 .get(&ident.name).cloned() {
+                    Some(prim_ty) => {
+                        let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
+                                       DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
+                        Ok((binding, Flags::PRELUDE))
                     }
+                    None => Err(Determinacy::Determined)
                 }
             };
 
             match result {
                 Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => {
                     if !record_used {
-                        return Ok(binding);
+                        return Some(Ok(binding));
                     }
 
                     if let Some((innermost_binding, innermost_flags)) = innermost_result {
@@ -791,11 +623,11 @@ impl<'a> Resolver<'a> {
                                 Some(AmbiguityKind::LegacyHelperVsPrelude)
                             } else if innermost_flags.contains(Flags::MACRO_RULES) &&
                                       flags.contains(Flags::MODULE) &&
-                                      !self.disambiguate_legacy_vs_modern(innermost_binding,
+                                      !this.disambiguate_legacy_vs_modern(innermost_binding,
                                                                           binding) ||
                                       flags.contains(Flags::MACRO_RULES) &&
                                       innermost_flags.contains(Flags::MODULE) &&
-                                      !self.disambiguate_legacy_vs_modern(binding,
+                                      !this.disambiguate_legacy_vs_modern(binding,
                                                                           innermost_binding) {
                                 Some(AmbiguityKind::LegacyVsModern)
                             } else if innermost_binding.is_glob_import() {
@@ -816,7 +648,7 @@ impl<'a> Resolver<'a> {
                                 } else {
                                     AmbiguityErrorMisc::None
                                 };
-                                self.ambiguity_errors.push(AmbiguityError {
+                                this.ambiguity_errors.push(AmbiguityError {
                                     kind,
                                     ident: orig_ident,
                                     b1: innermost_binding,
@@ -824,7 +656,7 @@ impl<'a> Resolver<'a> {
                                     misc1: misc(innermost_flags),
                                     misc2: misc(flags),
                                 });
-                                return Ok(innermost_binding);
+                                return Some(Ok(innermost_binding));
                             }
                         }
                     } else {
@@ -836,55 +668,11 @@ impl<'a> Resolver<'a> {
                 Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined
             }
 
-            where_to_resolve = match where_to_resolve {
-                WhereToResolve::DeriveHelpers =>
-                    WhereToResolve::MacroRules(parent_scope.legacy),
-                WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
-                    LegacyScope::Binding(binding) => WhereToResolve::MacroRules(
-                        binding.parent_legacy_scope
-                    ),
-                    LegacyScope::Invocation(invoc) => WhereToResolve::MacroRules(
-                        invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
-                    ),
-                    LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
-                }
-                WhereToResolve::CrateRoot => match ns {
-                    TypeNS => {
-                        ident.span.adjust(Mark::root());
-                        WhereToResolve::ExternPrelude
-                    }
-                    ValueNS | MacroNS => break,
-                }
-                WhereToResolve::Module(module) => {
-                    match self.hygienic_lexical_parent(module, &mut ident.span) {
-                        Some(parent_module) => WhereToResolve::Module(parent_module),
-                        None => {
-                            ident.span.adjust(Mark::root());
-                            use_prelude = !module.no_implicit_prelude;
-                            match ns {
-                                TypeNS => WhereToResolve::ExternPrelude,
-                                ValueNS => WhereToResolve::StdLibPrelude,
-                                MacroNS => WhereToResolve::MacroUsePrelude,
-                            }
-                        }
-                    }
-                }
-                WhereToResolve::MacroUsePrelude => WhereToResolve::StdLibPrelude,
-                WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
-                WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
-                WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
-                WhereToResolve::ExternPrelude if is_absolute_path => break,
-                WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
-                WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
-                WhereToResolve::StdLibPrelude => match ns {
-                    TypeNS => WhereToResolve::BuiltinTypes,
-                    ValueNS => break, // nowhere else to search
-                    MacroNS => WhereToResolve::BuiltinMacros,
-                }
-                WhereToResolve::BuiltinTypes => break, // nowhere else to search
-            };
+            None
+        });
 
-            continue;
+        if let Some(break_result) = break_result {
+            return break_result;
         }
 
         // The first found solution was the only one, return it.
@@ -893,13 +681,14 @@ impl<'a> Resolver<'a> {
         }
 
         let determinacy = Determinacy::determined(determinacy == Determinacy::Determined || force);
-        if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) {
+        if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) &&
+           self.session.features_untracked().custom_attribute {
             // For single-segment attributes interpret determinate "no resolution" as a custom
             // attribute. (Lexical resolution implies the first segment and attr kind should imply
             // the last segment, so we are certainly working with a single-segment attribute here.)
             assert!(ns == MacroNS);
             let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
-                           ty::Visibility::Public, ident.span, Mark::root())
+                           ty::Visibility::Public, orig_ident.span, Mark::root())
                            .to_name_binding(self.arenas);
             Ok(binding)
         } else {
@@ -992,7 +781,7 @@ impl<'a> Resolver<'a> {
                     let msg =
                         format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
                     let mut err = self.session.struct_span_err(ident.span, &msg);
-                    self.suggest_macro_name(ident.name, kind, &mut err, ident.span);
+                    self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
                     err.emit();
                 }
             }
@@ -1042,64 +831,6 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind,
-                          err: &mut DiagnosticBuilder<'a>, span: Span) {
-        if kind == MacroKind::Derive && (name.as_str() == "Send" || name.as_str() == "Sync") {
-            let msg = format!("unsafe traits like `{}` should be implemented explicitly", name);
-            err.span_note(span, &msg);
-            return;
-        }
-
-        // First check if this is a locally-defined bang macro.
-        let suggestion = if let MacroKind::Bang = kind {
-            find_best_match_for_name(
-                self.macro_names.iter().map(|ident| &ident.name), &name.as_str(), None)
-        } else {
-            None
-        // Then check global macros.
-        }.or_else(|| {
-            let names = self.builtin_macros.iter().chain(self.macro_use_prelude.iter())
-                                                  .filter_map(|(name, binding)| {
-                if binding.macro_kind() == Some(kind) { Some(name) } else { None }
-            });
-            find_best_match_for_name(names, &name.as_str(), None)
-        // Then check modules.
-        }).or_else(|| {
-            let is_macro = |res| {
-                if let Res::Def(DefKind::Macro(def_kind), _) = res {
-                    def_kind == kind
-                } else {
-                    false
-                }
-            };
-            let ident = Ident::new(name, span);
-            self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span)
-                .map(|suggestion| suggestion.candidate)
-        });
-
-        if let Some(suggestion) = suggestion {
-            if suggestion != name {
-                if let MacroKind::Bang = kind {
-                    err.span_suggestion(
-                        span,
-                        "you could try the macro",
-                        suggestion.to_string(),
-                        Applicability::MaybeIncorrect
-                    );
-                } else {
-                    err.span_suggestion(
-                        span,
-                        "try",
-                        suggestion.to_string(),
-                        Applicability::MaybeIncorrect
-                    );
-                }
-            } else {
-                err.help("have you added the `#[macro_use]` on the module/import?");
-            }
-        }
-    }
-
     crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 5edfe923e68..14622fd9f91 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -1,15 +1,15 @@
 use ImportDirectiveSubclass::*;
 
 use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
-use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak};
+use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope, Weak};
 use crate::Determinacy::{self, *};
 use crate::Namespace::{self, TypeNS, MacroNS};
 use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
 use crate::{Resolver, Segment};
 use crate::{names_to_string, module_to_string};
-use crate::{resolve_error, ResolutionError, Suggestion};
+use crate::{resolve_error, ResolutionError};
 use crate::ModuleKind;
-use crate::macros::ParentScope;
+use crate::diagnostics::Suggestion;
 
 use errors::Applicability;
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c527ed02bc0..04de3374d05 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -6,6 +6,7 @@ use rustc::lint as lint;
 use rustc::ty;
 use syntax;
 use syntax::ast::{self, Ident};
+use syntax::ext::base::SyntaxExtensionKind;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
@@ -425,12 +426,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
 /// Resolves a string as a macro.
 fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
-    use syntax::ext::base::{MacroKind, SyntaxExtensionKind};
-    let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
-    let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
+    let path = ast::Path::from_ident(Ident::from_str(path_str));
     cx.enter_resolver(|resolver| {
         if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
-            &path, MacroKind::Bang, &resolver.dummy_parent_scope(), false, false
+            &path, None, &resolver.dummy_parent_scope(), false, false
         ) {
             if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
                 return Some(res.map_id(|_| panic!("unexpected id")));
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 8da3e6c19d5..f23ed7371c6 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -604,6 +604,7 @@ symbols! {
         rustc_then_this_would_need,
         rustc_variance,
         rustdoc,
+        rustfmt,
         rust_eh_personality,
         rust_eh_unwind_resume,
         rust_oom,
diff --git a/src/test/ui/attributes/obsolete-attr.rs b/src/test/ui/attributes/obsolete-attr.rs
index 89e2ad2669c..8759344e6f8 100644
--- a/src/test/ui/attributes/obsolete-attr.rs
+++ b/src/test/ui/attributes/obsolete-attr.rs
@@ -1,7 +1,9 @@
 // Obsolete attributes fall back to feature gated custom attributes.
 
-#[ab_isize="stdcall"] extern {} //~ ERROR attribute `ab_isize` is currently unknown
+#[ab_isize="stdcall"] extern {}
+//~^ ERROR cannot find attribute macro `ab_isize` in this scope
 
-#[fixed_stack_segment] fn f() {} //~ ERROR attribute `fixed_stack_segment` is currently unknown
+#[fixed_stack_segment] fn f() {}
+//~^ ERROR cannot find attribute macro `fixed_stack_segment` in this scope
 
 fn main() {}
diff --git a/src/test/ui/attributes/obsolete-attr.stderr b/src/test/ui/attributes/obsolete-attr.stderr
index 6021700dfbb..9c6909f65f3 100644
--- a/src/test/ui/attributes/obsolete-attr.stderr
+++ b/src/test/ui/attributes/obsolete-attr.stderr
@@ -1,21 +1,14 @@
-error[E0658]: The attribute `fixed_stack_segment` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/obsolete-attr.rs:5:3
+error: cannot find attribute macro `fixed_stack_segment` in this scope
+  --> $DIR/obsolete-attr.rs:6:3
    |
 LL | #[fixed_stack_segment] fn f() {}
    |   ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: The attribute `ab_isize` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `ab_isize` in this scope
   --> $DIR/obsolete-attr.rs:3:3
    |
 LL | #[ab_isize="stdcall"] extern {}
    |   ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/attributes/unknown-attr.rs b/src/test/ui/attributes/unknown-attr.rs
index e2a4f3226d5..140a1fc3f93 100644
--- a/src/test/ui/attributes/unknown-attr.rs
+++ b/src/test/ui/attributes/unknown-attr.rs
@@ -2,8 +2,11 @@
 
 #![feature(custom_inner_attributes)]
 
-#![mutable_doc] //~ ERROR attribute `mutable_doc` is currently unknown
+#![mutable_doc]
+//~^ ERROR cannot find attribute macro `mutable_doc` in this scope
 
-#[dance] mod a {} //~ ERROR attribute `dance` is currently unknown
+#[dance] mod a {}
+//~^ ERROR cannot find attribute macro `dance` in this scope
 
-#[dance] fn main() {} //~ ERROR attribute `dance` is currently unknown
+#[dance] fn main() {}
+//~^ ERROR cannot find attribute macro `dance` in this scope
diff --git a/src/test/ui/attributes/unknown-attr.stderr b/src/test/ui/attributes/unknown-attr.stderr
index b46db566293..4d463874d66 100644
--- a/src/test/ui/attributes/unknown-attr.stderr
+++ b/src/test/ui/attributes/unknown-attr.stderr
@@ -1,30 +1,20 @@
-error[E0658]: The attribute `mutable_doc` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `mutable_doc` in this scope
   --> $DIR/unknown-attr.rs:5:4
    |
 LL | #![mutable_doc]
    |    ^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: The attribute `dance` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/unknown-attr.rs:7:3
+error: cannot find attribute macro `dance` in this scope
+  --> $DIR/unknown-attr.rs:8:3
    |
 LL | #[dance] mod a {}
    |   ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: The attribute `dance` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/unknown-attr.rs:9:3
+error: cannot find attribute macro `dance` in this scope
+  --> $DIR/unknown-attr.rs:11:3
    |
 LL | #[dance] fn main() {}
    |   ^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
index 1ed2ddcda44..22dbac76670 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs
@@ -1,6 +1,7 @@
 macro_rules! foo {
     () => {
-        #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown
+        #[cfg_attr(all(), unknown)]
+        //~^ ERROR cannot find attribute macro `unknown` in this scope
         fn foo() {}
     }
 }
diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
index cf4d0fc5ad0..c7c52a2923a 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr
@@ -1,4 +1,4 @@
-error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `unknown` in this scope
   --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27
    |
 LL |         #[cfg_attr(all(), unknown)]
@@ -6,10 +6,6 @@ LL |         #[cfg_attr(all(), unknown)]
 ...
 LL | foo!();
    | ------- in this macro invocation
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/custom_attribute.rs b/src/test/ui/custom_attribute.rs
index 9cb43ab07ad..13c873c3b7e 100644
--- a/src/test/ui/custom_attribute.rs
+++ b/src/test/ui/custom_attribute.rs
@@ -1,9 +1,9 @@
 #![feature(stmt_expr_attributes)]
 
-#[foo] //~ ERROR The attribute `foo`
+#[foo] //~ ERROR cannot find attribute macro `foo` in this scope
 fn main() {
-    #[foo] //~ ERROR The attribute `foo`
+    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
     let x = ();
-    #[foo] //~ ERROR The attribute `foo`
+    #[foo] //~ ERROR cannot find attribute macro `foo` in this scope
     x
 }
diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr
index 84c4e33e55a..b4f9f3f49b2 100644
--- a/src/test/ui/custom_attribute.stderr
+++ b/src/test/ui/custom_attribute.stderr
@@ -1,30 +1,20 @@
-error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `foo` in this scope
   --> $DIR/custom_attribute.rs:3:3
    |
 LL | #[foo]
    |   ^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
+error: cannot find attribute macro `foo` in this scope
   --> $DIR/custom_attribute.rs:5:7
    |
 LL |     #[foo]
    |       ^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
+error: cannot find attribute macro `foo` in this scope
   --> $DIR/custom_attribute.rs:7:7
    |
 LL |     #[foo]
    |       ^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/derives/deriving-meta-unknown-trait.stderr b/src/test/ui/derives/deriving-meta-unknown-trait.stderr
index cf0173dfad5..1b8e689c753 100644
--- a/src/test/ui/derives/deriving-meta-unknown-trait.stderr
+++ b/src/test/ui/derives/deriving-meta-unknown-trait.stderr
@@ -2,7 +2,7 @@ error: cannot find derive macro `Eqr` in this scope
   --> $DIR/deriving-meta-unknown-trait.rs:1:10
    |
 LL | #[derive(Eqr)]
-   |          ^^^ help: try: `Eq`
+   |          ^^^ help: a derive macro with a similar name exists: `Eq`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
index f31c9d5afc4..d34936b42a6 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.rs
@@ -1,23 +1,18 @@
 // Check that literals in attributes parse just fine.
 
+#[fake_attr] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(100)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(1, 2, 3)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr("hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(name = "hello")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR cannot find attribute macro `fake_attr` in th
+#[fake_attr(key = "hello", val = 10)] //~ ERROR cannot find attribute macro `fake_attr` in this scop
+#[fake_attr(key("hello"), val(10))] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR cannot find attribute macro `fake_attr` in
+#[fake_attr(true)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(pi = 3.14159)] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_attr(b"hi")] //~ ERROR cannot find attribute macro `fake_attr` in this scope
+#[fake_doc(r"doc")] //~ ERROR cannot find attribute macro `fake_doc` in this scope
+struct Q {}
 
-#![allow(dead_code)]
-#![allow(unused_variables)]
-
-#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
-#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
-struct Q {  }
-
-
-fn main() { }
+fn main() {}
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 12175feadd6..efdc2d1cd31 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr
@@ -1,120 +1,80 @@
-error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/feature-gate-custom_attribute.rs:7:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:3:3
    |
 LL | #[fake_attr]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:8:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:4:3
    |
 LL | #[fake_attr(100)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:9:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:5:3
    |
 LL | #[fake_attr(1, 2, 3)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:10:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:6:3
    |
 LL | #[fake_attr("hello")]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:11:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:7:3
    |
 LL | #[fake_attr(name = "hello")]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:12:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:8:3
    |
 LL | #[fake_attr(1, "hi", key = 12, true, false)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:13:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:9:3
    |
 LL | #[fake_attr(key = "hello", val = 10)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:14:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:10:3
    |
 LL | #[fake_attr(key("hello"), val(10))]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:15:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:11:3
    |
 LL | #[fake_attr(enabled = true, disabled = false)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:16:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:12:3
    |
 LL | #[fake_attr(true)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:17:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:13:3
    |
 LL | #[fake_attr(pi = 3.14159)]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:18:3
+error: cannot find attribute macro `fake_attr` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:14:3
    |
 LL | #[fake_attr(b"hi")]
    |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = 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
-  --> $DIR/feature-gate-custom_attribute.rs:19:3
+error: cannot find attribute macro `fake_doc` in this scope
+  --> $DIR/feature-gate-custom_attribute.rs:15:3
    |
 LL | #[fake_doc(r"doc")]
    |   ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 13 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
index 9ce2fb58ab0..13983726c78 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -19,5 +19,5 @@ fn g() {}
 //~^ ERROR used by the test suite
 #[rustc_unknown]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
-//~| ERROR attribute `rustc_unknown` is currently unknown
+//~| ERROR cannot find attribute macro `rustc_unknown` in this scope
 fn main() {}
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 7c5aa5381e8..23cf936ee83 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -37,14 +37,11 @@ LL | #[rustc_unknown]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: The attribute `rustc_unknown` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `rustc_unknown` in this scope
   --> $DIR/feature-gate-rustc-attrs.rs:20:3
    |
 LL | #[rustc_unknown]
    |   ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error[E0658]: used by the test suite
   --> $DIR/feature-gate-rustc-attrs.rs:18:1
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
index e7ae7afa02a..0fdb18d967a 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
@@ -3,8 +3,6 @@ error: cannot find macro `print!` in this scope
    |
 LL |         print!();
    |         ^^^^^
-   |
-   = help: have you added the `#[macro_use]` on the module/import?
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 737b375ed89..a89176fe690 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -13,7 +13,6 @@ error: cannot find macro `panic!` in this scope
 LL |         assert_eq!(0, 0);
    |         ^^^^^^^^^^^^^^^^^
    |
-   = help: have you added the `#[macro_use]` on the module/import?
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0599]: no method named `clone` found for type `()` in the current scope
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.rs b/src/test/ui/hygiene/rustc-macro-transparency.rs
index a0a3d411d28..5f36993af2f 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.rs
+++ b/src/test/ui/hygiene/rustc-macro-transparency.rs
@@ -26,6 +26,6 @@ fn main() {
     Opaque; //~ ERROR cannot find value `Opaque` in this scope
 
     transparent; // OK
-    semitransparent; //~ ERROR cannot find value `semitransparent` in this scope
-    opaque; //~ ERROR cannot find value `opaque` in this scope
+    semitransparent; //~ ERROR expected value, found macro `semitransparent`
+    opaque; //~ ERROR expected value, found macro `opaque`
 }
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index 2a9df221e2c..5eacfdf8dee 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -4,18 +4,19 @@ error[E0425]: cannot find value `Opaque` in this scope
 LL |     Opaque;
    |     ^^^^^^ help: a local variable with a similar name exists: `opaque`
 
-error[E0425]: cannot find value `semitransparent` in this scope
+error[E0423]: expected value, found macro `semitransparent`
   --> $DIR/rustc-macro-transparency.rs:29:5
    |
 LL |     semitransparent;
-   |     ^^^^^^^^^^^^^^^ not found in this scope
+   |     ^^^^^^^^^^^^^^^ help: use `!` to invoke the macro: `semitransparent!`
 
-error[E0425]: cannot find value `opaque` in this scope
+error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
    |
 LL |     opaque;
-   |     ^^^^^^ not found in this scope
+   |     ^^^^^^ help: use `!` to invoke the macro: `opaque!`
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0425`.
+Some errors have detailed explanations: E0423, E0425.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.rs b/src/test/ui/impl-trait/universal_wrong_bounds.rs
index 56a13ea257e..2182506c7b7 100644
--- a/src/test/ui/impl-trait/universal_wrong_bounds.rs
+++ b/src/test/ui/impl-trait/universal_wrong_bounds.rs
@@ -6,9 +6,8 @@ fn foo(f: impl Display + Clone) -> String {
     wants_clone(f);
 }
 
-fn wants_debug(g: impl Debug) { } //~ ERROR cannot find
-fn wants_display(g: impl Debug) { } //~ ERROR cannot find
+fn wants_debug(g: impl Debug) { } //~ ERROR expected trait, found derive macro `Debug`
+fn wants_display(g: impl Debug) { } //~ ERROR expected trait, found derive macro `Debug`
 fn wants_clone(g: impl Clone) { }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr
index 1fd3ebff62a..f530792955b 100644
--- a/src/test/ui/impl-trait/universal_wrong_bounds.stderr
+++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr
@@ -1,23 +1,23 @@
-error[E0405]: cannot find trait `Debug` in this scope
+error[E0404]: expected trait, found derive macro `Debug`
   --> $DIR/universal_wrong_bounds.rs:9:24
    |
 LL | fn wants_debug(g: impl Debug) { }
-   |                        ^^^^^ not found in this scope
-help: possible candidate is found in another module, you can import it into scope
+   |                        ^^^^^ not a trait
+help: possible better candidate is found in another module, you can import it into scope
    |
 LL | use std::fmt::Debug;
    |
 
-error[E0405]: cannot find trait `Debug` in this scope
+error[E0404]: expected trait, found derive macro `Debug`
   --> $DIR/universal_wrong_bounds.rs:10:26
    |
 LL | fn wants_display(g: impl Debug) { }
-   |                          ^^^^^ not found in this scope
-help: possible candidate is found in another module, you can import it into scope
+   |                          ^^^^^ not a trait
+help: possible better candidate is found in another module, you can import it into scope
    |
 LL | use std::fmt::Debug;
    |
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0405`.
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/test/ui/issues/issue-32655.rs b/src/test/ui/issues/issue-32655.rs
index 4634179d4e1..fad7bf55cf4 100644
--- a/src/test/ui/issues/issue-32655.rs
+++ b/src/test/ui/issues/issue-32655.rs
@@ -1,9 +1,6 @@
-#![allow(dead_code)]
-#![feature(rustc_attrs)]
-
 macro_rules! foo (
     () => (
-        #[derive_Clone] //~ ERROR attribute `derive_Clone` is currently unknown
+        #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
         struct T;
     );
 );
@@ -15,7 +12,7 @@ macro_rules! bar (
 foo!();
 
 bar!(
-    #[derive_Clone] //~ ERROR attribute `derive_Clone` is currently unknown
+    #[derive_Clone] //~ ERROR cannot find attribute macro `derive_Clone` in this scope
     struct S;
 );
 
diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr
index 43bb4105c8d..e13bed0fbfd 100644
--- a/src/test/ui/issues/issue-32655.stderr
+++ b/src/test/ui/issues/issue-32655.stderr
@@ -1,24 +1,17 @@
-error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/issue-32655.rs:6:11
+error: cannot find attribute macro `derive_Clone` in this scope
+  --> $DIR/issue-32655.rs:3:11
    |
 LL |         #[derive_Clone]
    |           ^^^^^^^^^^^^
 ...
 LL | foo!();
    | ------- in this macro invocation
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
-error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/issue-32655.rs:18:7
+error: cannot find attribute macro `derive_Clone` in this scope
+  --> $DIR/issue-32655.rs:15:7
    |
 LL |     #[derive_Clone]
    |       ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-37534.rs b/src/test/ui/issues/issue-37534.rs
index 9386b4516a3..1e67e9a8158 100644
--- a/src/test/ui/issues/issue-37534.rs
+++ b/src/test/ui/issues/issue-37534.rs
@@ -1,5 +1,5 @@
 struct Foo<T: ?Hash> { }
-//~^ ERROR cannot find trait `Hash` in this scope
+//~^ ERROR expected trait, found derive macro `Hash`
 //~^^ ERROR parameter `T` is never used
 //~^^^ WARN default bound relaxed for a type parameter, but this does nothing
 
diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr
index 741e93561bc..3a0ab32dcc6 100644
--- a/src/test/ui/issues/issue-37534.stderr
+++ b/src/test/ui/issues/issue-37534.stderr
@@ -1,9 +1,9 @@
-error[E0405]: cannot find trait `Hash` in this scope
+error[E0404]: expected trait, found derive macro `Hash`
   --> $DIR/issue-37534.rs:1:16
    |
 LL | struct Foo<T: ?Hash> { }
-   |                ^^^^ not found in this scope
-help: possible candidate is found in another module, you can import it into scope
+   |                ^^^^ not a trait
+help: possible better candidate is found in another module, you can import it into scope
    |
 LL | use std::hash::Hash;
    |
@@ -24,5 +24,5 @@ LL | struct Foo<T: ?Hash> { }
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0392, E0405.
+Some errors have detailed explanations: E0392, E0404.
 For more information about an error, try `rustc --explain E0392`.
diff --git a/src/test/ui/issues/issue-49074.rs b/src/test/ui/issues/issue-49074.rs
index ad66e421c6b..38074d5b05c 100644
--- a/src/test/ui/issues/issue-49074.rs
+++ b/src/test/ui/issues/issue-49074.rs
@@ -1,7 +1,7 @@
 // Check that unknown attribute error is shown even if there are unresolved macros.
 
 #[marco_use] // typo
-//~^ ERROR The attribute `marco_use` is currently unknown to the compiler
+//~^ ERROR cannot find attribute macro `marco_use` in this scope
 mod foo {
     macro_rules! bar {
         () => ();
diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr
index 3ab876dbf42..c557255ab50 100644
--- a/src/test/ui/issues/issue-49074.stderr
+++ b/src/test/ui/issues/issue-49074.stderr
@@ -1,11 +1,8 @@
-error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `marco_use` in this scope
   --> $DIR/issue-49074.rs:3:3
    |
 LL | #[marco_use] // typo
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_use`
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: cannot find macro `bar!` in this scope
   --> $DIR/issue-49074.rs:12:4
@@ -17,4 +14,3 @@ LL |    bar!();
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr
index a8930f243f8..967f4f3c4ac 100644
--- a/src/test/ui/macros/macro-name-typo.stderr
+++ b/src/test/ui/macros/macro-name-typo.stderr
@@ -2,7 +2,7 @@ error: cannot find macro `printlx!` in this scope
   --> $DIR/macro-name-typo.rs:2:5
    |
 LL |     printlx!("oh noes!");
-   |     ^^^^^^^ help: you could try the macro: `println`
+   |     ^^^^^^^ help: a macro with a similar name exists: `println`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/macro-path-prelude-fail-3.stderr b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
index 7eeddb88547..96b8a24cff2 100644
--- a/src/test/ui/macros/macro-path-prelude-fail-3.stderr
+++ b/src/test/ui/macros/macro-path-prelude-fail-3.stderr
@@ -2,7 +2,7 @@ error: cannot find macro `inline!` in this scope
   --> $DIR/macro-path-prelude-fail-3.rs:2:5
    |
 LL |     inline!();
-   |     ^^^^^^ help: you could try the macro: `line`
+   |     ^^^^^^ help: a macro with a similar name exists: `line`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/macro-reexport-removed.rs b/src/test/ui/macros/macro-reexport-removed.rs
index fb33794a5ca..b69a1fa4df0 100644
--- a/src/test/ui/macros/macro-reexport-removed.rs
+++ b/src/test/ui/macros/macro-reexport-removed.rs
@@ -2,7 +2,7 @@
 
 #![feature(macro_reexport)] //~ ERROR feature has been removed
 
-#[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown
+#[macro_reexport(macro_one)] //~ ERROR cannot find attribute macro `macro_reexport` in this scope
 extern crate two_macros;
 
 fn main() {}
diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr
index 44233d7b7dd..25778fba68f 100644
--- a/src/test/ui/macros/macro-reexport-removed.stderr
+++ b/src/test/ui/macros/macro-reexport-removed.stderr
@@ -10,16 +10,12 @@ note: subsumed by `pub use`
 LL | #![feature(macro_reexport)]
    |            ^^^^^^^^^^^^^^
 
-error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `macro_reexport` in this scope
   --> $DIR/macro-reexport-removed.rs:5:3
    |
 LL | #[macro_reexport(macro_one)]
    |   ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export`
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0557, E0658.
-For more information about an error, try `rustc --explain E0557`.
+For more information about this error, try `rustc --explain E0557`.
diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr
index d178d4e4a60..28f727d6a58 100644
--- a/src/test/ui/macros/macro-use-wrong-name.stderr
+++ b/src/test/ui/macros/macro-use-wrong-name.stderr
@@ -2,7 +2,7 @@ error: cannot find macro `macro_two!` in this scope
   --> $DIR/macro-use-wrong-name.rs:7:5
    |
 LL |     macro_two!();
-   |     ^^^^^^^^^ help: you could try the macro: `macro_one`
+   |     ^^^^^^^^^ help: a macro with a similar name exists: `macro_one`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr
index b516f91c67d..9239b2a51e6 100644
--- a/src/test/ui/macros/macro_undefined.stderr
+++ b/src/test/ui/macros/macro_undefined.stderr
@@ -2,7 +2,7 @@ error: cannot find macro `k!` in this scope
   --> $DIR/macro_undefined.rs:11:5
    |
 LL |     k!();
-   |     ^ help: you could try the macro: `kl`
+   |     ^ help: a macro with a similar name exists: `kl`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/no-implicit-prelude-nested.rs b/src/test/ui/no-implicit-prelude-nested.rs
index fae52c0edc1..c314967da4f 100644
--- a/src/test/ui/no-implicit-prelude-nested.rs
+++ b/src/test/ui/no-implicit-prelude-nested.rs
@@ -9,7 +9,7 @@ mod foo {
     mod baz {
         struct Test;
         impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope
-        impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope
+        impl Clone for Test {} //~ ERROR expected trait, found derive macro `Clone`
         impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope
         impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope
         impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope
@@ -21,7 +21,7 @@ mod foo {
 
     struct Test;
     impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope
-    impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope
+    impl Clone for Test {} //~ ERROR expected trait, found derive macro `Clone`
     impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope
     impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope
     impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope
@@ -36,7 +36,7 @@ fn qux() {
     mod qux_inner {
         struct Test;
         impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope
-        impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope
+        impl Clone for Test {} //~ ERROR expected trait, found derive macro `Clone`
         impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope
         impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope
         impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope
diff --git a/src/test/ui/no-implicit-prelude-nested.stderr b/src/test/ui/no-implicit-prelude-nested.stderr
index 79b9396d41c..8d695e45da4 100644
--- a/src/test/ui/no-implicit-prelude-nested.stderr
+++ b/src/test/ui/no-implicit-prelude-nested.stderr
@@ -8,12 +8,12 @@ help: possible candidate is found in another module, you can import it into scop
 LL |         use std::ops::Add;
    |
 
-error[E0405]: cannot find trait `Clone` in this scope
+error[E0404]: expected trait, found derive macro `Clone`
   --> $DIR/no-implicit-prelude-nested.rs:12:14
    |
 LL |         impl Clone for Test {}
-   |              ^^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
+   |              ^^^^^ not a trait
+help: possible better candidates are found in other modules, you can import them into scope
    |
 LL |         use std::clone::Clone;
    |
@@ -72,12 +72,12 @@ help: possible candidate is found in another module, you can import it into scop
 LL |     use std::ops::Add;
    |
 
-error[E0405]: cannot find trait `Clone` in this scope
+error[E0404]: expected trait, found derive macro `Clone`
   --> $DIR/no-implicit-prelude-nested.rs:24:10
    |
 LL |     impl Clone for Test {}
-   |          ^^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
+   |          ^^^^^ not a trait
+help: possible better candidates are found in other modules, you can import them into scope
    |
 LL |     use std::clone::Clone;
    |
@@ -136,12 +136,12 @@ help: possible candidate is found in another module, you can import it into scop
 LL |         use std::ops::Add;
    |
 
-error[E0405]: cannot find trait `Clone` in this scope
+error[E0404]: expected trait, found derive macro `Clone`
   --> $DIR/no-implicit-prelude-nested.rs:39:14
    |
 LL |         impl Clone for Test {}
-   |              ^^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
+   |              ^^^^^ not a trait
+help: possible better candidates are found in other modules, you can import them into scope
    |
 LL |         use std::clone::Clone;
    |
@@ -192,5 +192,5 @@ LL |         use std::prelude::v1::drop;
 
 error: aborting due to 18 previous errors
 
-Some errors have detailed explanations: E0405, E0425.
-For more information about an error, try `rustc --explain E0405`.
+Some errors have detailed explanations: E0404, E0405, E0425.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/src/test/ui/no-implicit-prelude.rs b/src/test/ui/no-implicit-prelude.rs
index e2074bbb8c8..4b0ca4d524e 100644
--- a/src/test/ui/no-implicit-prelude.rs
+++ b/src/test/ui/no-implicit-prelude.rs
@@ -8,7 +8,7 @@
 
 struct Test;
 impl Add for Test {} //~ ERROR cannot find trait `Add` in this scope
-impl Clone for Test {} //~ ERROR cannot find trait `Clone` in this scope
+impl Clone for Test {} //~ ERROR expected trait, found derive macro `Clone`
 impl Iterator for Test {} //~ ERROR cannot find trait `Iterator` in this scope
 impl ToString for Test {} //~ ERROR cannot find trait `ToString` in this scope
 impl Writer for Test {} //~ ERROR cannot find trait `Writer` in this scope
diff --git a/src/test/ui/no-implicit-prelude.stderr b/src/test/ui/no-implicit-prelude.stderr
index eac1fcb7b67..6ae889df602 100644
--- a/src/test/ui/no-implicit-prelude.stderr
+++ b/src/test/ui/no-implicit-prelude.stderr
@@ -8,12 +8,12 @@ help: possible candidate is found in another module, you can import it into scop
 LL | use std::ops::Add;
    |
 
-error[E0405]: cannot find trait `Clone` in this scope
+error[E0404]: expected trait, found derive macro `Clone`
   --> $DIR/no-implicit-prelude.rs:11:6
    |
 LL | impl Clone for Test {}
-   |      ^^^^^ not found in this scope
-help: possible candidates are found in other modules, you can import them into scope
+   |      ^^^^^ not a trait
+help: possible better candidates are found in other modules, you can import them into scope
    |
 LL | use std::clone::Clone;
    |
@@ -64,5 +64,5 @@ LL | use std::prelude::v1::drop;
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0405, E0425.
-For more information about an error, try `rustc --explain E0405`.
+Some errors have detailed explanations: E0404, E0405, E0425.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs
index cdc0d6da946..59ba1390e13 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.rs
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs
@@ -19,7 +19,7 @@ struct S {
         struct U;
 
         mod inner {
-            #[empty_helper] //~ ERROR attribute `empty_helper` is currently unknown
+            #[empty_helper] //~ ERROR cannot find attribute macro `empty_helper` in this scope
             struct V;
         }
 
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
index 984ea4fb8ad..149f6eef443 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
@@ -1,11 +1,8 @@
-error[E0658]: The attribute `empty_helper` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `empty_helper` in this scope
   --> $DIR/derive-helper-shadowing.rs:22:15
    |
 LL |             #[empty_helper]
    |               ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
   --> $DIR/derive-helper-shadowing.rs:8:3
@@ -27,5 +24,4 @@ LL | use test_macros::empty_attr as empty_helper;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0658, E0659.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/proc-macro/derive-still-gated.rs b/src/test/ui/proc-macro/derive-still-gated.rs
index d895d26f267..4e6f9b07220 100644
--- a/src/test/ui/proc-macro/derive-still-gated.rs
+++ b/src/test/ui/proc-macro/derive-still-gated.rs
@@ -3,7 +3,7 @@
 #[macro_use]
 extern crate test_macros;
 
-#[derive_Empty] //~ ERROR attribute `derive_Empty` is currently unknown
+#[derive_Empty] //~ ERROR cannot find attribute macro `derive_Empty` in this scope
 struct A;
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr
index a6c0ce6260a..4df1715db94 100644
--- a/src/test/ui/proc-macro/derive-still-gated.stderr
+++ b/src/test/ui/proc-macro/derive-still-gated.stderr
@@ -1,12 +1,8 @@
-error[E0658]: The attribute `derive_Empty` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `derive_Empty` in this scope
   --> $DIR/derive-still-gated.rs:6:3
    |
 LL | #[derive_Empty]
    |   ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.rs b/src/test/ui/proc-macro/expand-to-unstable-2.rs
index 437ae930934..da7c89fdd46 100644
--- a/src/test/ui/proc-macro/expand-to-unstable-2.rs
+++ b/src/test/ui/proc-macro/expand-to-unstable-2.rs
@@ -1,11 +1,12 @@
 // aux-build:derive-unstable-2.rs
 
+#![feature(custom_attribute)]
+
 #[macro_use]
 extern crate derive_unstable_2;
 
 #[derive(Unstable)]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
-//~| ERROR attribute `rustc_foo` is currently unknown to the compiler
 
 struct A;
 
diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr
index 3a729846d78..01e6a4a8ab9 100644
--- a/src/test/ui/proc-macro/expand-to-unstable-2.stderr
+++ b/src/test/ui/proc-macro/expand-to-unstable-2.stderr
@@ -1,5 +1,5 @@
 error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler
-  --> $DIR/expand-to-unstable-2.rs:6:10
+  --> $DIR/expand-to-unstable-2.rs:8:10
    |
 LL | #[derive(Unstable)]
    |          ^^^^^^^^
@@ -7,15 +7,6 @@ LL | #[derive(Unstable)]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: The attribute `rustc_foo` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/expand-to-unstable-2.rs:6:10
-   |
-LL | #[derive(Unstable)]
-   |          ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/issue-41211.rs b/src/test/ui/proc-macro/issue-41211.rs
index ee9246e1c9b..491b89b2f55 100644
--- a/src/test/ui/proc-macro/issue-41211.rs
+++ b/src/test/ui/proc-macro/issue-41211.rs
@@ -3,11 +3,11 @@
 // FIXME: https://github.com/rust-lang/rust/issues/41430
 // This is a temporary regression test for the ICE reported in #41211
 
+#![feature(custom_attribute)]
 #![feature(custom_inner_attributes)]
 
 #![identity_attr]
-//~^ ERROR attribute `identity_attr` is currently unknown to the compiler
-//~| ERROR inconsistent resolution for a macro: first custom attribute, then attribute macro
+//~^ ERROR inconsistent resolution for a macro: first custom attribute, then attribute macro
 extern crate test_macros;
 use test_macros::identity_attr;
 
diff --git a/src/test/ui/proc-macro/issue-41211.stderr b/src/test/ui/proc-macro/issue-41211.stderr
index b5c08587e19..f01cba0c930 100644
--- a/src/test/ui/proc-macro/issue-41211.stderr
+++ b/src/test/ui/proc-macro/issue-41211.stderr
@@ -1,18 +1,8 @@
-error[E0658]: The attribute `identity_attr` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/issue-41211.rs:8:4
-   |
-LL | #![identity_attr]
-   |    ^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
 error: inconsistent resolution for a macro: first custom attribute, then attribute macro
-  --> $DIR/issue-41211.rs:8:4
+  --> $DIR/issue-41211.rs:9:4
    |
 LL | #![identity_attr]
    |    ^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
index 7a9e472c6c3..8a26df9e76a 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs
@@ -35,7 +35,7 @@ fn check_bang3() {
                        //~| ERROR expected macro, found derive macro `crate::MyTrait`
 }
 
-#[my_macro] //~ ERROR attribute `my_macro` is currently unknown
+#[my_macro] //~ ERROR cannot find attribute macro `my_macro` in this scope
 #[crate::my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
                    //~| ERROR expected attribute, found macro `crate::my_macro`
 fn check_attr1() {}
diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
index 8a5e346c2b5..e6017dc4d11 100644
--- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
+++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
@@ -76,15 +76,6 @@ error: can't use a procedural macro from the same crate that defines it
 LL | #[derive(MyTrait)]
    |          ^^^^^^^
 
-error[E0658]: The attribute `my_macro` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/macro-namespace-reserved-2.rs:38:3
-   |
-LL | #[my_macro]
-   |   ^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
 error: can't use a procedural macro from the same crate that defines it
   --> $DIR/macro-namespace-reserved-2.rs:39:3
    |
@@ -97,6 +88,12 @@ error: expected attribute, found macro `crate::my_macro`
 LL | #[crate::my_macro]
    |   ^^^^^^^^^^^^^^^ not an attribute
 
+error: cannot find attribute macro `my_macro` in this scope
+  --> $DIR/macro-namespace-reserved-2.rs:38:3
+   |
+LL | #[my_macro]
+   |   ^^^^^^^^
+
 error: cannot find derive macro `my_macro` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:48:10
    |
@@ -117,4 +114,3 @@ LL |     MyTrait!();
 
 error: aborting due to 19 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.rs b/src/test/ui/proc-macro/proc-macro-attributes.rs
index 062053453ee..04215226c6d 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.rs
+++ b/src/test/ui/proc-macro/proc-macro-attributes.rs
@@ -4,7 +4,7 @@
 extern crate derive_b;
 
 #[B] //~ ERROR `B` is ambiguous
-#[C] //~ ERROR attribute `C` is currently unknown to the compiler
+#[C] //~ ERROR cannot find attribute macro `C` in this scope
 #[B(D)] //~ ERROR `B` is ambiguous
 #[B(E = "foo")] //~ ERROR `B` is ambiguous
 #[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr
index 02dfce1a735..b068c6bc83b 100644
--- a/src/test/ui/proc-macro/proc-macro-attributes.stderr
+++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr
@@ -1,11 +1,8 @@
-error[E0658]: The attribute `C` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `C` in this scope
   --> $DIR/proc-macro-attributes.rs:7:3
    |
 LL | #[C]
-   |   ^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
+   |   ^ help: a derive helper attribute with a similar name exists: `B`
 
 error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
   --> $DIR/proc-macro-attributes.rs:6:3
@@ -77,5 +74,4 @@ LL | #[macro_use]
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0658, E0659.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/proc-macro/resolve-error.rs b/src/test/ui/proc-macro/resolve-error.rs
index 1298c08df84..0a7861aba6e 100644
--- a/src/test/ui/proc-macro/resolve-error.rs
+++ b/src/test/ui/proc-macro/resolve-error.rs
@@ -24,11 +24,11 @@ macro_rules! attr_proc_mac {
 struct Foo;
 
 // Interpreted as a feature gated custom attribute
-#[attr_proc_macra] //~ ERROR attribute `attr_proc_macra` is currently unknown
+#[attr_proc_macra] //~ ERROR cannot find attribute macro `attr_proc_macra` in this scope
 struct Bar;
 
 // Interpreted as a feature gated custom attribute
-#[FooWithLongNan] //~ ERROR attribute `FooWithLongNan` is currently unknown
+#[FooWithLongNan] //~ ERROR cannot find attribute macro `FooWithLongNan` in this scope
 struct Asdf;
 
 #[derive(Dlone)]
diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr
index 02cf7cdb964..3c9b2baacbd 100644
--- a/src/test/ui/proc-macro/resolve-error.stderr
+++ b/src/test/ui/proc-macro/resolve-error.stderr
@@ -1,38 +1,32 @@
-error[E0658]: The attribute `attr_proc_macra` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find derive macro `FooWithLongNan` in this scope
+  --> $DIR/resolve-error.rs:22:10
+   |
+LL | #[derive(FooWithLongNan)]
+   |          ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName`
+
+error: cannot find attribute macro `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:27:3
    |
 LL | #[attr_proc_macra]
-   |   ^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
+   |   ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro`
 
-error[E0658]: The attribute `FooWithLongNan` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `FooWithLongNan` in this scope
   --> $DIR/resolve-error.rs:31:3
    |
 LL | #[FooWithLongNan]
    |   ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error: cannot find derive macro `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:22:10
-   |
-LL | #[derive(FooWithLongNan)]
-   |          ^^^^^^^^^^^^^^ help: try: `FooWithLongName`
 
 error: cannot find derive macro `Dlone` in this scope
   --> $DIR/resolve-error.rs:34:10
    |
 LL | #[derive(Dlone)]
-   |          ^^^^^ help: try: `Clone`
+   |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
 
 error: cannot find derive macro `Dlona` in this scope
   --> $DIR/resolve-error.rs:38:10
    |
 LL | #[derive(Dlona)]
-   |          ^^^^^ help: try: `Clona`
+   |          ^^^^^ help: a derive macro with a similar name exists: `Clona`
 
 error: cannot find derive macro `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:42:10
@@ -44,13 +38,13 @@ error: cannot find macro `FooWithLongNama!` in this scope
   --> $DIR/resolve-error.rs:47:5
    |
 LL |     FooWithLongNama!();
-   |     ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam`
+   |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam`
 
 error: cannot find macro `attr_proc_macra!` in this scope
   --> $DIR/resolve-error.rs:50:5
    |
 LL |     attr_proc_macra!();
-   |     ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac`
+   |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac`
 
 error: cannot find macro `Dlona!` in this scope
   --> $DIR/resolve-error.rs:53:5
@@ -62,8 +56,7 @@ error: cannot find macro `bang_proc_macrp!` in this scope
   --> $DIR/resolve-error.rs:56:5
    |
 LL |     bang_proc_macrp!();
-   |     ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro`
+   |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro`
 
 error: aborting due to 10 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.rs b/src/test/ui/reserved/reserved-attr-on-macro.rs
index cb535362266..fddb991da82 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.rs
+++ b/src/test/ui/reserved/reserved-attr-on-macro.rs
@@ -1,5 +1,5 @@
 #[rustc_attribute_should_be_reserved]
-//~^ ERROR attribute `rustc_attribute_should_be_reserved` is currently unknown
+//~^ ERROR cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 macro_rules! foo {
diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr
index cbd111b47bf..d4b97d290ea 100644
--- a/src/test/ui/reserved/reserved-attr-on-macro.stderr
+++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr
@@ -7,14 +7,11 @@ LL | #[rustc_attribute_should_be_reserved]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: The attribute `rustc_attribute_should_be_reserved` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `rustc_attribute_should_be_reserved` in this scope
   --> $DIR/reserved-attr-on-macro.rs:1:3
    |
 LL | #[rustc_attribute_should_be_reserved]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: cannot determine resolution for the macro `foo`
   --> $DIR/reserved-attr-on-macro.rs:10:5
diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr
index 7af2cdf7b57..2e3c0f5448e 100644
--- a/src/test/ui/resolve/levenshtein.stderr
+++ b/src/test/ui/resolve/levenshtein.stderr
@@ -2,7 +2,7 @@ error[E0412]: cannot find type `esize` in this scope
   --> $DIR/levenshtein.rs:5:11
    |
 LL | fn foo(c: esize) {} // Misspelled primitive type name.
-   |           ^^^^^ help: a primitive type with a similar name exists: `isize`
+   |           ^^^^^ help: a builtin type with a similar name exists: `isize`
 
 error[E0412]: cannot find type `Baz` in this scope
   --> $DIR/levenshtein.rs:10:10
diff --git a/src/test/ui/span/issue-36530.rs b/src/test/ui/span/issue-36530.rs
index e11be9e17f2..14b2c8644e0 100644
--- a/src/test/ui/span/issue-36530.rs
+++ b/src/test/ui/span/issue-36530.rs
@@ -1,9 +1,10 @@
 // gate-test-custom_inner_attributes
 
-#[foo] //~ ERROR is currently unknown to the compiler
+#![feature(custom_attribute)]
+
+#[foo]
 mod foo {
-    #![foo] //~ ERROR is currently unknown to the compiler
-            //~| ERROR non-builtin inner attributes are unstable
+    #![foo] //~ ERROR non-builtin inner attributes are unstable
 }
 
 fn main() {}
diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr
index 65f03e756a2..c6b7895e65a 100644
--- a/src/test/ui/span/issue-36530.stderr
+++ b/src/test/ui/span/issue-36530.stderr
@@ -1,14 +1,5 @@
-error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/issue-36530.rs:3:3
-   |
-LL | #[foo]
-   |   ^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
 error[E0658]: non-builtin inner attributes are unstable
-  --> $DIR/issue-36530.rs:5:5
+  --> $DIR/issue-36530.rs:7:5
    |
 LL |     #![foo]
    |     ^^^^^^^
@@ -16,15 +7,6 @@ LL |     #![foo]
    = note: for more information, see https://github.com/rust-lang/rust/issues/54726
    = help: add `#![feature(custom_inner_attributes)]` 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
-  --> $DIR/issue-36530.rs:5:8
-   |
-LL |     #![foo]
-   |        ^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/suggestions/attribute-typos.rs b/src/test/ui/suggestions/attribute-typos.rs
index 0e10131ce8d..74f63f2b0ed 100644
--- a/src/test/ui/suggestions/attribute-typos.rs
+++ b/src/test/ui/suggestions/attribute-typos.rs
@@ -1,11 +1,11 @@
-#[deprcated] //~ ERROR attribute `deprcated` is currently unknown
+#[deprcated] //~ ERROR cannot find attribute macro `deprcated` in this scope
 fn foo() {}
 
-#[tests] //~ ERROR attribute `tests` is currently unknown to the compiler
+#[tests] //~ ERROR cannot find attribute macro `tests` in this scope
 fn bar() {}
 
 #[rustc_err]
-//~^ ERROR attribute `rustc_err` is currently unknown
+//~^ ERROR cannot find attribute macro `rustc_err` in this scope
 //~| ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 
 fn main() {}
diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr
index 7c28e882728..6b2f591b9e7 100644
--- a/src/test/ui/suggestions/attribute-typos.stderr
+++ b/src/test/ui/suggestions/attribute-typos.stderr
@@ -7,32 +7,23 @@ LL | #[rustc_err]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29642
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-error[E0658]: The attribute `rustc_err` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `rustc_err` in this scope
   --> $DIR/attribute-typos.rs:7:3
    |
 LL | #[rustc_err]
-   |   ^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
+   |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_error`
 
-error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `tests` in this scope
   --> $DIR/attribute-typos.rs:4:3
    |
 LL | #[tests]
-   |   ^^^^^ help: a built-in attribute with a similar name exists: `test`
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
+   |   ^^^^^ help: an attribute macro with a similar name exists: `test`
 
-error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future
+error: cannot find attribute macro `deprcated` in this scope
   --> $DIR/attribute-typos.rs:1:3
    |
 LL | #[deprcated]
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated`
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
index ce902b7e7d2..8c62b34bd9e 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
@@ -5,7 +5,7 @@ type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::
 struct S;
 
 // Interpreted as a feature gated custom attribute
-#[rustfmt] //~ ERROR attribute `rustfmt` is currently unknown
+#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
 fn check() {}
 
 #[rustfmt::skip] // OK
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
index 32c9a1e8b6e..33581a17082 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
@@ -1,18 +1,15 @@
-error[E0658]: The attribute `rustfmt` is currently unknown to the compiler and may have meaning added to it in the future
-  --> $DIR/tool-attributes-misplaced-1.rs:8:3
-   |
-LL | #[rustfmt]
-   |   ^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/29642
-   = help: add `#![feature(custom_attribute)]` to the crate attributes to enable
-
 error: cannot find derive macro `rustfmt` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:4:10
    |
 LL | #[derive(rustfmt)]
    |          ^^^^^^^
 
+error: cannot find attribute macro `rustfmt` in this scope
+  --> $DIR/tool-attributes-misplaced-1.rs:8:3
+   |
+LL | #[rustfmt]
+   |   ^^^^^^^
+
 error: cannot find macro `rustfmt!` in this scope
   --> $DIR/tool-attributes-misplaced-1.rs:14:5
    |
@@ -45,5 +42,4 @@ LL |     rustfmt::skip;
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0423, E0658.
-For more information about an error, try `rustc --explain E0423`.
+For more information about this error, try `rustc --explain E0423`.