]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #67102 - Aaron1011:patch-3, r=Mark-Simulacrum
authorMazdak Farrokhzad <twingoow@gmail.com>
Fri, 6 Dec 2019 22:27:08 +0000 (23:27 +0100)
committerGitHub <noreply@github.com>
Fri, 6 Dec 2019 22:27:08 +0000 (23:27 +0100)
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.

134 files changed:
src/libcore/alloc.rs
src/libcore/bool.rs
src/libcore/convert.rs [deleted file]
src/libcore/convert/mod.rs [new file with mode: 0644]
src/libcore/convert/num.rs [new file with mode: 0644]
src/libcore/intrinsics.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/num/mod.rs
src/libcore/tests/bool.rs
src/libfmt_macros/lib.rs
src/librustc/hir/map/blocks.rs
src/librustc/infer/outlives/verify.rs
src/librustc/lib.rs
src/librustc/mir/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/ty/mod.rs
src/librustc/ty/query/job.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_llvm/common.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/lib.rs
src/librustc_codegen_ssa/back/rpath.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/lib.rs
src/librustc_error_codes/error_codes.rs
src/librustc_error_codes/error_codes/E0017.md [deleted file]
src/librustc_feature/active.rs
src/librustc_interface/lib.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_interface/util.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/lib.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/step.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/transform/check_consts/ops.rs
src/librustc_mir/transform/check_consts/validation.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_mir/transform/uninhabited_enum_branching.rs
src/librustc_parse/config.rs
src/librustc_parse/lib.rs
src/librustc_parse/parser/attr.rs
src/librustc_parse/parser/item.rs
src/librustc_parse/parser/path.rs
src/librustc_parse/validate_attr.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/late.rs
src/librustc_resolve/lib.rs
src/librustc_session/session.rs
src/librustc_target/abi/call/aarch64.rs
src/librustc_target/abi/call/arm.rs
src/librustc_target/abi/call/mod.rs
src/librustc_target/abi/call/powerpc64.rs
src/librustc_target/abi/call/sparc64.rs
src/librustc_target/lib.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/lib.rs
src/libstd/sync/mutex.rs
src/libstd/sync/rwlock.rs
src/libsyntax/lib.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/lev_distance.rs
src/libsyntax_expand/proc_macro.rs
src/libsyntax_ext/format_foreign.rs
src/libsyntax_ext/lib.rs
src/libsyntax_pos/symbol.rs
src/libtest/lib.rs
src/test/compile-fail/consts/const-fn-error.rs
src/test/ui/async-await/suggest-missing-await.fixed
src/test/ui/async-await/suggest-missing-await.rs
src/test/ui/async-await/suggest-missing-await.stderr
src/test/ui/check-static-immutable-mut-slices.stderr
src/test/ui/conditional-compilation/cfg-attr-parse.rs
src/test/ui/conditional-compilation/cfg-attr-parse.stderr
src/test/ui/consts/const-eval/issue-65394.stderr
src/test/ui/consts/const-multi-ref.stderr
src/test/ui/consts/const-mut-refs/const_mut_refs.rs [new file with mode: 0644]
src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs [new file with mode: 0644]
src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr [new file with mode: 0644]
src/test/ui/consts/const_let_assign3.stderr
src/test/ui/consts/miri_unleashed/mutable_const.rs
src/test/ui/consts/miri_unleashed/mutable_const.stderr
src/test/ui/consts/miri_unleashed/mutable_references.rs
src/test/ui/consts/miri_unleashed/mutable_references.stderr
src/test/ui/consts/miri_unleashed/read_from_static.rs [new file with mode: 0644]
src/test/ui/consts/projection_qualif.mut_refs.stderr [new file with mode: 0644]
src/test/ui/consts/projection_qualif.rs
src/test/ui/consts/projection_qualif.stderr [deleted file]
src/test/ui/consts/projection_qualif.stock.stderr [new file with mode: 0644]
src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr [new file with mode: 0644]
src/test/ui/consts/static_mut_containing_mut_ref2.rs
src/test/ui/consts/static_mut_containing_mut_ref2.stderr [deleted file]
src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr [new file with mode: 0644]
src/test/ui/enum/union-in-enum.rs [new file with mode: 0644]
src/test/ui/error-codes/E0017.rs
src/test/ui/error-codes/E0017.stderr
src/test/ui/error-codes/E0388.rs [new file with mode: 0644]
src/test/ui/error-codes/E0388.stderr [new file with mode: 0644]
src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
src/test/ui/issues/issue-17718-const-bad-values.stderr
src/test/ui/issues/issue-46604.rs
src/test/ui/issues/issue-46604.stderr
src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
src/test/ui/issues/issue-59756.rs
src/test/ui/issues/issue-59756.stderr
src/test/ui/malformed/malformed-derive-entry.rs
src/test/ui/malformed/malformed-derive-entry.stderr
src/test/ui/malformed/malformed-meta-delim.rs [new file with mode: 0644]
src/test/ui/malformed/malformed-meta-delim.stderr [new file with mode: 0644]
src/test/ui/malformed/malformed-special-attrs.rs
src/test/ui/malformed/malformed-special-attrs.stderr
src/test/ui/mismatched_types/abridged.stderr
src/test/ui/on-unimplemented/expected-comma-found-token.rs
src/test/ui/on-unimplemented/expected-comma-found-token.stderr
src/test/ui/proc-macro/span-preservation.stderr
src/test/ui/span/macro-ty-params.rs
src/test/ui/span/macro-ty-params.stderr
src/test/ui/tail-typeck.stderr
src/test/ui/wrong-ret-type.stderr

index 4798769823f436b254a57b097ef0ea8a15199821..20248f7f6c13e374e471f423a37b48ef14556f24 100644 (file)
@@ -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<T>() -> Self {
     #[inline]
     pub fn for_value<T: ?Sized>(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`.
index 617bdd238f4c63d4660628b84cf5e4d5a140af6a..1b3c254a05f98126a3ff6b0a47ed1b407dba3671 100644 (file)
@@ -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<T>(self, t: T) -> Option<T> {
+    pub fn then_some<T>(self, t: T) -> Option<T> {
         if self {
             Some(t)
         } else {
@@ -29,12 +29,12 @@ pub fn then<T>(self, t: T) -> Option<T> {
     /// ```
     /// #![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, F: FnOnce() -> T>(self, f: F) -> Option<T> {
+    pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
         if self {
             Some(f())
         } else {
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
deleted file mode 100644 (file)
index 08802b3..0000000
+++ /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<T>`][`From`] or
-//! [`TryFrom<T>`][`TryFrom`] rather than [`Into<U>`][`Into`] or [`TryInto<U>`][`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`]`<U> for T` implies [`Into`]`<T> for U`
-//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> 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<T>`:
-///
-/// ```rust
-/// use std::convert::identity;
-///
-/// let iter = vec![Some(1), None, Some(3)].into_iter();
-/// let filtered = iter.filter_map(identity).collect::<Vec<_>>();
-/// assert_eq!(vec![1, 3], filtered);
-/// ```
-#[stable(feature = "convert_id", since = "1.33.0")]
-#[inline]
-pub const fn identity<T>(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<T>`] or a [`Result<T, E>`].
-///
-/// # 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<str>` 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<str>` we can accept both as input argument.
-///
-/// [`Option<T>`]: ../../std/option/enum.Option.html
-/// [`Result<T, E>`]: ../../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<T: AsRef<str>>(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<T: ?Sized> {
-    /// 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<T>`] or a [`Result<T, E>`].
-///
-/// [`Option<T>`]: ../../std/option/enum.Option.html
-/// [`Result<T, E>`]: ../../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<T>`] implements `AsMut<T>` we can
-/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
-/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
-/// `&mut Box<u64>` as well:
-///
-/// ```
-/// fn add_one<T: AsMut<u64>>(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<T>`]: ../../std/boxed/struct.Box.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait AsMut<T: ?Sized> {
-    /// 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`]`<T> for U` implies `Into<U> for T`
-/// - [`Into`] is reflexive, which means that `Into<T> 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<T>(Vec<T>);
-/// impl<T> From<Wrapper<T>> for Vec<T> {
-///     fn from(w: Wrapper<T>) -> Vec<T> {
-///         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<T>(Vec<T>);
-/// impl<T> Into<Vec<T>> for Wrapper<T> {
-///     fn into(self) -> Vec<T> {
-///         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`]`<T>`.
-/// For example: The function `is_hello` takes all arguments that can be converted into a
-/// [`Vec`]`<`[`u8`]`>`.
-///
-/// ```
-/// fn is_hello<T: Into<Vec<u8>>>(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<T>`]: ../../std/option/enum.Option.html
-/// [`Result<T, E>`]: ../../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<T>: 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<T, E>`.
-/// 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<T> for U` implies [`Into`]`<U> for T`
-/// - `From` is reflexive, which means that `From<T> 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<CliError>::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<io::Error> for CliError {
-///     fn from(error: io::Error) -> Self {
-///         CliError::IoError(error)
-///     }
-/// }
-///
-/// impl From<num::ParseIntError> for CliError {
-///     fn from(error: num::ParseIntError) -> Self {
-///         CliError::ParseError(error)
-///     }
-/// }
-///
-/// fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
-///     let mut contents = fs::read_to_string(&file_name)?;
-///     let num: i32 = contents.trim().parse()?;
-///     Ok(num)
-/// }
-/// ```
-///
-/// [`TryFrom`]: trait.TryFrom.html
-/// [`Option<T>`]: ../../std/option/enum.Option.html
-/// [`Result<T, E>`]: ../../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<T>: 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<T>: 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<T, Self::Error>;
-}
-
-/// 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<T> for U` implies [`TryInto`]`<U> for T`
-/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
-/// is implemented and cannot fail -- the associated `Error` type for
-/// calling `T::try_from()` on a value of type `T` is [`!`].
-///
-/// `TryFrom<T>` can be implemented as follows:
-///
-/// ```
-/// use std::convert::TryFrom;
-///
-/// struct GreaterThanZero(i32);
-///
-/// impl TryFrom<i32> for GreaterThanZero {
-///     type Error = &'static str;
-///
-///     fn try_from(value: i32) -> Result<Self, Self::Error> {
-///         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<T>: 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<Self, Self::Error>;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// GENERIC IMPLS
-////////////////////////////////////////////////////////////////////////////////
-
-// As lifts over &
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
-where
-    T: AsRef<U>,
-{
-    fn as_ref(&self) -> &U {
-        <T as AsRef<U>>::as_ref(*self)
-    }
-}
-
-// As lifts over &mut
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
-where
-    T: AsRef<U>,
-{
-    fn as_ref(&self) -> &U {
-        <T as AsRef<U>>::as_ref(*self)
-    }
-}
-
-// FIXME (#45742): replace the above impls for &/&mut with the following more general one:
-// // As lifts over Deref
-// impl<D: ?Sized + Deref<Target: AsRef<U>>, U: ?Sized> AsRef<U> for D {
-//     fn as_ref(&self) -> &U {
-//         self.deref().as_ref()
-//     }
-// }
-
-// AsMut lifts over &mut
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
-where
-    T: AsMut<U>,
-{
-    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<D: ?Sized + Deref<Target: AsMut<U>>, U: ?Sized> AsMut<U> 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<T, U> Into<U> for T
-where
-    U: From<T>,
-{
-    fn into(self) -> U {
-        U::from(self)
-    }
-}
-
-// From (and thus Into) is reflexive
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> From<T> 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<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
-impl<T> From<!> for T {
-    fn from(t: !) -> T {
-        t
-    }
-}
-
-// TryFrom implies TryInto
-#[stable(feature = "try_from", since = "1.34.0")]
-impl<T, U> TryInto<U> for T
-where
-    U: TryFrom<T>,
-{
-    type Error = U::Error;
-
-    fn try_into(self) -> Result<U, U::Error> {
-        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<T, U> TryFrom<U> for T
-where
-    U: Into<T>,
-{
-    type Error = Infallible;
-
-    fn try_from(value: U) -> Result<Self, Self::Error> {
-        Ok(U::into(value))
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CONCRETE IMPLS
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> AsRef<[T]> for [T] {
-    fn as_ref(&self) -> &[T] {
-        self
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> AsMut<[T]> for [T] {
-    fn as_mut(&mut self) -> &mut [T] {
-        self
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRef<str> 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<T, U> TryFrom<U> for T where U: Into<T> {
-///     type Error = Infallible;
-///
-///     fn try_from(value: U) -> Result<Self, Infallible> {
-///         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 (file)
index 0000000..16d5375
--- /dev/null
@@ -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<T>`][`From`] or
+//! [`TryFrom<T>`][`TryFrom`] rather than [`Into<U>`][`Into`] or [`TryInto<U>`][`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`]`<U> for T` implies [`Into`]`<T> for U`
+//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> 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<T>`:
+///
+/// ```rust
+/// use std::convert::identity;
+///
+/// let iter = vec![Some(1), None, Some(3)].into_iter();
+/// let filtered = iter.filter_map(identity).collect::<Vec<_>>();
+/// assert_eq!(vec![1, 3], filtered);
+/// ```
+#[stable(feature = "convert_id", since = "1.33.0")]
+#[inline]
+pub const fn identity<T>(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<T>`] or a [`Result<T, E>`].
+///
+/// # 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<str>` 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<str>` we can accept both as input argument.
+///
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../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<T: AsRef<str>>(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<T: ?Sized> {
+    /// 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<T>`] or a [`Result<T, E>`].
+///
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../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<T>`] implements `AsMut<T>` we can
+/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
+/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
+/// `&mut Box<u64>` as well:
+///
+/// ```
+/// fn add_one<T: AsMut<u64>>(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<T>`]: ../../std/boxed/struct.Box.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsMut<T: ?Sized> {
+    /// 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`]`<T> for U` implies `Into<U> for T`
+/// - [`Into`] is reflexive, which means that `Into<T> 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<T>(Vec<T>);
+/// impl<T> From<Wrapper<T>> for Vec<T> {
+///     fn from(w: Wrapper<T>) -> Vec<T> {
+///         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<T>(Vec<T>);
+/// impl<T> Into<Vec<T>> for Wrapper<T> {
+///     fn into(self) -> Vec<T> {
+///         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`]`<T>`.
+/// For example: The function `is_hello` takes all arguments that can be converted into a
+/// [`Vec`]`<`[`u8`]`>`.
+///
+/// ```
+/// fn is_hello<T: Into<Vec<u8>>>(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<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../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<T>: 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<T, E>`.
+/// 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<T> for U` implies [`Into`]`<U> for T`
+/// - `From` is reflexive, which means that `From<T> 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<CliError>::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<io::Error> for CliError {
+///     fn from(error: io::Error) -> Self {
+///         CliError::IoError(error)
+///     }
+/// }
+///
+/// impl From<num::ParseIntError> for CliError {
+///     fn from(error: num::ParseIntError) -> Self {
+///         CliError::ParseError(error)
+///     }
+/// }
+///
+/// fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
+///     let mut contents = fs::read_to_string(&file_name)?;
+///     let num: i32 = contents.trim().parse()?;
+///     Ok(num)
+/// }
+/// ```
+///
+/// [`TryFrom`]: trait.TryFrom.html
+/// [`Option<T>`]: ../../std/option/enum.Option.html
+/// [`Result<T, E>`]: ../../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<T>: 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<T>: 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<T, Self::Error>;
+}
+
+/// 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<T> for U` implies [`TryInto`]`<U> for T`
+/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
+/// is implemented and cannot fail -- the associated `Error` type for
+/// calling `T::try_from()` on a value of type `T` is [`!`].
+///
+/// `TryFrom<T>` can be implemented as follows:
+///
+/// ```
+/// use std::convert::TryFrom;
+///
+/// struct GreaterThanZero(i32);
+///
+/// impl TryFrom<i32> for GreaterThanZero {
+///     type Error = &'static str;
+///
+///     fn try_from(value: i32) -> Result<Self, Self::Error> {
+///         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<T>: 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<Self, Self::Error>;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GENERIC IMPLS
+////////////////////////////////////////////////////////////////////////////////
+
+// As lifts over &
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
+where
+    T: AsRef<U>,
+{
+    fn as_ref(&self) -> &U {
+        <T as AsRef<U>>::as_ref(*self)
+    }
+}
+
+// As lifts over &mut
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
+where
+    T: AsRef<U>,
+{
+    fn as_ref(&self) -> &U {
+        <T as AsRef<U>>::as_ref(*self)
+    }
+}
+
+// FIXME (#45742): replace the above impls for &/&mut with the following more general one:
+// // As lifts over Deref
+// impl<D: ?Sized + Deref<Target: AsRef<U>>, U: ?Sized> AsRef<U> for D {
+//     fn as_ref(&self) -> &U {
+//         self.deref().as_ref()
+//     }
+// }
+
+// AsMut lifts over &mut
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
+where
+    T: AsMut<U>,
+{
+    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<D: ?Sized + Deref<Target: AsMut<U>>, U: ?Sized> AsMut<U> 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<T, U> Into<U> for T
+where
+    U: From<T>,
+{
+    fn into(self) -> U {
+        U::from(self)
+    }
+}
+
+// From (and thus Into) is reflexive
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> From<T> 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<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
+impl<T> From<!> for T {
+    fn from(t: !) -> T {
+        t
+    }
+}
+
+// TryFrom implies TryInto
+#[stable(feature = "try_from", since = "1.34.0")]
+impl<T, U> TryInto<U> for T
+where
+    U: TryFrom<T>,
+{
+    type Error = U::Error;
+
+    fn try_into(self) -> Result<U, U::Error> {
+        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<T, U> TryFrom<U> for T
+where
+    U: Into<T>,
+{
+    type Error = Infallible;
+
+    fn try_from(value: U) -> Result<Self, Self::Error> {
+        Ok(U::into(value))
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CONCRETE IMPLS
+////////////////////////////////////////////////////////////////////////////////
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsRef<[T]> for [T] {
+    fn as_ref(&self) -> &[T] {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> AsMut<[T]> for [T] {
+    fn as_mut(&mut self) -> &mut [T] {
+        self
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<str> 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<T, U> TryFrom<U> for T where U: Into<T> {
+///     type Error = Infallible;
+///
+///     fn try_from(value: U) -> Result<Self, Infallible> {
+///         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 (file)
index 0000000..0877dac
--- /dev/null
@@ -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<Int>: 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<Self, Self::Error> {
+                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);
+}
index 19928f30f2ea5907076ad43501fbb4b58c7fd86f..18aae59573d7d56a0707f586617bf86570a816ad 100644 (file)
@@ -1144,6 +1144,11 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
     /// May assume inputs are finite.
     pub fn frem_fast<T>(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<Float, Int>(value: Float) -> Int;
+
 
     /// Returns the number of bits set in an integer type `T`
     pub fn ctpop<T>(x: T) -> T;
index 913c0f96d118da09e2d974915fa5a41696415823..ac06f95e244b6f97c407804b0812dac9d151fa12 100644 (file)
@@ -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::<u16>() };
+    /// assert_eq!(rounded, 4);
+    ///
+    /// let value = -128.9_f32;
+    /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+    /// 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<Int>(self) -> Int where Self: FloatToInt<Int> {
+        FloatToInt::<Int>::approx_unchecked(self)
+    }
+
     /// Raw transmutation to `u32`.
     ///
     /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
index 6ca830b1f38afa190f8a3b4d4a4fb4df2b756205..794f77fcfc1be379e879214ee5a4cd2672ac9ae8 100644 (file)
@@ -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::<u16>() };
+    /// assert_eq!(rounded, 4);
+    ///
+    /// let value = -128.9_f32;
+    /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+    /// 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<Int>(self) -> Int where Self: FloatToInt<Int> {
+        FloatToInt::<Int>::approx_unchecked(self)
+    }
+
     /// Raw transmutation to `u64`.
     ///
     /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
index 4313248f2636a2dab1957c795a8b7851719932c5..585f144cf8a9f3b76ce64f2851c47a03409acc48 100644 (file)
@@ -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<Self, ParseIntError> {
 /// 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<Self, Self::Error> {
-                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")] }
index 0f1e6e89451e9b4294a6aad180c3250e623f2122..e89eb2c7f94d5731a04e320de4427c0dc4d2af68 100644 (file)
@@ -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));
 }
index 900c6ed5ff32235d487ec6a187a0f8970ad8ef9f..2ecbe770729b5b278f21213df8902e31104ef224 100644 (file)
@@ -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<usize> {
                 break;
             }
         }
-        if found {
-            Some(cur)
-        } else {
-            None
-        }
+        found.then_some(cur)
     }
 }
 
index f25f3b5741a0ef2984e1c9287e96722f413da9b5..8f9f3983262372fdcd28e8782d6e6855c4ed933c 100644 (file)
@@ -147,13 +147,7 @@ pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
             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 {
index 3110b027c5bbe5f360aea5b5a85a9a2e455b992c..3e28145c0fa0a544b7022a2050fa74a93ea322a6 100644 (file)
@@ -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
index e708c5ab6e77d0da21e6e75270a1c4dda3d19bec..24b87ffc80c2a5b60a425a1a17dfa6683080560b 100644 (file)
@@ -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)]
index df5d4997e089aac8cbd297b8ff5054ab1fb5d41e..814c244ecbc2b6b5dd6ec97107912c8e59b52d84 100644 (file)
@@ -242,11 +242,7 @@ pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
     pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + '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)
         })
     }
 
index ba44c6c3b9a1f27cd993131bd1fb6e6a29ad6276..35017d6330da31555805556276b32139d5099d16 100644 (file)
@@ -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);
index c9a934e9ebd8490ff86cbfb73096bf596cf1501e..05a2704cc5dfc67792b24a3ea6cc4ea7e3fee915 100644 (file)
@@ -2784,11 +2784,7 @@ pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> {
             }
         };
 
-        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| {
index e5f4e793132f4b0d74166cfa1f955e5f970f1a90..2f30b797fb1516d11c4ecd31bd1398e9802a3655 100644 (file)
@@ -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
index 33dc2513de5844892e35e0a94007dab34904bc21..1ea9362dc4260ea16c52a90cac5518903533a1ba 100644 (file)
@@ -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::<FxHashMap<_, _>>();
 
         let mut ret = FxHashMap::default();
index f38f9dfecd38705e63e7b0c418da2ee828b0f8e5..419e99d55d72d703d8895fa97422f8df6fb622b9 100644 (file)
@@ -245,11 +245,7 @@ fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
             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))
         })
     }
 
index 9df75a800f1239a971a56e771181aace6cd88fc6..1767ad118e7c0912bd706b9527caabbbdbdaaeee 100644 (file)
@@ -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)
             }
index 2ff5872370fd10ccbe467b1859b38a672abc89b7..00a84f8d80f36467f52fbfd4b1abeb815750e8c0 100644 (file)
@@ -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)]
index e27cb6d8dda8973ade54bda2621b77dda290bebe..cd3d99951e2b1054330c477b528239edcc636755 100644 (file)
@@ -119,11 +119,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
     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();
index f8b3e0ffe5cd9774416126d04a0530aa715789e4..cea5dc18c136296391e6dd89e2b460150123065a 100644 (file)
@@ -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.
index 9784d870b31ba44ae4aa69d6ea5faf0c9176b429..9919666027a2116c101fac344efc1dbccd44da06 100644 (file)
@@ -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(),
index 9e4b704170b9b38271269b01e42f5e8068002484..9c1bec39b29e2834533163c00bab032c12003b7f 100644 (file)
@@ -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 (file)
index d5e6857..0000000
+++ /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`.
index fc880b9e9295114f5d7d953074f3a32ebbcc6aab..b1ae7c6ca33d872d6e802ae4a0251c660a0c0fae 100644 (file)
@@ -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
     // -------------------------------------------------------------------------
index 76af4342f5c9ef0c59877cdb020394bd6287b98f..9bb18788171b4a51851e054984664a6446dc05f9 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(set_stdio)]
 #![feature(nll)]
index 235184382c5cc18873e5c09f72e86b5cff6bdcc2..2a4bc41f85072192bda1c0c202451dcbf9b83514 100644 (file)
@@ -547,13 +547,7 @@ fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool
 }
 
 fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
-    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)
 }
 
index d1fbb949fb164326eb4fc93237e2831d0d221d66..e429b4d101a904b524bd5d3d61e88d67c30c2978 100644 (file)
@@ -117,11 +117,9 @@ fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
 
     pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
         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())
+            }))
         })
     }
 
index d8e20e17ce835f927239b304185d818771f7e4a8..8c225b83f40e8234b0f0f55506150cb6cdca5411 100644 (file)
@@ -107,11 +107,7 @@ pub fn create_session(
 fn get_stack_size() -> Option<usize> {
     // 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<Mutex<Vec<u8>>>);
@@ -285,11 +281,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
             } else {
                 "rustc"
             });
-            if candidate.exists() {
-                Some(candidate)
-            } else {
-                None
-            }
+            candidate.exists().then_some(candidate)
         })
         .next()
 }
index 0fd7145f425d3027cf58e59594035682aec631dc..10b00d35d9bcaa9d0e12bf19ef2eee101d311770 100644 (file)
@@ -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
                 }
index e60c025c3ef8b2f5671865f3672c53001e95b415..12aab4b4f84e4549a329d46124e88bdb5e3f5f51 100644 (file)
@@ -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)]
index dbf2dcf1c0aea461d6be050c33deaf806f453dc5..25bd2c45da5f5b05bacf24355a8a666448ac5ae4 100644 (file)
@@ -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
index 8c0b7345e1e8aa0a81cea3b9b5acf345f98d08ca..aaaff7e3b0a4a9eef42da430219e455ecdbebeeb 100644 (file)
@@ -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)]
index b9363200cdf2855dc60ab6c6801895642f8d7ecd..7a5bbb4d892980d3c6850c427c14b54ea17b0f18 100644 (file)
@@ -173,11 +173,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>>>,
     Option<ClosureRegionRequirements<'tcx>>,
 ) {
-    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);
 
index 85031d6210a4d2202bbc4dab2c2d66affd5753f6..0b3cb29e39ef4e38d183aceebeae3ef2a9e87bc0 100644 (file)
@@ -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<ty::RegionVid> {
             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];
index c893d6f485630da75b81915f7f78c26781f27836..e320811ca0556e10ef1519c9997c23b32c238f5d 100644 (file)
@@ -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)
index 92c7178da53e0b163d546a59b14787427e3acb7f..0086c3b0e103ff999f55fe787879902ac0401f41 100644 (file)
@@ -1154,13 +1154,7 @@ pub fn compare_const_vals<'tcx>(
 ) -> Option<Ordering> {
     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);
 
index ee7fb18fd05a544fb5133f32c1094ff04b68f8be..8f177ad1225806c3e5858822eb0077cc97e508f9 100644 (file)
@@ -324,7 +324,7 @@ pub fn check_ptr_access(
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
-        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)
     }
 
index d7493338a5352f083a9db4a3733366d44baf7715..55b9427a75ba303d0c5fe3e9877c893eeb4f3672 100644 (file)
@@ -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,
index f4fb9a5e4f2a2ad20a2438ca5d9835fcd272f0ad..42b72b64f8a3053ae209ae62294eb59ece03b520 100644 (file)
@@ -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)]
 
index 42f08771f866d57b32b1f4242ec8b3ddc05017f1..591f220549deaf1c7f21547b312636c5d56b6285 100644 (file)
@@ -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()
index aec3cf04a97ca195cec04325bc6b0108b71d96a4..393ae9442a17e2976c9d85072f85b13da582393c 100644 (file)
@@ -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<bool> {
+        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<bool> {
+        Some(tcx.features().const_mut_refs)
+    }
+}
 
 #[derive(Debug)]
 pub struct Panic;
index f44bac126f276c4a4752a2caff0b44c347c095ad..7170857926b3786599075bb551f4edad7aad98fc 100644 (file)
@@ -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>,
index 2c45dcfbe2665c077c70617c29ed0e290170e02a..284285c327c34428d26f7eabfb83fb00a4599633 100644 (file)
@@ -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 {
index 3030d2e646b8d494cb8b68a1bd9fe65eba7173a8..cf2e1306dc44b42bcb1622a424e4a260b39f4fee 100644 (file)
@@ -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) {
index de070d75ad8e2a88d9f1e4260728e3890c7051b4..26081d93946640f9d39c118a6b97ab75a705eb80 100644 (file)
@@ -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(),
     }
index 30e056e52d25acd58b770a1d27145e2cb81fc5fd..1e9203f377f383b028978416b6f6c34d5b2a9788 100644 (file)
@@ -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 \
+    <https://doc.rust-lang.org/reference/conditional-compilation.html\
+    #the-cfg_attr-attribute>";
+
 impl<'a> StripUnconfigured<'a> {
     pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
         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<T: HasAttrs>(&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<ast::Attribute> {
+    fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
         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 \
-                       <https://doc.rust-lang.org/reference/conditional-compilation.html\
-                       #the-cfg_attr-attribute>")
-                .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<ast::Attribute> {
         // 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<ast::FnDecl>) {
     }
 }
 
-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<ast::Attribute>) {
+    attrs: &[Attribute],
+) -> (bool, Vec<Attribute>) {
     // Don't perform gated feature checking.
     let mut strip_unconfigured = StripUnconfigured { sess, features: None };
     let mut attrs = attrs.to_owned();
index a222f3f00c4633fe4a0a47f2ad8d7be6b15d6944..faff386e9231826d42924eba891daf68bd0397dc 100644 (file)
@@ -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()?;
index b2ae934ce64746f879ab94d8e277205cb10ebd07..00fd6b8a25bc3df5ec298423cb17789dd135de58 100644 (file)
@@ -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<ast::NestedMetaItem>> {
+        // 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? ')' )? ;
index ccf78e6402b3c06c789384c4f763c5a85640d25f..c3e5b39635f03530c14a878cf80486c3bbee8db2 100644 (file)
@@ -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);
index 70c3458e7c0203095c5cb53249a94c741f95e56e..5334fc485e7a63a26d8aba09e1a173f28ed16a82 100644 (file)
@@ -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<Path>> {
-        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<PathSegment>,
index 97e9cb8dcdf6fc9bf339a513de5166c23001db59..94d3fe7b55167e65b69ffc5c9a5819c56106a0f1 100644 (file)
@@ -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 {
index 4dcafb6d2798ccdbf9d2d7281b3040f2c48a7e4b..8dd45f5df4cabc08e106448b4ee7e5d5149f19e7 100644 (file)
@@ -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))
                         })
                     )
                 }
index 666c482c680462bb6ff213a0b0658004c8919656..4f95d6fe70f1712f38d089e4d687b909d623a619 100644 (file)
@@ -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))
                 }
             }));
 
index be36e02f5b5b1e17fc8659c2d5092a98890f3b91..31f59e47d0aceebbf67e954aa54e6f6c44c57436 100644 (file)
@@ -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)]
index 9369c1771a35ed10c6c90caa5e5db0e3c7043ed8..150d207e5bfe9cb6fa46b24b212eda63ad788962 100644 (file)
@@ -752,11 +752,7 @@ pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> {
     }
 
     pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
-        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|
index 45fe4751a3dae9dc4e07eae26513e3157e97e09f..06c001e577b870c95bf1f2fb7159e0cbf88eb2cc 100644 (file)
@@ -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 })
     })
 }
 
index ff929f33d8bc94a0ecab52cdc8faf40b266498e0..36971c1c5013cc981c91921d802e6ade01970c9a 100644 (file)
@@ -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 })
     })
 }
 
index 6f53577b450550ca064cae8aa7c192c6ada7da65..5119464b1cc5fbc6323f78d0bb8d748b8a6334f5 100644 (file)
@@ -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);
     }
index f967a83d5f9b603ba41d7dea50f0df8f0b365357..fe4594802f66abe8278d9f98f5ad37efc71101ef 100644 (file)
@@ -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 })
     })
 }
 
index fe2c427f703100ba19445da7414015ab9fd31a1e..32be7b89cb064c300b60f4ef830e799555eda740 100644 (file)
@@ -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 })
     })
 }
 
index 5582eaf47c426f09b3409bd78b68dc7edc2e0c3e..6a1498e98e816017eed9f21bb5ceea802c48556d 100644 (file)
@@ -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)]
 
index 901a2192e20dd91c92fa1d3510281b38a60b2615..253fc5575c5bc1639f3010d82a2e078755c6978c 100644 (file)
@@ -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());
index 32df6c4636c2d88338e4a791e0622f9de924d9af..16a55d2a4d318214c4c48ab95eb83d6f4c2693b5 100644 (file)
 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))
     }
index 9f034e65b6eaa6a5faa04f20010ee850de1c7c40..b967c6e36e35ebc209ba4f7d73e69a42254e1655 100644 (file)
@@ -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),
index 9717190045afb38bf73663781b321b6f3f0853e1..992308183b42f951fd9dde5645722fb13c8af6f2 100644 (file)
@@ -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
             })
         })
index c7a0190a1d1b4314569981f670a7e8b12cba0b8e..a956aba4f62b9896ff13b0f56e35b1b31eafa326 100644 (file)
@@ -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)
                 }
             }
         }
index 3002459d56f3c392cb7f81fcada250b8f7563cf1..c5a6c072979182c5ff457536a26f168ef54cb2f5 100644 (file)
@@ -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
         };
index c606feab087279ca5f7bc1c04a6cfa13ebac9e17..6a6294b6f87982635f2da36ffc706cab3443e0d8 100644 (file)
@@ -59,6 +59,7 @@
 
 #![allow(non_camel_case_types)]
 
+#![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
index 87c2318a9377c56ff3b3922915d664cd2aeaeaa8..e90da69906009e9e01568eee6e60a3340d337ac7 100644 (file)
@@ -143,10 +143,8 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
 #[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<T>,
-    __poison: poison::Guard,
+    lock: &'a Mutex<T>,
+    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<T>) -> LockResult<MutexGuard<'mutex, T>> {
         poison::map_result(lock.poison.borrow(), |guard| {
             MutexGuard {
-                __lock: lock,
-                __poison: guard,
+                lock: lock,
+                poison: guard,
             }
         })
     }
@@ -429,14 +427,14 @@ impl<T: ?Sized> 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<T: ?Sized> 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<T: ?Sized> 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")))]
index b1b56f321fc6b8fb162c68a7ba2362de91621ab3..c217291a42e4856de7192aa5bc2f0f52802577a3 100644 (file)
@@ -87,7 +87,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
 #[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<T>,
+    lock: &'a RwLock<T>,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -108,8 +108,8 @@ unsafe impl<T: ?Sized + Sync> 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<T>,
-    __poison: poison::Guard,
+    lock: &'a RwLock<T>,
+    poison: poison::Guard,
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -465,7 +465,7 @@ unsafe fn new(lock: &'rwlock RwLock<T>)
                   -> LockResult<RwLockReadGuard<'rwlock, T>> {
         poison::map_result(lock.poison.borrow(), |_| {
             RwLockReadGuard {
-                __lock: lock,
+                lock: lock,
             }
         })
     }
@@ -476,8 +476,8 @@ unsafe fn new(lock: &'rwlock RwLock<T>)
                   -> LockResult<RwLockWriteGuard<'rwlock, T>> {
         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<T>)
 impl<T: fmt::Debug> 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<T: fmt::Debug> 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<T: ?Sized> 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<T: ?Sized> 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<T: ?Sized> 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<T: ?Sized> 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<T: ?Sized> 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(); }
     }
 }
 
index a94742634cf17919e7f3378f391284896ef0f17f..36173801eae3d31dc760fcc5f869185ef0c2b938 100644 (file)
@@ -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)]
index 4821bbd9ec6e2a63eb548f4936d05a1db3fee2c4..b2e8d8526fd2e9ec26511f074734763d7f6922bb 100644 (file)
@@ -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)
 }
 
index 4127a8c7fce2502650e8d52868b0b8320632fab8..efb3c2396c32d54b5deead0a04bc0a3b851c7edb 100644 (file)
@@ -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)
     }
 }
index 8e56e2bb00b4b19b0b4be46370a197e5bdc23b6f..520488c658676bfc07e179951269d44458e4f0a2 100644 (file)
@@ -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
 }
index 3d4f82764413a0021fd93b3dfb194b259ad18264..0d1d2926c85d92d3ca02b5d24d77f868bd30dda0 100644 (file)
@@ -95,12 +95,12 @@ pub fn translate(&self) -> Option<String> {
             };
 
             // 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;
index b9287d2fe7062ed1f3cd742225b748b84bd00340..55c7f3fa5749ae10988e3d9acced10f2856f427f 100644 (file)
@@ -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)]
index c68e03be88c045fb2de599346b6c95c5bef278dd..e8f7a125739ac07cb190bb5f0dd4d3ccd219aaae 100644 (file)
         const_indexing,
         const_in_array_repeat_expressions,
         const_let,
+        const_mut_refs,
         const_panic,
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
index 7647978b3d975dfd0f69667ecf4a95bc6953caf9..0097558eae6c1488ff6922173ccf361f8deea21a 100644 (file)
@@ -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::<Vec<_>>();
         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() {
index 1a4fc72e8178647074a35c253deb89a1bf47baca..5d26059644d17a04dd5832cd2ff4bcdaa98c1dac 100644 (file)
@@ -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
index 7c02a907ce7ad03649175f63ad5ef81411b6f149..1ec59d906206eada93ce9282dfd81e12afef9517 100644 (file)
@@ -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() {}
index 91abd44e65caf3294d9b70b99043cacf3ebe1a5d..70cc1f1d5a2c6078da0f8c4014b9a2e1eec4bd70 100644 (file)
@@ -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() {}
index 7a635a37107d2d718ae7febe501b4ce6d62a4a1b..7ab024434b2bf86250d4c2db32263b20e8259be3 100644 (file)
@@ -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`.
index 4f4bf16a0ff69eae02be861849cadf7b1f5db052..39da824ede57c256ec7eee6ca20bc365597264cf 100644 (file)
@@ -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`.
index 93aef72220cc413d41c3d4cae363b83745535221..8ca31c118369c23f9db2f495676bcb647f5f61ae 100644 (file)
@@ -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
 #[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() {}
index 3dfbd6df256ebbdc3e09708544a0771a3e1473b0..3a590d3282d46b04bfba865e320b69270e4b45d8 100644 (file)
@@ -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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
-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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
-error: aborting due to 5 previous errors
+error: aborting due to 9 previous errors
 
index acf5cbaede66597b552d4df556447e32495be118..54b35073340fd3ca80582a816ed5f023e4689472 100644 (file)
@@ -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::<i32>::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`.
index ed3837e9c9ee589be2aea3a8298887e2ac8dfb93..0809c77c1b604514d0451fcfc232f99309c699f9 100644 (file)
@@ -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 (file)
index 0000000..99006a2
--- /dev/null
@@ -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 (file)
index 0000000..2207599
--- /dev/null
@@ -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 (file)
index 0000000..4fae119
--- /dev/null
@@ -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`.
index 53b960b4ec0e04b116197ca5bebec5143efa1abe..7852874944b22c8bce3a9cab994c41af395c4cc6 100644 (file)
@@ -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`.
index 44b408494679c1eca307ffe20076bcf4dcc93aac..972f59549ea7415806e1ce8e64098e9a9adbb7c6 100644 (file)
@@ -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
     }
 };
 
index 757f0ffb59ff7540114aad37a6d90a762bac8ea1..9daca765c7cd0760cd698778ba1a4c40ecea7bf2 100644 (file)
@@ -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)]
    |         ^^^^^^^^^
index 59dafcbf4d50c06fef31a564b2491bf0285f6592..fe3c4ee70f2a21ee9b81282bd32ed05c8d05a442 100644 (file)
@@ -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>(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<i32>,
@@ -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 {
index b9c0af33c39cdd410575086a7ccef68a474a0509..3e1300c63c17d6a737ecea4fd9806b2d5c6fb6bb 100644 (file)
@@ -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 (file)
index 0000000..821c501
--- /dev/null
@@ -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 (file)
index 0000000..2353877
--- /dev/null
@@ -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`.
index dedb7db5920891315da02e88b4ef7988207dae46..cfe8e7f03d5e45e8445ff79094bf79610b71de1d 100644 (file)
@@ -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 (file)
index 0efb6bf..0000000
+++ /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 (file)
index 0000000..472d260
--- /dev/null
@@ -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 (file)
index 0000000..b43fbc8
--- /dev/null
@@ -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`.
index ef378fa84518e5cc1e208e87d5e6c192d486042f..74162fbd54b046537817eeb17a99b8e716632077 100644 (file)
@@ -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 (file)
index ca691b0..0000000
+++ /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 (file)
index 0000000..430cef9
--- /dev/null
@@ -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 (file)
index 0000000..048913e
--- /dev/null
@@ -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(){}
index 3bc518c2c2b719c8ef983aecbea807d58e9b68e4..64be41170d0c897156211e5d7fc5c1b8b4f9959c 100644 (file)
@@ -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() {}
index 8c8660adceb7a6d1ccdec30ef256aaf07b998871..9a87195a9d05efb9b4df524cd8c0ed2d26d278a8 100644 (file)
@@ -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 (file)
index 0000000..5954e34
--- /dev/null
@@ -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 (file)
index 0000000..986307d
--- /dev/null
@@ -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`.
index b388f38a7fac70b928f7d89c6633acf6de422f60..ca61fb0c171febdbd67445dac6811c3d94f2e7c1 100644 (file)
@@ -4,7 +4,10 @@ error[E0308]: mismatched types
 LL | fn bar(x: usize) -> Option<usize> {
    |                     ------------- expected `std::option::Option<usize>` 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<usize>`
               found type `usize`
index 8d875d37d85f9ceeb143ba1fe1c7a8620372c9ec..7e4a62ac96957482ed612afbb68297f1e44a69eb 100644 (file)
@@ -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`.
index 4f1ad38dbdd944bab8929e40a5bb20736a69f513..e1967eb7655425e642cfaaf60efc7350081810f0 100644 (file)
@@ -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<T: AsRef<[u8]>>(buffer: T) { }
 
 fn main() {
index c72f580f24391c5730d727e8b716d2f9c770f167..32c7ecbf72e951ca5c299d0fc923eb7f42081e3a 100644 (file)
@@ -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`.
index aef6dc54747ce8f048f138dc00e9654c73260c1a..9ca983df30af51392b22145e8f56abc28e9c550e 100644 (file)
@@ -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<isize, ()>`
               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
 
index cccae396b721015a5f07a951c3acbe85389621e5..d6df0592be32c7edfe0165c94189bac43ffe1932 100644 (file)
@@ -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)]
 
index 150916c03668add7142659857097b1d3911246b6..9066e57aabfe5eefafb8d89b2261c8921805bc70 100644 (file)
@@ -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<A, B>`
             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
 
index a6d886318e8202b281d53217155934f2ade49805..77fa2f566a8fc1524bd5d61ea5e58e23d1392387 100644 (file)
@@ -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
index 8d750b66838439c05efb3251deee5b08a44ac41b..1f1ee39b049e309a35cbfe14139458ff15b14f28 100644 (file)
@@ -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 (file)
index 0000000..5b1614b
--- /dev/null
@@ -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 (file)
index 0000000..407193d
--- /dev/null
@@ -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
+
index e67fbdd5ddd32d4776df583db21a26e9c7045214..05b7ebe4666622c61f309087e983617db31c5dbc 100644 (file)
@@ -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
index 319c05eadbf1dbfcb4955f82608179217f946177..6f535e03e6aec31035d8bd73b56231aaebeaad30 100644 (file)
@@ -6,11 +6,13 @@ LL | #[cfg_attr]
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
-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 <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: malformed `derive` attribute input
   --> $DIR/malformed-special-attrs.rs:7:1
index c2081878629a6025caddb77de23c7cfb01ea0a07..c73130643db7b18c06d1a215878db53ed361ae80 100644 (file)
@@ -26,7 +26,10 @@ error[E0308]: mismatched types
 LL | fn b() -> Option<Foo> {
    |           ----------- expected `std::option::Option<Foo>` 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<Foo>`
             found struct `Foo`
@@ -37,7 +40,10 @@ error[E0308]: mismatched types
 LL | fn c() -> Result<Foo, Bar> {
    |           ---------------- expected `std::result::Result<Foo, Bar>` 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<Foo, Bar>`
             found struct `Foo`
index 77c0ea17269f0e07ee29bff5d4dd8f51c63c370e..8fb34f21152ab513fb1a3cfb2daeeedaee6e2e9e 100644 (file)
@@ -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 {}
 
index 2e1d484e05a5a4d8fa670382efda5fee6b1531a4..048b72ee3bcdff21f184fc6b1bb5df22a5471ccb 100644 (file)
@@ -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
 
index cd6f0ea10eac90d96677084eba264de488eedbc3..a77e92022e2b676a4eab4dba9b85bf345174760b 100644 (file)
@@ -14,6 +14,11 @@ LL | fn b(x: Option<isize>) -> 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
index b077d590915cb04932847f11f934fad105f84cad..713b9eb542cfac9e3be6a637f5a7a2a10c7d3119 100644 (file)
@@ -10,5 +10,4 @@ fn main() {
     foo::<T>!(); //~ 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
 }
index 39b3edc67033d63ca2f42f1e50d80ae27a75941e..21683b2fb8643cb414c123da09b3fa09e06a4a65 100644 (file)
@@ -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
 
index eeeb258da215d3dae6d6cc8309f934e765e72b61..69f8ffa581bc128c0dcabbdd9aa6113d38d97bde 100644 (file)
@@ -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
 
index 440620f40b1e26525fc244ccef430b4aef5fdc83..c1274bd0ea6bc3226bdb8a7ca79e3780ad46ebac 100644 (file)
@@ -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