about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir/src/diagnostic_items.rs17
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/builtin.rs28
-rw-r--r--compiler/rustc_lint/src/internal.rs31
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs7
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs7
-rw-r--r--compiler/rustc_lint/src/types.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs16
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs9
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs8
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs110
-rw-r--r--src/test/ui/suggestions/derive-trait-for-method-call.stderr11
15 files changed, 142 insertions, 146 deletions
diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs
new file mode 100644
index 00000000000..243014b0027
--- /dev/null
+++ b/compiler/rustc_hir/src/diagnostic_items.rs
@@ -0,0 +1,17 @@
+use crate::def_id::DefId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_span::Symbol;
+
+#[derive(Debug, Default)]
+pub struct DiagnosticItems {
+    pub id_to_name: FxHashMap<DefId, Symbol>,
+    pub name_to_id: FxHashMap<Symbol, DefId>,
+}
+
+impl<CTX: crate::HashStableContext> HashStable<CTX> for DiagnosticItems {
+    #[inline]
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.name_to_id.hash_stable(ctx, hasher);
+    }
+}
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index ce36648d6df..f5ea044e248 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -18,6 +18,7 @@ mod arena;
 pub mod def;
 pub mod def_path_hash_map;
 pub mod definitions;
+pub mod diagnostic_items;
 pub use rustc_span::def_id;
 mod hir;
 pub mod hir_id;
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5656fff2fcb..57c1c8f3ecb 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2478,14 +2478,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 // Find calls to `mem::{uninitialized,zeroed}` methods.
                 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                     let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
-
-                    if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
-                        return Some(InitKind::Zeroed);
-                    } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) {
-                        return Some(InitKind::Uninit);
-                    } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0])
-                    {
-                        return Some(InitKind::Zeroed);
+                    match cx.tcx.get_diagnostic_name(def_id) {
+                        Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
+                        Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
+                        Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
+                        _ => {}
                     }
                 }
             } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
@@ -2497,11 +2494,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                     if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                             let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
-
-                            if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
-                                return Some(InitKind::Zeroed);
-                            } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
-                                return Some(InitKind::Uninit);
+                            match cx.tcx.get_diagnostic_name(def_id) {
+                                Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
+                                Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
+                                _ => {}
                             }
                         }
                     }
@@ -3091,8 +3087,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
                 rustc_hir::ExprKind::Call(ref path, _) => {
                     if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
                         if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
-                            return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
-                                || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
+                            return matches!(
+                                cx.tcx.get_diagnostic_name(def_id),
+                                Some(sym::ptr_null | sym::ptr_null_mut)
+                            );
                         }
                     }
                 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index a4940e5aae7..50a0d211a36 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -33,12 +33,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
             // don't lint imports, only actual usages
             return;
         }
-        let replace = if cx.tcx.is_diagnostic_item(sym::HashMap, def_id) {
-            "FxHashMap"
-        } else if cx.tcx.is_diagnostic_item(sym::HashSet, def_id) {
-            "FxHashSet"
-        } else {
-            return;
+        let replace = match cx.tcx.get_diagnostic_name(def_id) {
+            Some(sym::HashMap) => "FxHashMap",
+            Some(sym::HashSet) => "FxHashSet",
+            _ => return,
         };
         cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
             let msg = format!(
@@ -174,26 +172,29 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
     if let TyKind::Path(qpath) = &ty.kind {
         if let QPath::Resolved(_, path) = qpath {
             match path.res {
-                Res::Def(_, did) => {
-                    if cx.tcx.is_diagnostic_item(sym::Ty, did) {
-                        return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
-                    } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
-                        return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+                Res::Def(_, def_id) => {
+                    if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
+                    {
+                        return Some(format!(
+                            "{}{}",
+                            name,
+                            gen_args(path.segments.last().unwrap())
+                        ));
                     }
                 }
                 // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
                 Res::SelfTy(None, Some((did, _))) => {
                     if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
-                        if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) {
+                        if let Some(name @ (sym::Ty | sym::TyCtxt)) =
+                            cx.tcx.get_diagnostic_name(adt.did)
+                        {
                             // NOTE: This path is currently unreachable as `Ty<'tcx>` is
                             // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
                             // is not actually allowed.
                             //
                             // I(@lcnr) still kept this branch in so we don't miss this
                             // if we ever change it in the future.
-                            return Some(format!("Ty<{}>", substs[0]));
-                        } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) {
-                            return Some(format!("TyCtxt<{}>", substs[0]));
+                            return Some(format!("{}<{}>", name, substs[0]));
                         }
                     }
                 }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index b945c764320..103555a6752 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -54,9 +54,10 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
                     || Some(def_id) == cx.tcx.lang_items().panic_str()
                 {
                     if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
-                        if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
-                            || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
-                        {
+                        if matches!(
+                            cx.tcx.get_diagnostic_name(id),
+                            Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
+                        ) {
                             check_panic(cx, f, arg);
                         }
                     }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index c14f16b6d11..d2c970468ab 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -51,9 +51,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
             Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
                 // Check that we're dealing with a trait method for one of the traits we care about.
                 Some(trait_id)
-                    if [sym::Clone, sym::Deref, sym::Borrow]
-                        .iter()
-                        .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
+                    if matches!(
+                        cx.tcx.get_diagnostic_name(trait_id),
+                        Some(sym::Borrow | sym::Clone | sym::Deref)
+                    ) =>
                 {
                     (trait_id, did)
                 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index ac4bffc239b..708cd56e068 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1541,8 +1541,7 @@ impl InvalidAtomicOrdering {
             if let ExprKind::Call(ref func, ref args) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
-            if cx.tcx.is_diagnostic_item(sym::fence, def_id) ||
-                cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id);
+            if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence));
             if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
             if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
             if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 08fc11f21d9..c7d0f594f01 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -18,6 +18,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
+use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::lang_items;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::hir::exports::Export;
@@ -1052,16 +1053,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     /// Iterates over the diagnostic items in the given crate.
-    fn get_diagnostic_items(&self) -> FxHashMap<Symbol, DefId> {
+    fn get_diagnostic_items(&self) -> DiagnosticItems {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any diagnostic-items to the target.
             Default::default()
         } else {
-            self.root
+            let mut id_to_name = FxHashMap::default();
+            let name_to_id = self
+                .root
                 .diagnostic_items
                 .decode(self)
-                .map(|(name, def_index)| (name, self.local_def_id(def_index)))
-                .collect()
+                .map(|(name, def_index)| {
+                    let id = self.local_def_id(def_index);
+                    id_to_name.insert(id, name);
+                    (name, id)
+                })
+                .collect();
+            DiagnosticItems { id_to_name, name_to_id }
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 072398983af..dacb1e4029c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1750,7 +1750,7 @@ impl EncodeContext<'a, 'tcx> {
     fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE);
+        let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
         self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
     }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b4f7a9fa8e9..9b0b1377875 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1442,7 +1442,7 @@ rustc_queries! {
     }
 
     /// Returns all diagnostic items defined in all crates.
-    query all_diagnostic_items(_: ()) -> FxHashMap<Symbol, DefId> {
+    query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
         storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "calculating the diagnostic items map" }
@@ -1454,7 +1454,7 @@ rustc_queries! {
     }
 
     /// Returns the diagnostic items defined in a crate.
-    query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
+    query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the diagnostic items map in a crate" }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 080e2fef203..6a6fb30dce8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1232,12 +1232,17 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
     /// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
     pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
-        self.all_diagnostic_items(()).get(&name).copied()
+        self.all_diagnostic_items(()).name_to_id.get(&name).copied()
+    }
+
+    /// Obtain the diagnostic item's name
+    pub fn get_diagnostic_name(self, id: DefId) -> Option<Symbol> {
+        self.diagnostic_items(id.krate).id_to_name.get(&id).copied()
     }
 
     /// Check whether the diagnostic item with the given `name` has the given `DefId`.
     pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool {
-        self.diagnostic_items(did.krate).get(&name) == Some(&did)
+        self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did)
     }
 
     pub fn stability(self) -> &'tcx stability::Index<'tcx> {
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index d35a1cc293e..30a0071f0f2 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -10,8 +10,8 @@
 //! * Compiler internal types like `Ty` and `TyCtxt`
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
+use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -19,9 +19,8 @@ use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
 struct DiagnosticItemCollector<'tcx> {
-    // items from this crate
-    items: FxHashMap<Symbol, DefId>,
     tcx: TyCtxt<'tcx>,
+    diagnostic_items: DiagnosticItems,
 }
 
 impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
@@ -44,7 +43,7 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
 
 impl<'tcx> DiagnosticItemCollector<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
-        DiagnosticItemCollector { tcx, items: Default::default() }
+        DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
     }
 
     fn observe_item(&mut self, def_id: LocalDefId) {
@@ -52,19 +51,14 @@ impl<'tcx> DiagnosticItemCollector<'tcx> {
         let attrs = self.tcx.hir().attrs(hir_id);
         if let Some(name) = extract(attrs) {
             // insert into our table
-            collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
+            collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
         }
     }
 }
 
-fn collect_item(
-    tcx: TyCtxt<'_>,
-    items: &mut FxHashMap<Symbol, DefId>,
-    name: Symbol,
-    item_def_id: DefId,
-) {
-    // Check for duplicates.
-    if let Some(original_def_id) = items.insert(name, item_def_id) {
+fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) {
+    items.id_to_name.insert(item_def_id, name);
+    if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
         if original_def_id != item_def_id {
             let mut err = match tcx.hir().span_if_local(item_def_id) {
                 Some(span) => tcx.sess.struct_span_err(
@@ -98,7 +92,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
 }
 
 /// Traverse and collect the diagnostic items in the current
-fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol, DefId> {
+fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems {
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
@@ -107,22 +101,22 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol
     // Collect diagnostic items in this crate.
     tcx.hir().visit_all_item_likes(&mut collector);
 
-    collector.items
+    collector.diagnostic_items
 }
 
 /// Traverse and collect all the diagnostic items in all crates.
-fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap<Symbol, DefId> {
+fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems {
     // Initialize the collector.
-    let mut collector = FxHashMap::default();
+    let mut items = DiagnosticItems::default();
 
     // Collect diagnostic items in other crates.
     for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) {
-        for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() {
-            collect_item(tcx, &mut collector, name, def_id);
+        for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id {
+            collect_item(tcx, &mut items, name, def_id);
         }
     }
 
-    collector
+    items
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index cd678b96446..a73d2285d45 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1636,12 +1636,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
         // Special case the primary error message when send or sync is the trait that was
         // not implemented.
-        let is_send = self.tcx.is_diagnostic_item(sym::Send, trait_ref.def_id);
-        let is_sync = self.tcx.is_diagnostic_item(sym::Sync, trait_ref.def_id);
         let hir = self.tcx.hir();
-        let trait_explanation = if is_send || is_sync {
+        let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
+            self.tcx.get_diagnostic_name(trait_ref.def_id)
+        {
             let (trait_name, trait_verb) =
-                if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
+                if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
 
             err.clear_code();
             err.set_primary_message(format!(
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 8c7ec219464..183ebc559ae 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1047,51 +1047,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
     ) {
-        let derivables = [
-            sym::Eq,
-            sym::PartialEq,
-            sym::Ord,
-            sym::PartialOrd,
-            sym::Clone,
-            sym::Copy,
-            sym::Hash,
-            sym::Default,
-            sym::Debug,
-        ];
-        let mut derives = unsatisfied_predicates
-            .iter()
-            .filter_map(|(pred, _)| {
-                let trait_pred =
-                    if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() {
-                        trait_pred
-                    } else {
-                        return None;
-                    };
-                let trait_ref = trait_pred.trait_ref;
-                let adt_def = if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
-                    adt_def
-                } else {
-                    return None;
-                };
-                if adt_def.did.is_local() {
-                    let diagnostic_items = self.tcx.diagnostic_items(trait_ref.def_id.krate);
-                    return derivables.iter().find_map(|trait_derivable| {
-                        let item_def_id = diagnostic_items.get(trait_derivable)?;
-                        if item_def_id == &trait_pred.trait_ref.def_id
-                            && !(adt_def.is_enum() && *trait_derivable == sym::Default)
-                        {
-                            return Some((
-                                format!("{}", trait_ref.self_ty()),
-                                self.tcx.def_span(adt_def.did),
-                                format!("{}", trait_ref.print_only_trait_name()),
-                            ));
-                        }
-                        None
-                    });
-                }
-                None
-            })
-            .collect::<Vec<(String, Span, String)>>();
+        let mut derives = Vec::<(String, Span, String)>::new();
+        let mut traits = Vec::<Span>::new();
+        for (pred, _) in unsatisfied_predicates {
+            let trait_pred = match pred.kind().skip_binder() {
+                ty::PredicateKind::Trait(trait_pred) => trait_pred,
+                _ => continue,
+            };
+            let adt = match trait_pred.self_ty().ty_adt_def() {
+                Some(adt) if adt.did.is_local() => adt,
+                _ => continue,
+            };
+            let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) {
+                Some(sym::Default) => !adt.is_enum(),
+                Some(
+                    sym::Eq
+                    | sym::PartialEq
+                    | sym::Ord
+                    | sym::PartialOrd
+                    | sym::Clone
+                    | sym::Copy
+                    | sym::Hash
+                    | sym::Debug,
+                ) => true,
+                _ => false,
+            };
+            if can_derive {
+                derives.push((
+                    format!("{}", trait_pred.self_ty()),
+                    self.tcx.def_span(adt.did),
+                    format!("{}", trait_pred.trait_ref.print_only_trait_name()),
+                ));
+            } else {
+                traits.push(self.tcx.def_span(trait_pred.def_id()));
+            }
+        }
         derives.sort();
         let derives_grouped = derives.into_iter().fold(
             Vec::<(String, Span, String)>::new(),
@@ -1106,36 +1096,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 acc
             },
         );
-        let mut traits: Vec<_> = unsatisfied_predicates
-            .iter()
-            .filter_map(|(pred, _)| {
-                let trait_pred =
-                    if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() {
-                        trait_pred
-                    } else {
-                        return None;
-                    };
-                if let ty::Adt(adt_def, _) = trait_pred.trait_ref.self_ty().kind() {
-                    if !adt_def.did.is_local() {
-                        return None;
-                    }
-                } else {
-                    return None;
-                };
-
-                let did = trait_pred.def_id();
-                let diagnostic_items = self.tcx.diagnostic_items(did.krate);
-
-                if !derivables
-                    .iter()
-                    .any(|trait_derivable| diagnostic_items.get(trait_derivable) == Some(&did))
-                {
-                    Some(self.tcx.def_span(did))
-                } else {
-                    None
-                }
-            })
-            .collect();
         traits.sort();
         traits.dedup();
 
diff --git a/src/test/ui/suggestions/derive-trait-for-method-call.stderr b/src/test/ui/suggestions/derive-trait-for-method-call.stderr
index 97fc1134a94..2af3ba1d5bb 100644
--- a/src/test/ui/suggestions/derive-trait-for-method-call.stderr
+++ b/src/test/ui/suggestions/derive-trait-for-method-call.stderr
@@ -20,6 +20,17 @@ LL |     let y = x.test();
            `Enum: Clone`
            `Enum: Default`
            `CloneEnum: Default`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/default.rs:LL:COL
+   |
+LL | / pub trait Default: Sized {
+LL | |     /// Returns the "default value" for a type.
+LL | |     ///
+LL | |     /// Default values are often some kind of initial value, identity value, or anything else that
+...  |
+LL | |     fn default() -> Self;
+LL | | }
+   | |_^
 help: consider annotating `Enum` with `#[derive(Clone)]`
    |
 LL | #[derive(Clone)]