From ba6857d801b6217a190e92e43cacd8468ff2d72a Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 26 Jun 2020 14:28:11 +0200 Subject: [PATCH 01/15] Document the trait keyword --- src/libstd/keyword_docs.rs | 175 ++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 3 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index f987eb67ea5f2..7bedb6fd6238b 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1353,11 +1353,180 @@ 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 an interface that types can implement. It is said they +/// "implement" the trait or "conform" to the trait. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// This interface is made up of three varieties of items: +/// +/// - functions +/// - types +/// - constants +/// +/// Traits may also contain additional type parameters. Those type parameters +/// or the trait itself can be constrained by other traits. +/// +/// 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 +/// [Ref-Traits]: ../reference/items/traits.html +/// [Ref-Trait-Objects]: ../reference/types/trait-object.html mod trait_keyword {} #[doc(keyword = "true")] From 18be370342c9b2a93f1d56b2b674bd2fbdcbb019 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 5 Apr 2020 17:50:45 +0200 Subject: [PATCH 02/15] Add core::ready! macro --- src/libcore/task/mod.rs | 4 +++ src/libcore/task/ready.rs | 60 +++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 3 files changed, 65 insertions(+) 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/libstd/lib.rs b/src/libstd/lib.rs index bd585d39c242f..939db4bb12e56 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -299,6 +299,7 @@ #![feature(ptr_internals)] #![feature(raw)] #![feature(raw_ref_macros)] +#![feature(ready_macro)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] From 8a2f147b5b9756e67dc2299777b8b534bbd73d0b Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Thu, 16 Jul 2020 23:58:57 +0200 Subject: [PATCH 03/15] Fix small nits, clarfying some confusing vocabulary and using more consistent wording --- src/libstd/keyword_docs.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 7bedb6fd6238b..19f3503bb842f 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1355,18 +1355,24 @@ mod super_keyword {} // /// A common interface for a group of types. /// -/// A `trait` is an interface that types can implement. It is said they -/// "implement" the trait or "conform" to the trait. +/// 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. /// -/// This interface is made up of three varieties of items: +/// Traits can be made up of three varieties of associated items: /// -/// - functions +/// - 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 @@ -1525,6 +1531,8 @@ mod super_keyword {} /// [`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 {} From 0bac36105e24a1abef87644c3bcd1b3d92169b5d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 13:03:20 +0200 Subject: [PATCH 04/15] add test for #62878 --- .../ui/const-generics/issues/issue-62878.rs | 11 ++++++ .../const-generics/issues/issue-62878.stderr | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-62878.rs create mode 100644 src/test/ui/const-generics/issues/issue-62878.stderr diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs new file mode 100644 index 0000000000000..ccc05fdf100e7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +fn foo() {} +//~^ ERROR the type of const parameters must not + +fn main() { + foo::<_, {[1]}>(); + //~^ ERROR wrong number of const arguments + //~| ERROR wrong number of type arguments + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr new file mode 100644 index 0000000000000..fe0990d8241fa --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.stderr @@ -0,0 +1,37 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:3:38 + | +LL | fn foo() {} + | ^ the type must not depend on the parameter `N` + +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-62878.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0107]: wrong number of const arguments: expected 2, found 1 + --> $DIR/issue-62878.rs:7:5 + | +LL | foo::<_, {[1]}>(); + | ^^^^^^^^^^^^^^^ expected 2 const arguments + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/issue-62878.rs:7:11 + | +LL | foo::<_, {[1]}>(); + | ^ unexpected type argument + +error[E0308]: mismatched types + --> $DIR/issue-62878.rs:7:15 + | +LL | foo::<_, {[1]}>(); + | ^^^ expected `usize`, found array `[{integer}; 1]` + +error: aborting due to 4 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0107, E0308, E0770. +For more information about an error, try `rustc --explain E0107`. From 4fefa2c75d43dcf1184c7a7116cbd9595a8e49ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 21:57:13 +0200 Subject: [PATCH 05/15] Make unreachable_unchecked a const fn --- src/libcore/hint.rs | 3 ++- src/libcore/intrinsics.rs | 1 + src/libcore/lib.rs | 1 + src/librustc_mir/interpret/intrinsics.rs | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 9ebcde79b633d..3116815f5d655 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -45,7 +45,8 @@ use crate::intrinsics; /// ``` #[inline] #[stable(feature = "unreachable", since = "1.27.0")] -pub unsafe fn unreachable_unchecked() -> ! { +#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] +pub const unsafe fn unreachable_unchecked() -> ! { // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. unsafe { intrinsics::unreachable() } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 080760aa81f30..8f0cf4361e708 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -932,6 +932,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). + #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 96436bb253df0..a8c9b8f257700 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(const_slice_ptr_len)] #![feature(const_type_name)] #![feature(const_likely)] +#![feature(const_unreachable_unchecked)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 851862640226f..5836fc9c95a80 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -95,6 +95,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (dest, ret) = match ret { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), + sym::unreachable => throw_ub!(Unreachable), sym::abort => M::abort(self)?, // Unsupported diverging intrinsic. _ => return Ok(false), From 2f28d5945dab495a77c67c6051eea116ce9ceee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 21:59:37 +0200 Subject: [PATCH 06/15] Add a passing test for const unsafe_unreachable --- src/test/ui/consts/const_unsafe_unreachable.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/ui/consts/const_unsafe_unreachable.rs diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs new file mode 100644 index 0000000000000..cfed6e5deb999 --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable.rs @@ -0,0 +1,17 @@ +// run-pass + +#![feature(const_fn)] +#![feature(const_unreachable_unchecked)] + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(true) }; + +fn main() { + assert_eq!(BAR, true); +} From c45e9c86ca5e1aa20ec8ec9904c4ad9a33a072e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Fri, 17 Jul 2020 22:03:33 +0200 Subject: [PATCH 07/15] Add a test for const unsafe_unreachable that triggers UB --- .../ui/consts/const_unsafe_unreachable_ub.rs | 15 ++++++++++++++ .../consts/const_unsafe_unreachable_ub.stderr | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/ui/consts/const_unsafe_unreachable_ub.rs create mode 100644 src/test/ui/consts/const_unsafe_unreachable_ub.stderr diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs new file mode 100644 index 0000000000000..2e4dfd1522b9a --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs @@ -0,0 +1,15 @@ +#![feature(const_fn)] +#![feature(const_unreachable_unchecked)] + +const unsafe fn foo(x: bool) -> bool { + match x { + true => true, + false => std::hint::unreachable_unchecked(), + } +} + +const BAR: bool = unsafe { foo(false) }; + +fn main() { + assert_eq!(BAR, true); +} diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr new file mode 100644 index 0000000000000..0a7aa4e00214f --- /dev/null +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -0,0 +1,20 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/hint.rs:LL:COL + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | entering unreachable code + | inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL + | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:7:18 + | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:11:28 + | + ::: $DIR/const_unsafe_unreachable_ub.rs:11:1 + | +LL | const BAR: bool = unsafe { foo(false) }; + | ---------------------------------------- + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + From 6cd164f49e6f9c2b914fa5d55755d78e3fabbc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 18 Jul 2020 02:27:41 +0200 Subject: [PATCH 08/15] Update UB test to fail during build with contant errors --- .../ui/consts/const_unsafe_unreachable_ub.rs | 5 +++ .../consts/const_unsafe_unreachable_ub.stderr | 34 ++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs index 2e4dfd1522b9a..11920d852e02f 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.rs +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs @@ -1,3 +1,5 @@ +// build-fail + #![feature(const_fn)] #![feature(const_unreachable_unchecked)] @@ -8,8 +10,11 @@ const unsafe fn foo(x: bool) -> bool { } } +#[warn(const_err)] const BAR: bool = unsafe { foo(false) }; fn main() { assert_eq!(BAR, true); + //~^ ERROR E0080 + //~| ERROR erroneous constant } diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr index 0a7aa4e00214f..3ef8043a54d88 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +warning: any use of this value will cause an error --> $SRC_DIR/libcore/hint.rs:LL:COL | LL | unsafe { intrinsics::unreachable() } @@ -6,15 +6,39 @@ LL | unsafe { intrinsics::unreachable() } | | | entering unreachable code | inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL - | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:7:18 - | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:11:28 + | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18 + | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28 | - ::: $DIR/const_unsafe_unreachable_ub.rs:11:1 + ::: $DIR/const_unsafe_unreachable_ub.rs:14:1 | LL | const BAR: bool = unsafe { foo(false) }; | ---------------------------------------- | +note: the lint level is defined here + --> $DIR/const_unsafe_unreachable_ub.rs:13:8 + | +LL | #[warn(const_err)] + | ^^^^^^^^^ + +error[E0080]: evaluation of constant expression failed + --> $DIR/const_unsafe_unreachable_ub.rs:17:3 + | +LL | assert_eq!(BAR, true); + | ^^^^^^^^^^^---^^^^^^^^ + | | + | referenced constant has errors + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: erroneous constant used + --> $DIR/const_unsafe_unreachable_ub.rs:17:3 + | +LL | assert_eq!(BAR, true); + | ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0080`. From de03a12675fe923a02589ce05afec8682194bfef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 4 Jul 2020 19:01:21 +0300 Subject: [PATCH 09/15] rustc_metadata: Remove a bit of ancient profiling --- src/librustc_metadata/locator.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 1bdac1039b55a..54ab849bf1a42 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -234,7 +234,6 @@ 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; @@ -940,19 +939,6 @@ impl<'a> CrateLocator<'a> { } } -// 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 -} - /// A trivial wrapper for `Mmap` that implements `StableDeref`. struct StableDerefMmap(memmap::Mmap); @@ -966,7 +952,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, From 926ac5a2fd6cd4a0994b0c7cff5a43040c9c0e4c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 4 Jul 2020 20:47:06 +0300 Subject: [PATCH 10/15] rustc_metadata: Remove some extra diagnostics for legacy plugins They are deprecated so doing extra work for error recovery doesn't make sense --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_metadata/locator.rs | 33 ++----------------------- src/tools/tidy/src/error_codes_check.rs | 10 ++++---- 3 files changed, 8 insertions(+), 37 deletions(-) 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/locator.rs b/src/librustc_metadata/locator.rs index 54ab849bf1a42..dfdedc9f27538 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -1014,10 +1014,6 @@ pub fn find_plugin_registrar( name: Symbol, ) -> Option<(PathBuf, CrateDisambiguator)> { 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, @@ -1032,36 +1028,11 @@ pub fn find_plugin_registrar( 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, + let library = match locator.maybe_load_library_crate() { + Some(library) => library, 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 => { 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... From 4044cbc559be2c00a4718a086c3443d429032446 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 4 Jul 2020 21:38:56 +0300 Subject: [PATCH 11/15] rustc_metadata: Refactor away `CrateLocator::(dy,static)libname` --- src/librustc_metadata/locator.rs | 46 +++++++++++++------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index dfdedc9f27538..ecb2548c7469f 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -495,7 +495,6 @@ impl<'a> CrateLocator<'a> { }; 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!( @@ -505,7 +504,7 @@ impl<'a> CrateLocator<'a> { )) .help(&format!( "file name should be lib*.rlib or {}*.{}", - dylibname.0, dylibname.1 + self.target.options.dll_prefix, self.target.options.dll_suffix )); } } @@ -520,13 +519,12 @@ impl<'a> CrateLocator<'a> { extra_prefix: &str, seen_paths: &mut FxHashSet, ) -> Option { - let dypair = self.dylibname(); - let staticpair = self.staticlibname(); - // 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(); @@ -554,10 +552,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() }); } @@ -859,32 +865,19 @@ 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 { // 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 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!( @@ -909,8 +902,7 @@ impl<'a> CrateLocator<'a> { { return true; } else { - let (ref prefix, ref suffix) = dylibname; - if file.starts_with(&prefix[..]) && file.ends_with(&suffix[..]) { + if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { return true; } } From 0a4217d09f41d64f8be076c26d16d3474ca66c03 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 5 Jul 2020 10:39:15 +0300 Subject: [PATCH 12/15] rustc_metadata: Make crate loading fully speculative --- src/librustc_metadata/creader.rs | 183 ++--- src/librustc_metadata/locator.rs | 673 ++++++++++-------- 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/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 +- 14 files changed, 453 insertions(+), 471 deletions(-) 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 ecb2548c7469f..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,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, @@ -274,6 +262,7 @@ crate struct CrateLocator<'a> { rejected_via_filename: Vec, } +#[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, ) -> 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 { + 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 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, - ) -> Option { + ) -> Result, 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::(); - 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, 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 { @@ -703,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 @@ -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> = 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) = @@ -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 { + 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 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, + 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/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`. From 09240a4b4b92f8e4a7f662e052ef1ddffa2eeaac Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 18 Jul 2020 16:59:16 +0200 Subject: [PATCH 13/15] Revert "Use an UTF-8 locale for the linker." --- src/librustc_codegen_ssa/back/linker.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 6f40aac83eb9c..e64aafa599fd8 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -28,9 +28,7 @@ use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; pub fn disable_localization(linker: &mut Command) { // No harm in setting both env vars simultaneously. // Unix-style linkers. - // We use an UTF-8 locale, as the generic C locale disables support for non-ASCII - // bytes in filenames on some platforms. - linker.env("LC_ALL", "en_US.UTF-8"); + linker.env("LC_ALL", "C"); // MSVC's `link.exe`. linker.env("VSLANG", "1033"); } From f08aae6a2bbd5c509029da592ea3a5634a7bc743 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Fri, 3 Jul 2020 22:11:10 -0400 Subject: [PATCH 14/15] impl Index> for CStr --- src/libstd/ffi/c_str.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index dca1fdde48242..ce254f73619aa 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.45.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()..]; + } } From 30b8835d1d0f531aa1d5875cde5ffae347177fd3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 18 Jul 2020 12:16:25 -0700 Subject: [PATCH 15/15] Update stability attribute for CStr indexing --- src/libstd/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index ce254f73619aa..da25a0ede729d 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1551,7 +1551,7 @@ impl ops::Index for CString { } } -#[stable(feature = "cstr_range_from", since = "1.45.0")] +#[stable(feature = "cstr_range_from", since = "1.47.0")] impl ops::Index> for CStr { type Output = CStr;