From c560fc87353a44d341f951f156564c3a50119a17 Mon Sep 17 00:00:00 2001 From: Rust timing bot Date: Tue, 21 Jul 2020 12:15:11 -0400 Subject: [PATCH] rust-timer simulated merge of 43ba8409d7c7f93d6f0b3c22fe1b193788ff6162 Original message: Rollup merge of #74071 - petrochenkov:cload3, r=matthewjasper rustc_metadata: Make crate loading fully speculative Instead of reporting `span_err`s on the spot crate loading errors are now wrapped into the `CrateError` enum and returned, so they are reported only at the top level `resolve_crate` call, and not reported at all if we are resolving speculatively with `maybe_resolve_crate`. As a result we can attempt loading crates for error recovery (e.g. import suggestions) without any risk of producing extra errors. Also, this means better separation between error reporting and actual logic. Fixes https://github.com/rust-lang/rust/issues/55103 Fixes https://github.com/rust-lang/rust/issues/56590 --- src/libcore/task/mod.rs | 4 + src/libcore/task/ready.rs | 60 ++ src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_metadata/creader.rs | 183 ++--- src/librustc_metadata/locator.rs | 754 +++++++++--------- src/librustc_plugin_impl/load.rs | 12 +- src/librustc_resolve/diagnostics.rs | 4 +- src/librustc_resolve/late/diagnostics.rs | 9 +- src/librustc_resolve/lib.rs | 2 +- src/libstd/ffi/c_str.rs | 38 + src/libstd/keyword_docs.rs | 183 ++++- src/libstd/lib.rs | 1 + src/test/compile-fail/empty-extern-arg.rs | 2 +- src/test/ui-fulldeps/macro-crate-rlib.rs | 4 +- src/test/ui-fulldeps/macro-crate-rlib.stderr | 12 +- .../extern/extern-prelude-no-speculative.rs | 2 +- .../crate_name_nonascii_forbidden-1.rs | 1 - .../crate_name_nonascii_forbidden-1.stderr | 9 +- .../crate_name_nonascii_forbidden-2.rs | 2 - .../crate_name_nonascii_forbidden-2.stderr | 9 +- src/tools/tidy/src/error_codes_check.rs | 10 +- 21 files changed, 757 insertions(+), 546 deletions(-) create mode 100644 src/libcore/task/ready.rs diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 27760749c1d4b..3d6f4f5971a62 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -9,3 +9,7 @@ pub use self::poll::Poll; mod wake; #[stable(feature = "futures_api", since = "1.36.0")] pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; + +mod ready; +#[unstable(feature = "ready_macro", issue = "70922")] +pub use ready::ready; diff --git a/src/libcore/task/ready.rs b/src/libcore/task/ready.rs new file mode 100644 index 0000000000000..d4e733eb2bcf5 --- /dev/null +++ b/src/libcore/task/ready.rs @@ -0,0 +1,60 @@ +/// Extracts the successful type of a `Poll`. +/// +/// This macro bakes in propagation of `Pending` signals by returning early. +/// +/// # Examples +/// +/// ``` +/// #![feature(future_readiness_fns)] +/// #![feature(ready_macro)] +/// +/// use core::task::{ready, Context, Poll}; +/// use core::future::{self, Future}; +/// use core::pin::Pin; +/// +/// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { +/// let mut fut = future::ready(42); +/// let fut = Pin::new(&mut fut); +/// +/// let num = ready!(fut.poll(cx)); +/// # drop(num); +/// // ... use num +/// +/// Poll::Ready(()) +/// } +/// ``` +/// +/// The `ready!` call expands to: +/// +/// ``` +/// # #![feature(future_readiness_fns)] +/// # #![feature(ready_macro)] +/// # +/// # use core::task::{Context, Poll}; +/// # use core::future::{self, Future}; +/// # use core::pin::Pin; +/// # +/// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { +/// # let mut fut = future::ready(42); +/// # let fut = Pin::new(&mut fut); +/// # +/// let num = match fut.poll(cx) { +/// Poll::Ready(t) => t, +/// Poll::Pending => return Poll::Pending, +/// }; +/// # drop(num); +/// # // ... use num +/// # +/// # Poll::Ready(()) +/// # } +/// ``` +#[unstable(feature = "ready_macro", issue = "70922")] +#[rustc_macro_transparency = "semitransparent"] +pub macro ready($e:expr) { + match $e { + $crate::task::Poll::Ready(t) => t, + $crate::task::Poll::Pending => { + return $crate::task::Poll::Pending; + } + } +} diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 6160450d76676..bbbd8359f0126 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -554,7 +554,7 @@ E0770: include_str!("./error_codes/E0770.md"), // E0420, merged into 532 // E0421, merged into 531 // E0427, merged into 530 - E0456, // plugin `..` is not available for triple `..` +// E0456, // plugin `..` is not available for triple `..` E0457, // plugin `..` only found in rlib format, but must be available... E0460, // found possibly newer version of crate `..` E0461, // couldn't find crate `..` with expected target triple .. diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 0563894e6348d..0d2101cb2cb08 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, root: Option<&CratePaths>, - span: Span, lib: Library, dep_kind: DepKind, name: Symbol, - ) -> CrateNum { + ) -> Result { 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)> + ) -> Result)>, 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> { + ) -> Result { 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 { - let library = locator.maybe_load_library_crate()?; + fn load(&self, locator: &mut CrateLocator<'_>) -> Result, 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 { 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 { - self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok() + pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { + self.maybe_resolve_crate(name, DepKind::Explicit, None).ok() } } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 1bdac1039b55a..371ec4cd91148 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,25 +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 std::time::Instant; - 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> { @@ -263,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, @@ -275,6 +262,7 @@ crate struct CrateLocator<'a> { rejected_via_filename: Vec, } +#[derive(Clone)] crate struct CratePaths { name: Symbol, source: CrateSource, @@ -287,7 +275,7 @@ impl CratePaths { } #[derive(Copy, Clone, PartialEq)] -enum CrateFlavor { +crate enum CrateFlavor { Rlib, Rmeta, Dylib, @@ -313,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, ) -> CrateLocator<'a> { @@ -349,7 +336,6 @@ impl<'a> CrateLocator<'a> { } else { sess.target_filesearch(path_kind) }, - span, root, is_proc_macro, rejected_via_hash: Vec::new(), @@ -368,166 +354,30 @@ impl<'a> CrateLocator<'a> { self.rejected_via_filename.clear(); } - crate fn maybe_load_library_crate(&mut self) -> Option { + crate fn maybe_load_library_crate(&mut self) -> Result, 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 dylibname = self.dylibname(); - 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 {}*.{}", - dylibname.0, dylibname.1 - )); + 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, - ) -> Option { - let dypair = self.dylibname(); - let staticpair = self.staticlibname(); - + ) -> Result, CrateError> { // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" - let dylib_prefix = format!("{}{}{}", dypair.0, self.crate_name, extra_prefix); + let dylib_prefix = + format!("{}{}{}", self.target.options.dll_prefix, self.crate_name, extra_prefix); let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix); - let staticlib_prefix = format!("{}{}{}", staticpair.0, self.crate_name, extra_prefix); + let staticlib_prefix = + format!("{}{}{}", self.target.options.staticlib_prefix, self.crate_name, extra_prefix); let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> = Default::default(); @@ -555,10 +405,18 @@ impl<'a> CrateLocator<'a> { (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") { (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) - } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) { - (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) + } else if file.starts_with(&dylib_prefix) + && file.ends_with(&self.target.options.dll_suffix) + { + ( + &file + [(dylib_prefix.len())..(file.len() - self.target.options.dll_suffix.len())], + CrateFlavor::Dylib, + ) } else { - if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) { + if file.starts_with(&staticlib_prefix) + && file.ends_with(&self.target.options.staticlib_suffix) + { staticlibs .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() }); } @@ -567,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) { @@ -577,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) @@ -603,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); } } @@ -612,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::(); - 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)), } } @@ -653,16 +473,16 @@ impl<'a> CrateLocator<'a> { rlibs: FxHashMap, rmetas: FxHashMap, dylibs: FxHashMap, - ) -> Option<(Svh, Library)> { + ) -> Result, 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 { @@ -698,10 +518,7 @@ impl<'a> CrateLocator<'a> { m: FxHashMap, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob)>, - ) -> Option<(PathBuf, PathKind)> { - let mut ret: Option<(PathBuf, PathKind)> = None; - let mut error = 0; - + ) -> Result, 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 @@ -718,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> = None; + let mut ret: Option<(PathBuf, PathKind)> = None; + let mut err_data: Option> = None; for (lib, kind) in m { info!("{} reading metadata from: {}", flavor, lib.display()); let (hash, metadata) = @@ -744,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; } @@ -790,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) { @@ -801,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) } } @@ -860,71 +665,29 @@ impl<'a> CrateLocator<'a> { Some(hash) } - // Returns the corresponding (prefix, suffix) that files need to have for - // dynamic libraries - fn dylibname(&self) -> (String, String) { - let t = &self.target; - (t.options.dll_prefix.clone(), t.options.dll_suffix.clone()) - } - - // Returns the corresponding (prefix, suffix) that files need to have for - // static libraries - fn staticlibname(&self) -> (String, String) { - let t = &self.target; - (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone()) - } - - fn find_commandline_library(&mut self) -> Option { + fn find_commandline_library(&mut self) -> Result, 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 dylibname = self.dylibname(); 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 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 { - let (ref prefix, ref suffix) = dylibname; - if file.starts_with(&prefix[..]) && file.ends_with(&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") { @@ -932,25 +695,30 @@ 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)) } -} -// Just a small wrapper to time how long reading metadata takes. -fn get_metadata_section( - target: &Target, - flavor: CrateFlavor, - filename: &Path, - loader: &dyn MetadataLoader, -) -> Result { - let start = Instant::now(); - let ret = get_metadata_section_imp(target, flavor, filename, loader); - info!("reading {:?} => {:?}", filename.file_name().unwrap(), start.elapsed()); - ret + 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, + }) + } } /// A trivial wrapper for `Mmap` that implements `StableDeref`. @@ -966,7 +734,7 @@ impl Deref for StableDerefMmap { unsafe impl stable_deref_trait::StableDeref for StableDerefMmap {} -fn get_metadata_section_imp( +fn get_metadata_section( target: &Target, flavor: CrateFlavor, filename: &Path, @@ -1026,12 +794,19 @@ 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 target_triple = sess.opts.target_triple.clone(); - let host_triple = TargetTriple::from_triple(config::host_triple()); - let is_cross = target_triple != host_triple; - let mut target_only = false; let mut locator = CrateLocator::new( sess, metadata_loader, @@ -1041,57 +816,16 @@ pub fn find_plugin_registrar( None, // extra_filename true, // is_host PathKind::Crate, - span, None, // root None, // is_proc_macro ); - let library = locator.maybe_load_library_crate().or_else(|| { - if !is_cross { - return None; - } - // Try loading from target crates. This will abort later if we - // try to load a plugin registrar function, - target_only = true; - - locator.target = &sess.target.target; - locator.triple = target_triple; - locator.filesearch = sess.target_filesearch(PathKind::Crate); - - locator.maybe_load_library_crate() - }); - let library = match library { - Some(l) => l, - None => locator.report_errs(), - }; - - if target_only { - let message = format!( - "plugin `{}` is not available for triple `{}` (only found {})", - name, - config::host_triple(), - sess.opts.target_triple - ); - struct_span_err!(sess, span, E0456, "{}", &message).emit(); - return None; - } - - 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()), } } @@ -1100,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 @@ -1115,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, + triple: TargetTriple, + dll_prefix: String, + dll_suffix: String, + rejected_via_hash: Vec, + rejected_via_triple: Vec, + rejected_via_kind: Vec, + rejected_via_version: Vec, + rejected_via_filename: Vec, +} + +crate enum CrateError { + NonAsciiName(Symbol), + ExternLocationNotExist(Symbol, PathBuf), + ExternLocationNotFile(Symbol, PathBuf), + MultipleCandidates(Symbol, CrateFlavor, Vec), + MultipleMatchingCrates(Symbol, FxHashMap), + 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::(); + 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 c3a6016696888..62a87b47a2f74 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 575049c6bac2f..a7a005bdeb9f2 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 95888c38ba5e1..9323c15a94109 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 686385e24ece8..da39f79efcd3b 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/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index dca1fdde48242..da25a0ede729d 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1551,6 +1551,27 @@ impl ops::Index for CString { } } +#[stable(feature = "cstr_range_from", since = "1.47.0")] +impl ops::Index> for CStr { + type Output = CStr; + + fn index(&self, index: ops::RangeFrom) -> &CStr { + let bytes = self.to_bytes_with_nul(); + // we need to manually check the starting index to account for the null + // byte, since otherwise we could get an empty string that doesn't end + // in a null. + if index.start < bytes.len() { + unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) } + } else { + panic!( + "index out of bounds: the len is {} but the index is {}", + bytes.len(), + index.start + ); + } + } +} + #[stable(feature = "cstring_asref", since = "1.7.0")] impl AsRef for CStr { #[inline] @@ -1747,4 +1768,21 @@ mod tests { assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); } + + #[test] + fn cstr_index_from() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); + + assert_eq!(&cstr[7..], result); + } + + #[test] + #[should_panic] + fn cstr_index_from_empty() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let _ = &cstr[original.len()..]; + } } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a53e7f5cf57aa..d985f10ccb486 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1497,11 +1497,188 @@ mod super_keyword {} #[doc(keyword = "trait")] // -/// A common interface for a class of types. +/// A common interface for a group of types. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `trait` is like an interface that data types can implement. When a type +/// implements a trait it can be treated abstractly as that trait using generics +/// or trait objects. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// Traits can be made up of three varieties of associated items: +/// +/// - functions and methods +/// - types +/// - constants +/// +/// Traits may also contain additional type parameters. Those type parameters +/// or the trait itself can be constrained by other traits. +/// +/// Traits can serve as markers or carry other logical semantics that +/// aren't expressed through their items. When a type implements that +/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two +/// such marker traits present in the standard library. +/// +/// See the [Reference][Ref-Traits] for a lot more information on traits. +/// +/// # Examples +/// +/// Traits are declared using the `trait` keyword. Types can implement them +/// using [`impl`] `Trait` [`for`] `Type`: +/// +/// ```rust +/// trait Zero { +/// const ZERO: Self; +/// fn is_zero(&self) -> bool; +/// } +/// +/// impl Zero for i32 { +/// const ZERO: Self = 0; +/// +/// fn is_zero(&self) -> bool { +/// *self == Self::ZERO +/// } +/// } +/// +/// assert_eq!(i32::ZERO, 0); +/// assert!(i32::ZERO.is_zero()); +/// assert!(!4.is_zero()); +/// ``` +/// +/// With an associated type: +/// +/// ```rust +/// trait Builder { +/// type Built; +/// +/// fn build(&self) -> Self::Built; +/// } +/// ``` +/// +/// Traits can be generic, with constraints or without: +/// +/// ```rust +/// trait MaybeFrom { +/// fn maybe_from(value: T) -> Option +/// where +/// Self: Sized; +/// } +/// ``` +/// +/// Traits can build upon the requirements of other traits. In the example +/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**: +/// +/// ```rust +/// trait ThreeIterator: std::iter::Iterator { +/// fn next_three(&mut self) -> Option<[Self::Item; 3]>; +/// } +/// ``` +/// +/// Traits can be used in functions, as parameters: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn debug_iter(it: I) where I::Item: std::fmt::Debug { +/// for elem in it { +/// println!("{:#?}", elem); +/// } +/// } +/// +/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent +/// +/// fn u8_len_1(val: impl Into>) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_2>>(val: T) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_3(val: T) -> usize +/// where +/// T: Into>, +/// { +/// val.into().len() +/// } +/// ``` +/// +/// Or as return types: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn from_zero_to(v: u8) -> impl Iterator { +/// (0..v).into_iter() +/// } +/// ``` +/// +/// The use of the [`impl`] keyword in this position allows the function writer +/// to hide the concrete type as an implementation detail which can change +/// without breaking user's code. +/// +/// # Trait objects +/// +/// A *trait object* is an opaque value of another type that implements a set of +/// traits. A trait object implements all specified traits as well as their +/// supertraits (if any). +/// +/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`. +/// Only one `BaseTrait` can be used so this will not compile: +/// +/// ```rust,compile_fail,E0225 +/// trait A {} +/// trait B {} +/// +/// let _: Box; +/// ``` +/// +/// Neither will this, which is a syntax error: +/// +/// ```rust,compile_fail +/// trait A {} +/// trait B {} +/// +/// let _: Box; +/// ``` +/// +/// On the other hand, this is correct: +/// +/// ```rust +/// trait A {} +/// +/// let _: Box; +/// ``` +/// +/// The [Reference][Ref-Trait-Objects] has more information about trait objects, +/// their limitations and the differences between editions. +/// +/// # Unsafe traits +/// +/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in +/// front of the trait's declaration is used to mark this: +/// +/// ```rust +/// unsafe trait UnsafeTrait {} +/// +/// unsafe impl UnsafeTrait for i32 {} +/// ``` +/// +/// # Differences between the 2015 and 2018 editions +/// +/// In the 2015 edition parameters pattern where not needed for traits: +/// +/// ```rust,edition2015 +/// trait Tr { +/// fn f(i32); +/// } +/// ``` +/// +/// This behavior is no longer valid in edition 2018. +/// +/// [`for`]: keyword.for.html +/// [`impl`]: keyword.impl.html +/// [`unsafe`]: keyword.unsafe.html +/// [`Send`]: marker/trait.Send.html +/// [`Sync`]: marker/trait.Sync.html +/// [Ref-Traits]: ../reference/items/traits.html +/// [Ref-Trait-Objects]: ../reference/types/trait-object.html mod trait_keyword {} #[doc(keyword = "true")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0397153098cb3..11b8f953be460 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -305,6 +305,7 @@ #![feature(ptr_internals)] #![feature(raw)] #![feature(raw_ref_macros)] +#![feature(ready_macro)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] diff --git a/src/test/compile-fail/empty-extern-arg.rs b/src/test/compile-fail/empty-extern-arg.rs index ae28fcad903be..d3cb5aaaeba89 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 b5038a58249d2..1fd514c617329 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 342663312a853..7b31f28a26e7d 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 cc00737ab591d..3ba124159e000 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 3fb1cf9f557b2..310545b92d549 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 1e424237fd238..11108f2fb8678 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 e1acdbff06189..0249848b35ac0 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 c06405ebb37ec..8d3548ed33dcf 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`. diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 3af71f69d2457..51f135d376161 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -8,11 +8,11 @@ use std::path::Path; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ - "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0456", - "E0461", "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", - "E0480", "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", - "E0514", "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", - "E0727", "E0729", + "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461", + "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", + "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", + "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727", + "E0729", ]; // Some error codes don't have any tests apparently...