From: Mazdak Farrokhzad Date: Fri, 6 Dec 2019 22:27:08 +0000 (+0100) Subject: Rollup merge of #67102 - Aaron1011:patch-3, r=Mark-Simulacrum X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=dbc9f306b69153cdff991303c1dfd7a29136b752;hp=3c14f0eaa7eafb1a61dab61fc37c11c3e450cba2;p=rust.git Rollup merge of #67102 - Aaron1011:patch-3, r=Mark-Simulacrum Add note to src/ci/docker/README.md about multiple docker images I spent a while debugging a strage linker error about an outdated `glibc` version, only to discover that it was caused by a stale `obj` directory. It wasn't obviously to be that using the same obj dir with multiple Docker images (for the same target triple) could be a problem. This commit adds a note to the README, which should hopefully be helpful to anyone else who runs into this issue. --- diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 4798769823f..20248f7f6c1 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -53,7 +53,7 @@ pub struct Layout { impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `LayoutErr` if either of the following conditions + /// or returns `LayoutErr` if any of the following conditions /// are not met: /// /// * `align` must not be zero, @@ -137,7 +137,7 @@ pub fn new() -> Self { #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - // See rationale in `new` for why this us using an unsafe variant below + // See rationale in `new` for why this is using an unsafe variant below debug_assert!(Layout::from_size_align(size, align).is_ok()); unsafe { Layout::from_size_align_unchecked(size, align) @@ -196,7 +196,7 @@ pub fn padding_needed_for(&self, align: usize) -> usize { // valid. // // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the + // so the &-mask with `!(align - 1)` will ensure that in the // case of overflow, `len_rounded_up` will itself be 0. // Thus the returned padding, when added to `len`, yields 0, // which trivially satisfies the alignment `align`. diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 617bdd238f4..1b3c254a05f 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -9,12 +9,12 @@ impl bool { /// ``` /// #![feature(bool_to_option)] /// - /// assert_eq!(false.then(0), None); - /// assert_eq!(true.then(0), Some(0)); + /// assert_eq!(false.then_some(0), None); + /// assert_eq!(true.then_some(0), Some(0)); /// ``` #[unstable(feature = "bool_to_option", issue = "64260")] #[inline] - pub fn then(self, t: T) -> Option { + pub fn then_some(self, t: T) -> Option { if self { Some(t) } else { @@ -29,12 +29,12 @@ pub fn then(self, t: T) -> Option { /// ``` /// #![feature(bool_to_option)] /// - /// assert_eq!(false.then_with(|| 0), None); - /// assert_eq!(true.then_with(|| 0), Some(0)); + /// assert_eq!(false.then(|| 0), None); + /// assert_eq!(true.then(|| 0), Some(0)); /// ``` #[unstable(feature = "bool_to_option", issue = "64260")] #[inline] - pub fn then_with T>(self, f: F) -> Option { + pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs deleted file mode 100644 index 08802b3a97a..00000000000 --- a/src/libcore/convert.rs +++ /dev/null @@ -1,660 +0,0 @@ -//! Traits for conversions between types. -//! -//! The traits in this module provide a way to convert from one type to another type. -//! Each trait serves a different purpose: -//! -//! - Implement the [`AsRef`] trait for cheap reference-to-reference conversions -//! - Implement the [`AsMut`] trait for cheap mutable-to-mutable conversions -//! - Implement the [`From`] trait for consuming value-to-value conversions -//! - Implement the [`Into`] trait for consuming value-to-value conversions to types -//! outside the current crate -//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], -//! but should be implemented when the conversion can fail. -//! -//! The traits in this module are often used as trait bounds for generic functions such that to -//! arguments of multiple types are supported. See the documentation of each trait for examples. -//! -//! As a library author, you should always prefer implementing [`From`][`From`] or -//! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], -//! as [`From`] and [`TryFrom`] provide greater flexibility and offer -//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a -//! blanket implementation in the standard library. Only implement [`Into`] or [`TryInto`] -//! when a conversion to a type outside the current crate is required. -//! -//! # Generic Implementations -//! -//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference -//! - [`From`]` for T` implies [`Into`]` for U` -//! - [`TryFrom`]` for T` implies [`TryInto`]` for U` -//! - [`From`] and [`Into`] are reflexive, which means that all types can -//! `into` themselves and `from` themselves -//! -//! See each trait for usage examples. -//! -//! [`Into`]: trait.Into.html -//! [`From`]: trait.From.html -//! [`TryFrom`]: trait.TryFrom.html -//! [`TryInto`]: trait.TryInto.html -//! [`AsRef`]: trait.AsRef.html -//! [`AsMut`]: trait.AsMut.html - -#![stable(feature = "rust1", since = "1.0.0")] - -/// The identity function. -/// -/// Two things are important to note about this function: -/// -/// - It is not always equivalent to a closure like `|x| x`, since the -/// closure may coerce `x` into a different type. -/// -/// - It moves the input `x` passed to the function. -/// -/// While it might seem strange to have a function that just returns back the -/// input, there are some interesting uses. -/// -/// # Examples -/// -/// Using `identity` to do nothing in a sequence of other, interesting, -/// functions: -/// -/// ```rust -/// use std::convert::identity; -/// -/// fn manipulation(x: u32) -> u32 { -/// // Let's pretend that adding one is an interesting function. -/// x + 1 -/// } -/// -/// let _arr = &[identity, manipulation]; -/// ``` -/// -/// Using `identity` as a "do nothing" base case in a conditional: -/// -/// ```rust -/// use std::convert::identity; -/// -/// # let condition = true; -/// # -/// # fn manipulation(x: u32) -> u32 { x + 1 } -/// # -/// let do_stuff = if condition { manipulation } else { identity }; -/// -/// // Do more interesting stuff... -/// -/// let _results = do_stuff(42); -/// ``` -/// -/// Using `identity` to keep the `Some` variants of an iterator of `Option`: -/// -/// ```rust -/// use std::convert::identity; -/// -/// let iter = vec![Some(1), None, Some(3)].into_iter(); -/// let filtered = iter.filter_map(identity).collect::>(); -/// assert_eq!(vec![1, 3], filtered); -/// ``` -#[stable(feature = "convert_id", since = "1.33.0")] -#[inline] -pub const fn identity(x: T) -> T { - x -} - -/// Used to do a cheap reference-to-reference conversion. -/// -/// This trait is similar to [`AsMut`] which is used for converting between mutable references. -/// If you need to do a costly conversion it is better to implement [`From`] with type -/// `&T` or write a custom function. -/// -/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in few aspects: -/// -/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either -/// a reference or a value. -/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for borrowed value are -/// equivalent to those of the owned value. For this reason, if you want to -/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`]. -/// -/// **Note: This trait must not fail**. If the conversion can fail, use a -/// dedicated method which returns an [`Option`] or a [`Result`]. -/// -/// # Generic Implementations -/// -/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type -/// `&mut Foo` or `&&mut Foo`) -/// -/// # Examples -/// -/// By using trait bounds we can accept arguments of different types as long as they can be -/// converted to the specified type `T`. -/// -/// For example: By creating a generic function that takes an `AsRef` we express that we -/// want to accept all references that can be converted to [`&str`] as an argument. -/// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. -/// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Borrow`]: ../../std/borrow/trait.Borrow.html -/// [`Hash`]: ../../std/hash/trait.Hash.html -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Ord`]: ../../std/cmp/trait.Ord.html -/// [`&str`]: ../../std/primitive.str.html -/// [`String`]: ../../std/string/struct.String.html -/// -/// ``` -/// fn is_hello>(s: T) { -/// assert_eq!("hello", s.as_ref()); -/// } -/// -/// let s = "hello"; -/// is_hello(s); -/// -/// let s = "hello".to_string(); -/// is_hello(s); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRef { - /// Performs the conversion. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_ref(&self) -> &T; -} - -/// Used to do a cheap mutable-to-mutable reference conversion. -/// -/// This trait is similar to [`AsRef`] but used for converting between mutable -/// references. If you need to do a costly conversion it is better to -/// implement [`From`] with type `&mut T` or write a custom function. -/// -/// **Note: This trait must not fail**. If the conversion can fail, use a -/// dedicated method which returns an [`Option`] or a [`Result`]. -/// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// -/// # Generic Implementations -/// -/// - `AsMut` auto-dereferences if the inner type is a mutable reference -/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` -/// or `&mut &mut Foo`) -/// -/// # Examples -/// -/// Using `AsMut` as trait bound for a generic function we can accept all mutable references -/// that can be converted to type `&mut T`. Because [`Box`] implements `AsMut` we can -/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`. -/// Because [`Box`] implements `AsMut`, `add_one` accepts arguments of type -/// `&mut Box` as well: -/// -/// ``` -/// fn add_one>(num: &mut T) { -/// *num.as_mut() += 1; -/// } -/// -/// let mut boxed_num = Box::new(0); -/// add_one(&mut boxed_num); -/// assert_eq!(*boxed_num, 1); -/// ``` -/// -/// [`Box`]: ../../std/boxed/struct.Box.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsMut { - /// Performs the conversion. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_mut(&mut self) -> &mut T; -} - -/// A value-to-value conversion that consumes the input value. The -/// opposite of [`From`]. -/// -/// One should avoid implementing [`Into`] and implement [`From`] instead. -/// Implementing [`From`] automatically provides one with an implementation of [`Into`] -/// thanks to the blanket implementation in the standard library. -/// -/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function -/// to ensure that types that only implement [`Into`] can be used as well. -/// -/// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`]. -/// -/// # Generic Implementations -/// -/// - [`From`]` for U` implies `Into for T` -/// - [`Into`] is reflexive, which means that `Into for T` is implemented -/// -/// # Implementing [`Into`] for conversions to external types in old versions of Rust -/// -/// Prior to Rust 1.40, if the destination type was not part of the current crate -/// then you couldn't implement [`From`] directly. -/// For example, take this code: -/// -/// ``` -/// struct Wrapper(Vec); -/// impl From> for Vec { -/// fn from(w: Wrapper) -> Vec { -/// w.0 -/// } -/// } -/// ``` -/// This will fail to compile in older versions of the language because Rust's orphaning rules -/// used to be a little bit more strict. To bypass this, you could implement [`Into`] directly: -/// -/// ``` -/// struct Wrapper(Vec); -/// impl Into> for Wrapper { -/// fn into(self) -> Vec { -/// self.0 -/// } -/// } -/// ``` -/// -/// It is important to understand that [`Into`] does not provide a [`From`] implementation -/// (as [`From`] does with [`Into`]). Therefore, you should always try to implement [`From`] -/// and then fall back to [`Into`] if [`From`] can't be implemented. -/// -/// # Examples -/// -/// [`String`] implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>`: -/// -/// In order to express that we want a generic function to take all arguments that can be -/// converted to a specified type `T`, we can use a trait bound of [`Into`]``. -/// For example: The function `is_hello` takes all arguments that can be converted into a -/// [`Vec`]`<`[`u8`]`>`. -/// -/// ``` -/// fn is_hello>>(s: T) { -/// let bytes = b"hello".to_vec(); -/// assert_eq!(bytes, s.into()); -/// } -/// -/// let s = "hello".to_string(); -/// is_hello(s); -/// ``` -/// -/// [`TryInto`]: trait.TryInto.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`String`]: ../../std/string/struct.String.html -/// [`From`]: trait.From.html -/// [`Into`]: trait.Into.html -/// [`Vec`]: ../../std/vec/struct.Vec.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Into: Sized { - /// Performs the conversion. - #[stable(feature = "rust1", since = "1.0.0")] - fn into(self) -> T; -} - -/// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of -/// [`Into`]. -/// -/// One should always prefer implementing `From` over [`Into`] -/// because implementing `From` automatically provides one with a implementation of [`Into`] -/// thanks to the blanket implementation in the standard library. -/// -/// Only implement [`Into`] if a conversion to a type outside the current crate is required. -/// `From` cannot do these type of conversions because of Rust's orphaning rules. -/// See [`Into`] for more details. -/// -/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function. -/// This way, types that directly implement [`Into`] can be used as arguments as well. -/// -/// The `From` is also very useful when performing error handling. When constructing a function -/// that is capable of failing, the return type will generally be of the form `Result`. -/// The `From` trait simplifies error handling by allowing a function to return a single error type -/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more -/// details. -/// -/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`]. -/// -/// # Generic Implementations -/// -/// - `From for U` implies [`Into`]` for T` -/// - `From` is reflexive, which means that `From for T` is implemented -/// -/// # Examples -/// -/// [`String`] implements `From<&str>`: -/// -/// An explicit conversion from a `&str` to a String is done as follows: -/// -/// ``` -/// let string = "hello".to_string(); -/// let other_string = String::from("hello"); -/// -/// assert_eq!(string, other_string); -/// ``` -/// -/// While performing error handling it is often useful to implement `From` for your own error type. -/// By converting underlying error types to our own custom error type that encapsulates the -/// underlying error type, we can return a single error type without losing information on the -/// underlying cause. The '?' operator automatically converts the underlying error type to our -/// custom error type by calling `Into::into` which is automatically provided when -/// implementing `From`. The compiler then infers which implementation of `Into` should be used. -/// -/// ``` -/// use std::fs; -/// use std::io; -/// use std::num; -/// -/// enum CliError { -/// IoError(io::Error), -/// ParseError(num::ParseIntError), -/// } -/// -/// impl From for CliError { -/// fn from(error: io::Error) -> Self { -/// CliError::IoError(error) -/// } -/// } -/// -/// impl From for CliError { -/// fn from(error: num::ParseIntError) -> Self { -/// CliError::ParseError(error) -/// } -/// } -/// -/// fn open_and_parse_file(file_name: &str) -> Result { -/// let mut contents = fs::read_to_string(&file_name)?; -/// let num: i32 = contents.trim().parse()?; -/// Ok(num) -/// } -/// ``` -/// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`String`]: ../../std/string/struct.String.html -/// [`Into`]: trait.Into.html -/// [`from`]: trait.From.html#tymethod.from -/// [book]: ../../book/ch09-00-error-handling.html -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented(on( - all(_Self = "&str", T = "std::string::String"), - note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", -))] -pub trait From: Sized { - /// Performs the conversion. - #[stable(feature = "rust1", since = "1.0.0")] - fn from(_: T) -> Self; -} - -/// An attempted conversion that consumes `self`, which may or may not be -/// expensive. -/// -/// Library authors should usually not directly implement this trait, -/// but should prefer implementing the [`TryFrom`] trait, which offers -/// greater flexibility and provides an equivalent `TryInto` -/// implementation for free, thanks to a blanket implementation in the -/// standard library. For more information on this, see the -/// documentation for [`Into`]. -/// -/// # Implementing `TryInto` -/// -/// This suffers the same restrictions and reasoning as implementing -/// [`Into`], see there for details. -/// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html -#[stable(feature = "try_from", since = "1.34.0")] -pub trait TryInto: Sized { - /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.34.0")] - type Error; - - /// Performs the conversion. - #[stable(feature = "try_from", since = "1.34.0")] - fn try_into(self) -> Result; -} - -/// Simple and safe type conversions that may fail in a controlled -/// way under some circumstances. It is the reciprocal of [`TryInto`]. -/// -/// This is useful when you are doing a type conversion that may -/// trivially succeed but may also need special handling. -/// For example, there is no way to convert an [`i64`] into an [`i32`] -/// using the [`From`] trait, because an [`i64`] may contain a value -/// that an [`i32`] cannot represent and so the conversion would lose data. -/// This might be handled by truncating the [`i64`] to an [`i32`] (essentially -/// giving the [`i64`]'s value modulo [`i32::MAX`]) or by simply returning -/// [`i32::MAX`], or by some other method. The [`From`] trait is intended -/// for perfect conversions, so the `TryFrom` trait informs the -/// programmer when a type conversion could go bad and lets them -/// decide how to handle it. -/// -/// # Generic Implementations -/// -/// - `TryFrom for U` implies [`TryInto`]` for T` -/// - [`try_from`] is reflexive, which means that `TryFrom for T` -/// is implemented and cannot fail -- the associated `Error` type for -/// calling `T::try_from()` on a value of type `T` is [`!`]. -/// -/// `TryFrom` can be implemented as follows: -/// -/// ``` -/// use std::convert::TryFrom; -/// -/// struct GreaterThanZero(i32); -/// -/// impl TryFrom for GreaterThanZero { -/// type Error = &'static str; -/// -/// fn try_from(value: i32) -> Result { -/// if value <= 0 { -/// Err("GreaterThanZero only accepts value superior than zero!") -/// } else { -/// Ok(GreaterThanZero(value)) -/// } -/// } -/// } -/// ``` -/// -/// # Examples -/// -/// As described, [`i32`] implements `TryFrom<`[`i64`]`>`: -/// -/// ``` -/// use std::convert::TryFrom; -/// -/// let big_number = 1_000_000_000_000i64; -/// // Silently truncates `big_number`, requires detecting -/// // and handling the truncation after the fact. -/// let smaller_number = big_number as i32; -/// assert_eq!(smaller_number, -727379968); -/// -/// // Returns an error because `big_number` is too big to -/// // fit in an `i32`. -/// let try_smaller_number = i32::try_from(big_number); -/// assert!(try_smaller_number.is_err()); -/// -/// // Returns `Ok(3)`. -/// let try_successful_smaller_number = i32::try_from(3); -/// assert!(try_successful_smaller_number.is_ok()); -/// ``` -/// -/// [`try_from`]: trait.TryFrom.html#tymethod.try_from -/// [`TryInto`]: trait.TryInto.html -/// [`i32::MAX`]: ../../std/i32/constant.MAX.html -/// [`!`]: ../../std/primitive.never.html -#[stable(feature = "try_from", since = "1.34.0")] -pub trait TryFrom: Sized { - /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.34.0")] - type Error; - - /// Performs the conversion. - #[stable(feature = "try_from", since = "1.34.0")] - fn try_from(value: T) -> Result; -} - -//////////////////////////////////////////////////////////////////////////////// -// GENERIC IMPLS -//////////////////////////////////////////////////////////////////////////////// - -// As lifts over & -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for &T -where - T: AsRef, -{ - fn as_ref(&self) -> &U { - >::as_ref(*self) - } -} - -// As lifts over &mut -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for &mut T -where - T: AsRef, -{ - fn as_ref(&self) -> &U { - >::as_ref(*self) - } -} - -// FIXME (#45742): replace the above impls for &/&mut with the following more general one: -// // As lifts over Deref -// impl>, U: ?Sized> AsRef for D { -// fn as_ref(&self) -> &U { -// self.deref().as_ref() -// } -// } - -// AsMut lifts over &mut -#[stable(feature = "rust1", since = "1.0.0")] -impl AsMut for &mut T -where - T: AsMut, -{ - fn as_mut(&mut self) -> &mut U { - (*self).as_mut() - } -} - -// FIXME (#45742): replace the above impl for &mut with the following more general one: -// // AsMut lifts over DerefMut -// impl>, U: ?Sized> AsMut for D { -// fn as_mut(&mut self) -> &mut U { -// self.deref_mut().as_mut() -// } -// } - -// From implies Into -#[stable(feature = "rust1", since = "1.0.0")] -impl Into for T -where - U: From, -{ - fn into(self) -> U { - U::from(self) - } -} - -// From (and thus Into) is reflexive -#[stable(feature = "rust1", since = "1.0.0")] -impl From for T { - fn from(t: T) -> T { - t - } -} - -/// **Stability note:** This impl does not yet exist, but we are -/// "reserving space" to add it in the future. See -/// [rust-lang/rust#64715][#64715] for details. -/// -/// [#64715]: https://github.com/rust-lang/rust/issues/64715 -#[stable(feature = "convert_infallible", since = "1.34.0")] -#[rustc_reservation_impl = "permitting this impl would forbid us from adding \ - `impl From for T` later; see rust-lang/rust#64715 for details"] -impl From for T { - fn from(t: !) -> T { - t - } -} - -// TryFrom implies TryInto -#[stable(feature = "try_from", since = "1.34.0")] -impl TryInto for T -where - U: TryFrom, -{ - type Error = U::Error; - - fn try_into(self) -> Result { - U::try_from(self) - } -} - -// Infallible conversions are semantically equivalent to fallible conversions -// with an uninhabited error type. -#[stable(feature = "try_from", since = "1.34.0")] -impl TryFrom for T -where - U: Into, -{ - type Error = Infallible; - - fn try_from(value: U) -> Result { - Ok(U::into(value)) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// CONCRETE IMPLS -//////////////////////////////////////////////////////////////////////////////// - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<[T]> for [T] { - fn as_ref(&self) -> &[T] { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsMut<[T]> for [T] { - fn as_mut(&mut self) -> &mut [T] { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for str { - #[inline] - fn as_ref(&self) -> &str { - self - } -} - -//////////////////////////////////////////////////////////////////////////////// -// THE NO-ERROR ERROR TYPE -//////////////////////////////////////////////////////////////////////////////// - -/// A type alias for [the `!` “never” type][never]. -/// -/// `Infallible` represents types of errors that can never happen since `!` has no valid values. -/// This can be useful for generic APIs that use [`Result`] and parameterize the error type, -/// to indicate that the result is always [`Ok`]. -/// -/// For example, the [`TryFrom`] trait (conversion that returns a [`Result`]) -/// has a blanket implementation for all types where a reverse [`Into`] implementation exists. -/// -/// ```ignore (illustrates std code, duplicating the impl in a doctest would be an error) -/// impl TryFrom for T where U: Into { -/// type Error = Infallible; -/// -/// fn try_from(value: U) -> Result { -/// Ok(U::into(value)) // Never returns `Err` -/// } -/// } -/// ``` -/// -/// # Eventual deprecation -/// -/// Previously, `Infallible` was defined as `enum Infallible {}`. -/// Now that it is merely a type alias to `!`, we will eventually deprecate `Infallible`. -/// -/// [`Ok`]: ../result/enum.Result.html#variant.Ok -/// [`Result`]: ../result/enum.Result.html -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html -/// [never]: ../../std/primitive.never.html -#[stable(feature = "convert_infallible", since = "1.34.0")] -pub type Infallible = !; diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs new file mode 100644 index 00000000000..16d5375059f --- /dev/null +++ b/src/libcore/convert/mod.rs @@ -0,0 +1,665 @@ +//! Traits for conversions between types. +//! +//! The traits in this module provide a way to convert from one type to another type. +//! Each trait serves a different purpose: +//! +//! - Implement the [`AsRef`] trait for cheap reference-to-reference conversions +//! - Implement the [`AsMut`] trait for cheap mutable-to-mutable conversions +//! - Implement the [`From`] trait for consuming value-to-value conversions +//! - Implement the [`Into`] trait for consuming value-to-value conversions to types +//! outside the current crate +//! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], +//! but should be implemented when the conversion can fail. +//! +//! The traits in this module are often used as trait bounds for generic functions such that to +//! arguments of multiple types are supported. See the documentation of each trait for examples. +//! +//! As a library author, you should always prefer implementing [`From`][`From`] or +//! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], +//! as [`From`] and [`TryFrom`] provide greater flexibility and offer +//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a +//! blanket implementation in the standard library. Only implement [`Into`] or [`TryInto`] +//! when a conversion to a type outside the current crate is required. +//! +//! # Generic Implementations +//! +//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference +//! - [`From`]` for T` implies [`Into`]` for U` +//! - [`TryFrom`]` for T` implies [`TryInto`]` for U` +//! - [`From`] and [`Into`] are reflexive, which means that all types can +//! `into` themselves and `from` themselves +//! +//! See each trait for usage examples. +//! +//! [`Into`]: trait.Into.html +//! [`From`]: trait.From.html +//! [`TryFrom`]: trait.TryFrom.html +//! [`TryInto`]: trait.TryInto.html +//! [`AsRef`]: trait.AsRef.html +//! [`AsMut`]: trait.AsMut.html + +#![stable(feature = "rust1", since = "1.0.0")] + +mod num; + +#[unstable(feature = "convert_float_to_int", issue = "67057")] +pub use num::FloatToInt; + +/// The identity function. +/// +/// Two things are important to note about this function: +/// +/// - It is not always equivalent to a closure like `|x| x`, since the +/// closure may coerce `x` into a different type. +/// +/// - It moves the input `x` passed to the function. +/// +/// While it might seem strange to have a function that just returns back the +/// input, there are some interesting uses. +/// +/// # Examples +/// +/// Using `identity` to do nothing in a sequence of other, interesting, +/// functions: +/// +/// ```rust +/// use std::convert::identity; +/// +/// fn manipulation(x: u32) -> u32 { +/// // Let's pretend that adding one is an interesting function. +/// x + 1 +/// } +/// +/// let _arr = &[identity, manipulation]; +/// ``` +/// +/// Using `identity` as a "do nothing" base case in a conditional: +/// +/// ```rust +/// use std::convert::identity; +/// +/// # let condition = true; +/// # +/// # fn manipulation(x: u32) -> u32 { x + 1 } +/// # +/// let do_stuff = if condition { manipulation } else { identity }; +/// +/// // Do more interesting stuff... +/// +/// let _results = do_stuff(42); +/// ``` +/// +/// Using `identity` to keep the `Some` variants of an iterator of `Option`: +/// +/// ```rust +/// use std::convert::identity; +/// +/// let iter = vec![Some(1), None, Some(3)].into_iter(); +/// let filtered = iter.filter_map(identity).collect::>(); +/// assert_eq!(vec![1, 3], filtered); +/// ``` +#[stable(feature = "convert_id", since = "1.33.0")] +#[inline] +pub const fn identity(x: T) -> T { + x +} + +/// Used to do a cheap reference-to-reference conversion. +/// +/// This trait is similar to [`AsMut`] which is used for converting between mutable references. +/// If you need to do a costly conversion it is better to implement [`From`] with type +/// `&T` or write a custom function. +/// +/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in few aspects: +/// +/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either +/// a reference or a value. +/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for borrowed value are +/// equivalent to those of the owned value. For this reason, if you want to +/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`]. +/// +/// **Note: This trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. +/// +/// # Generic Implementations +/// +/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) +/// +/// # Examples +/// +/// By using trait bounds we can accept arguments of different types as long as they can be +/// converted to the specified type `T`. +/// +/// For example: By creating a generic function that takes an `AsRef` we express that we +/// want to accept all references that can be converted to [`&str`] as an argument. +/// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. +/// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Borrow`]: ../../std/borrow/trait.Borrow.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Ord`]: ../../std/cmp/trait.Ord.html +/// [`&str`]: ../../std/primitive.str.html +/// [`String`]: ../../std/string/struct.String.html +/// +/// ``` +/// fn is_hello>(s: T) { +/// assert_eq!("hello", s.as_ref()); +/// } +/// +/// let s = "hello"; +/// is_hello(s); +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRef { + /// Performs the conversion. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_ref(&self) -> &T; +} + +/// Used to do a cheap mutable-to-mutable reference conversion. +/// +/// This trait is similar to [`AsRef`] but used for converting between mutable +/// references. If you need to do a costly conversion it is better to +/// implement [`From`] with type `&mut T` or write a custom function. +/// +/// **Note: This trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. +/// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// +/// # Generic Implementations +/// +/// - `AsMut` auto-dereferences if the inner type is a mutable reference +/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` +/// or `&mut &mut Foo`) +/// +/// # Examples +/// +/// Using `AsMut` as trait bound for a generic function we can accept all mutable references +/// that can be converted to type `&mut T`. Because [`Box`] implements `AsMut` we can +/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`. +/// Because [`Box`] implements `AsMut`, `add_one` accepts arguments of type +/// `&mut Box` as well: +/// +/// ``` +/// fn add_one>(num: &mut T) { +/// *num.as_mut() += 1; +/// } +/// +/// let mut boxed_num = Box::new(0); +/// add_one(&mut boxed_num); +/// assert_eq!(*boxed_num, 1); +/// ``` +/// +/// [`Box`]: ../../std/boxed/struct.Box.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsMut { + /// Performs the conversion. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_mut(&mut self) -> &mut T; +} + +/// A value-to-value conversion that consumes the input value. The +/// opposite of [`From`]. +/// +/// One should avoid implementing [`Into`] and implement [`From`] instead. +/// Implementing [`From`] automatically provides one with an implementation of [`Into`] +/// thanks to the blanket implementation in the standard library. +/// +/// Prefer using [`Into`] over [`From`] when specifying trait bounds on a generic function +/// to ensure that types that only implement [`Into`] can be used as well. +/// +/// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`]. +/// +/// # Generic Implementations +/// +/// - [`From`]` for U` implies `Into for T` +/// - [`Into`] is reflexive, which means that `Into for T` is implemented +/// +/// # Implementing [`Into`] for conversions to external types in old versions of Rust +/// +/// Prior to Rust 1.40, if the destination type was not part of the current crate +/// then you couldn't implement [`From`] directly. +/// For example, take this code: +/// +/// ``` +/// struct Wrapper(Vec); +/// impl From> for Vec { +/// fn from(w: Wrapper) -> Vec { +/// w.0 +/// } +/// } +/// ``` +/// This will fail to compile in older versions of the language because Rust's orphaning rules +/// used to be a little bit more strict. To bypass this, you could implement [`Into`] directly: +/// +/// ``` +/// struct Wrapper(Vec); +/// impl Into> for Wrapper { +/// fn into(self) -> Vec { +/// self.0 +/// } +/// } +/// ``` +/// +/// It is important to understand that [`Into`] does not provide a [`From`] implementation +/// (as [`From`] does with [`Into`]). Therefore, you should always try to implement [`From`] +/// and then fall back to [`Into`] if [`From`] can't be implemented. +/// +/// # Examples +/// +/// [`String`] implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>`: +/// +/// In order to express that we want a generic function to take all arguments that can be +/// converted to a specified type `T`, we can use a trait bound of [`Into`]``. +/// For example: The function `is_hello` takes all arguments that can be converted into a +/// [`Vec`]`<`[`u8`]`>`. +/// +/// ``` +/// fn is_hello>>(s: T) { +/// let bytes = b"hello".to_vec(); +/// assert_eq!(bytes, s.into()); +/// } +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` +/// +/// [`TryInto`]: trait.TryInto.html +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`String`]: ../../std/string/struct.String.html +/// [`From`]: trait.From.html +/// [`Into`]: trait.Into.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Into: Sized { + /// Performs the conversion. + #[stable(feature = "rust1", since = "1.0.0")] + fn into(self) -> T; +} + +/// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of +/// [`Into`]. +/// +/// One should always prefer implementing `From` over [`Into`] +/// because implementing `From` automatically provides one with a implementation of [`Into`] +/// thanks to the blanket implementation in the standard library. +/// +/// Only implement [`Into`] if a conversion to a type outside the current crate is required. +/// `From` cannot do these type of conversions because of Rust's orphaning rules. +/// See [`Into`] for more details. +/// +/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function. +/// This way, types that directly implement [`Into`] can be used as arguments as well. +/// +/// The `From` is also very useful when performing error handling. When constructing a function +/// that is capable of failing, the return type will generally be of the form `Result`. +/// The `From` trait simplifies error handling by allowing a function to return a single error type +/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more +/// details. +/// +/// **Note: This trait must not fail**. If the conversion can fail, use [`TryFrom`]. +/// +/// # Generic Implementations +/// +/// - `From for U` implies [`Into`]` for T` +/// - `From` is reflexive, which means that `From for T` is implemented +/// +/// # Examples +/// +/// [`String`] implements `From<&str>`: +/// +/// An explicit conversion from a `&str` to a String is done as follows: +/// +/// ``` +/// let string = "hello".to_string(); +/// let other_string = String::from("hello"); +/// +/// assert_eq!(string, other_string); +/// ``` +/// +/// While performing error handling it is often useful to implement `From` for your own error type. +/// By converting underlying error types to our own custom error type that encapsulates the +/// underlying error type, we can return a single error type without losing information on the +/// underlying cause. The '?' operator automatically converts the underlying error type to our +/// custom error type by calling `Into::into` which is automatically provided when +/// implementing `From`. The compiler then infers which implementation of `Into` should be used. +/// +/// ``` +/// use std::fs; +/// use std::io; +/// use std::num; +/// +/// enum CliError { +/// IoError(io::Error), +/// ParseError(num::ParseIntError), +/// } +/// +/// impl From for CliError { +/// fn from(error: io::Error) -> Self { +/// CliError::IoError(error) +/// } +/// } +/// +/// impl From for CliError { +/// fn from(error: num::ParseIntError) -> Self { +/// CliError::ParseError(error) +/// } +/// } +/// +/// fn open_and_parse_file(file_name: &str) -> Result { +/// let mut contents = fs::read_to_string(&file_name)?; +/// let num: i32 = contents.trim().parse()?; +/// Ok(num) +/// } +/// ``` +/// +/// [`TryFrom`]: trait.TryFrom.html +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`String`]: ../../std/string/struct.String.html +/// [`Into`]: trait.Into.html +/// [`from`]: trait.From.html#tymethod.from +/// [book]: ../../book/ch09-00-error-handling.html +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented(on( + all(_Self = "&str", T = "std::string::String"), + note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", +))] +pub trait From: Sized { + /// Performs the conversion. + #[stable(feature = "rust1", since = "1.0.0")] + fn from(_: T) -> Self; +} + +/// An attempted conversion that consumes `self`, which may or may not be +/// expensive. +/// +/// Library authors should usually not directly implement this trait, +/// but should prefer implementing the [`TryFrom`] trait, which offers +/// greater flexibility and provides an equivalent `TryInto` +/// implementation for free, thanks to a blanket implementation in the +/// standard library. For more information on this, see the +/// documentation for [`Into`]. +/// +/// # Implementing `TryInto` +/// +/// This suffers the same restrictions and reasoning as implementing +/// [`Into`], see there for details. +/// +/// [`TryFrom`]: trait.TryFrom.html +/// [`Into`]: trait.Into.html +#[stable(feature = "try_from", since = "1.34.0")] +pub trait TryInto: Sized { + /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.34.0")] + type Error; + + /// Performs the conversion. + #[stable(feature = "try_from", since = "1.34.0")] + fn try_into(self) -> Result; +} + +/// Simple and safe type conversions that may fail in a controlled +/// way under some circumstances. It is the reciprocal of [`TryInto`]. +/// +/// This is useful when you are doing a type conversion that may +/// trivially succeed but may also need special handling. +/// For example, there is no way to convert an [`i64`] into an [`i32`] +/// using the [`From`] trait, because an [`i64`] may contain a value +/// that an [`i32`] cannot represent and so the conversion would lose data. +/// This might be handled by truncating the [`i64`] to an [`i32`] (essentially +/// giving the [`i64`]'s value modulo [`i32::MAX`]) or by simply returning +/// [`i32::MAX`], or by some other method. The [`From`] trait is intended +/// for perfect conversions, so the `TryFrom` trait informs the +/// programmer when a type conversion could go bad and lets them +/// decide how to handle it. +/// +/// # Generic Implementations +/// +/// - `TryFrom for U` implies [`TryInto`]` for T` +/// - [`try_from`] is reflexive, which means that `TryFrom for T` +/// is implemented and cannot fail -- the associated `Error` type for +/// calling `T::try_from()` on a value of type `T` is [`!`]. +/// +/// `TryFrom` can be implemented as follows: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// struct GreaterThanZero(i32); +/// +/// impl TryFrom for GreaterThanZero { +/// type Error = &'static str; +/// +/// fn try_from(value: i32) -> Result { +/// if value <= 0 { +/// Err("GreaterThanZero only accepts value superior than zero!") +/// } else { +/// Ok(GreaterThanZero(value)) +/// } +/// } +/// } +/// ``` +/// +/// # Examples +/// +/// As described, [`i32`] implements `TryFrom<`[`i64`]`>`: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// let big_number = 1_000_000_000_000i64; +/// // Silently truncates `big_number`, requires detecting +/// // and handling the truncation after the fact. +/// let smaller_number = big_number as i32; +/// assert_eq!(smaller_number, -727379968); +/// +/// // Returns an error because `big_number` is too big to +/// // fit in an `i32`. +/// let try_smaller_number = i32::try_from(big_number); +/// assert!(try_smaller_number.is_err()); +/// +/// // Returns `Ok(3)`. +/// let try_successful_smaller_number = i32::try_from(3); +/// assert!(try_successful_smaller_number.is_ok()); +/// ``` +/// +/// [`try_from`]: trait.TryFrom.html#tymethod.try_from +/// [`TryInto`]: trait.TryInto.html +/// [`i32::MAX`]: ../../std/i32/constant.MAX.html +/// [`!`]: ../../std/primitive.never.html +#[stable(feature = "try_from", since = "1.34.0")] +pub trait TryFrom: Sized { + /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.34.0")] + type Error; + + /// Performs the conversion. + #[stable(feature = "try_from", since = "1.34.0")] + fn try_from(value: T) -> Result; +} + +//////////////////////////////////////////////////////////////////////////////// +// GENERIC IMPLS +//////////////////////////////////////////////////////////////////////////////// + +// As lifts over & +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for &T +where + T: AsRef, +{ + fn as_ref(&self) -> &U { + >::as_ref(*self) + } +} + +// As lifts over &mut +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for &mut T +where + T: AsRef, +{ + fn as_ref(&self) -> &U { + >::as_ref(*self) + } +} + +// FIXME (#45742): replace the above impls for &/&mut with the following more general one: +// // As lifts over Deref +// impl>, U: ?Sized> AsRef for D { +// fn as_ref(&self) -> &U { +// self.deref().as_ref() +// } +// } + +// AsMut lifts over &mut +#[stable(feature = "rust1", since = "1.0.0")] +impl AsMut for &mut T +where + T: AsMut, +{ + fn as_mut(&mut self) -> &mut U { + (*self).as_mut() + } +} + +// FIXME (#45742): replace the above impl for &mut with the following more general one: +// // AsMut lifts over DerefMut +// impl>, U: ?Sized> AsMut for D { +// fn as_mut(&mut self) -> &mut U { +// self.deref_mut().as_mut() +// } +// } + +// From implies Into +#[stable(feature = "rust1", since = "1.0.0")] +impl Into for T +where + U: From, +{ + fn into(self) -> U { + U::from(self) + } +} + +// From (and thus Into) is reflexive +#[stable(feature = "rust1", since = "1.0.0")] +impl From for T { + fn from(t: T) -> T { + t + } +} + +/// **Stability note:** This impl does not yet exist, but we are +/// "reserving space" to add it in the future. See +/// [rust-lang/rust#64715][#64715] for details. +/// +/// [#64715]: https://github.com/rust-lang/rust/issues/64715 +#[stable(feature = "convert_infallible", since = "1.34.0")] +#[rustc_reservation_impl = "permitting this impl would forbid us from adding \ + `impl From for T` later; see rust-lang/rust#64715 for details"] +impl From for T { + fn from(t: !) -> T { + t + } +} + +// TryFrom implies TryInto +#[stable(feature = "try_from", since = "1.34.0")] +impl TryInto for T +where + U: TryFrom, +{ + type Error = U::Error; + + fn try_into(self) -> Result { + U::try_from(self) + } +} + +// Infallible conversions are semantically equivalent to fallible conversions +// with an uninhabited error type. +#[stable(feature = "try_from", since = "1.34.0")] +impl TryFrom for T +where + U: Into, +{ + type Error = Infallible; + + fn try_from(value: U) -> Result { + Ok(U::into(value)) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// CONCRETE IMPLS +//////////////////////////////////////////////////////////////////////////////// + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef<[T]> for [T] { + fn as_ref(&self) -> &[T] { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsMut<[T]> for [T] { + fn as_mut(&mut self) -> &mut [T] { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for str { + #[inline] + fn as_ref(&self) -> &str { + self + } +} + +//////////////////////////////////////////////////////////////////////////////// +// THE NO-ERROR ERROR TYPE +//////////////////////////////////////////////////////////////////////////////// + +/// A type alias for [the `!` “never” type][never]. +/// +/// `Infallible` represents types of errors that can never happen since `!` has no valid values. +/// This can be useful for generic APIs that use [`Result`] and parameterize the error type, +/// to indicate that the result is always [`Ok`]. +/// +/// For example, the [`TryFrom`] trait (conversion that returns a [`Result`]) +/// has a blanket implementation for all types where a reverse [`Into`] implementation exists. +/// +/// ```ignore (illustrates std code, duplicating the impl in a doctest would be an error) +/// impl TryFrom for T where U: Into { +/// type Error = Infallible; +/// +/// fn try_from(value: U) -> Result { +/// Ok(U::into(value)) // Never returns `Err` +/// } +/// } +/// ``` +/// +/// # Eventual deprecation +/// +/// Previously, `Infallible` was defined as `enum Infallible {}`. +/// Now that it is merely a type alias to `!`, we will eventually deprecate `Infallible`. +/// +/// [`Ok`]: ../result/enum.Result.html#variant.Ok +/// [`Result`]: ../result/enum.Result.html +/// [`TryFrom`]: trait.TryFrom.html +/// [`Into`]: trait.Into.html +/// [never]: ../../std/primitive.never.html +#[stable(feature = "convert_infallible", since = "1.34.0")] +pub type Infallible = !; diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs new file mode 100644 index 00000000000..0877dacb38d --- /dev/null +++ b/src/libcore/convert/num.rs @@ -0,0 +1,369 @@ +use super::{From, TryFrom}; +use crate::num::TryFromIntError; + +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `FloatToInt` trait, + /// which allows potentially adding more trait methods after the trait is `#[stable]`. + #[unstable(feature = "convert_float_to_int", issue = "67057")] + pub trait Sealed {} +} + +/// Supporting trait for inherent methods of `f32` and `f64` such as `round_unchecked_to`. +/// Typically doesn’t need to be used directly. +#[unstable(feature = "convert_float_to_int", issue = "67057")] +pub trait FloatToInt: private::Sealed + Sized { + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[doc(hidden)] + unsafe fn approx_unchecked(self) -> Int; +} + +macro_rules! impl_float_to_int { + ( $Float: ident => $( $Int: ident )+ ) => { + #[unstable(feature = "convert_float_to_int", issue = "67057")] + impl private::Sealed for $Float {} + $( + #[unstable(feature = "convert_float_to_int", issue = "67057")] + impl FloatToInt<$Int> for $Float { + #[cfg(not(bootstrap))] + #[doc(hidden)] + #[inline] + unsafe fn approx_unchecked(self) -> $Int { + crate::intrinsics::float_to_int_approx_unchecked(self) + } + } + )+ + } +} + +impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); +impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); + +// Conversion traits for primitive integer and float types +// Conversions T -> T are covered by a blanket impl and therefore excluded +// Some conversions from and to usize/isize are not implemented due to portability concerns +macro_rules! impl_from { + ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { + #[$attr] + #[doc = $doc] + impl From<$Small> for $Large { + #[inline] + fn from(small: $Small) -> $Large { + small as $Large + } + } + }; + ($Small: ty, $Large: ty, #[$attr:meta]) => { + impl_from!($Small, + $Large, + #[$attr], + concat!("Converts `", + stringify!($Small), + "` to `", + stringify!($Large), + "` losslessly.")); + } +} + +macro_rules! impl_from_bool { + ($target: ty, #[$attr:meta]) => { + impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", + stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` +values. + +# Examples + +``` +assert_eq!(", stringify!($target), "::from(true), 1); +assert_eq!(", stringify!($target), "::from(false), 0); +```")); + }; +} + +// Bool -> Any +impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } + +// Unsigned -> Unsigned +impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } + +// Signed -> Signed +impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } + +// Unsigned -> Signed +impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } +impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } + +// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX +// which imply that pointer-sized integers must be at least 16 bits: +// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 +impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } + +// RISC-V defines the possibility of a 128-bit address space (RV128). + +// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. +// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf +// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf + + +// Note: integers can only be represented with full precision in a float if +// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. +// Lossy float conversions are not implemented at this time. + +// Signed -> Float +impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// Unsigned -> Float +impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// Float -> Float +impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + +// only negative bounds +macro_rules! try_from_lower_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u >= 0 { + Ok(u as $target) + } else { + Err(TryFromIntError(())) + } + } + } + )*} +} + +// unsigned to signed (only positive bound) +macro_rules! try_from_upper_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + if u > (<$target>::max_value() as $source) { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +// all other cases +macro_rules! try_from_both_bounded { + ($source:ty, $($target:ty),*) => {$( + #[stable(feature = "try_from", since = "1.34.0")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + /// Try to create the target number type from a source + /// number type. This returns an error if the source value + /// is outside of the range of the target type. + #[inline] + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target>::min_value() as $source; + let max = <$target>::max_value() as $source; + if u < min || u > max { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +macro_rules! rev { + ($mac:ident, $source:ty, $($target:ty),*) => {$( + $mac!($target, $source); + )*} +} + +// intra-sign conversions +try_from_upper_bounded!(u16, u8); +try_from_upper_bounded!(u32, u16, u8); +try_from_upper_bounded!(u64, u32, u16, u8); +try_from_upper_bounded!(u128, u64, u32, u16, u8); + +try_from_both_bounded!(i16, i8); +try_from_both_bounded!(i32, i16, i8); +try_from_both_bounded!(i64, i32, i16, i8); +try_from_both_bounded!(i128, i64, i32, i16, i8); + +// unsigned-to-signed +try_from_upper_bounded!(u8, i8); +try_from_upper_bounded!(u16, i8, i16); +try_from_upper_bounded!(u32, i8, i16, i32); +try_from_upper_bounded!(u64, i8, i16, i32, i64); +try_from_upper_bounded!(u128, i8, i16, i32, i64, i128); + +// signed-to-unsigned +try_from_lower_bounded!(i8, u8, u16, u32, u64, u128); +try_from_lower_bounded!(i16, u16, u32, u64, u128); +try_from_lower_bounded!(i32, u32, u64, u128); +try_from_lower_bounded!(i64, u64, u128); +try_from_lower_bounded!(i128, u128); +try_from_both_bounded!(i16, u8); +try_from_both_bounded!(i32, u16, u8); +try_from_both_bounded!(i64, u32, u16, u8); +try_from_both_bounded!(i128, u64, u32, u16, u8); + +// usize/isize +try_from_upper_bounded!(usize, isize); +try_from_lower_bounded!(isize, usize); + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); + try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); + rev!(try_from_lower_bounded, usize, i8, i16); + rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); + try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); + rev!(try_from_lower_bounded, usize, i8, i16, i32); + rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::TryFromIntError; + use crate::convert::TryFrom; + + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); + try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); + rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); + rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 19928f30f2e..18aae59573d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1144,6 +1144,11 @@ pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, /// May assume inputs are finite. pub fn frem_fast(a: T, b: T) -> T; + /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// https://github.com/rust-lang/rust/issues/10184 + #[cfg(not(bootstrap))] + pub fn float_to_int_approx_unchecked(value: Float) -> Int; + /// Returns the number of bits set in an integer type `T` pub fn ctpop(x: T) -> T; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 913c0f96d11..ac06f95e244 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -7,9 +7,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::convert::FloatToInt; #[cfg(not(test))] use crate::intrinsics; - use crate::mem; use crate::num::FpCategory; @@ -400,6 +401,35 @@ pub fn min(self, other: f32) -> f32 { intrinsics::minnumf32(self, other) } + /// Rounds toward zero and converts to any primitive integer type, + /// assuming that the value is finite and fits in that type. + /// + /// ``` + /// #![feature(float_approx_unchecked_to)] + /// + /// let value = 4.6_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, 4); + /// + /// let value = -128.9_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, std::i8::MIN); + /// ``` + /// + /// # Safety + /// + /// The value must: + /// + /// * Not be `NaN` + /// * Not be infinite + /// * Be representable in the return type `Int`, after truncating off its fractional part + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[inline] + pub unsafe fn approx_unchecked_to(self) -> Int where Self: FloatToInt { + FloatToInt::::approx_unchecked(self) + } + /// Raw transmutation to `u32`. /// /// This is currently identical to `transmute::(self)` on all platforms. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 6ca830b1f38..794f77fcfc1 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -7,9 +7,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::convert::FloatToInt; #[cfg(not(test))] use crate::intrinsics; - use crate::mem; use crate::num::FpCategory; @@ -413,6 +414,35 @@ pub fn min(self, other: f64) -> f64 { intrinsics::minnumf64(self, other) } + /// Rounds toward zero and converts to any primitive integer type, + /// assuming that the value is finite and fits in that type. + /// + /// ``` + /// #![feature(float_approx_unchecked_to)] + /// + /// let value = 4.6_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, 4); + /// + /// let value = -128.9_f32; + /// let rounded = unsafe { value.approx_unchecked_to::() }; + /// assert_eq!(rounded, std::i8::MIN); + /// ``` + /// + /// # Safety + /// + /// The value must: + /// + /// * Not be `NaN` + /// * Not be infinite + /// * Be representable in the return type `Int`, after truncating off its fractional part + #[cfg(not(bootstrap))] + #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[inline] + pub unsafe fn approx_unchecked_to(self) -> Int where Self: FloatToInt { + FloatToInt::::approx_unchecked(self) + } + /// Raw transmutation to `u64`. /// /// This is currently identical to `transmute::(self)` on all platforms. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4313248f263..585f144cf8a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4,7 +4,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::convert::TryFrom; use crate::fmt; use crate::intrinsics; use crate::mem; @@ -4701,7 +4700,7 @@ fn from_str(src: &str) -> Result { /// The error type returned when a checked integral type conversion fails. #[stable(feature = "try_from", since = "1.34.0")] #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(()); +pub struct TryFromIntError(pub(crate) ()); impl TryFromIntError { #[unstable(feature = "int_error_internals", @@ -4728,206 +4727,6 @@ fn from(never: !) -> TryFromIntError { } } -// no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(value: $source) -> Result { - Ok(value as $target) - } - } - )*} -} - -// only negative bounds -macro_rules! try_from_lower_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - if u >= 0 { - Ok(u as $target) - } else { - Err(TryFromIntError(())) - } - } - } - )*} -} - -// unsigned to signed (only positive bound) -macro_rules! try_from_upper_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - if u > (<$target>::max_value() as $source) { - Err(TryFromIntError(())) - } else { - Ok(u as $target) - } - } - } - )*} -} - -// all other cases -macro_rules! try_from_both_bounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - /// Try to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. - #[inline] - fn try_from(u: $source) -> Result<$target, TryFromIntError> { - let min = <$target>::min_value() as $source; - let max = <$target>::max_value() as $source; - if u < min || u > max { - Err(TryFromIntError(())) - } else { - Ok(u as $target) - } - } - } - )*} -} - -macro_rules! rev { - ($mac:ident, $source:ty, $($target:ty),*) => {$( - $mac!($target, $source); - )*} -} - -// intra-sign conversions -try_from_upper_bounded!(u16, u8); -try_from_upper_bounded!(u32, u16, u8); -try_from_upper_bounded!(u64, u32, u16, u8); -try_from_upper_bounded!(u128, u64, u32, u16, u8); - -try_from_both_bounded!(i16, i8); -try_from_both_bounded!(i32, i16, i8); -try_from_both_bounded!(i64, i32, i16, i8); -try_from_both_bounded!(i128, i64, i32, i16, i8); - -// unsigned-to-signed -try_from_upper_bounded!(u8, i8); -try_from_upper_bounded!(u16, i8, i16); -try_from_upper_bounded!(u32, i8, i16, i32); -try_from_upper_bounded!(u64, i8, i16, i32, i64); -try_from_upper_bounded!(u128, i8, i16, i32, i64, i128); - -// signed-to-unsigned -try_from_lower_bounded!(i8, u8, u16, u32, u64, u128); -try_from_lower_bounded!(i16, u16, u32, u64, u128); -try_from_lower_bounded!(i32, u32, u64, u128); -try_from_lower_bounded!(i64, u64, u128); -try_from_lower_bounded!(i128, u128); -try_from_both_bounded!(i16, u8); -try_from_both_bounded!(i32, u16, u8); -try_from_both_bounded!(i64, u32, u16, u8); -try_from_both_bounded!(i128, u64, u32, u16, u8); - -// usize/isize -try_from_upper_bounded!(usize, isize); -try_from_lower_bounded!(isize, usize); - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); - - try_from_both_bounded!(isize, u8); - try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); - - rev!(try_from_upper_bounded, usize, u32, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16); - rev!(try_from_both_bounded, usize, i32, i64, i128); - - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_both_bounded, isize, i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); - - try_from_both_bounded!(isize, u8, u16); - try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u32); - rev!(try_from_upper_bounded, usize, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32); - rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i32); - rev!(try_from_both_bounded, isize, i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::TryFromIntError; - use crate::convert::TryFrom; - - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); - - try_from_both_bounded!(isize, u8, u16, u32); - try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u32, u64); - rev!(try_from_upper_bounded, usize, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); - rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i32, i64); - rev!(try_from_both_bounded, isize, i128); -} - #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; @@ -5110,131 +4909,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[stable(feature = "rust1", since = "1.0.0")] pub use crate::num::dec2flt::ParseFloatError; - -// Conversion traits for primitive integer and float types -// Conversions T -> T are covered by a blanket impl and therefore excluded -// Some conversions from and to usize/isize are not implemented due to portability concerns -macro_rules! impl_from { - ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { - #[$attr] - #[doc = $doc] - impl From<$Small> for $Large { - #[inline] - fn from(small: $Small) -> $Large { - small as $Large - } - } - }; - ($Small: ty, $Large: ty, #[$attr:meta]) => { - impl_from!($Small, - $Large, - #[$attr], - concat!("Converts `", - stringify!($Small), - "` to `", - stringify!($Large), - "` losslessly.")); - } -} - -macro_rules! impl_from_bool { - ($target: ty, #[$attr:meta]) => { - impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", - stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` -values. - -# Examples - -``` -assert_eq!(", stringify!($target), "::from(true), 1); -assert_eq!(", stringify!($target), "::from(false), 0); -```")); - }; -} - -// Bool -> Any -impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } - -// Unsigned -> Unsigned -impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } - -// Signed -> Signed -impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } - -// Unsigned -> Signed -impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } - -// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX -// which imply that pointer-sized integers must be at least 16 bits: -// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 -impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } - -// RISC-V defines the possibility of a 128-bit address space (RV128). - -// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize. -// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf -// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf - - -// Note: integers can only be represented with full precision in a float if -// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. -// Lossy float conversions are not implemented at this time. - -// Signed -> Float -impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Unsigned -> Float -impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Float -> Float -impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } diff --git a/src/libcore/tests/bool.rs b/src/libcore/tests/bool.rs index 0f1e6e89451..e89eb2c7f94 100644 --- a/src/libcore/tests/bool.rs +++ b/src/libcore/tests/bool.rs @@ -1,7 +1,7 @@ #[test] fn test_bool_to_option() { - assert_eq!(false.then(0), None); - assert_eq!(true.then(0), Some(0)); - assert_eq!(false.then_with(|| 0), None); - assert_eq!(true.then_with(|| 0), Some(0)); + assert_eq!(false.then_some(0), None); + assert_eq!(true.then_some(0), Some(0)); + assert_eq!(false.then(|| 0), None); + assert_eq!(true.then(|| 0), Some(0)); } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 900c6ed5ff3..2ecbe770729 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -11,6 +11,7 @@ #![feature(nll)] #![feature(rustc_private)] #![feature(unicode_internals)] +#![feature(bool_to_option)] pub use Piece::*; pub use Position::*; @@ -644,11 +645,7 @@ fn integer(&mut self) -> Option { break; } } - if found { - Some(cur) - } else { - None - } + found.then_some(cur) } } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index f25f3b5741a..8f9f3983262 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -147,13 +147,7 @@ pub fn from_node(node: Node<'_>) -> Option> { map::Node::Expr(e) => e.is_fn_like(), _ => false }; - if fn_like { - Some(FnLikeNode { - node, - }) - } else { - None - } + fn_like.then_some(FnLikeNode { node }) } pub fn body(self) -> ast::BodyId { diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index 3110b027c5b..3e28145c0fa 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -211,11 +211,7 @@ fn declared_generic_bounds_from_env_with_compare_fn( (r, p) ); let p_ty = p.to_ty(tcx); - if compare_ty(p_ty) { - Some(ty::OutlivesPredicate(p_ty, r)) - } else { - None - } + compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r)) }); param_bounds diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e708c5ab6e7..24b87ffc80c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(arbitrary_self_types)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index df5d4997e08..814c244ecbc 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -242,11 +242,7 @@ pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable() { - Some(local) - } else { - None - } + self.local_decls[local].is_user_variable().then_some(local) }) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba44c6c3b9a..35017d6330d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -363,11 +363,7 @@ fn impl_similar_to(&self, return None }; - if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) { - Some(impl_def_id) - } else { - None - } + tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id) } fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { @@ -2214,6 +2210,10 @@ fn note_obligation_cause_for_async_await( } let span = self.tcx.def_span(generator_did); + // Do not ICE on closure typeck (#66868). + if let None = self.tcx.hir().as_local_hir_id(generator_did) { + return false; + } let tables = self.tcx.typeck_tables_of(generator_did); debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ", generator_did, span); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c9a934e9ebd..05a2704cc5d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2784,11 +2784,7 @@ pub fn opt_associated_item(self, def_id: DefId) -> Option { } }; - if is_associated_item { - Some(self.associated_item(def_id)) - } else { - None - } + is_associated_item.then(|| self.associated_item(def_id)) } fn associated_item_from_trait_item_ref(self, @@ -3253,7 +3249,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ParamEnv<'_> { let unnormalized_env = ty::ParamEnv::new( tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, - if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None } + tcx.sess.opts.debugging_opts.chalk.then_some(def_id), ); let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| { diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index e5f4e793132..2f30b797fb1 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -303,13 +303,8 @@ fn connected_to_root<'tcx>( return true; } - visit_waiters(query, |_, successor| { - if connected_to_root(successor, visited) { - Some(None) - } else { - None - } - }).is_some() + visit_waiters(query, |_, successor| connected_to_root(successor, visited).then_some(None)) + .is_some() } // Deterministically pick an query from a list diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 33dc2513de5..1ea9362dc42 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -375,11 +375,7 @@ pub fn provide_extern(providers: &mut Providers<'_>) { let native_libs = tcx.native_libraries(cnum); let def_id_to_native_lib = native_libs.iter().filter_map(|lib| - if let Some(id) = lib.foreign_module { - Some((id, lib)) - } else { - None - } + lib.foreign_module.map(|id| (id, lib)) ).collect::>(); let mut ret = FxHashMap::default(); diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index f38f9dfecd3..419e99d55d7 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -245,11 +245,7 @@ fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option { let (mut lo, mut hi) = (0u64, 0u64); let success = llvm::LLVMRustConstInt128Get(v, sign_ext, &mut hi, &mut lo); - if success { - Some(hi_lo_to_u128(lo, hi)) - } else { - None - } + success.then_some(hi_lo_to_u128(lo, hi)) }) } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 9df75a800f1..1767ad118e7 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -516,9 +516,36 @@ fn codegen_intrinsic_call( return; } } - }, + "float_to_int_approx_unchecked" => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `float_to_int_approx_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", arg_tys[0])); + return; + } + match int_type_width_signed(ret_ty, self.cx) { + Some((width, signed)) => { + if signed { + self.fptosi(args[0].immediate(), self.cx.type_ix(width)) + } else { + self.fptoui(args[0].immediate(), self.cx.type_ix(width)) + } + } + None => { + span_invalid_monomorphization_error( + tcx.sess, span, + &format!("invalid monomorphization of `float_to_int_approx_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", ret_ty)); + return; + } + } + } + "discriminant_value" => { args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 2ff5872370f..00a84f8d80f 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -6,6 +6,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_cstr_unchecked)] diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs index e27cb6d8dda..cd3d99951e2 100644 --- a/src/librustc_codegen_ssa/back/rpath.rs +++ b/src/librustc_codegen_ssa/back/rpath.rs @@ -119,11 +119,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option { use std::path::Component; if path.is_absolute() != base.is_absolute() { - if path.is_absolute() { - Some(PathBuf::from(path)) - } else { - None - } + path.is_absolute().then(|| PathBuf::from(path)) } else { let mut ita = path.components(); let mut itb = base.components(); diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index f8b3e0ffe5c..cea5dc18c13 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -85,11 +85,7 @@ fn reachable_non_generics_provider( match tcx.hir().get(hir_id) { Node::ForeignItem(..) => { let def_id = tcx.hir().local_def_id(hir_id); - if tcx.is_statically_included_foreign_item(def_id) { - Some(def_id) - } else { - None - } + tcx.is_statically_included_foreign_item(def_id).then_some(def_id) } // Only consider nodes that actually have exported symbols. diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 9784d870b31..9919666027a 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -1,5 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(core_intrinsics)] @@ -68,22 +69,14 @@ pub fn into_compiled_module(self, emit_bc: bool, emit_bc_compressed: bool, outputs: &OutputFilenames) -> CompiledModule { - let object = if emit_obj { - Some(outputs.temp_path(OutputType::Object, Some(&self.name))) - } else { - None - }; - let bytecode = if emit_bc { - Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))) - } else { - None - }; - let bytecode_compressed = if emit_bc_compressed { - Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)) - .with_extension(RLIB_BYTECODE_EXTENSION)) - } else { - None - }; + let object = emit_obj + .then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); + let bytecode = emit_bc + .then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); + let bytecode_compressed = emit_bc_compressed.then(|| { + outputs.temp_path(OutputType::Bitcode, Some(&self.name)) + .with_extension(RLIB_BYTECODE_EXTENSION) + }); CompiledModule { name: self.name.clone(), diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 9e4b704170b..9c1bec39b29 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -18,7 +18,6 @@ E0013: include_str!("./error_codes/E0013.md"), E0014: include_str!("./error_codes/E0014.md"), E0015: include_str!("./error_codes/E0015.md"), -E0017: include_str!("./error_codes/E0017.md"), E0019: include_str!("./error_codes/E0019.md"), E0023: include_str!("./error_codes/E0023.md"), E0025: include_str!("./error_codes/E0025.md"), diff --git a/src/librustc_error_codes/error_codes/E0017.md b/src/librustc_error_codes/error_codes/E0017.md deleted file mode 100644 index d5e6857b4d6..00000000000 --- a/src/librustc_error_codes/error_codes/E0017.md +++ /dev/null @@ -1,20 +0,0 @@ -References in statics and constants may only refer to immutable values. - -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index fc880b9e929..b1ae7c6ca33 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -523,6 +523,9 @@ pub fn set(&self, features: &mut Features, span: Span) { /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), + /// Allows using `&mut` in constant functions. + (active, const_mut_refs, "1.41.0", Some(57349), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 76af4342f5c..9bb18788171 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -1,3 +1,4 @@ +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(set_stdio)] #![feature(nll)] diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 235184382c5..2a4bc41f850 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -547,13 +547,7 @@ fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool } fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { - let check = |output_path: &PathBuf| { - if output_path.is_dir() { - Some(output_path.clone()) - } else { - None - } - }; + let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone()); check_output(output_paths, check) } diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index d1fbb949fb1..e429b4d101a 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -117,11 +117,9 @@ fn codegen_backend(&self) -> &Lrc> { pub fn dep_graph_future(&self) -> Result<&Query>> { self.dep_graph_future.compute(|| { - Ok(if self.session().opts.build_dep_graph() { - Some(rustc_incremental::load_dep_graph(self.session())) - } else { - None - }) + Ok(self.session().opts.build_dep_graph().then(|| { + rustc_incremental::load_dep_graph(self.session()) + })) }) } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index d8e20e17ce8..8c225b83f40 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -107,11 +107,7 @@ pub fn create_session( fn get_stack_size() -> Option { // FIXME: Hacks on hacks. If the env is trying to override the stack size // then *don't* set it explicitly. - if env::var_os("RUST_MIN_STACK").is_none() { - Some(STACK_SIZE) - } else { - None - } + env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } struct Sink(Arc>>); @@ -285,11 +281,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option { } else { "rustc" }); - if candidate.exists() { - Some(candidate) - } else { - None - } + candidate.exists().then_some(candidate) }) .next() } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0fd7145f425..10b00d35d9b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1491,11 +1491,7 @@ fn lifetimes_outliving_type<'tcx>( match pred { ty::Predicate::TypeOutlives(outlives) => { let outlives = outlives.skip_binder(); - if outlives.0.is_param(index) { - Some(outlives.1) - } else { - None - } + outlives.0.is_param(index).then_some(outlives.1) } _ => None } @@ -1554,11 +1550,7 @@ fn collect_outlives_bound_spans<'tcx>( }), _ => false, }; - if is_inferred { - Some((i, bound.span())) - } else { - None - } + is_inferred.then_some((i, bound.span())) } else { None } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e60c025c3ef..12aab4b4f84 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -12,6 +12,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(test, feature(test))] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(nll)] diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index dbf2dcf1c0a..25bd2c45da5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -802,11 +802,8 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) { // First up we check for global allocators. Look at the crate graph here // and see what's a global allocator, including if we ourselves are a // global allocator. - let mut global_allocator = if self.cstore.has_global_allocator { - Some(Symbol::intern("this crate")) - } else { - None - }; + let mut global_allocator = self.cstore.has_global_allocator + .then(|| Symbol::intern("this crate")); self.cstore.iter_crate_data(|_, data| { if !data.has_global_allocator() { return diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 8c0b7345e1e..aaaff7e3b0a 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -1,5 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index b9363200cdf..7a5bbb4d892 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -173,11 +173,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( Option>>, Option>, ) { - let mut all_facts = if AllFacts::enabled(infcx.tcx) { - Some(AllFacts::default()) - } else { - None - }; + let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default()); let universal_regions = Rc::new(universal_regions); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 85031d6210a..0b3cb29e39e 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -493,7 +493,7 @@ pub(super) fn solve( // functions below, which will trigger them to report errors // eagerly. let mut outlives_requirements = - if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None }; + infcx.tcx.is_closure(mir_def_id).then(|| vec![]); self.check_type_tests( infcx, @@ -709,14 +709,11 @@ fn apply_member_constraint( let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); - if r1_outlives_r2 && r2_outlives_r1 { - Some(r1.min(r2)) - } else if r1_outlives_r2 { - Some(r2) - } else if r2_outlives_r1 { - Some(r1) - } else { - None + match (r1_outlives_r2, r2_outlives_r1) { + (true, true) => Some(r1.min(r2)), + (true, false) => Some(r2), + (false, true) => Some(r1), + (false, false) => None, } }; let mut min_choice = choice_regions[0]; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index c893d6f4856..e320811ca05 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -680,7 +680,7 @@ pub fn sort_candidate<'pat>( } })(); - if no_overlap == Some(true) { + if let Some(true) = no_overlap { // Testing range does not overlap with pattern range, // so the pattern can be matched only if this test fails. Some(1) @@ -690,7 +690,7 @@ pub fn sort_candidate<'pat>( } (&TestKind::Range(range), &PatKind::Constant { value }) => { - if self.const_range_contains(range, value) == Some(false) { + if let Some(false) = self.const_range_contains(range, value) { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. Some(1) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 92c7178da53..0086c3b0e10 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1154,13 +1154,7 @@ pub fn compare_const_vals<'tcx>( ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); - let from_bool = |v: bool| { - if v { - Some(Ordering::Equal) - } else { - None - } - }; + let from_bool = |v: bool| v.then_some(Ordering::Equal); let fallback = || from_bool(a == b); diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ee7fb18fd05..8f177ad1225 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -324,7 +324,7 @@ pub fn check_ptr_access( size: Size, align: Align, ) -> InterpResult<'tcx, Option>> { - let align = if M::CHECK_ALIGN { Some(align) } else { None }; + let align = M::CHECK_ALIGN.then_some(align); self.check_ptr_access_align(sptr, size, align, CheckInAllocMsg::MemoryAccessTest) } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index d7493338a53..55b9427a75b 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -157,9 +157,9 @@ pub fn eval_rvalue_into_place( } BinaryOp(bin_op, ref left, ref right) => { - let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None }; + let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); let left = self.read_immediate(self.eval_operand(left, layout)?)?; - let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None }; + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(self.eval_operand(right, layout)?)?; self.binop_ignore_overflow( bin_op, @@ -172,7 +172,7 @@ pub fn eval_rvalue_into_place( CheckedBinaryOp(bin_op, ref left, ref right) => { // Due to the extra boolean in the result, we can never reuse the `dest.layout`. let left = self.read_immediate(self.eval_operand(left, None)?)?; - let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None }; + let layout = binop_right_homogeneous(bin_op).then_some(left.layout); let right = self.read_immediate(self.eval_operand(right, layout)?)?; self.binop_with_overflow( bin_op, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f4fb9a5e4f2..42b72b64f8a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -8,6 +8,7 @@ #![feature(in_band_lifetimes)] #![feature(inner_deref)] #![feature(slice_patterns)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -27,7 +28,6 @@ #![feature(associated_type_bounds)] #![feature(range_is_empty)] #![feature(stmt_expr_attributes)] -#![feature(bool_to_option)] #![feature(trait_alias)] #![feature(matches_macro)] diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 42f08771f86..591f220549d 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -761,11 +761,7 @@ fn compute_codegen_unit_name( .iter() .map(|part| part.data.as_symbol()); - let volatile_suffix = if volatile { - Some("volatile") - } else { - None - }; + let volatile_suffix = volatile.then_some("volatile"); name_builder.build_cgu_name(def_path.krate, components, volatile_suffix) }).clone() diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index aec3cf04a97..393ae9442a1 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -1,7 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use rustc::hir::def_id::DefId; -use rustc::mir::BorrowKind; use rustc::session::config::nightly_options; use rustc::ty::TyCtxt; use syntax::feature_gate::feature_err; @@ -181,38 +180,53 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) { } #[derive(Debug)] -pub struct MutBorrow(pub BorrowKind); +pub struct CellBorrow; +impl NonConstOp for CellBorrow { + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { + span_err!(item.tcx.sess, span, E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead"); + } +} + +#[derive(Debug)] +pub struct MutBorrow; impl NonConstOp for MutBorrow { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_mut_refs) + } + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - let kind = self.0; - if let BorrowKind::Mut { .. } = kind { - let mut err = struct_span_err!(item.tcx.sess, span, E0017, - "references in {}s may only refer \ - to immutable values", item.const_kind()); - err.span_label(span, format!("{}s require immutable values", - item.const_kind())); - if item.tcx.sess.teach(&err.get_code().unwrap()) { - err.note("References in statics and constants may only refer \ - to immutable values.\n\n\ - Statics are shared everywhere, and if they refer to \ - mutable data one might violate memory safety since \ - holding multiple mutable references to shared data \ - is not allowed.\n\n\ - If you really want global mutable state, try using \ - static mut or a global UnsafeCell."); - } - err.emit(); - } else { - span_err!(item.tcx.sess, span, E0492, - "cannot borrow a constant which may contain \ - interior mutability, create a static instead"); + let mut err = feature_err( + &item.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("references in {}s may only refer \ + to immutable values", item.const_kind()) + ); + err.span_label(span, format!("{}s require immutable values", + item.const_kind())); + if item.tcx.sess.teach(&err.get_code().unwrap()) { + err.note("References in statics and constants may only refer \ + to immutable values.\n\n\ + Statics are shared everywhere, and if they refer to \ + mutable data one might violate memory safety since \ + holding multiple mutable references to shared data \ + is not allowed.\n\n\ + If you really want global mutable state, try using \ + static mut or a global UnsafeCell."); } + err.emit(); } } #[derive(Debug)] pub struct MutDeref; -impl NonConstOp for MutDeref {} +impl NonConstOp for MutDeref { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_mut_refs) + } +} #[derive(Debug)] pub struct Panic; diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index f44bac126f2..7170857926b 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -359,7 +359,11 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { }; if !is_allowed { - self.check_op(ops::MutBorrow(kind)); + if let BorrowKind::Mut{ .. } = kind { + self.check_op(ops::MutBorrow); + } else { + self.check_op(ops::CellBorrow); + } } } @@ -384,7 +388,11 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { ); if borrowed_place_has_mut_interior { - self.check_op(ops::MutBorrow(kind)); + if let BorrowKind::Mut{ .. } = kind { + self.check_op(ops::MutBorrow); + } else { + self.check_op(ops::CellBorrow); + } } } @@ -451,7 +459,6 @@ fn visit_operand( } } } - fn visit_projection_elem( &mut self, place_base: &PlaceBase<'tcx>, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 2c45dcfbe26..284285c327c 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -658,7 +658,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect(); unsafe_blocks.sort_by_cached_key(|(hir_id, _)| tcx.hir().hir_to_node_id(*hir_id)); let used_unsafe: FxHashSet<_> = unsafe_blocks.iter() - .flat_map(|&&(id, used)| if used { Some(id) } else { None }) + .flat_map(|&&(id, used)| used.then_some(id)) .collect(); for &(block_id, is_used) in unsafe_blocks { if !is_used { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 3030d2e646b..cf2e1306dc4 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -79,10 +79,14 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { for ty in ty.walk() { match ty.kind { - ty::Ref(_, _, hir::Mutability::Mutable) => return Err(( - span, - "mutable references in const fn are unstable".into(), - )), + ty::Ref(_, _, hir::Mutability::Mutable) => { + if !tcx.features().const_mut_refs { + return Err(( + span, + "mutable references in const fn are unstable".into(), + )) + } + } ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs index de070d75ad8..26081d93946 100644 --- a/src/librustc_mir/transform/uninhabited_enum_branching.rs +++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs @@ -29,7 +29,7 @@ fn get_switched_on_type<'tcx>( // Only bother checking blocks which terminate by switching on a local. if let Some(local) = get_discriminant_local(&terminator.kind) { let stmt_before_term = (block_data.statements.len() > 0) - .then_with(|| &block_data.statements[block_data.statements.len() - 1].kind); + .then(|| &block_data.statements[block_data.statements.len() - 1].kind); if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term { @@ -59,7 +59,7 @@ fn variant_discriminants<'tcx>( .iter_enumerated() .filter_map(|(idx, layout)| { (layout.abi != Abi::Uninhabited) - .then_with(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) + .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val) }) .collect(), } diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 30e056e52d2..1e9203f377f 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -8,18 +8,19 @@ //! //! [#64197]: https://github.com/rust-lang/rust/issues/64197 -use crate::validate_attr; +use crate::{parse_in, validate_attr}; use rustc_feature::Features; use rustc_errors::Applicability; use syntax::attr::HasAttrs; use syntax::feature_gate::{feature_err, get_features}; use syntax::attr; -use syntax::ast; +use syntax::ast::{self, Attribute, AttrItem, MetaItem}; use syntax::edition::Edition; use syntax::mut_visit::*; use syntax::ptr::P; use syntax::sess::ParseSess; use syntax::util::map_in_place::MapInPlace; +use syntax_pos::Span; use syntax_pos::symbol::sym; use smallvec::SmallVec; @@ -72,10 +73,15 @@ macro_rules! configure { } } +const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; +const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + "; + impl<'a> StripUnconfigured<'a> { pub fn configure(&mut self, mut node: T) -> Option { self.process_cfg_attrs(&mut node); - if self.in_cfg(node.attrs()) { Some(node) } else { None } + self.in_cfg(node.attrs()).then_some(node) } /// Parse and expand all `cfg_attr` attributes into a list of attributes @@ -97,34 +103,14 @@ pub fn process_cfg_attrs(&mut self, node: &mut T) { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { + fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if let ast::MacArgs::Empty = attr.get_normal_item().args { - self.sess.span_diagnostic - .struct_span_err( - attr.span, - "malformed `cfg_attr` attribute input", - ).span_suggestion( - attr.span, - "missing condition and attribute", - "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(), - Applicability::HasPlaceholders, - ).note("for more information, visit \ - ") - .emit(); - return vec![]; - } - let res = crate::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr()); - let (cfg_predicate, expanded_attrs) = match res { - Ok(result) => result, - Err(mut e) => { - e.emit(); - return vec![]; - } + let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { + None => return vec![], + Some(r) => r, }; // Lint on zero attributes in source. @@ -135,24 +121,56 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { // At this point we know the attribute is considered used. attr::mark_used(&attr); - if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { - // We call `process_cfg_attr` recursively in case there's a - // `cfg_attr` inside of another `cfg_attr`. E.g. - // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. - expanded_attrs.into_iter() - .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item( - attr.style, - item, - span, - ))) + if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + return vec![]; + } + + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs + .into_iter() + .flat_map(|(item, span)| { + let attr = attr::mk_attr_from_item(attr.style, item, span); + self.process_cfg_attr(attr) + }) .collect() - } else { - vec![] + } + + fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + match attr.get_normal_item().args { + ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { + let msg = "wrong `cfg_attr` delimiters"; + validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg); + match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { + Ok(r) => return Some(r), + Err(mut e) => e + .help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) + .note(CFG_ATTR_NOTE_REF) + .emit(), + } + } + _ => self.error_malformed_cfg_attr_missing(attr.span), } + None + } + + fn error_malformed_cfg_attr_missing(&self, span: Span) { + self.sess + .span_diagnostic + .struct_span_err(span, "malformed `cfg_attr` attribute input") + .span_suggestion( + span, + "missing condition and attribute", + CFG_ATTR_GRAMMAR_HELP.to_string(), + Applicability::HasPlaceholders, + ) + .note(CFG_ATTR_NOTE_REF) + .emit(); } /// Determines if a node with the given attributes should be included in this configuration. - pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool { + pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { attrs.iter().all(|attr| { if !is_cfg(attr) { return true; @@ -199,7 +217,7 @@ pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool { } /// Visit attributes on expression and statements (but not attributes on items in blocks). - fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { + fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { // flag the offending attributes for attr in attrs.iter() { self.maybe_emit_expr_attr_err(attr); @@ -207,7 +225,7 @@ fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { } /// If attributes are not allowed on expressions, emit an error for `attr` - pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { + pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { let mut err = feature_err(self.sess, sym::stmt_expr_attributes, @@ -350,7 +368,7 @@ fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { } } -fn is_cfg(attr: &ast::Attribute) -> bool { +fn is_cfg(attr: &Attribute) -> bool { attr.check_name(sym::cfg) } @@ -359,8 +377,8 @@ fn is_cfg(attr: &ast::Attribute) -> bool { pub fn process_configure_mod( sess: &ParseSess, cfg_mods: bool, - attrs: &[ast::Attribute], -) -> (bool, Vec) { + attrs: &[Attribute], +) -> (bool, Vec) { // Don't perform gated feature checking. let mut strip_unconfigured = StripUnconfigured { sess, features: None }; let mut attrs = attrs.to_owned(); diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index a222f3f00c4..faff386e923 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -1,5 +1,6 @@ //! The main parser interface. +#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] use syntax::ast; @@ -270,21 +271,13 @@ pub fn stream_to_parser_with_base_dir<'a>( } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. -pub fn parse_in_attr<'a, T>( +pub fn parse_in<'a, T>( sess: &'a ParseSess, - attr: &ast::Attribute, + tts: TokenStream, + name: &'static str, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, T> { - let mut parser = Parser::new( - sess, - // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't - // require reconstructing and immediately re-parsing delimiters. - attr.get_normal_item().args.outer_tokens(), - None, - false, - false, - Some("attribute"), - ); + let mut parser = Parser::new(sess, tts, None, false, false, Some(name)); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index b2ae934ce64..00fd6b8a25b 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -220,7 +220,7 @@ pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { Ok(attrs) } - pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); @@ -238,25 +238,36 @@ pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - self.expect(&token::OpenDelim(token::Paren))?; - let cfg_predicate = self.parse_meta_item()?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. let mut expanded_attrs = Vec::with_capacity(1); - - while !self.check(&token::CloseDelim(token::Paren)) { - let lo = self.token.span.lo(); + while self.token.kind != token::Eof { + let lo = self.token.span; let item = self.parse_attr_item()?; - expanded_attrs.push((item, self.prev_span.with_lo(lo))); - self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + expanded_attrs.push((item, lo.to(self.prev_span))); + if !self.eat(&token::Comma) { + break; + } } - self.expect(&token::CloseDelim(token::Paren))?; Ok((cfg_predicate, expanded_attrs)) } + /// Matches `COMMASEP(meta_item_inner)`. + crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec> { + // Presumably, the majority of the time there will only be one attr. + let mut nmis = Vec::with_capacity(1); + while self.token.kind != token::Eof { + nmis.push(self.parse_meta_item_inner()?); + if !self.eat(&token::Comma) { + break; + } + } + Ok(nmis) + } + /// Matches the following grammar (per RFC 1559). /// /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index ccf78e6402b..c3e5b39635f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1727,9 +1727,10 @@ fn report_invalid_macro_expansion_item(&self) { /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case /// it is, we try to parse the item and report error about nested types. fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> { - if self.token.is_keyword(kw::Enum) || + if (self.token.is_keyword(kw::Enum) || self.token.is_keyword(kw::Struct) || - self.token.is_keyword(kw::Union) + self.token.is_keyword(kw::Union)) + && self.look_ahead(1, |t| t.is_ident()) { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 70c3458e7c0..5334fc485e7 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -3,7 +3,6 @@ use rustc_errors::{PResult, Applicability, pluralize}; use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; -use syntax::ast::MacArgs; use syntax::ThinVec; use syntax::token::{self, Token}; use syntax_pos::source_map::{Span, BytePos}; @@ -109,42 +108,6 @@ pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { Ok(Path { segments, span: lo.to(self.prev_span) }) } - /// Like `parse_path`, but also supports parsing `Word` meta items into paths for - /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]` - /// attributes. - fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { - let meta_ident = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref item) => match item.args { - MacArgs::Empty => Some(item.path.clone()), - _ => None, - }, - _ => None, - }, - _ => None, - }; - if let Some(path) = meta_ident { - self.bump(); - return Ok(path); - } - self.parse_path(style) - } - - /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`. - pub fn parse_derive_paths(&mut self) -> PResult<'a, Vec> { - self.expect(&token::OpenDelim(token::Paren))?; - let mut list = Vec::new(); - while !self.eat(&token::CloseDelim(token::Paren)) { - let path = self.parse_path_allowing_meta(PathStyle::Mod)?; - list.push(path); - if !self.eat(&token::Comma) { - self.expect(&token::CloseDelim(token::Paren))?; - break - } - } - Ok(list) - } - pub(super) fn parse_path_segments( &mut self, segments: &mut Vec, diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index 97e9cb8dcdf..94d3fe7b551 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -1,10 +1,13 @@ //! Meta-syntax validation logic of attributes for post-expansion. +use crate::parse_in; + use rustc_errors::{PResult, Applicability}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind}; +use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; use syntax::attr::mk_name_value_item_str; use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT; +use syntax::tokenstream::DelimSpan; use syntax::sess::ParseSess; use syntax_pos::{Symbol, sym}; @@ -27,9 +30,20 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { Ok(match attr.kind { AttrKind::Normal(ref item) => MetaItem { - path: item.path.clone(), - kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?, span: attr.span, + path: item.path.clone(), + kind: match &attr.get_normal_item().args { + MacArgs::Empty => MetaItemKind::Word, + MacArgs::Eq(_, t) => { + let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?; + MetaItemKind::NameValue(v) + } + MacArgs::Delimited(dspan, delim, t) => { + check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); + let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; + MetaItemKind::List(nmis) + } + } }, AttrKind::DocComment(comment) => { mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span) @@ -37,6 +51,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } +crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { + if let ast::MacDelimiter::Parenthesis = delim { + return; + } + + sess.span_diagnostic + .struct_span_err(span.entire(), msg) + .multipart_suggestion( + "the delimiters should be `(` and `)`", + vec![ + (span.open, "(".to_string()), + (span.close, ")".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); +} + /// Checks that the given meta-item is compatible with this `AttributeTemplate`. fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { match meta { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4dcafb6d279..8dd45f5df4c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -422,11 +422,7 @@ fn early_lookup_typo_candidate( Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| { let res = binding.res(); - if filter_fn(res) { - Some(TypoSuggestion::from_res(*name, res)) - } else { - None - } + filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) })); } Scope::BuiltinAttrs => { @@ -440,11 +436,7 @@ fn early_lookup_typo_candidate( Scope::ExternPrelude => { suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)); - if filter_fn(res) { - Some(TypoSuggestion::from_res(ident.name, res)) - } else { - None - } + filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res)) })); } Scope::ToolPrelude => { @@ -467,11 +459,7 @@ fn early_lookup_typo_candidate( suggestions.extend( primitive_types.iter().flat_map(|(name, prim_ty)| { let res = Res::PrimTy(*prim_ty); - if filter_fn(res) { - Some(TypoSuggestion::from_res(*name, res)) - } else { - None - } + filter_fn(res).then_some(TypoSuggestion::from_res(*name, res)) }) ) } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 666c482c680..4f95d6fe70f 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -496,11 +496,7 @@ fn visit_generics(&mut self, generics: &'tcx Generics) { GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { ref default, .. } => { found_default |= default.is_some(); - if found_default { - Some((Ident::with_dummy_span(param.ident.name), Res::Err)) - } else { - None - } + found_default.then_some((Ident::with_dummy_span(param.ident.name), Res::Err)) } })); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be36e02f5b5..31f59e47d0a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -9,6 +9,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 9369c1771a3..150d207e5bf 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -752,11 +752,7 @@ pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> { } pub fn incr_comp_session_dir_opt(&self) -> Option> { - if self.opts.incremental.is_some() { - Some(self.incr_comp_session_dir()) - } else { - None - } + self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir()) } pub fn print_perf_stats(&self) { @@ -1079,8 +1075,9 @@ fn build_session_( None } } - } - else { None }; + } else { + None + }; let host_triple = TargetTriple::from_triple(config::host_triple()); let host = Target::search(&host_triple).unwrap_or_else(|e| diff --git a/src/librustc_target/abi/call/aarch64.rs b/src/librustc_target/abi/call/aarch64.rs index 45fe4751a3d..06c001e577b 100644 --- a/src/librustc_target/abi/call/aarch64.rs +++ b/src/librustc_target/abi/call/aarch64.rs @@ -20,14 +20,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) RegKind::Vector => size.bits() == 64 || size.bits() == 128 }; - if valid_unit { - Some(Uniform { - unit, - total: size - }) - } else { - None - } + valid_unit.then_some(Uniform { unit, total: size }) }) } diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs index ff929f33d8b..36971c1c501 100644 --- a/src/librustc_target/abi/call/arm.rs +++ b/src/librustc_target/abi/call/arm.rs @@ -21,14 +21,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) RegKind::Vector => size.bits() == 64 || size.bits() == 128 }; - if valid_unit { - Some(Uniform { - unit, - total: size - }) - } else { - None - } + valid_unit.then_some(Uniform { unit, total: size }) }) } diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 6f53577b450..5119464b1cc 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -416,11 +416,7 @@ pub fn make_indirect(&mut self) { // i686-pc-windows-msvc, it results in wrong stack offsets. // attrs.pointee_align = Some(self.layout.align.abi); - let extra_attrs = if self.layout.is_unsized() { - Some(ArgAttributes::new()) - } else { - None - }; + let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new()); self.mode = PassMode::Indirect(attrs, extra_attrs); } diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs index f967a83d5f9..fe4594802f6 100644 --- a/src/librustc_target/abi/call/powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -32,14 +32,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: AB RegKind::Vector => arg.layout.size.bits() == 128 }; - if valid_unit { - Some(Uniform { - unit, - total: arg.layout.size - }) - } else { - None - } + valid_unit.then_some(Uniform { unit, total: arg.layout.size }) }) } diff --git a/src/librustc_target/abi/call/sparc64.rs b/src/librustc_target/abi/call/sparc64.rs index fe2c427f703..32be7b89cb0 100644 --- a/src/librustc_target/abi/call/sparc64.rs +++ b/src/librustc_target/abi/call/sparc64.rs @@ -20,14 +20,7 @@ fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) RegKind::Vector => arg.layout.size.bits() == 128 }; - if valid_unit { - Some(Uniform { - unit, - total: arg.layout.size - }) - } else { - None - } + valid_unit.then_some(Uniform { unit, total: arg.layout.size }) }) } diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 5582eaf47c4..6a1498e98e8 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -10,6 +10,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_syntax)] +#![feature(bool_to_option)] #![feature(nll)] #![feature(slice_patterns)] diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 901a2192e20..253fc5575c5 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1284,6 +1284,10 @@ fn coerce_inner<'a>( augment_error(&mut err); } + if let Some(expr) = expression { + fcx.emit_coerce_suggestions(&mut err, expr, found, expected); + } + // Error possibly reported in `check_assign` so avoid emitting error again. err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)) .is_some()); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 32df6c4636c..16a55d2a4d3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -15,6 +15,22 @@ use super::method::probe; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + + pub fn emit_coerce_suggestions( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr, + expr_ty: Ty<'tcx>, + expected: Ty<'tcx> + ) { + self.annotate_expected_due_to_let_ty(err, expr); + self.suggest_compatible_variants(err, expr, expected, expr_ty); + self.suggest_ref_or_into(err, expr, expected, expr_ty); + self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); + self.suggest_missing_await(err, expr, expected, expr_ty); + } + + // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { @@ -137,11 +153,7 @@ pub fn demand_coerce_diag( return (expected, None) } - self.annotate_expected_due_to_let_ty(&mut err, expr); - self.suggest_compatible_variants(&mut err, expr, expected, expr_ty); - self.suggest_ref_or_into(&mut err, expr, expected, expr_ty); - self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty); - self.suggest_missing_await(&mut err, expr, expected, expr_ty); + self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected); (expected, Some(err)) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9f034e65b6e..b967c6e36e3 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -336,6 +336,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { (1, vec![param(0), param(0)], param(0)), "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => (1, vec![param(0), param(0)], param(0)), + "float_to_int_approx_unchecked" => (2, vec![ param(0) ], param(1)), "assume" => (0, vec![tcx.types.bool], tcx.mk_unit()), "likely" => (0, vec![tcx.types.bool], tcx.types.bool), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9717190045a..992308183b4 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1105,11 +1105,7 @@ fn pick_autorefd_method( r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref = Some(mutbl); - pick.unsize = if step.unsize { - Some(self_ty) - } else { - None - }; + pick.unsize = step.unsize.then_some(self_ty); pick }) }) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7a0190a1d1..a956aba4f62 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4584,8 +4584,6 @@ pub fn suggest_mismatched_types_on_tail( pointing_at_return_type = self.suggest_missing_return_type( err, &fn_decl, expected, found, can_suggest); } - self.suggest_ref_or_into(err, expr, expected, found); - self.suggest_boxing_when_appropriate(err, expr, expected, found); pointing_at_return_type } @@ -4957,7 +4955,9 @@ fn suggest_missing_await( ty: expected, })); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + debug!("suggest_missing_await: trying obligation {:?}", obligation); if self.infcx.predicate_may_hold(&obligation) { + debug!("suggest_missing_await: obligation held: {:?}", obligation); if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { err.span_suggestion( sp, @@ -4965,7 +4965,11 @@ fn suggest_missing_await( format!("{}.await", code), Applicability::MaybeIncorrect, ); + } else { + debug!("suggest_missing_await: no snippet for {:?}", sp); } + } else { + debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) } } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 3002459d56f..c5a6c072979 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -114,11 +114,7 @@ fn analyze_closure( }; let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { - if self.closure_kind(closure_def_id, closure_substs).is_none() { - Some(closure_substs) - } else { - None - } + self.closure_kind(closure_def_id, closure_substs).is_none().then_some(closure_substs) } else { None }; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index c606feab087..6a6294b6f87 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -59,6 +59,7 @@ #![allow(non_camel_case_types)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 87c2318a937..e90da699060 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -143,10 +143,8 @@ unsafe impl Sync for Mutex { } #[must_use = "if unused the Mutex will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { - // funny underscores due to how Deref/DerefMut currently work (they - // disregard field privacy). - __lock: &'a Mutex, - __poison: poison::Guard, + lock: &'a Mutex, + poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] @@ -417,8 +415,8 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { unsafe fn new(lock: &'mutex Mutex) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { MutexGuard { - __lock: lock, - __poison: guard, + lock: lock, + poison: guard, } }) } @@ -429,14 +427,14 @@ impl Deref for MutexGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for MutexGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.lock.data.get() } } } @@ -445,8 +443,8 @@ impl Drop for MutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { - self.__lock.poison.done(&self.__poison); - self.__lock.inner.raw_unlock(); + self.lock.poison.done(&self.poison); + self.lock.inner.raw_unlock(); } } } @@ -466,11 +464,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { - &guard.__lock.inner + &guard.lock.inner } pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { - &guard.__lock.poison + &guard.lock.poison } #[cfg(all(test, not(target_os = "emscripten")))] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index b1b56f321fc..c217291a42e 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -87,7 +87,7 @@ unsafe impl Sync for RwLock {} #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, + lock: &'a RwLock, } #[stable(feature = "rust1", since = "1.0.0")] @@ -108,8 +108,8 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} #[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - __lock: &'a RwLock, - __poison: poison::Guard, + lock: &'a RwLock, + poison: poison::Guard, } #[stable(feature = "rust1", since = "1.0.0")] @@ -465,7 +465,7 @@ unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { poison::map_result(lock.poison.borrow(), |_| { RwLockReadGuard { - __lock: lock, + lock: lock, } }) } @@ -476,8 +476,8 @@ unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| { RwLockWriteGuard { - __lock: lock, - __poison: guard, + lock: lock, + poison: guard, } }) } @@ -487,7 +487,7 @@ unsafe fn new(lock: &'rwlock RwLock) impl fmt::Debug for RwLockReadGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockReadGuard") - .field("lock", &self.__lock) + .field("lock", &self.lock) .finish() } } @@ -503,7 +503,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl fmt::Debug for RwLockWriteGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RwLockWriteGuard") - .field("lock", &self.__lock) + .field("lock", &self.lock) .finish() } } @@ -520,7 +520,7 @@ impl Deref for RwLockReadGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } @@ -529,29 +529,29 @@ impl Deref for RwLockWriteGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.__lock.data.get() } + unsafe { &*self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl DerefMut for RwLockWriteGuard<'_, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.lock.data.get() } } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for RwLockReadGuard<'_, T> { fn drop(&mut self) { - unsafe { self.__lock.inner.read_unlock(); } + unsafe { self.lock.inner.read_unlock(); } } } #[stable(feature = "rust1", since = "1.0.0")] impl Drop for RwLockWriteGuard<'_, T> { fn drop(&mut self) { - self.__lock.poison.done(&self.__poison); - unsafe { self.__lock.inner.write_unlock(); } + self.lock.poison.done(&self.poison); + unsafe { self.lock.inner.write_unlock(); } } } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index a94742634cf..36173801eae 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(const_fn)] #![feature(const_transmute)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4821bbd9ec6..b2e8d8526fd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -317,7 +317,7 @@ pub fn token_to_string(token: &Token) -> String { } fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { - let convert_dollar_crate = if convert_dollar_crate { Some(token.span) } else { None }; + let convert_dollar_crate = convert_dollar_crate.then_some(token.span); token_kind_to_string_ext(&token.kind, convert_dollar_crate) } diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs index 4127a8c7fce..efb3c2396c3 100644 --- a/src/libsyntax/util/lev_distance.rs +++ b/src/libsyntax/util/lev_distance.rs @@ -77,6 +77,6 @@ pub fn find_best_match_for_name<'a, T>(iter_names: T, if let Some(candidate) = case_insensitive_match { Some(candidate) // exact case insensitive match has a higher priority } else { - if let Some((candidate, _)) = levenstein_match { Some(candidate) } else { None } + levenstein_match.map(|(candidate, _)| candidate) } } diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 8e56e2bb00b..520488c6586 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -1,7 +1,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; -use syntax::ast::{self, ItemKind, MacArgs}; +use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; use syntax::errors::{Applicability, FatalError}; use syntax::symbol::sym; use syntax::token; @@ -171,34 +171,71 @@ fn expand(&self, if !attr.has_name(sym::derive) { return true; } - if !attr.is_meta_item_list() { - cx.struct_span_err(attr.span, "malformed `derive` attribute input") - .span_suggestion( - attr.span, - "missing traits to be derived", - "#[derive(Trait1, Trait2, ...)]".to_owned(), - Applicability::HasPlaceholders, - ).emit(); - return false; - } - let parse_derive_paths = |attr: &ast::Attribute| { - if let MacArgs::Empty = attr.get_normal_item().args { - return Ok(Vec::new()); + // 1) First let's ensure that it's a meta item. + let nmis = match attr.meta_item_list() { + None => { + cx.struct_span_err(attr.span, "malformed `derive` attribute input") + .span_suggestion( + attr.span, + "missing traits to be derived", + "#[derive(Trait1, Trait2, ...)]".to_owned(), + Applicability::HasPlaceholders, + ) + .emit(); + return false; } - rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) + Some(x) => x, }; - match parse_derive_paths(attr) { - Ok(traits) => { - result.extend(traits); - true - } - Err(mut e) => { - e.emit(); - false - } - } + let mut error_reported_filter_map = false; + let mut error_reported_map = false; + let traits = nmis + .into_iter() + // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`. + .filter_map(|nmi| match nmi { + NestedMetaItem::Literal(lit) => { + error_reported_filter_map = true; + cx.struct_span_err(lit.span, "expected path to a trait, found literal") + .help("for example, write `#[derive(Debug)]` for `Debug`") + .emit(); + None + } + NestedMetaItem::MetaItem(mi) => Some(mi), + }) + // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]` + // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`. + // In this case we can still at least determine that the user + // wanted this trait to be derived, so let's keep it. + .map(|mi| { + let mut traits_dont_accept = |title, action| { + error_reported_map = true; + let sp = mi.span.with_lo(mi.path.span.hi()); + cx.struct_span_err(sp, title) + .span_suggestion( + sp, + action, + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + }; + match &mi.kind { + MetaItemKind::List(..) => traits_dont_accept( + "traits in `#[derive(...)]` don't accept arguments", + "remove the arguments", + ), + MetaItemKind::NameValue(..) => traits_dont_accept( + "traits in `#[derive(...)]` don't accept values", + "remove the value", + ), + MetaItemKind::Word => {} + } + mi.path + }); + + result.extend(traits); + !error_reported_filter_map && !error_reported_map }); result } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index 3d4f8276441..0d1d2926c85 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -95,12 +95,12 @@ pub fn translate(&self) -> Option { }; // Has a special form in Rust for numbers. - let fill = if c_zero { Some("0") } else { None }; + let fill = c_zero.then_some("0"); - let align = if c_left { Some("<") } else { None }; + let align = c_left.then_some("<"); // Rust doesn't have an equivalent to the `' '` flag. - let sign = if c_plus { Some("+") } else { None }; + let sign = c_plus.then_some("+"); // Not *quite* the same, depending on the type... let alt = c_alt; diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index b9287d2fe70..55c7f3fa574 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -3,6 +3,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(nll)] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index c68e03be88c..e8f7a125739 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -213,6 +213,7 @@ const_indexing, const_in_array_repeat_expressions, const_let, + const_mut_refs, const_panic, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 7647978b3d9..0097558eae6 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -24,6 +24,7 @@ #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] #![feature(rustc_private)] #![feature(nll)] +#![feature(bool_to_option)] #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] @@ -562,11 +563,7 @@ fn run_test_in_process( None }; - let start = if report_time { - Some(Instant::now()) - } else { - None - }; + let start = report_time.then(Instant::now); let result = catch_unwind(AssertUnwindSafe(testfn)); let exec_time = start.map(|start| { let duration = start.elapsed(); @@ -597,11 +594,7 @@ fn spawn_test_subprocess( let args = env::args().collect::>(); let current_exe = &args[0]; - let start = if report_time { - Some(Instant::now()) - } else { - None - }; + let start = report_time.then(Instant::now); let output = match Command::new(current_exe) .env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice()) .output() { diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 1a4fc72e817..5d26059644d 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -6,7 +6,7 @@ const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { //~^ ERROR E0015 - //~| ERROR E0017 + //~| ERROR E0658 //~| ERROR E0080 //~| ERROR E0744 //~| ERROR E0019 diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed index 7c02a907ce7..1ec59d90620 100644 --- a/src/test/ui/async-await/suggest-missing-await.fixed +++ b/src/test/ui/async-await/suggest-missing-await.fixed @@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() { //~| SUGGESTION x.await } +async fn dummy() {} + +#[allow(unused)] +async fn suggest_await_in_async_fn_return() { + dummy().await; + //~^ ERROR mismatched types [E0308] + //~| HELP try adding a semicolon + //~| HELP consider using `.await` here + //~| SUGGESTION dummy().await +} + fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs index 91abd44e65c..70cc1f1d5a2 100644 --- a/src/test/ui/async-await/suggest-missing-await.rs +++ b/src/test/ui/async-await/suggest-missing-await.rs @@ -16,4 +16,15 @@ async fn suggest_await_in_async_fn() { //~| SUGGESTION x.await } +async fn dummy() {} + +#[allow(unused)] +async fn suggest_await_in_async_fn_return() { + dummy() + //~^ ERROR mismatched types [E0308] + //~| HELP try adding a semicolon + //~| HELP consider using `.await` here + //~| SUGGESTION dummy().await +} + fn main() {} diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 7a635a37107..7ab024434b2 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -10,6 +10,23 @@ LL | take_u32(x) = note: expected type `u32` found opaque type `impl std::future::Future` -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/suggest-missing-await.rs:23:5 + | +LL | dummy() + | ^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `impl std::future::Future` +help: try adding a semicolon + | +LL | dummy(); + | ^ +help: consider using `.await` here + | +LL | dummy().await + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr index 4f4bf16a0ff..39da824ede5 100644 --- a/src/test/ui/check-static-immutable-mut-slices.stderr +++ b/src/test/ui/check-static-immutable-mut-slices.stderr @@ -1,9 +1,12 @@ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/check-static-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut []; | ^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0017`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs index 93aef72220c..8ca31c11836 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-parse.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs @@ -1,11 +1,11 @@ // Parse `cfg_attr` with varying numbers of attributes and trailing commas // Completely empty `cfg_attr` input -#[cfg_attr()] //~ error: expected identifier, found `)` +#[cfg_attr()] //~ error: malformed `cfg_attr` attribute input struct NoConfigurationPredicate; // Zero attributes, zero trailing comma (comma manatory here) -#[cfg_attr(all())] //~ error: expected `,`, found `)` +#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr` struct A0C0; // Zero attributes, one trailing comma @@ -40,4 +40,16 @@ #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier struct A2C2; +// Wrong delimiter `[` +#[cfg_attr[all(),,]] +//~^ ERROR wrong `cfg_attr` delimiters +//~| ERROR expected identifier, found `,` +struct BracketZero; + +// Wrong delimiter `{` +#[cfg_attr{all(),,}] +//~^ ERROR wrong `cfg_attr` delimiters +//~| ERROR expected identifier, found `,` +struct BraceZero; + fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr index 3dfbd6df256..3a590d3282d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr @@ -1,32 +1,86 @@ -error: expected identifier, found `)` - --> $DIR/cfg-attr-parse.rs:4:12 +error: malformed `cfg_attr` attribute input + --> $DIR/cfg-attr-parse.rs:4:1 | LL | #[cfg_attr()] - | ^ expected identifier + | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | + = note: for more information, visit -error: expected `,`, found `)` +error: expected `,`, found end of `cfg_attr` input --> $DIR/cfg-attr-parse.rs:8:17 | LL | #[cfg_attr(all())] | ^ expected `,` + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:16:18 | LL | #[cfg_attr(all(),,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:28:28 | LL | #[cfg_attr(all(), must_use,,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:40:40 | LL | #[cfg_attr(all(), must_use, deprecated,,)] | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit + +error: wrong `cfg_attr` delimiters + --> $DIR/cfg-attr-parse.rs:44:11 + | +LL | #[cfg_attr[all(),,]] + | ^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[cfg_attr(all(),,)] + | ^ ^ + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:44:18 + | +LL | #[cfg_attr[all(),,]] + | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit + +error: wrong `cfg_attr` delimiters + --> $DIR/cfg-attr-parse.rs:50:11 + | +LL | #[cfg_attr{all(),,}] + | ^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[cfg_attr(all(),,)] + | ^ ^ + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:50:18 + | +LL | #[cfg_attr{all(),,}] + | ^ expected identifier + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index acf5cbaede6..54b35073340 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-65394.rs:8:13 | LL | let r = &mut x; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/issue-65394.rs:7:9 @@ -12,5 +15,5 @@ LL | let mut x = Vec::::new(); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0493. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0493, E0658. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index ed3837e9c9e..0809c77c1b6 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const-multi-ref.rs:6:13 | LL | let p = &mut a; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/const-multi-ref.rs:16:13 @@ -12,5 +15,5 @@ LL | let p = &a; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0492. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0492, E0658. +For more information about an error, try `rustc --explain E0492`. diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs new file mode 100644 index 00000000000..99006a20b1b --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -0,0 +1,36 @@ +// run-pass + +#![feature(const_mut_refs)] + +struct Foo { + x: usize +} + +const fn foo() -> Foo { + Foo { x: 0 } +} + +impl Foo { + const fn bar(&mut self) -> usize { + self.x = 1; + self.x + } + +} + +const fn baz(foo: &mut Foo) -> usize { + let x = &mut foo.x; + *x = 2; + *x +} + +const fn bazz(foo: &mut Foo) -> usize { + foo.x = 3; + foo.x +} + +fn main() { + let _: [(); foo().bar()] = [(); 1]; + let _: [(); baz(&mut foo())] = [(); 2]; + let _: [(); bazz(&mut foo())] = [(); 3]; +} diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs new file mode 100644 index 00000000000..2207599815e --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -0,0 +1,7 @@ +fn main() { + foo(&mut 5); +} + +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable + *x + 1 +} diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr new file mode 100644 index 00000000000..4fae119f026 --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -0,0 +1,12 @@ +error[E0723]: mutable references in const fn are unstable + --> $DIR/feature-gate-const_mut_refs.rs:5:14 + | +LL | const fn foo(x: &mut i32) -> i32 { + | ^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 53b960b4ec0..7852874944b 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -4,17 +4,23 @@ error[E0019]: constant function contains unimplemented expression type LL | self.state = x; | ^^^^^^^^^^^^^^ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:16:5 | LL | s.foo(3); | ^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:22:13 | LL | let y = &mut x; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: constant contains unimplemented expression type --> $DIR/const_let_assign3.rs:24:5 @@ -24,5 +30,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0017, E0019. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs index 44b40849467..972f59549ea 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs @@ -1,6 +1,7 @@ // compile-flags: -Zunleash-the-miri-inside-of-you #![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] #![deny(const_err)] use std::cell::UnsafeCell; @@ -12,9 +13,7 @@ const MUTATING_BEHIND_RAW: () = { // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. unsafe { - *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks - //~^ ERROR any use of this value will cause an error - //~^^ tried to modify constant memory + *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error } }; diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr index 757f0ffb59f..9daca765c7c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -1,30 +1,23 @@ warning: skipping const checks - --> $DIR/mutable_const.rs:9:38 + --> $DIR/mutable_const.rs:10:38 | LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ -warning: skipping const checks - --> $DIR/mutable_const.rs:15:9 - | -LL | *MUTABLE_BEHIND_RAW = 99 - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error: any use of this value will cause an error - --> $DIR/mutable_const.rs:15:9 + --> $DIR/mutable_const.rs:16:9 | LL | / const MUTATING_BEHIND_RAW: () = { LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. LL | | unsafe { LL | | *MUTABLE_BEHIND_RAW = 99 | | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory -... | LL | | } LL | | }; | |__- | note: lint level defined here - --> $DIR/mutable_const.rs:4:9 + --> $DIR/mutable_const.rs:5:9 | LL | #![deny(const_err)] | ^^^^^^^^^ diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs index 59dafcbf4d5..fe3c4ee70f2 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs @@ -1,20 +1,22 @@ // compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_mut_refs)] #![allow(const_err)] use std::cell::UnsafeCell; // a test demonstrating what things we could allow with a smarter const qualification +// this is fine because is not possible to mutate through an immutable reference. static FOO: &&mut u32 = &&mut 42; -//~^ WARN: skipping const checks +// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR` +// which puts the mutable reference behind an immutable one. static BAR: &mut () = &mut (); -//~^ WARN: skipping const checks struct Foo(T); +// this is fine for the same reason as `BAR`. static BOO: &mut Foo<()> = &mut Foo(()); -//~^ WARN: skipping const checks struct Meh { x: &'static UnsafeCell, @@ -27,8 +29,8 @@ unsafe impl Sync for Meh {} //~^ WARN: skipping const checks }; +// this is fine for the same reason as `BAR`. static OH_YES: &mut i32 = &mut 42; -//~^ WARN: skipping const checks fn main() { unsafe { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index b9c0af33c39..3e1300c63c1 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,35 +1,11 @@ warning: skipping const checks - --> $DIR/mutable_references.rs:8:26 - | -LL | static FOO: &&mut u32 = &&mut 42; - | ^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:11:23 - | -LL | static BAR: &mut () = &mut (); - | ^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:16:28 - | -LL | static BOO: &mut Foo<()> = &mut Foo(()); - | ^^^^^^^^^^^^ - -warning: skipping const checks - --> $DIR/mutable_references.rs:26:8 + --> $DIR/mutable_references.rs:28:8 | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -warning: skipping const checks - --> $DIR/mutable_references.rs:30:27 - | -LL | static OH_YES: &mut i32 = &mut 42; - | ^^^^^^^ - error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:37:5 + --> $DIR/mutable_references.rs:39:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign diff --git a/src/test/ui/consts/miri_unleashed/read_from_static.rs b/src/test/ui/consts/miri_unleashed/read_from_static.rs new file mode 100644 index 00000000000..821c501c9fc --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/read_from_static.rs @@ -0,0 +1,11 @@ +// run-pass +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(const_mut_refs)] +#![allow(const_err)] + +static OH_YES: &mut i32 = &mut 42; + +fn main() { + // Make sure `OH_YES` can be read. + assert_eq!(*OH_YES, 42); +} diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr new file mode 100644 index 00000000000..23538777c9d --- /dev/null +++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr @@ -0,0 +1,12 @@ +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index dedb7db5920..cfe8e7f03d5 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -1,11 +1,15 @@ +// revisions: stock mut_refs + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + use std::cell::Cell; const FOO: &u32 = { let mut a = 42; { - let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values + let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants - //~^ contains unimplemented expression + //[stock]~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr deleted file mode 100644 index 0efb6bfd10a..00000000000 --- a/src/test/ui/consts/projection_qualif.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0017]: references in constants may only refer to immutable values - --> $DIR/projection_qualif.rs:6:27 - | -LL | let b: *mut u32 = &mut a; - | ^^^^^^ constants require immutable values - -error[E0658]: dereferencing raw pointers in constants is unstable - --> $DIR/projection_qualif.rs:7:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/51911 - = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable - -error[E0019]: constant contains unimplemented expression type - --> $DIR/projection_qualif.rs:7:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0017, E0019, E0658. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr new file mode 100644 index 00000000000..472d2607453 --- /dev/null +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -0,0 +1,28 @@ +error[E0658]: references in constants may only refer to immutable values + --> $DIR/projection_qualif.rs:10:27 + | +LL | let b: *mut u32 = &mut a; + | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error[E0019]: constant contains unimplemented expression type + --> $DIR/projection_qualif.rs:11:18 + | +LL | unsafe { *b = 5; } + | ^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr new file mode 100644 index 00000000000..b43fbc86f99 --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -0,0 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index ef378fa8451..74162fbd54b 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -1,7 +1,12 @@ +// revisions: stock mut_refs + +#![cfg_attr(mut_refs, feature(const_mut_refs))] + static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//~^ ERROR references in statics may only refer to immutable values -//~| ERROR static contains unimplemented expression type +//[mut_refs]~^ ERROR could not evaluate static initializer +//[stock]~^^ ERROR references in statics may only refer to immutable values +//[stock]~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr deleted file mode 100644 index ca691b07be0..00000000000 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0017]: references in statics may only refer to immutable values - --> $DIR/static_mut_containing_mut_ref2.rs:3:46 - | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values - -error[E0019]: static contains unimplemented expression type - --> $DIR/static_mut_containing_mut_ref2.rs:3:45 - | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0017, E0019. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr new file mode 100644 index 00000000000..430cef94dc3 --- /dev/null +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -0,0 +1,19 @@ +error[E0658]: references in statics may only refer to immutable values + --> $DIR/static_mut_containing_mut_ref2.rs:7:46 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0019]: static contains unimplemented expression type + --> $DIR/static_mut_containing_mut_ref2.rs:7:45 + | +LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/enum/union-in-enum.rs b/src/test/ui/enum/union-in-enum.rs new file mode 100644 index 00000000000..048913e25cd --- /dev/null +++ b/src/test/ui/enum/union-in-enum.rs @@ -0,0 +1,13 @@ +// This test checks that the union keyword +// is accepted as the name of an enum variant +// when not followed by an identifier +// This special case exists because `union` is a contextual keyword. + +#![allow(warnings)] + +// check-pass + +enum A { union } +enum B { union {} } +enum C { union() } +fn main(){} diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 3bc518c2c2b..64be41170d0 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -2,10 +2,10 @@ const C: i32 = 2; static mut M: i32 = 3; -const CR: &'static mut i32 = &mut C; //~ ERROR E0017 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 +const CR: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 //~| ERROR E0019 //~| ERROR cannot borrow -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 -static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0017 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 8c8660adceb..9a87195a9d0 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0019]: static contains unimplemented expression type --> $DIR/E0017.rs:6:39 @@ -10,11 +13,14 @@ error[E0019]: static contains unimplemented expression type LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:6:39 @@ -22,19 +28,25 @@ error[E0596]: cannot borrow immutable static item `X` as mutable LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:10:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 6 previous errors -Some errors have detailed explanations: E0017, E0019, E0596. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0019, E0596, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs new file mode 100644 index 00000000000..5954e3490b0 --- /dev/null +++ b/src/test/ui/error-codes/E0388.rs @@ -0,0 +1,10 @@ +static X: i32 = 1; +const C: i32 = 2; + +const CR: &'static mut i32 = &mut C; //~ ERROR E0658 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 + //~| ERROR cannot borrow + //~| ERROR E0019 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 + +fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr new file mode 100644 index 00000000000..986307d3f12 --- /dev/null +++ b/src/test/ui/error-codes/E0388.stderr @@ -0,0 +1,43 @@ +error[E0658]: references in constants may only refer to immutable values + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0019]: static contains unimplemented expression type + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ + +error[E0658]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/E0388.rs:5:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ cannot borrow as mutable + +error[E0658]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:8:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0019, E0596, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr index b388f38a7fa..ca61fb0c171 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr @@ -4,7 +4,10 @@ error[E0308]: mismatched types LL | fn bar(x: usize) -> Option { | ------------- expected `std::option::Option` because of return type LL | return x; - | ^ expected enum `std::option::Option`, found `usize` + | ^ + | | + | expected enum `std::option::Option`, found `usize` + | help: try using a variant of the expected enum: `Some(x)` | = note: expected enum `std::option::Option` found type `usize` diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr index 8d875d37d85..7e4a62ac969 100644 --- a/src/test/ui/issues/issue-17718-const-bad-values.stderr +++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-17718-const-bad-values.rs:1:34 | LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0013]: constants cannot refer to statics, use a constant instead --> $DIR/issue-17718-const-bad-values.rs:5:46 @@ -10,13 +13,16 @@ error[E0013]: constants cannot refer to statics, use a constant instead LL | const C2: &'static mut usize = unsafe { &mut S }; | ^ -error[E0017]: references in constants may only refer to immutable values +error[E0658]: references in constants may only refer to immutable values --> $DIR/issue-17718-const-bad-values.rs:5:41 | LL | const C2: &'static mut usize = unsafe { &mut S }; | ^^^^^^ constants require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 3 previous errors -Some errors have detailed explanations: E0013, E0017. +Some errors have detailed explanations: E0013, E0658. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs index 4f1ad38dbdd..e1967eb7655 100644 --- a/src/test/ui/issues/issue-46604.rs +++ b/src/test/ui/issues/issue-46604.rs @@ -1,4 +1,4 @@ -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0017 +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658 fn write>(buffer: T) { } fn main() { diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr index c72f580f243..32c7ecbf72e 100644 --- a/src/test/ui/issues/issue-46604.stderr +++ b/src/test/ui/issues/issue-46604.stderr @@ -1,8 +1,11 @@ -error[E0017]: references in statics may only refer to immutable values +error[E0658]: references in statics may only refer to immutable values --> $DIR/issue-46604.rs:1:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values + | + = note: for more information, see https://github.com/rust-lang/rust/issues/57349 + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:6:5 @@ -12,5 +15,5 @@ LL | buf[0]=2; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0017, E0594. -For more information about an error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0594, E0658. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index aef6dc54747..9ca983df30a 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? - | ^^^^^^^^^^^^^^^^^^^^- - | | | - | | help: try removing this `?` - | expected enum `std::result::Result`, found `isize` + | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize` | = note: expected enum `std::result::Result` found type `isize` +help: try removing this `?` + | +LL | missing_discourses() + | -- +help: try using a variant of the expected enum + | +LL | Ok(missing_discourses()?) + | error: aborting due to previous error diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs index cccae396b72..d6df0592be3 100644 --- a/src/test/ui/issues/issue-59756.rs +++ b/src/test/ui/issues/issue-59756.rs @@ -1,4 +1,8 @@ // run-rustfix +// ignore-test +// +// FIXME: Re-enable this test once we support choosing +// between multiple mutually exclusive suggestions for the same span #![allow(warnings)] diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr index 150916c0366..9066e57aabf 100644 --- a/src/test/ui/issues/issue-59756.stderr +++ b/src/test/ui/issues/issue-59756.stderr @@ -2,13 +2,18 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-59756.rs:13:5 | LL | foo()? - | ^^^^^- - | | | - | | help: try removing this `?` - | expected enum `std::result::Result`, found struct `A` + | ^^^^^^ expected enum `std::result::Result`, found struct `A` | = note: expected enum `std::result::Result` found struct `A` +help: try removing this `?` + | +LL | foo() + | -- +help: try using a variant of the expected enum + | +LL | Ok(foo()?) + | error: aborting due to previous error diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs index a6d886318e8..77fa2f566a8 100644 --- a/src/test/ui/malformed/malformed-derive-entry.rs +++ b/src/test/ui/malformed/malformed-derive-entry.rs @@ -1,7 +1,11 @@ -#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(` +#[derive(Copy(Bad))] +//~^ ERROR traits in `#[derive(...)]` don't accept arguments +//~| ERROR the trait bound struct Test1; -#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=` +#[derive(Copy="bad")] +//~^ ERROR traits in `#[derive(...)]` don't accept values +//~| ERROR the trait bound struct Test2; #[derive] //~ ERROR malformed `derive` attribute input diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index 8d750b66838..1f1ee39b049 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -1,20 +1,33 @@ -error: expected one of `)`, `,`, or `::`, found `(` +error: traits in `#[derive(...)]` don't accept arguments --> $DIR/malformed-derive-entry.rs:1:14 | LL | #[derive(Copy(Bad))] - | ^ expected one of `)`, `,`, or `::` + | ^^^^^ help: remove the arguments -error: expected one of `)`, `,`, or `::`, found `=` - --> $DIR/malformed-derive-entry.rs:4:14 +error: traits in `#[derive(...)]` don't accept values + --> $DIR/malformed-derive-entry.rs:6:14 | LL | #[derive(Copy="bad")] - | ^ expected one of `)`, `,`, or `::` + | ^^^^^^ help: remove the value error: malformed `derive` attribute input - --> $DIR/malformed-derive-entry.rs:7:1 + --> $DIR/malformed-derive-entry.rs:11:1 | LL | #[derive] | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` -error: aborting due to 3 previous errors +error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied + --> $DIR/malformed-derive-entry.rs:1:10 + | +LL | #[derive(Copy(Bad))] + | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1` + +error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied + --> $DIR/malformed-derive-entry.rs:6:10 + | +LL | #[derive(Copy="bad")] + | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2` + +error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/malformed/malformed-meta-delim.rs b/src/test/ui/malformed/malformed-meta-delim.rs new file mode 100644 index 00000000000..5b1614b69a9 --- /dev/null +++ b/src/test/ui/malformed/malformed-meta-delim.rs @@ -0,0 +1,11 @@ +fn main() {} + +#[allow { foo_lint } ] +//~^ ERROR wrong meta list delimiters +//~| HELP the delimiters should be `(` and `)` +fn delim_brace() {} + +#[allow [ foo_lint ] ] +//~^ ERROR wrong meta list delimiters +//~| HELP the delimiters should be `(` and `)` +fn delim_bracket() {} diff --git a/src/test/ui/malformed/malformed-meta-delim.stderr b/src/test/ui/malformed/malformed-meta-delim.stderr new file mode 100644 index 00000000000..407193d4ade --- /dev/null +++ b/src/test/ui/malformed/malformed-meta-delim.stderr @@ -0,0 +1,24 @@ +error: wrong meta list delimiters + --> $DIR/malformed-meta-delim.rs:3:9 + | +LL | #[allow { foo_lint } ] + | ^^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[allow ( foo_lint ) ] + | ^ ^ + +error: wrong meta list delimiters + --> $DIR/malformed-meta-delim.rs:8:9 + | +LL | #[allow [ foo_lint ] ] + | ^^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL | #[allow ( foo_lint ) ] + | ^ ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs index e67fbdd5ddd..05b7ebe4666 100644 --- a/src/test/ui/malformed/malformed-special-attrs.rs +++ b/src/test/ui/malformed/malformed-special-attrs.rs @@ -1,7 +1,7 @@ #[cfg_attr] //~ ERROR malformed `cfg_attr` attribute struct S1; -#[cfg_attr = ""] //~ ERROR expected `(`, found `=` +#[cfg_attr = ""] //~ ERROR malformed `cfg_attr` attribute struct S2; #[derive] //~ ERROR malformed `derive` attribute diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr index 319c05eadbf..6f535e03e6a 100644 --- a/src/test/ui/malformed/malformed-special-attrs.stderr +++ b/src/test/ui/malformed/malformed-special-attrs.stderr @@ -6,11 +6,13 @@ LL | #[cfg_attr] | = note: for more information, visit -error: expected `(`, found `=` - --> $DIR/malformed-special-attrs.rs:4:12 +error: malformed `cfg_attr` attribute input + --> $DIR/malformed-special-attrs.rs:4:1 | LL | #[cfg_attr = ""] - | ^ expected `(` + | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]` + | + = note: for more information, visit error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c2081878629..c73130643db 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -26,7 +26,10 @@ error[E0308]: mismatched types LL | fn b() -> Option { | ----------- expected `std::option::Option` because of return type LL | Foo { bar: 1 } - | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo` + | ^^^^^^^^^^^^^^ + | | + | expected enum `std::option::Option`, found struct `Foo` + | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })` | = note: expected enum `std::option::Option` found struct `Foo` @@ -37,7 +40,10 @@ error[E0308]: mismatched types LL | fn c() -> Result { | ---------------- expected `std::result::Result` because of return type LL | Foo { bar: 1 } - | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo` + | ^^^^^^^^^^^^^^ + | | + | expected enum `std::result::Result`, found struct `Foo` + | help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })` | = note: expected enum `std::result::Result` found struct `Foo` diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.rs b/src/test/ui/on-unimplemented/expected-comma-found-token.rs index 77c0ea17269..8fb34f21152 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.rs +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.rs @@ -6,7 +6,7 @@ #[rustc_on_unimplemented( message="the message" - label="the label" //~ ERROR expected one of `)` or `,`, found `label` + label="the label" //~ ERROR expected `,`, found `label` )] trait T {} diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr index 2e1d484e05a..048b72ee3bc 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr @@ -1,11 +1,8 @@ -error: expected one of `)` or `,`, found `label` +error: expected `,`, found `label` --> $DIR/expected-comma-found-token.rs:9:5 | LL | message="the message" - | - - | | - | expected one of `)` or `,` - | help: missing `,` + | - expected `,` LL | label="the label" | ^^^^^ unexpected token diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index cd6f0ea10ea..a77e92022e2 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -14,6 +14,11 @@ LL | fn b(x: Option) -> usize { LL | match x { LL | Some(x) => { return x }, | ^ expected `usize`, found `isize` + | +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | Some(x) => { return x.try_into().unwrap() }, + | ^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/span-preservation.rs:33:22 diff --git a/src/test/ui/span/macro-ty-params.rs b/src/test/ui/span/macro-ty-params.rs index b077d590915..713b9eb542c 100644 --- a/src/test/ui/span/macro-ty-params.rs +++ b/src/test/ui/span/macro-ty-params.rs @@ -10,5 +10,4 @@ fn main() { foo::!(); //~ ERROR generic arguments in macro path foo::<>!(); //~ ERROR generic arguments in macro path m!(Default<>); //~ ERROR generic arguments in macro path - //~^ ERROR unexpected generic arguments in path } diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr index 39b3edc6703..21683b2fb86 100644 --- a/src/test/ui/span/macro-ty-params.stderr +++ b/src/test/ui/span/macro-ty-params.stderr @@ -10,17 +10,11 @@ error: generic arguments in macro path LL | foo::<>!(); | ^^ -error: unexpected generic arguments in path - --> $DIR/macro-ty-params.rs:12:8 - | -LL | m!(Default<>); - | ^^^^^^^^^ - error: generic arguments in macro path --> $DIR/macro-ty-params.rs:12:15 | LL | m!(Default<>); | ^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index eeeb258da21..69f8ffa581b 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -5,6 +5,11 @@ LL | fn f() -> isize { return g(); } | ----- ^^^ expected `isize`, found `usize` | | | expected `isize` because of return type + | +help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit + | +LL | fn f() -> isize { return g().try_into().unwrap(); } + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index 440620f40b1..c1274bd0ea6 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -5,6 +5,11 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; } | ----- ^ expected `usize`, found `isize` | | | expected `usize` because of return type + | +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error