about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-07-05 10:39:15 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2020-07-18 14:06:04 +0400
commit0a4217d09f41d64f8be076c26d16d3474ca66c03 (patch)
treec9b9cc76c0386d3ae0f63041c2d3508083da1734
parent4044cbc559be2c00a4718a086c3443d429032446 (diff)
downloadrust-0a4217d09f41d64f8be076c26d16d3474ca66c03.tar.gz
rust-0a4217d09f41d64f8be076c26d16d3474ca66c03.zip
rustc_metadata: Make crate loading fully speculative
-rw-r--r--src/librustc_metadata/creader.rs183
-rw-r--r--src/librustc_metadata/locator.rs673
-rw-r--r--src/librustc_plugin_impl/load.rs12
-rw-r--r--src/librustc_resolve/diagnostics.rs4
-rw-r--r--src/librustc_resolve/late/diagnostics.rs9
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/test/compile-fail/empty-extern-arg.rs2
-rw-r--r--src/test/ui-fulldeps/macro-crate-rlib.rs4
-rw-r--r--src/test/ui-fulldeps/macro-crate-rlib.stderr12
-rw-r--r--src/test/ui/extern/extern-prelude-no-speculative.rs2
-rw-r--r--src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs1
-rw-r--r--src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr9
-rw-r--r--src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs2
-rw-r--r--src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr9
14 files changed, 453 insertions, 471 deletions
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 0563894e634..0d2101cb2cb 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -1,6 +1,7 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::locator::{CrateLocator, CratePaths};
+use crate::dynamic_lib::DynamicLibrary;
+use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
 use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
@@ -8,15 +9,12 @@ use rustc_ast::{ast, attr};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::cstore::DepKind;
-use rustc_middle::middle::cstore::{
-    CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn,
-};
+use rustc_middle::middle::cstore::{CrateSource, DepKind, ExternCrate};
+use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::lint;
@@ -31,7 +29,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use log::{debug, info, log_enabled};
 use proc_macro::bridge::client::ProcMacro;
 use std::path::Path;
-use std::{cmp, fs};
+use std::{cmp, env, fs};
 
 #[derive(Clone)]
 pub struct CStore {
@@ -69,18 +67,6 @@ enum LoadResult {
     Loaded(Library),
 }
 
-enum LoadError<'a> {
-    LocatorError(CrateLocator<'a>),
-}
-
-impl<'a> LoadError<'a> {
-    fn report(self) -> ! {
-        match self {
-            LoadError::LocatorError(locator) => locator.report_errs(),
-        }
-    }
-}
-
 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
 #[derive(Clone, Copy)]
 crate struct CrateMetadataRef<'a> {
@@ -280,60 +266,43 @@ impl<'a> CrateLoader<'a> {
         ret
     }
 
-    fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
+    fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
         // Check for (potential) conflicts with the local crate
         if self.local_crate_name == root.name()
             && self.sess.local_crate_disambiguator() == root.disambiguator()
         {
-            struct_span_err!(
-                self.sess,
-                span,
-                E0519,
-                "the current crate is indistinguishable from one of its \
-                         dependencies: it has the same crate-name `{}` and was \
-                         compiled with the same `-C metadata` arguments. This \
-                         will result in symbol conflicts between the two.",
-                root.name()
-            )
-            .emit()
+            return Err(CrateError::SymbolConflictsCurrent(root.name()));
         }
 
         // Check for conflicts with any crate loaded so far
+        let mut res = Ok(());
         self.cstore.iter_crate_data(|_, other| {
             if other.name() == root.name() && // same crate-name
-               other.disambiguator() == root.disambiguator() &&  // same crate-disambiguator
+               other.disambiguator() == root.disambiguator() && // same crate-disambiguator
                other.hash() != root.hash()
             {
                 // but different SVH
-                struct_span_err!(
-                    self.sess,
-                    span,
-                    E0523,
-                    "found two different crates with name `{}` that are \
-                         not distinguished by differing `-C metadata`. This \
-                         will result in symbol conflicts between the two.",
-                    root.name()
-                )
-                .emit();
+                res = Err(CrateError::SymbolConflictsOthers(root.name()));
             }
         });
+
+        res
     }
 
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
         root: Option<&CratePaths>,
-        span: Span,
         lib: Library,
         dep_kind: DepKind,
         name: Symbol,
-    ) -> CrateNum {
+    ) -> Result<CrateNum, CrateError> {
         let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
 
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        self.verify_no_symbol_conflicts(span, &crate_root);
+        self.verify_no_symbol_conflicts(&crate_root)?;
 
         let private_dep =
             self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
@@ -353,7 +322,7 @@ impl<'a> CrateLoader<'a> {
             &crate_paths
         };
 
-        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
+        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -365,7 +334,7 @@ impl<'a> CrateLoader<'a> {
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator(), span))
+            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
         } else {
             None
         };
@@ -386,14 +355,14 @@ impl<'a> CrateLoader<'a> {
             ),
         );
 
-        cnum
+        Ok(cnum)
     }
 
     fn load_proc_macro<'b>(
         &self,
         locator: &mut CrateLocator<'b>,
         path_kind: PathKind,
-    ) -> Option<(LoadResult, Option<Library>)>
+    ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
     where
         'a: 'b,
     {
@@ -408,8 +377,11 @@ impl<'a> CrateLoader<'a> {
         let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
             proc_macro_locator.reset();
             let result = match self.load(&mut proc_macro_locator)? {
-                LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
-                LoadResult::Loaded(library) => Some(LoadResult::Loaded(library)),
+                Some(LoadResult::Previous(cnum)) => {
+                    return Ok(Some((LoadResult::Previous(cnum), None)));
+                }
+                Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
+                None => return Ok(None),
             };
             locator.hash = locator.host_hash;
             // Use the locator when looking for the host proc macro crate, as that is required
@@ -427,9 +399,12 @@ impl<'a> CrateLoader<'a> {
         locator.triple = TargetTriple::from_triple(config::host_triple());
         locator.filesearch = self.sess.host_filesearch(path_kind);
 
-        let host_result = self.load(locator)?;
+        let host_result = match self.load(locator)? {
+            Some(host_result) => host_result,
+            None => return Ok(None),
+        };
 
-        Some(if self.sess.opts.debugging_opts.dual_proc_macros {
+        Ok(Some(if self.sess.opts.debugging_opts.dual_proc_macros {
             let host_result = match host_result {
                 LoadResult::Previous(..) => {
                     panic!("host and target proc macros must be loaded in lock-step")
@@ -439,7 +414,7 @@ impl<'a> CrateLoader<'a> {
             (target_result.unwrap(), Some(host_result))
         } else {
             (host_result, None)
-        })
+        }))
     }
 
     fn resolve_crate<'b>(
@@ -452,25 +427,20 @@ impl<'a> CrateLoader<'a> {
         if dep.is_none() {
             self.used_extern_options.insert(name);
         }
-        if !name.as_str().is_ascii() {
-            self.sess
-                .struct_span_err(
-                    span,
-                    &format!("cannot load a crate with a non-ascii name `{}`", name,),
-                )
-                .emit();
-        }
-        self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
+        self.maybe_resolve_crate(name, dep_kind, dep)
+            .unwrap_or_else(|err| err.report(self.sess, span))
     }
 
     fn maybe_resolve_crate<'b>(
         &'b mut self,
         name: Symbol,
-        span: Span,
         mut dep_kind: DepKind,
         dep: Option<(&'b CratePaths, &'b CrateDep)>,
-    ) -> Result<CrateNum, LoadError<'b>> {
+    ) -> Result<CrateNum, CrateError> {
         info!("resolving crate `{}`", name);
+        if !name.as_str().is_ascii() {
+            return Err(CrateError::NonAsciiName(name));
+        }
         let (root, hash, host_hash, extra_filename, path_kind) = match dep {
             Some((root, dep)) => (
                 Some(root),
@@ -494,18 +464,20 @@ impl<'a> CrateLoader<'a> {
                 extra_filename,
                 false, // is_host
                 path_kind,
-                span,
                 root,
                 Some(false), // is_proc_macro
             );
 
-            self.load(&mut locator)
-                .map(|r| (r, None))
-                .or_else(|| {
+            match self.load(&mut locator)? {
+                Some(res) => (res, None),
+                None => {
                     dep_kind = DepKind::MacrosOnly;
-                    self.load_proc_macro(&mut locator, path_kind)
-                })
-                .ok_or_else(move || LoadError::LocatorError(locator))?
+                    match self.load_proc_macro(&mut locator, path_kind)? {
+                        Some(res) => res,
+                        None => return Err(locator.into_error()),
+                    }
+                }
+            }
         };
 
         match result {
@@ -518,14 +490,17 @@ impl<'a> CrateLoader<'a> {
                 Ok(cnum)
             }
             (LoadResult::Loaded(library), host_library) => {
-                Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
+                self.register_crate(host_library, root, library, dep_kind, name)
             }
             _ => panic!(),
         }
     }
 
-    fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
-        let library = locator.maybe_load_library_crate()?;
+    fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
+        let library = match locator.maybe_load_library_crate()? {
+            Some(library) => library,
+            None => return Ok(None),
+        };
 
         // In the case that we're loading a crate, but not matching
         // against a hash, we could load a crate which has the same hash
@@ -536,7 +511,7 @@ impl<'a> CrateLoader<'a> {
         // don't want to match a host crate against an equivalent target one
         // already loaded.
         let root = library.metadata.get_root();
-        if locator.triple == self.sess.opts.target_triple {
+        Ok(Some(if locator.triple == self.sess.opts.target_triple {
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
                 if data.name() == root.name() && root.hash() == data.hash() {
@@ -545,10 +520,10 @@ impl<'a> CrateLoader<'a> {
                     result = LoadResult::Previous(cnum);
                 }
             });
-            Some(result)
+            result
         } else {
-            Some(LoadResult::Loaded(library))
-        }
+            LoadResult::Loaded(library)
+        }))
     }
 
     fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
@@ -569,53 +544,51 @@ impl<'a> CrateLoader<'a> {
         crate_root: &CrateRoot<'_>,
         metadata: &MetadataBlob,
         krate: CrateNum,
-        span: Span,
         dep_kind: DepKind,
-    ) -> CrateNumMap {
+    ) -> Result<CrateNumMap, CrateError> {
         debug!("resolving deps of external crate");
         if crate_root.is_proc_macro_crate() {
-            return CrateNumMap::new();
+            return Ok(CrateNumMap::new());
         }
 
         // The map from crate numbers in the crate we're resolving to local crate numbers.
         // We map 0 and all other holes in the map to our parent crate. The "additional"
         // self-dependencies should be harmless.
-        std::iter::once(krate)
-            .chain(crate_root.decode_crate_deps(metadata).map(|dep| {
-                info!(
-                    "resolving dep crate {} hash: `{}` extra filename: `{}`",
-                    dep.name, dep.hash, dep.extra_filename
-                );
-                let dep_kind = match dep_kind {
-                    DepKind::MacrosOnly => DepKind::MacrosOnly,
-                    _ => dep.kind,
-                };
-                self.resolve_crate(dep.name, span, dep_kind, Some((root, &dep)))
-            }))
-            .collect()
+        let deps = crate_root.decode_crate_deps(metadata);
+        let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
+        crate_num_map.push(krate);
+        for dep in deps {
+            info!(
+                "resolving dep crate {} hash: `{}` extra filename: `{}`",
+                dep.name, dep.hash, dep.extra_filename
+            );
+            let dep_kind = match dep_kind {
+                DepKind::MacrosOnly => DepKind::MacrosOnly,
+                _ => dep.kind,
+            };
+            let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?;
+            crate_num_map.push(cnum);
+        }
+        Ok(crate_num_map)
     }
 
     fn dlsym_proc_macros(
         &self,
         path: &Path,
         disambiguator: CrateDisambiguator,
-        span: Span,
-    ) -> &'static [ProcMacro] {
-        use crate::dynamic_lib::DynamicLibrary;
-        use std::env;
-
+    ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
         let lib = match DynamicLibrary::open(&path) {
             Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(span, &err),
+            Err(s) => return Err(CrateError::DlOpen(s)),
         };
 
         let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
         let decls = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
-                Err(err) => self.sess.span_fatal(span, &err),
+                Err(s) => return Err(CrateError::DlSym(s)),
             };
             *(sym as *const &[ProcMacro])
         };
@@ -624,7 +597,7 @@ impl<'a> CrateLoader<'a> {
         // since the library can make things that will live arbitrarily long.
         std::mem::forget(lib);
 
-        decls
+        Ok(decls)
     }
 
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -952,7 +925,7 @@ impl<'a> CrateLoader<'a> {
         cnum
     }
 
-    pub fn maybe_process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()
+    pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
+        self.maybe_resolve_crate(name, DepKind::Explicit, None).ok()
     }
 }
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index ecb2548c746..371ec4cd911 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -216,9 +216,10 @@ use crate::creader::Library;
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::struct_span_err;
 use rustc_middle::middle::cstore::{CrateSource, MetadataLoader};
 use rustc_session::config::{self, CrateType};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
@@ -228,24 +229,12 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
 
-use std::cmp;
-use std::fmt;
-use std::fs;
-use std::io::{self, Read};
-use std::ops::Deref;
-use std::path::{Path, PathBuf};
-
 use flate2::read::DeflateDecoder;
-
-use rustc_data_structures::owning_ref::OwningRef;
-
 use log::{debug, info, warn};
-
-#[derive(Clone)]
-struct CrateMismatch {
-    path: PathBuf,
-    got: String,
-}
+use std::io::{Read, Result as IoResult, Write};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+use std::{cmp, fmt, fs};
 
 #[derive(Clone)]
 crate struct CrateLocator<'a> {
@@ -262,7 +251,6 @@ crate struct CrateLocator<'a> {
     pub target: &'a Target,
     pub triple: TargetTriple,
     pub filesearch: FileSearch<'a>,
-    span: Span,
     root: Option<&'a CratePaths>,
     pub is_proc_macro: Option<bool>,
 
@@ -274,6 +262,7 @@ crate struct CrateLocator<'a> {
     rejected_via_filename: Vec<CrateMismatch>,
 }
 
+#[derive(Clone)]
 crate struct CratePaths {
     name: Symbol,
     source: CrateSource,
@@ -286,7 +275,7 @@ impl CratePaths {
 }
 
 #[derive(Copy, Clone, PartialEq)]
-enum CrateFlavor {
+crate enum CrateFlavor {
     Rlib,
     Rmeta,
     Dylib,
@@ -312,7 +301,6 @@ impl<'a> CrateLocator<'a> {
         extra_filename: Option<&'a str>,
         is_host: bool,
         path_kind: PathKind,
-        span: Span,
         root: Option<&'a CratePaths>,
         is_proc_macro: Option<bool>,
     ) -> CrateLocator<'a> {
@@ -348,7 +336,6 @@ impl<'a> CrateLocator<'a> {
             } else {
                 sess.target_filesearch(path_kind)
             },
-            span,
             root,
             is_proc_macro,
             rejected_via_hash: Vec::new(),
@@ -367,158 +354,24 @@ impl<'a> CrateLocator<'a> {
         self.rejected_via_filename.clear();
     }
 
-    crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
+    crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
         if !self.exact_paths.is_empty() {
             return self.find_commandline_library();
         }
         let mut seen_paths = FxHashSet::default();
-        match self.extra_filename {
-            Some(s) => self
-                .find_library_crate(s, &mut seen_paths)
-                .or_else(|| self.find_library_crate("", &mut seen_paths)),
-            None => self.find_library_crate("", &mut seen_paths),
-        }
-    }
-
-    crate fn report_errs(self) -> ! {
-        let add = match self.root {
-            None => String::new(),
-            Some(r) => format!(" which `{}` depends on", r.name),
-        };
-        let mut msg = "the following crate versions were found:".to_string();
-        let mut err = if !self.rejected_via_hash.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0460,
-                "found possibly newer version of crate `{}`{}",
-                self.crate_name,
-                add
-            );
-            err.note("perhaps that crate needs to be recompiled?");
-            let mismatches = self.rejected_via_hash.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display()));
-            }
-            match self.root {
-                None => {}
-                Some(r) => {
-                    for path in r.source.paths() {
-                        msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
-                    }
-                }
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_triple.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0461,
-                "couldn't find crate `{}` \
-                                            with expected target triple {}{}",
-                self.crate_name,
-                self.triple,
-                add
-            );
-            let mismatches = self.rejected_via_triple.iter();
-            for &CrateMismatch { ref path, ref got } in mismatches {
-                msg.push_str(&format!(
-                    "\ncrate `{}`, target triple {}: {}",
-                    self.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_kind.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0462,
-                "found staticlib `{}` instead of rlib or dylib{}",
-                self.crate_name,
-                add
-            );
-            err.help("please recompile that crate using --crate-type lib");
-            let mismatches = self.rejected_via_kind.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                msg.push_str(&format!("\ncrate `{}`: {}", self.crate_name, path.display()));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_version.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0514,
-                "found crate `{}` compiled by an incompatible version \
-                                            of rustc{}",
-                self.crate_name,
-                add
-            );
-            err.help(&format!(
-                "please recompile that crate using this compiler ({})",
-                rustc_version()
-            ));
-            let mismatches = self.rejected_via_version.iter();
-            for &CrateMismatch { ref path, ref got } in mismatches {
-                msg.push_str(&format!(
-                    "\ncrate `{}` compiled by {}: {}",
-                    self.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0463,
-                "can't find crate for `{}`{}",
-                self.crate_name,
-                add
-            );
-
-            if (self.crate_name == sym::std || self.crate_name == sym::core)
-                && self.triple != TargetTriple::from_triple(config::host_triple())
-            {
-                err.note(&format!("the `{}` target may not be installed", self.triple));
-            } else if self.crate_name == sym::profiler_builtins {
-                err.note(&"the compiler may have been built without the profiler runtime");
-            }
-            err.span_label(self.span, "can't find crate");
-            err
-        };
-
-        if !self.rejected_via_filename.is_empty() {
-            let mismatches = self.rejected_via_filename.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                err.note(&format!(
-                    "extern location for {} is of an unknown type: {}",
-                    self.crate_name,
-                    path.display()
-                ))
-                .help(&format!(
-                    "file name should be lib*.rlib or {}*.{}",
-                    self.target.options.dll_prefix, self.target.options.dll_suffix
-                ));
+        if let Some(extra_filename) = self.extra_filename {
+            if let library @ Some(_) = self.find_library_crate(extra_filename, &mut seen_paths)? {
+                return Ok(library);
             }
         }
-
-        err.emit();
-        self.sess.abort_if_errors();
-        unreachable!();
+        self.find_library_crate("", &mut seen_paths)
     }
 
     fn find_library_crate(
         &mut self,
         extra_prefix: &str,
         seen_paths: &mut FxHashSet<PathBuf>,
-    ) -> Option<Library> {
+    ) -> Result<Option<Library>, CrateError> {
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
         let dylib_prefix =
             format!("{}{}{}", self.target.options.dll_prefix, self.crate_name, extra_prefix);
@@ -572,9 +425,7 @@ impl<'a> CrateLocator<'a> {
 
             info!("lib candidate: {}", spf.path.display());
 
-            let hash_str = hash.to_string();
-            let slot = candidates.entry(hash_str).or_default();
-            let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
+            let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
             fs::canonicalize(&spf.path)
                 .map(|p| {
                     if seen_paths.contains(&p) {
@@ -582,16 +433,10 @@ impl<'a> CrateLocator<'a> {
                     };
                     seen_paths.insert(p.clone());
                     match found_kind {
-                        CrateFlavor::Rlib => {
-                            rlibs.insert(p, kind);
-                        }
-                        CrateFlavor::Rmeta => {
-                            rmetas.insert(p, kind);
-                        }
-                        CrateFlavor::Dylib => {
-                            dylibs.insert(p, kind);
-                        }
-                    }
+                        CrateFlavor::Rlib => rlibs.insert(p, kind),
+                        CrateFlavor::Rmeta => rmetas.insert(p, kind),
+                        CrateFlavor::Dylib => dylibs.insert(p, kind),
+                    };
                     FileMatches
                 })
                 .unwrap_or(FileDoesntMatch)
@@ -608,7 +453,7 @@ impl<'a> CrateLocator<'a> {
         // search is being performed for.
         let mut libraries = FxHashMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
-            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs) {
+            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
                 libraries.insert(svh, lib);
             }
         }
@@ -617,39 +462,9 @@ impl<'a> CrateLocator<'a> {
         // what we've got and figure out if we found multiple candidates for
         // libraries or not.
         match libraries.len() {
-            0 => None,
-            1 => Some(libraries.into_iter().next().unwrap().1),
-            _ => {
-                let mut err = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0464,
-                    "multiple matching crates for `{}`",
-                    self.crate_name
-                );
-                let candidates = libraries
-                    .iter()
-                    .filter_map(|(_, lib)| {
-                        let crate_name = &lib.metadata.get_root().name().as_str();
-                        match &(&lib.source.dylib, &lib.source.rlib) {
-                            &(&Some((ref pd, _)), &Some((ref pr, _))) => Some(format!(
-                                "\ncrate `{}`: {}\n{:>padding$}",
-                                crate_name,
-                                pd.display(),
-                                pr.display(),
-                                padding = 8 + crate_name.len()
-                            )),
-                            &(&Some((ref p, _)), &None) | &(&None, &Some((ref p, _))) => {
-                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
-                            }
-                            &(&None, &None) => None,
-                        }
-                    })
-                    .collect::<String>();
-                err.note(&format!("candidates:{}", candidates));
-                err.emit();
-                None
-            }
+            0 => Ok(None),
+            1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
+            _ => Err(CrateError::MultipleMatchingCrates(self.crate_name, libraries)),
         }
     }
 
@@ -658,16 +473,16 @@ impl<'a> CrateLocator<'a> {
         rlibs: FxHashMap<PathBuf, PathKind>,
         rmetas: FxHashMap<PathBuf, PathKind>,
         dylibs: FxHashMap<PathBuf, PathKind>,
-    ) -> Option<(Svh, Library)> {
+    ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first. See comment in
         // `extract_one` below.
         let source = CrateSource {
-            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
-            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
-            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
+            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
+            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
+            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
         };
-        slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
+        Ok(slot.map(|(svh, metadata)| (svh, Library { source, metadata })))
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
@@ -703,10 +518,7 @@ impl<'a> CrateLocator<'a> {
         m: FxHashMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob)>,
-    ) -> Option<(PathBuf, PathKind)> {
-        let mut ret: Option<(PathBuf, PathKind)> = None;
-        let mut error = 0;
-
+    ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
         // If we are producing an rlib, and we've already loaded metadata, then
         // we should not attempt to discover further crate sources (unless we're
         // locating a proc macro; exact logic is in needs_crate_flavor). This means
@@ -723,13 +535,14 @@ impl<'a> CrateLocator<'a> {
         // from the other crate sources.
         if slot.is_some() {
             if m.is_empty() || !self.needs_crate_flavor(flavor) {
-                return None;
+                return Ok(None);
             } else if m.len() == 1 {
-                return Some(m.into_iter().next().unwrap());
+                return Ok(Some(m.into_iter().next().unwrap()));
             }
         }
 
-        let mut err: Option<DiagnosticBuilder<'_>> = None;
+        let mut ret: Option<(PathBuf, PathKind)> = None;
+        let mut err_data: Option<Vec<PathBuf>> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
             let (hash, metadata) =
@@ -749,30 +562,18 @@ impl<'a> CrateLocator<'a> {
                 };
             // If we see multiple hashes, emit an error about duplicate candidates.
             if slot.as_ref().map_or(false, |s| s.0 != hash) {
-                let mut e = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0465,
-                    "multiple {} candidates for `{}` found",
-                    flavor,
-                    self.crate_name
-                );
-                e.span_note(
-                    self.span,
-                    &format!(r"candidate #1: {}", ret.as_ref().unwrap().0.display()),
-                );
-                if let Some(ref mut e) = err {
-                    e.emit();
+                if let Some(candidates) = err_data {
+                    return Err(CrateError::MultipleCandidates(
+                        self.crate_name,
+                        flavor,
+                        candidates,
+                    ));
                 }
-                err = Some(e);
-                error = 1;
+                err_data = Some(vec![ret.as_ref().unwrap().0.clone()]);
                 *slot = None;
             }
-            if error > 0 {
-                error += 1;
-                err.as_mut()
-                    .unwrap()
-                    .span_note(self.span, &format!(r"candidate #{}: {}", error, lib.display()));
+            if let Some(candidates) = &mut err_data {
+                candidates.push(lib);
                 continue;
             }
 
@@ -795,7 +596,7 @@ impl<'a> CrateLocator<'a> {
             // As a result, we favor the sysroot crate here. Note that the
             // candidates are all canonicalized, so we canonicalize the sysroot
             // as well.
-            if let Some((ref prev, _)) = ret {
+            if let Some((prev, _)) = &ret {
                 let sysroot = &self.sess.sysroot;
                 let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
@@ -806,11 +607,10 @@ impl<'a> CrateLocator<'a> {
             ret = Some((lib, kind));
         }
 
-        if error > 0 {
-            err.unwrap().emit();
-            None
+        if let Some(candidates) = err_data {
+            Err(CrateError::MultipleCandidates(self.crate_name, flavor, candidates))
         } else {
-            ret
+            Ok(ret)
         }
     }
 
@@ -865,57 +665,29 @@ impl<'a> CrateLocator<'a> {
         Some(hash)
     }
 
-    fn find_commandline_library(&mut self) -> Option<Library> {
+    fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
-        let sess = self.sess;
         let mut rlibs = FxHashMap::default();
         let mut rmetas = FxHashMap::default();
         let mut dylibs = FxHashMap::default();
-        {
-            let crate_name = self.crate_name;
-            let rejected_via_filename = &mut self.rejected_via_filename;
-            let dll_prefix = &self.target.options.dll_prefix;
-            let dll_suffix = &self.target.options.dll_suffix;
-            let locs = self.exact_paths.iter().filter(|loc| {
-                if !loc.exists() {
-                    sess.err(&format!(
-                        "extern location for {} does not exist: {}",
-                        crate_name,
-                        loc.display()
-                    ));
-                    return false;
-                }
-                let file = match loc.file_name().and_then(|s| s.to_str()) {
-                    Some(file) => file,
-                    None => {
-                        sess.err(&format!(
-                            "extern location for {} is not a file: {}",
-                            crate_name,
-                            loc.display()
-                        ));
-                        return false;
-                    }
-                };
-                if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
-                {
-                    return true;
-                } else {
-                    if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {
-                        return true;
-                    }
+        for loc in &self.exact_paths {
+            if !loc.exists() {
+                return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone()));
+            }
+            let file = match loc.file_name().and_then(|s| s.to_str()) {
+                Some(file) => file,
+                None => {
+                    return Err(CrateError::ExternLocationNotFile(self.crate_name, loc.clone()));
                 }
+            };
 
-                rejected_via_filename
-                    .push(CrateMismatch { path: (*loc).clone(), got: String::new() });
-
-                false
-            });
-
-            // Now that we have an iterator of good candidates, make sure
-            // there's at most one rlib and at most one dylib.
-            for loc in locs {
+            if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
+                || file.starts_with(&self.target.options.dll_prefix)
+                    && file.ends_with(&self.target.options.dll_suffix)
+            {
+                // Make sure there's at most one rlib and at most one dylib.
                 if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
                     rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
@@ -923,11 +695,29 @@ impl<'a> CrateLocator<'a> {
                 } else {
                     dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 }
+            } else {
+                self.rejected_via_filename
+                    .push(CrateMismatch { path: loc.clone(), got: String::new() });
             }
-        };
+        }
 
         // Extract the dylib/rlib/rmeta triple.
-        self.extract_lib(rlibs, rmetas, dylibs).map(|(_, lib)| lib)
+        Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
+    }
+
+    crate fn into_error(self) -> CrateError {
+        CrateError::LocatorCombined(CombinedLocatorError {
+            crate_name: self.crate_name,
+            root: self.root.cloned(),
+            triple: self.triple,
+            dll_prefix: self.target.options.dll_prefix.clone(),
+            dll_suffix: self.target.options.dll_suffix.clone(),
+            rejected_via_hash: self.rejected_via_hash,
+            rejected_via_triple: self.rejected_via_triple,
+            rejected_via_kind: self.rejected_via_kind,
+            rejected_via_version: self.rejected_via_version,
+            rejected_via_filename: self.rejected_via_filename,
+        })
     }
 }
 
@@ -1004,7 +794,18 @@ pub fn find_plugin_registrar(
     metadata_loader: &dyn MetadataLoader,
     span: Span,
     name: Symbol,
-) -> Option<(PathBuf, CrateDisambiguator)> {
+) -> (PathBuf, CrateDisambiguator) {
+    match find_plugin_registrar_impl(sess, metadata_loader, name) {
+        Ok(res) => res,
+        Err(err) => err.report(sess, span),
+    }
+}
+
+fn find_plugin_registrar_impl<'a>(
+    sess: &'a Session,
+    metadata_loader: &dyn MetadataLoader,
+    name: Symbol,
+) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
     info!("find plugin registrar `{}`", name);
     let mut locator = CrateLocator::new(
         sess,
@@ -1015,32 +816,16 @@ pub fn find_plugin_registrar(
         None, // extra_filename
         true, // is_host
         PathKind::Crate,
-        span,
         None, // root
         None, // is_proc_macro
     );
 
-    let library = match locator.maybe_load_library_crate() {
-        Some(library) => library,
-        None => locator.report_errs(),
-    };
-
-    match library.source.dylib {
-        Some(dylib) => Some((dylib.0, library.metadata.get_root().disambiguator())),
-        None => {
-            struct_span_err!(
-                sess,
-                span,
-                E0457,
-                "plugin `{}` only found in rlib format, but must be available \
-                        in dylib format",
-                name
-            )
-            .emit();
-            // No need to abort because the loading code will just ignore this
-            // empty dylib.
-            None
-        }
+    match locator.maybe_load_library_crate()? {
+        Some(library) => match library.source.dylib {
+            Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
+            None => Err(CrateError::NonDylibPlugin(name)),
+        },
+        None => Err(locator.into_error()),
     }
 }
 
@@ -1049,8 +834,8 @@ pub fn list_file_metadata(
     target: &Target,
     path: &Path,
     metadata_loader: &dyn MetadataLoader,
-    out: &mut dyn io::Write,
-) -> io::Result<()> {
+    out: &mut dyn Write,
+) -> IoResult<()> {
     let filename = path.file_name().unwrap().to_str().unwrap();
     let flavor = if filename.ends_with(".rlib") {
         CrateFlavor::Rlib
@@ -1064,3 +849,259 @@ pub fn list_file_metadata(
         Err(msg) => write!(out, "{}\n", msg),
     }
 }
+
+// ------------------------------------------ Error reporting -------------------------------------
+
+#[derive(Clone)]
+struct CrateMismatch {
+    path: PathBuf,
+    got: String,
+}
+
+/// Candidate rejection reasons collected during crate search.
+/// If no candidate is accepted, then these reasons are presented to the user,
+/// otherwise they are ignored.
+crate struct CombinedLocatorError {
+    crate_name: Symbol,
+    root: Option<CratePaths>,
+    triple: TargetTriple,
+    dll_prefix: String,
+    dll_suffix: String,
+    rejected_via_hash: Vec<CrateMismatch>,
+    rejected_via_triple: Vec<CrateMismatch>,
+    rejected_via_kind: Vec<CrateMismatch>,
+    rejected_via_version: Vec<CrateMismatch>,
+    rejected_via_filename: Vec<CrateMismatch>,
+}
+
+crate enum CrateError {
+    NonAsciiName(Symbol),
+    ExternLocationNotExist(Symbol, PathBuf),
+    ExternLocationNotFile(Symbol, PathBuf),
+    MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
+    MultipleMatchingCrates(Symbol, FxHashMap<Svh, Library>),
+    SymbolConflictsCurrent(Symbol),
+    SymbolConflictsOthers(Symbol),
+    DlOpen(String),
+    DlSym(String),
+    LocatorCombined(CombinedLocatorError),
+    NonDylibPlugin(Symbol),
+}
+
+impl CrateError {
+    crate fn report(self, sess: &Session, span: Span) -> ! {
+        let mut err = match self {
+            CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
+                span,
+                &format!("cannot load a crate with a non-ascii name `{}`", crate_name),
+            ),
+            CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} does not exist: {}", crate_name, loc.display()),
+            ),
+            CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} is not a file: {}", crate_name, loc.display()),
+            ),
+            CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0465,
+                    "multiple {} candidates for `{}` found",
+                    flavor,
+                    crate_name,
+                );
+                for (i, candidate) in candidates.iter().enumerate() {
+                    err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+                }
+                err
+            }
+            CrateError::MultipleMatchingCrates(crate_name, libraries) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0464,
+                    "multiple matching crates for `{}`",
+                    crate_name
+                );
+                let candidates = libraries
+                    .iter()
+                    .filter_map(|(_, lib)| {
+                        let crate_name = &lib.metadata.get_root().name().as_str();
+                        match (&lib.source.dylib, &lib.source.rlib) {
+                            (Some((pd, _)), Some((pr, _))) => Some(format!(
+                                "\ncrate `{}`: {}\n{:>padding$}",
+                                crate_name,
+                                pd.display(),
+                                pr.display(),
+                                padding = 8 + crate_name.len()
+                            )),
+                            (Some((p, _)), None) | (None, Some((p, _))) => {
+                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
+                            }
+                            (None, None) => None,
+                        }
+                    })
+                    .collect::<String>();
+                err.note(&format!("candidates:{}", candidates));
+                err
+            }
+            CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0519,
+                "the current crate is indistinguishable from one of its dependencies: it has the \
+                 same crate-name `{}` and was compiled with the same `-C metadata` arguments. \
+                 This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::SymbolConflictsOthers(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0523,
+                "found two different crates with name `{}` that are not distinguished by differing \
+                 `-C metadata`. This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s),
+            CrateError::LocatorCombined(locator) => {
+                let crate_name = locator.crate_name;
+                let add = match &locator.root {
+                    None => String::new(),
+                    Some(r) => format!(" which `{}` depends on", r.name),
+                };
+                let mut msg = "the following crate versions were found:".to_string();
+                let mut err = if !locator.rejected_via_hash.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0460,
+                        "found possibly newer version of crate `{}`{}",
+                        crate_name,
+                        add,
+                    );
+                    err.note("perhaps that crate needs to be recompiled?");
+                    let mismatches = locator.rejected_via_hash.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    if let Some(r) = locator.root {
+                        for path in r.source.paths() {
+                            msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
+                        }
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_triple.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0461,
+                        "couldn't find crate `{}` with expected target triple {}{}",
+                        crate_name,
+                        locator.triple,
+                        add,
+                    );
+                    let mismatches = locator.rejected_via_triple.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}`, target triple {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_kind.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0462,
+                        "found staticlib `{}` instead of rlib or dylib{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help("please recompile that crate using --crate-type lib");
+                    let mismatches = locator.rejected_via_kind.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_version.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0514,
+                        "found crate `{}` compiled by an incompatible version of rustc{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help(&format!(
+                        "please recompile that crate using this compiler ({})",
+                        rustc_version(),
+                    ));
+                    let mismatches = locator.rejected_via_version.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}` compiled by {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0463,
+                        "can't find crate for `{}`{}",
+                        crate_name,
+                        add,
+                    );
+
+                    if (crate_name == sym::std || crate_name == sym::core)
+                        && locator.triple != TargetTriple::from_triple(config::host_triple())
+                    {
+                        err.note(&format!("the `{}` target may not be installed", locator.triple));
+                    } else if crate_name == sym::profiler_builtins {
+                        err.note(&"the compiler may have been built without the profiler runtime");
+                    }
+                    err.span_label(span, "can't find crate");
+                    err
+                };
+
+                if !locator.rejected_via_filename.is_empty() {
+                    let mismatches = locator.rejected_via_filename.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        err.note(&format!(
+                            "extern location for {} is of an unknown type: {}",
+                            crate_name,
+                            path.display(),
+                        ))
+                        .help(&format!(
+                            "file name should be lib*.rlib or {}*.{}",
+                            locator.dll_prefix, locator.dll_suffix
+                        ));
+                    }
+                }
+                err
+            }
+            CrateError::NonDylibPlugin(crate_name) => struct_span_err!(
+                sess,
+                span,
+                E0457,
+                "plugin `{}` only found in rlib format, but must be available in dylib format",
+                crate_name,
+            ),
+        };
+
+        err.emit();
+        sess.abort_if_errors();
+        unreachable!();
+    }
+}
diff --git a/src/librustc_plugin_impl/load.rs b/src/librustc_plugin_impl/load.rs
index c3a60166968..62a87b47a2f 100644
--- a/src/librustc_plugin_impl/load.rs
+++ b/src/librustc_plugin_impl/load.rs
@@ -55,13 +55,11 @@ fn load_plugin(
     metadata_loader: &dyn MetadataLoader,
     ident: Ident,
 ) {
-    let registrar = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
-
-    if let Some((lib, disambiguator)) = registrar {
-        let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
-        let fun = dylink_registrar(sess, ident.span, lib, symbol);
-        plugins.push(fun);
-    }
+    let (lib, disambiguator) =
+        locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+    let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
+    let fun = dylink_registrar(sess, ident.span, lib, symbol);
+    plugins.push(fun);
 }
 
 // Dynamically link a registrar function into the compiler process.
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 575049c6bac..a7a005bdeb9 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -859,9 +859,7 @@ impl<'a> Resolver<'a> {
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                if let Some(crate_id) =
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)
-                {
+                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
                     let crate_root =
                         self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                     suggestions.extend(self.lookup_import_candidates_from_module(
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index 95888c38ba5..9323c15a941 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -760,10 +760,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                         if !module.no_implicit_prelude {
                             let extern_prelude = self.r.extern_prelude.clone();
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
-                                self.r
-                                    .crate_loader
-                                    .maybe_process_path_extern(ident.name, ident.span)
-                                    .and_then(|crate_id| {
+                                self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
+                                    |crate_id| {
                                         let crate_mod = Res::Def(
                                             DefKind::Mod,
                                             DefId { krate: crate_id, index: CRATE_DEF_INDEX },
@@ -774,7 +772,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
                                         } else {
                                             None
                                         }
-                                    })
+                                    },
+                                )
                             }));
 
                             if let Some(prelude) = self.r.prelude {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 686385e24ec..da39f79efcd 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2957,7 +2957,7 @@ impl<'a> Resolver<'a> {
                 let crate_id = if !speculative {
                     self.crate_loader.process_path_extern(ident.name, ident.span)
                 } else {
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)?
+                    self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                 Some(
diff --git a/src/test/compile-fail/empty-extern-arg.rs b/src/test/compile-fail/empty-extern-arg.rs
index ae28fcad903..d3cb5aaaeba 100644
--- a/src/test/compile-fail/empty-extern-arg.rs
+++ b/src/test/compile-fail/empty-extern-arg.rs
@@ -1,4 +1,4 @@
 // compile-flags: --extern std=
-// error-pattern: can't find crate for `std`
+// error-pattern: extern location for std does not exist
 
 fn main() {}
diff --git a/src/test/ui-fulldeps/macro-crate-rlib.rs b/src/test/ui-fulldeps/macro-crate-rlib.rs
index b5038a58249..1fd514c6173 100644
--- a/src/test/ui-fulldeps/macro-crate-rlib.rs
+++ b/src/test/ui-fulldeps/macro-crate-rlib.rs
@@ -1,10 +1,8 @@
 // aux-build:rlib-crate-test.rs
-// ignore-tidy-linelength
 // ignore-cross-compile gives a different error message
 
 #![feature(plugin)]
 #![plugin(rlib_crate_test)]
-//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
-//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated
+//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib
 
 fn main() {}
diff --git a/src/test/ui-fulldeps/macro-crate-rlib.stderr b/src/test/ui-fulldeps/macro-crate-rlib.stderr
index 342663312a8..7b31f28a26e 100644
--- a/src/test/ui-fulldeps/macro-crate-rlib.stderr
+++ b/src/test/ui-fulldeps/macro-crate-rlib.stderr
@@ -1,16 +1,8 @@
 error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
-  --> $DIR/macro-crate-rlib.rs:6:11
+  --> $DIR/macro-crate-rlib.rs:5:11
    |
 LL | #![plugin(rlib_crate_test)]
    |           ^^^^^^^^^^^^^^^
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/macro-crate-rlib.rs:6:1
-   |
-LL | #![plugin(rlib_crate_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
diff --git a/src/test/ui/extern/extern-prelude-no-speculative.rs b/src/test/ui/extern/extern-prelude-no-speculative.rs
index cc00737ab59..3ba124159e0 100644
--- a/src/test/ui/extern/extern-prelude-no-speculative.rs
+++ b/src/test/ui/extern/extern-prelude-no-speculative.rs
@@ -1,6 +1,6 @@
 // run-pass
 #![allow(unused_variables)]
-// compile-flags: --extern LooksLikeExternCrate
+// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere
 
 mod m {
     pub struct LooksLikeExternCrate;
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
index 3fb1cf9f557..310545b92d5 100644
--- a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
+++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
@@ -1,6 +1,5 @@
 #![feature(non_ascii_idents)]
 
 extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг`
-//~| ERROR can't find crate for `ьаг`
 
 fn main() {}
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
index 1e424237fd2..11108f2fb86 100644
--- a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
+++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `ьаг`
 LL | extern crate ьаг;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0463]: can't find crate for `ьаг`
-  --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
-   |
-LL | extern crate ьаг;
-   | ^^^^^^^^^^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
index e1acdbff061..0249848b35a 100644
--- a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
+++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
@@ -3,7 +3,5 @@
 #![feature(non_ascii_idents)]
 
 use му_сгате::baz; //~  ERROR cannot load a crate with a non-ascii name `му_сгате`
-                   //~| can't find crate for `му_сгате`
-
 
 fn main() {}
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
index c06405ebb37..8d3548ed33d 100644
--- a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
+++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `му_сгате`
 LL | use му_сгате::baz;
    |     ^^^^^^^^
 
-error[E0463]: can't find crate for `му_сгате`
-  --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
-   |
-LL | use му_сгате::baz;
-   |     ^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.