diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 796739c872174..755c648bc088b 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -58,7 +58,7 @@ use crate::ich::{Fingerprint, StableHashingContext};
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use std::fmt;
 use std::hash::Hash;
-use syntax_pos::symbol::InternedString;
+use syntax_pos::symbol::{InternedString, Symbol};
 use crate::traits;
 use crate::traits::query::{
     CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
@@ -593,6 +593,7 @@ define_dep_nodes!( <'tcx>
     [input] CrateDisambiguator(CrateNum),
     [input] CrateHash(CrateNum),
     [input] OriginalCrateName(CrateNum),
+    [input] MaybeLoadExternCrate(Symbol),
     [input] ExtraFileName(CrateNum),
 
     [] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
@@ -637,8 +638,7 @@ define_dep_nodes!( <'tcx>
     [input] MaybeUnusedExternCrates,
     [input] NamesImportedByGlobUse(DefId),
     [eval_always] StabilityIndex,
-    [eval_always] AllTraits,
-    [input] AllCrateNums,
+    [eval_always] AllSuggestibleTraits,
     [] ExportedSymbols(CrateNum),
     [eval_always] CollectAndPartitionMonoItems,
     [] IsCodegenedItem(DefId),
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 6e9552a1e9209..d605984576f16 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -201,6 +201,9 @@ pub trait CrateStore {
     fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
     fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
     fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
+    fn maybe_load_extern_crate_untracked(
+        &self, sess: &Session, name: Symbol
+    ) -> Option<CrateNum>;
 
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 18b0afe1fd91e..a4c96b1c6f089 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1334,8 +1334,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.stability_index(LOCAL_CRATE)
     }
 
-    pub fn crates(self) -> Lrc<Vec<CrateNum>> {
-        self.all_crate_nums(LOCAL_CRATE)
+    pub fn crates(self) -> Vec<CrateNum> {
+        self.cstore.crates_untracked()
     }
 
     pub fn features(self) -> Lrc<feature_gate::Features> {
@@ -2989,6 +2989,9 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         assert_eq!(id, LOCAL_CRATE);
         tcx.crate_name
     };
+    providers.maybe_load_extern_crate = |tcx, name| {
+        tcx.cstore.maybe_load_extern_crate_untracked(tcx.sess, name)
+    };
     providers.get_lib_features = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
         Lrc::new(middle::lib_features::collect(tcx))
@@ -3028,10 +3031,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         let id = tcx.hir().as_local_node_id(id).unwrap();
         tcx.cstore.extern_mod_stmt_cnum_untracked(id)
     };
-    providers.all_crate_nums = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(tcx.cstore.crates_untracked())
-    };
     providers.postorder_cnums = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
         Lrc::new(tcx.cstore.postorder_cnums_untracked())
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index a3ee92f8e1263..492cafb028b34 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -18,7 +18,7 @@ use crate::util::profiling::ProfileCategory;
 use std::borrow::Cow;
 use std::hash::Hash;
 use std::fmt::Debug;
-use syntax_pos::symbol::InternedString;
+use syntax_pos::symbol::{Symbol, InternedString};
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::fingerprint::Fingerprint;
 use crate::ich::StableHashingContext;
@@ -706,6 +706,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::original_crate_name<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::maybe_load_extern_crate<'tcx> {
+    fn describe(_tcx: TyCtxt<'_, '_, '_>, name: Symbol) -> Cow<'static, str> {
+        format!("loading crate with name {}", name).into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::extra_filename<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "looking up the extra filename for a crate".into()
@@ -832,18 +838,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::stability_index<'tcx> {
     }
 }
 
-impl<'tcx> QueryDescription<'tcx> for queries::all_traits<'tcx> {
+impl<'tcx> QueryDescription<'tcx> for queries::all_suggestible_traits<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "fetching all foreign and local traits".into()
     }
 }
 
-impl<'tcx> QueryDescription<'tcx> for queries::all_crate_nums<'tcx> {
-    fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
-        "fetching all foreign CrateNum instances".into()
-    }
-}
-
 impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "exported_symbols".into()
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index f5eb7374cc19b..8e4e5c82ef4f1 100644
--- a/src/librustc/ty/query/keys.rs
+++ b/src/librustc/ty/query/keys.rs
@@ -11,7 +11,7 @@ use crate::mir;
 use std::fmt::Debug;
 use std::hash::Hash;
 use syntax_pos::{Span, DUMMY_SP};
-use syntax_pos::symbol::InternedString;
+use syntax_pos::symbol::{Symbol, InternedString};
 
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
@@ -190,6 +190,15 @@ impl Key for InternedString {
     }
 }
 
+impl Key for Symbol {
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _tcx: TyCtxt<'_, '_, '_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T>
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 3b191d4201fbf..194217eb577b0 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -493,6 +493,7 @@ define_queries! { <'tcx>
         [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator,
         [] fn crate_hash: CrateHash(CrateNum) -> Svh,
         [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol,
+        [] fn maybe_load_extern_crate: MaybeLoadExternCrate(Symbol) -> Option<CrateNum>,
         [] fn extra_filename: ExtraFileName(CrateNum) -> String,
     },
 
@@ -557,12 +558,11 @@ define_queries! { <'tcx>
             -> Lrc<FxHashSet<ast::Name>>,
 
         [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>,
-        [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
 
         /// A vector of every trait accessible in the whole crate
         /// (i.e., including those from subcrates). This is used only for
         /// error reporting.
-        [] fn all_traits: all_traits_node(CrateNum) -> Lrc<Vec<DefId>>,
+        [] fn all_suggestible_traits: all_suggestible_traits_node(CrateNum) -> Lrc<Vec<DefId>>,
     },
 
     Linking {
@@ -894,12 +894,8 @@ fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::StabilityIndex
 }
 
-fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
-    DepConstructor::AllCrateNums
-}
-
-fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
-    DepConstructor::AllTraits
+fn all_suggestible_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::AllSuggestibleTraits
 }
 
 fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs
index c16f861dedb50..63aee243b2b7f 100644
--- a/src/librustc/ty/query/on_disk_cache.rs
+++ b/src/librustc/ty/query/on_disk_cache.rs
@@ -429,7 +429,7 @@ impl<'sess> OnDiskCache<'sess> {
                         -> IndexVec<CrateNum, Option<CrateNum>>
     {
         tcx.dep_graph.with_ignore(|| {
-            let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| {
+            let current_cnums = tcx.crates().iter().map(|&cnum| {
                 let crate_name = tcx.original_crate_name(cnum)
                                     .to_string();
                 let crate_disambiguator = tcx.crate_disambiguator(cnum);
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 267ee89a2ffed..f6bc8cb6bcc7b 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1242,6 +1242,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::MethodAutoderefSteps |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
+        DepKind::MaybeLoadExternCrate |
 
         // This one should never occur in this context
         DepKind::Null => {
@@ -1415,8 +1416,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::NamesImportedByGlobUse => { force!(names_imported_by_glob_use, def_id!()); }
         DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); }
         DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); }
-        DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); }
-        DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); }
+        DepKind::AllSuggestibleTraits => { force!(all_suggestible_traits, LOCAL_CRATE); }
         DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); }
         DepKind::CollectAndPartitionMonoItems => {
             force!(collect_and_partition_mono_items, LOCAL_CRATE);
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index c372892c521be..3116e9325bdb8 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -286,7 +286,7 @@ fn upstream_monomorphizations_provider<'a, 'tcx>(
 {
     debug_assert!(cnum == LOCAL_CRATE);
 
-    let cnums = tcx.all_crate_nums(LOCAL_CRATE);
+    let cnums = tcx.crates();
 
     let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index f49b88f14e60e..67ca03d962d35 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -1,4 +1,5 @@
 use crate::cstore::{self, LoadedMacro};
+use crate::creader::CrateLoader;
 use crate::encoder;
 use crate::link_args;
 use crate::native_libs;
@@ -31,7 +32,7 @@ use syntax::edition::Edition;
 use syntax::parse::source_file_to_stream;
 use syntax::parse::parser::emit_unclosed_delims;
 use syntax::symbol::Symbol;
-use syntax_pos::{Span, NO_EXPANSION, FileName};
+use syntax_pos::{Span, DUMMY_SP, NO_EXPANSION, FileName};
 use rustc_data_structures::bit_set::BitSet;
 
 macro_rules! provide {
@@ -328,7 +329,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
             // which is to say, its not deterministic in general. But
             // we believe that libstd is consistently assigned crate
             // num 1, so it should be enough to resolve #46112.
-            let mut crates: Vec<CrateNum> = (*tcx.crates()).clone();
+            let mut crates = tcx.crates();
             crates.sort();
 
             for &cnum in crates.iter() {
@@ -541,6 +542,15 @@ impl CrateStore for cstore::CStore {
         self.do_postorder_cnums_untracked()
     }
 
+    fn maybe_load_extern_crate_untracked(
+        &self,
+        sess: &Session,
+        name: Symbol
+    ) -> Option<CrateNum> {
+        let mut crate_loader = CrateLoader::new(sess, self, "");
+        crate_loader.maybe_process_path_extern(name, DUMMY_SP)
+    }
+
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>)
                                  -> EncodedMetadata
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index fd93fea00bcf5..95e9b9343070a 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -491,6 +491,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn reset(&mut self) {
+        debug!("reset");
         self.inherent_candidates.clear();
         self.extension_candidates.clear();
         self.impl_dups.clear();
@@ -505,6 +506,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                       candidate: Candidate<'tcx>,
                       is_inherent: bool)
     {
+        debug!("push_candidate: candidate={:?} is_inherent={:?}", candidate, is_inherent);
         let is_accessible = if let Some(name) = self.method_name {
             let item = candidate.item;
             let def_scope = self.tcx.adjust_ident(name, item.container.id(), self.body_id).1;
@@ -512,6 +514,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         } else {
             true
         };
+
+        debug!("push_candidate: is_accessible={:?}", is_accessible);
         if is_accessible {
             if is_inherent {
                 self.inherent_candidates.push(candidate);
@@ -847,8 +851,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
+        debug!("assemble_extension_candidates_for_all_traits");
         let mut duplicates = FxHashSet::default();
-        for trait_info in suggest::all_traits(self.tcx) {
+        for trait_info in suggest::all_suggestible_traits(self.tcx) {
             if duplicates.insert(trait_info.def_id) {
                 self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
             }
@@ -939,6 +944,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     // THE ACTUAL SEARCH
 
     fn pick(mut self) -> PickResult<'tcx> {
+        debug!("pick: method_name={:?}", self.method_name);
         assert!(self.method_name.is_some());
 
         if let Some(r) = self.pick_core() {
@@ -958,9 +964,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         self.assemble_extension_candidates_for_all_traits()?;
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.item.container.id()],
+            Some(Ok(p)) => {
+                debug!("pick: (ok) p={:?}", p);
+                vec![p.item.container.id()]
+            },
             //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
             Some(Err(MethodError::Ambiguity(v))) => {
+                debug!("pick: (ambiguity) v={:?}", v);
                 v.into_iter()
                     .map(|source| {
                         match source {
@@ -979,6 +989,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     .collect()
             }
             Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => {
+                debug!("pick: (no match) others={:?}", others);
                 assert!(others.is_empty());
                 vec![]
             }
@@ -990,6 +1001,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         }
         let lev_candidate = self.probe_for_lev_candidate()?;
 
+        debug!("pick: out_of_scope_traits={:?}", out_of_scope_traits);
         Err(MethodError::NoMatch(NoMatchData::new(static_candidates,
                                                   unsatisfied_predicates,
                                                   out_of_scope_traits,
@@ -1302,13 +1314,20 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                     let predicate = trait_ref.to_predicate();
                     let obligation =
                         traits::Obligation::new(cause, self.param_env, predicate);
+                    debug!(
+                        "consider_probe: predicate={:?} obligation={:?} trait_ref={:?}",
+                        predicate, obligation, trait_ref
+                    );
                     if !self.predicate_may_hold(&obligation) {
+                        debug!("consider_probe: predicate did not hold");
                         if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
+                            debug!("consider_probe: select_trait_candidate.is_err=true");
                             // This candidate's primary obligation doesn't even
                             // select - don't bother registering anything in
                             // `potentially_unsatisfied_predicates`.
                             return ProbeResult::NoMatch;
                         } else {
+                            debug!("consider_probe: nested subobligation");
                             // Some nested subobligation of this predicate
                             // failed.
                             //
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index aa6f73b29b4b5..90ce8df88c015 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -207,7 +207,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // Suggest clamping down the type if the method that is being attempted to
                     // be used exists at all, and the type is an ambiuous numeric type
                     // ({integer}/{float}).
-                    let mut candidates = all_traits(self.tcx)
+                    let mut candidates = all_suggestible_traits(self.tcx)
                         .into_iter()
                         .filter_map(|info|
                             self.associated_item(info.def_id, item_name, Namespace::Value)
@@ -430,15 +430,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       bound_list));
                 }
 
-                if actual.is_numeric() && actual.is_fresh() {
-
-                } else {
-                    self.suggest_traits_to_import(&mut err,
-                                                  span,
-                                                  rcvr_ty,
-                                                  item_name,
-                                                  source,
-                                                  out_of_scope_traits);
+                if !actual.is_numeric() || !actual.is_fresh() {
+                    self.suggest_traits_to_import(
+                        &mut err, span, rcvr_ty, item_name, source, out_of_scope_traits
+                    );
                 }
 
                 if let Some(lev_candidate) = lev_candidate {
@@ -575,13 +570,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn suggest_traits_to_import<'b>(&self,
-                                    err: &mut DiagnosticBuilder,
-                                    span: Span,
-                                    rcvr_ty: Ty<'tcx>,
-                                    item_name: ast::Ident,
-                                    source: SelfSource<'b>,
-                                    valid_out_of_scope_traits: Vec<DefId>) {
+    fn suggest_traits_to_import(
+        &self,
+        err: &mut DiagnosticBuilder,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        item_name: ast::Ident,
+        source: SelfSource<'a>,
+        valid_out_of_scope_traits: Vec<DefId>
+    ) {
+        debug!(
+            "suggest_traits_to_import: rcvr_ty={:?} item_name={:?} source={:?} \
+             valid_out_of_scope_traits={:?}",
+             rcvr_ty, item_name, source, valid_out_of_scope_traits,
+        );
         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
             return;
         }
@@ -591,7 +593,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // There are no traits implemented, so lets suggest some traits to
         // implement, by finding ones that have the item name, and are
         // legal to implement.
-        let mut candidates = all_traits(self.tcx)
+        let mut candidates = all_suggestible_traits(self.tcx)
             .into_iter()
             .filter(|info| {
                 // We approximate the coherence rules to only suggest
@@ -610,6 +612,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             })
             .collect::<Vec<_>>();
 
+        debug!("suggest_traits_to_import: candidates={:?}", candidates);
         if !candidates.is_empty() {
             // Sort from most relevant to least relevant.
             candidates.sort_by(|a, b| a.cmp(b).reverse());
@@ -676,13 +679,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum SelfSource<'a> {
     QPath(&'a hir::Ty),
     MethodCall(&'a hir::Expr /* rcvr */),
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct TraitInfo {
     pub def_id: DefId,
 }
@@ -692,12 +695,15 @@ impl PartialEq for TraitInfo {
         self.cmp(other) == Ordering::Equal
     }
 }
+
 impl Eq for TraitInfo {}
+
 impl PartialOrd for TraitInfo {
     fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
         Some(self.cmp(other))
     }
 }
+
 impl Ord for TraitInfo {
     fn cmp(&self, other: &TraitInfo) -> Ordering {
         // Local crates are more important than remote ones (local:
@@ -710,8 +716,8 @@ impl Ord for TraitInfo {
 }
 
 /// Retrieves all traits in this crate and any dependent crates.
-pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<TraitInfo> {
-    tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
+pub fn all_suggestible_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<TraitInfo> {
+    tcx.all_suggestible_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect()
 }
 
 /// Computes all traits in this crate and any dependent crates.
@@ -768,9 +774,20 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
             _ => {}
         }
     }
-    for &cnum in tcx.crates().iter() {
+
+    // Attempt to load all crates that we have `--extern` flags for, this means
+    // we will be able to make suggestions for traits they define. Particularly useful
+    // in Rust 2018 as there aren't `extern crate` lines that import a crate even if it isn't
+    // otherwise used.
+    for name in tcx.extern_prelude.keys() {
+        let cnum = tcx.maybe_load_extern_crate(*name);
+        debug!("compute_all_traits: (attempt load) name={:?} cnum={:?}", name, cnum);
+    }
+
+    for cnum in tcx.crates().iter() {
+        debug!("compute_all_traits: cnum={:?} name={:?}", cnum, tcx.crate_name(*cnum));
         let def_id = DefId {
-            krate: cnum,
+            krate: *cnum,
             index: CRATE_DEF_INDEX,
         };
         handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id));
@@ -780,7 +797,7 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId>
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    providers.all_traits = |tcx, cnum| {
+    providers.all_suggestible_traits = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
         Lrc::new(compute_all_traits(tcx))
     }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e90127ca162d2..522f7cb283ed8 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -532,7 +532,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                 fake_def_ids: Default::default(),
                 all_fake_def_ids: Default::default(),
                 generated_synthetics: Default::default(),
-                all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
+                all_traits: tcx.all_suggestible_traits(LOCAL_CRATE).to_vec(),
             };
             debug!("crate: {:?}", tcx.hir().krate());
 
diff --git a/src/test/ui/rust-2018/auxiliary/baz.rs b/src/test/ui/rust-2018/auxiliary/baz.rs
index b317c8a45368c..e679b38e8a46c 100644
--- a/src/test/ui/rust-2018/auxiliary/baz.rs
+++ b/src/test/ui/rust-2018/auxiliary/baz.rs
@@ -1,5 +1,12 @@
-// This file is used as part of the local-path-suggestions.rs test.
+// This file is used as part of the local-path-suggestions.rs and
+// the trait-import-suggestions.rs test.
 
 pub mod foobar {
     pub struct Baz;
 }
+
+pub trait BazTrait {
+    fn extern_baz(&self) { }
+}
+
+impl BazTrait for u32 { }
diff --git a/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs b/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
deleted file mode 100644
index d356f3294626f..0000000000000
--- a/src/test/ui/rust-2018/auxiliary/trait-import-suggestions.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub trait Baz {
-    fn baz(&self) { }
-}
-
-impl Baz for u32 { }
diff --git a/src/test/ui/rust-2018/extern-trait-impl-suggestions.rs b/src/test/ui/rust-2018/extern-trait-impl-suggestions.rs
new file mode 100644
index 0000000000000..f37369b9d8506
--- /dev/null
+++ b/src/test/ui/rust-2018/extern-trait-impl-suggestions.rs
@@ -0,0 +1,13 @@
+// edition:2018
+// aux-build:baz.rs
+// compile-flags:--extern baz
+
+// Don't use anything from baz - making suggestions from it when the only reference to it
+// is an `--extern` flag is what is tested by this test.
+
+struct Local;
+
+fn main() {
+    let local = Local;
+    local.extern_baz(); //~ ERROR no method named `extern_baz`
+}
diff --git a/src/test/ui/rust-2018/extern-trait-impl-suggestions.stderr b/src/test/ui/rust-2018/extern-trait-impl-suggestions.stderr
new file mode 100644
index 0000000000000..af7a9cb7bdab2
--- /dev/null
+++ b/src/test/ui/rust-2018/extern-trait-impl-suggestions.stderr
@@ -0,0 +1,16 @@
+error[E0599]: no method named `extern_baz` found for type `Local` in the current scope
+  --> $DIR/extern-trait-impl-suggestions.rs:12:11
+   |
+LL | struct Local;
+   | ------------- method `extern_baz` not found for this
+...
+LL |     local.extern_baz(); //~ ERROR no method named `extern_baz`
+   |           ^^^^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `extern_baz`, perhaps you need to implement it:
+           candidate #1: `baz::BazTrait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.rs b/src/test/ui/rust-2018/trait-import-suggestions.rs
index 9c67c3f4b4b2e..4e2b9b7a7f342 100644
--- a/src/test/ui/rust-2018/trait-import-suggestions.rs
+++ b/src/test/ui/rust-2018/trait-import-suggestions.rs
@@ -1,6 +1,9 @@
 // edition:2018
-// aux-build:trait-import-suggestions.rs
-// compile-flags:--extern trait-import-suggestions
+// aux-build:baz.rs
+// compile-flags:--extern baz
+
+// Don't use anything from baz - making suggestions from it when the only reference to it
+// is an `--extern` flag is one of the things tested by this test.
 
 mod foo {
     mod foobar {
@@ -26,6 +29,6 @@ mod foo {
 fn main() {
     let x: u32 = 22;
     x.bar(); //~ ERROR no method named `bar`
-    x.baz(); //~ ERROR no method named `baz`
+    x.extern_baz(); //~ ERROR no method named `extern_baz`
     let y = u32::from_str("33"); //~ ERROR no function or associated item named `from_str`
 }
diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr
index e4c17680c90a5..767dda842335b 100644
--- a/src/test/ui/rust-2018/trait-import-suggestions.stderr
+++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no method named `foobar` found for type `u32` in the current scope
-  --> $DIR/trait-import-suggestions.rs:22:11
+  --> $DIR/trait-import-suggestions.rs:25:11
    |
 LL |         x.foobar(); //~ ERROR no method named `foobar`
    |           ^^^^^^
@@ -9,7 +9,7 @@ LL |         x.foobar(); //~ ERROR no method named `foobar`
            `use crate::foo::foobar::Foobar;`
 
 error[E0599]: no method named `bar` found for type `u32` in the current scope
-  --> $DIR/trait-import-suggestions.rs:28:7
+  --> $DIR/trait-import-suggestions.rs:31:7
    |
 LL |     x.bar(); //~ ERROR no method named `bar`
    |       ^^^
@@ -20,14 +20,20 @@ help: the following trait is implemented but not in scope, perhaps add a `use` f
 LL | use crate::foo::Bar;
    |
 
-error[E0599]: no method named `baz` found for type `u32` in the current scope
-  --> $DIR/trait-import-suggestions.rs:29:7
+error[E0599]: no method named `extern_baz` found for type `u32` in the current scope
+  --> $DIR/trait-import-suggestions.rs:32:7
+   |
+LL |     x.extern_baz(); //~ ERROR no method named `extern_baz`
+   |       ^^^^^^^^^^
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope, perhaps add a `use` for it:
+   |
+LL | use baz::BazTrait;
    |
-LL |     x.baz(); //~ ERROR no method named `baz`
-   |       ^^^
 
 error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope
-  --> $DIR/trait-import-suggestions.rs:30:18
+  --> $DIR/trait-import-suggestions.rs:33:18
    |
 LL |     let y = u32::from_str("33"); //~ ERROR no function or associated item named `from_str`
    |             -----^^^^^^^^