diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a889eff75c044..3c060cc6e840b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1007,6 +1007,16 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. pub fn panic_if_uninhabited(); + /// A guard for unsafe functions that cannot ever be executed if `T` does not permit + /// zero-initialization: This will statically either panic, or do nothing. + #[cfg(not(bootstrap))] + pub fn panic_if_zero_invalid(); + + /// A guard for unsafe functions that cannot ever be executed if `T` has invalid + /// bit patterns: This will statically either panic, or do nothing. + #[cfg(not(bootstrap))] + pub fn panic_if_any_invalid(); + /// Gets a reference to a static `Location` indicating where it was called. #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1852,6 +1862,7 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html) + #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value(v: &T) -> u64; /// Rust's "try catch" construct which invokes the function pointer `f` with diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 81a3c419db86f..a1dde1d51ef80 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -72,6 +72,7 @@ #![feature(concat_idents)] #![feature(const_ascii_ctype_on_intrinsics)] #![feature(const_alloc_layout)] +#![feature(const_discriminant)] #![feature(const_if_match)] #![feature(const_loop)] #![feature(const_checked_int_methods)] @@ -130,7 +131,6 @@ #![feature(rtm_target_feature)] #![feature(f16c_target_feature)] #![feature(hexagon_target_feature)] -#![feature(const_int_conversion)] #![feature(const_transmute)] #![feature(structural_match)] #![feature(abi_unadjusted)] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 90144d11dc9d1..7d9a8bcd05b1c 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -496,6 +496,9 @@ pub const fn needs_drop() -> bool { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] pub unsafe fn zeroed() -> T { + #[cfg(not(bootstrap))] + intrinsics::panic_if_zero_invalid::(); + #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); intrinsics::init() } @@ -529,6 +532,9 @@ pub unsafe fn zeroed() -> T { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] pub unsafe fn uninitialized() -> T { + #[cfg(not(bootstrap))] + intrinsics::panic_if_any_invalid::(); + #[cfg(bootstrap)] intrinsics::panic_if_uninhabited::(); intrinsics::uninit() } @@ -864,6 +870,7 @@ impl fmt::Debug for Discriminant { /// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3))); /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] -pub fn discriminant(v: &T) -> Discriminant { +#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] +pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v), PhantomData) } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 889ce2f211e14..caffa6c509aaa 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2154,7 +2154,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -2174,7 +2174,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -2209,12 +2209,20 @@ assert_eq!( ); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes - unsafe { mem::transmute(self) } + unsafe { Bytes { val: self }.bytes } } } @@ -2243,7 +2251,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -2276,7 +2284,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -2319,11 +2327,19 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } + unsafe { Bytes { bytes }.val } } } @@ -4099,7 +4115,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); assert_eq!(bytes, ", $be_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { self.to_be().to_ne_bytes() @@ -4119,7 +4135,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); assert_eq!(bytes, ", $le_bytes, "); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { self.to_le().to_ne_bytes() @@ -4154,12 +4170,20 @@ assert_eq!( ); ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute them to arrays of bytes + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes - unsafe { mem::transmute(self) } + unsafe { Bytes { val: self }.bytes } } } @@ -4188,7 +4212,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) @@ -4221,7 +4245,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] #[inline] pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) @@ -4264,11 +4288,19 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } ```"), #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.43.0")] + // SAFETY: const sound because integers are plain old datatypes so we can always + // transmute to them + #[allow_internal_unstable(const_fn_union)] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + #[repr(C)] + union Bytes { + val: $SelfT, + bytes: [u8; mem::size_of::<$SelfT>()], + } // SAFETY: integers are plain old datatypes so we can always transmute to them - unsafe { mem::transmute(bytes) } + unsafe { Bytes { bytes }.val } } } diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 59a72799e2567..e9ec81394e32d 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -13,7 +13,7 @@ /// ``` /// use std::ops::Add; /// -/// #[derive(Debug, PartialEq)] +/// #[derive(Debug, Copy, Clone, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -42,7 +42,7 @@ /// ``` /// use std::ops::Add; /// -/// #[derive(Debug, PartialEq)] +/// #[derive(Debug, Copy, Clone, PartialEq)] /// struct Point { /// x: T, /// y: T, @@ -115,7 +115,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` /// use std::ops::Sub; /// -/// #[derive(Debug, PartialEq)] +/// #[derive(Debug, Copy, Clone, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -657,7 +657,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } /// ``` /// use std::ops::AddAssign; /// -/// #[derive(Debug, PartialEq)] +/// #[derive(Debug, Copy, Clone, PartialEq)] /// struct Point { /// x: i32, /// y: i32, @@ -715,7 +715,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` /// use std::ops::SubAssign; /// -/// #[derive(Debug, PartialEq)] +/// #[derive(Debug, Copy, Clone, PartialEq)] /// struct Point { /// x: i32, /// y: i32, diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 77b92b6ccbdaa..e3e5934b44be1 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -42,7 +42,7 @@ //! ```rust //! use std::ops::{Add, Sub}; //! -//! #[derive(Debug, PartialEq)] +//! #[derive(Debug, Copy, Clone, PartialEq)] //! struct Point { //! x: i32, //! y: i32, diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 71a061af28920..05f958cbe81fe 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(leading_trailing_ones)] +#![feature(const_forget)] extern crate test; diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index 59588d97787b7..8337ab103419f 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -129,3 +129,21 @@ fn test_discriminant_send_sync() { is_send_sync::>(); is_send_sync::>(); } + +#[test] +fn test_const_forget() { + const _: () = forget(0i32); + const _: () = forget(Vec::>>::new()); + + // Writing this function signature without const-forget + // triggers compiler errors: + // 1) That we use a non-const fn inside a const fn + // 2) without the forget, it complains about the destructor of Box + const fn const_forget_box(x: Box) { + forget(x); + } + + // Call the forget_box at runtime, + // as we can't const-construct a box yet. + const_forget_box(Box::new(0i32)); +} diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e257b48f11156..dedb3035cedb3 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1904,36 +1904,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { } } -pub trait MaybeResult { - type Error; - - fn from(x: Result) -> Self; - fn to_result(self) -> Result; -} - -impl MaybeResult for T { - type Error = !; - - fn from(x: Result) -> Self { - let Ok(x) = x; - x - } - fn to_result(self) -> Result { - Ok(self) - } -} - -impl MaybeResult for Result { - type Error = E; - - fn from(x: Result) -> Self { - x - } - fn to_result(self) -> Result { - self - } -} - pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index a1b54607b809e..c8d352cd2dd98 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); } + /// Returns `true` if this is indeed a panic intrinsic and codegen is done. + fn codegen_panic_intrinsic( + &mut self, + helper: &TerminatorCodegenHelper<'tcx>, + bx: &mut Bx, + intrinsic: Option<&str>, + instance: Option>, + span: Span, + destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, + cleanup: Option, + ) -> bool { + // Emit a panic or a no-op for `panic_if_uninhabited`. + // These are intrinsics that compile to panics so that we can get a message + // which mentions the offending type, even from a const context. + #[derive(Debug, PartialEq)] + enum PanicIntrinsic { + IfUninhabited, + IfZeroInvalid, + IfAnyInvalid, + }; + let panic_intrinsic = intrinsic.and_then(|i| match i { + // FIXME: Move to symbols instead of strings. + "panic_if_uninhabited" => Some(PanicIntrinsic::IfUninhabited), + "panic_if_zero_invalid" => Some(PanicIntrinsic::IfZeroInvalid), + "panic_if_any_invalid" => Some(PanicIntrinsic::IfAnyInvalid), + _ => None, + }); + if let Some(intrinsic) = panic_intrinsic { + use PanicIntrinsic::*; + let ty = instance.unwrap().substs.type_at(0); + let layout = bx.layout_of(ty); + let do_panic = match intrinsic { + IfUninhabited => layout.abi.is_uninhabited(), + // We unwrap as the error type is `!`. + IfZeroInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(), + // We unwrap as the error type is `!`. + IfAnyInvalid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(), + }; + if do_panic { + let msg_str = if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == IfZeroInvalid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!("attempted to leave type `{}` uninitialized, which is invalid", ty) + }; + let msg = bx.const_str(Symbol::intern(&msg_str)); + let location = self.get_caller_location(bx, span).immediate(); + + // Obtain the panic entry point. + // FIXME: dedup this with `codegen_assert_terminator` above. + let def_id = + common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); + let instance = ty::Instance::mono(bx.tcx(), def_id); + let fn_abi = FnAbi::of_instance(bx, instance, &[]); + let llfn = bx.get_fn_addr(instance); + + if let Some((_, target)) = destination.as_ref() { + helper.maybe_sideeffect(self.mir, bx, &[*target]); + } + // Codegen the actual panic invoke/call. + helper.do_call( + self, + bx, + fn_abi, + llfn, + &[msg.0, msg.1, location], + destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), + cleanup, + ); + } else { + // a NOP + let target = destination.as_ref().unwrap().1; + helper.maybe_sideeffect(self.mir, bx, &[target]); + helper.funclet_br(self, bx, target) + } + true + } else { + false + } + } + fn codegen_call_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -520,41 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("`miri_start_panic` should never end up in compiled code"); } - // Emit a panic or a no-op for `panic_if_uninhabited`. - if intrinsic == Some("panic_if_uninhabited") { - let ty = instance.unwrap().substs.type_at(0); - let layout = bx.layout_of(ty); - if layout.abi.is_uninhabited() { - let msg_str = format!("Attempted to instantiate uninhabited type {}", ty); - let msg = bx.const_str(Symbol::intern(&msg_str)); - let location = self.get_caller_location(&mut bx, span).immediate(); - - // Obtain the panic entry point. - let def_id = - common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); - let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance, &[]); - let llfn = bx.get_fn_addr(instance); - - if let Some((_, target)) = destination.as_ref() { - helper.maybe_sideeffect(self.mir, &mut bx, &[*target]); - } - // Codegen the actual panic invoke/call. - helper.do_call( - self, - &mut bx, - fn_abi, - llfn, - &[msg.0, msg.1, location], - destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), - cleanup, - ); - } else { - // a NOP - let target = destination.as_ref().unwrap().1; - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target) - } + if self.codegen_panic_intrinsic( + &helper, + &mut bx, + intrinsic, + instance, + span, + destination, + cleanup, + ) { return; } diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 1dfe97238a3df..7020939fa20b2 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -196,7 +196,7 @@ macro_rules! newtype_index { #[inline] fn index(self) -> usize { - usize::from(self) + self.as_usize() } } diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 77f1c6bf28109..966bd99787729 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -12,14 +12,15 @@ use crate::infer::canonical::{ Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; +use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxtBuilder; -use crate::infer::{InferCtxt, InferOk, InferResult}; +use crate::infer::{InferCtxt, InferCtxtBuilder, InferOk, InferResult, NLLRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; -use crate::traits::TraitEngine; +use crate::traits::{DomainGoal, TraitEngine}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc::arena::ArenaAllocatable; use rustc::ty::fold::TypeFoldable; +use rustc::ty::relate::TypeRelation; use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_data_structures::captures::Captures; @@ -304,13 +305,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); + TypeRelating::new( + self, + QueryTypeRelatingDelegate { + infcx: self, + param_env, + cause, + obligations: &mut obligations, + }, + ty::Variance::Invariant, + ) + .relate(&v1, &v2)?; } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); + TypeRelating::new( + self, + QueryTypeRelatingDelegate { + infcx: self, + param_env, + cause, + obligations: &mut obligations, + }, + ty::Variance::Invariant, + ) + .relate(&v1, &v2)?; } _ => { @@ -656,3 +675,55 @@ pub fn make_query_region_constraints<'tcx>( QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } } + +struct QueryTypeRelatingDelegate<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + obligations: &'a mut Vec>, + param_env: ty::ParamEnv<'tcx>, + cause: &'a ObligationCause<'tcx>, +} + +impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { + fn create_next_universe(&mut self) -> ty::UniverseIndex { + self.infcx.create_next_universe() + } + + fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + let origin = NLLRegionVariableOrigin::Existential { from_forall }; + self.infcx.next_nll_region_var(origin) + } + + fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { + self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder)) + } + + fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + self.infcx.next_nll_region_var_in_universe( + NLLRegionVariableOrigin::Existential { from_forall: false }, + universe, + ) + } + + fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + self.obligations.push(Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + predicate: ty::Predicate::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate( + sup, sub, + ))), + recursion_depth: 0, + }); + } + + fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) { + bug!("should never be invoked with eager normalization") + } + + fn normalization() -> NormalizationStrategy { + NormalizationStrategy::Eager + } + + fn forbid_inference_vars() -> bool { + true + } +} diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 86d93612e993b..2896682ea8268 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -998,10 +998,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { let ty = cx.tcx.erase_regions(&t); let layout = match cx.layout_of(ty) { Ok(layout) => layout, - Err(ty::layout::LayoutError::Unknown(_)) => return, - Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => { - bug!("failed to get layout for `{}`: {}", t, err); - } + Err(ty::layout::LayoutError::Unknown(_)) + | Err(ty::layout::LayoutError::SizeOverflow(_)) => return, }; let (variants, tag) = match layout.variants { layout::Variants::Multiple { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 891afbf437f2b..1e5ed76c467b4 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -216,6 +216,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(val, dest)?; } + sym::discriminant_value => { + let place = self.deref_operand(args[0])?; + let discr_val = self.read_discriminant(place.into())?.0; + self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + } sym::unchecked_shl | sym::unchecked_shr | sym::unchecked_add diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 71aefa85c99fd..37ad5f5ea4e38 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -480,7 +480,11 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. crate fn push(&mut self, row: PatStack<'p, 'tcx>) { if let Some(rows) = row.expand_or_pat() { - self.0.extend(rows); + for row in rows { + // We recursively expand the or-patterns of the new rows. + // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`. + self.push(row) + } } else { self.0.push(row); } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 126686c8defbf..a9c4de04c0a2e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1544,9 +1544,7 @@ impl<'a> Parser<'a> { let is_name_required = match self.token.kind { token::DotDotDot => false, - // FIXME: Consider using interpolated token for this edition check, - // it should match the intent of edition hygiene better. - _ => req_name(self.token.uninterpolate().span.edition()), + _ => req_name(self.token.span.edition()), }; let (pat, ty) = if is_name_required || self.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 1e09cd79dbe18..d8ce9bbdfb30b 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -265,6 +265,7 @@ symbols! { derive, diagnostic, direct, + discriminant_value, doc, doc_alias, doc_cfg, diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index a3a9b5427678d..2f8bbd66c322b 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -937,6 +937,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> { } } +/// Trait for context types that can compute layouts of things. pub trait LayoutOf { type Ty; type TyLayout; @@ -947,6 +948,38 @@ pub trait LayoutOf { } } +/// The `TyLayout` above will always be a `MaybeResult>`. +/// We can't add the bound due to the lifetime, but this trait is still useful when +/// writing code that's generic over the `LayoutOf` impl. +pub trait MaybeResult { + type Error; + + fn from(x: Result) -> Self; + fn to_result(self) -> Result; +} + +impl MaybeResult for T { + type Error = !; + + fn from(Ok(x): Result) -> Self { + x + } + fn to_result(self) -> Result { + Ok(self) + } +} + +impl MaybeResult for Result { + type Error = E; + + fn from(x: Result) -> Self { + x + } + fn to_result(self) -> Result { + self + } +} + #[derive(Copy, Clone, PartialEq, Eq)] pub enum PointerKind { /// Most general case, we know no restrictions to tell LLVM. @@ -987,6 +1020,9 @@ impl<'a, Ty> TyLayout<'a, Ty> { { Ty::for_variant(self, cx, variant_index) } + + /// Callers might want to use `C: LayoutOf>` + /// to allow recursion (see `might_permit_zero_init` below for an example). pub fn field(self, cx: &C, i: usize) -> C::TyLayout where Ty: TyLayoutMethods<'a, C>, @@ -994,6 +1030,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { { Ty::field(self, cx, i) } + pub fn pointee_info_at(self, cx: &C, offset: Size) -> Option where Ty: TyLayoutMethods<'a, C>, @@ -1017,4 +1054,52 @@ impl<'a, Ty> TyLayout<'a, Ty> { Abi::Aggregate { sized } => sized && self.size.bytes() == 0, } } + + /// Determines if this type permits "raw" initialization by just transmuting some + /// memory into an instance of `T`. + /// `zero` indicates if the memory is zero-initialized, or alternatively + /// left entirely uninitialized. + /// This is conservative: in doubt, it will answer `true`. + /// + /// FIXME: Once we removed all the conservatism, we could alternatively + /// create an all-0/all-undef constant and run the const value validator to see if + /// this is a valid value for the given type. + pub fn might_permit_raw_init(self, cx: &C, zero: bool) -> Result + where + Self: Copy, + Ty: TyLayoutMethods<'a, C>, + C: LayoutOf> + HasDataLayout, + { + let scalar_allows_raw_init = move |s: &Scalar| -> bool { + if zero { + let range = &s.valid_range; + // The range must contain 0. + range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0 + } else { + // The range must include all values. `valid_range_exclusive` handles + // the wrap-around using target arithmetic; with wrap-around then the full + // range is one where `start == end`. + let range = s.valid_range_exclusive(cx); + range.start == range.end + } + }; + + // Check the ABI. + let valid = match &self.abi { + Abi::Uninhabited => false, // definitely UB + Abi::Scalar(s) => scalar_allows_raw_init(s), + Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), + Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), + Abi::Aggregate { .. } => true, // Cannot be excluded *right now*. + }; + if !valid { + // This is definitely not okay. + trace!("might_permit_raw_init({:?}, zero={}): not valid", self.details, zero); + return Ok(false); + } + + // If we have not found an error yet, we need to recursively descend. + // FIXME(#66151): For now, we are conservative and do not do this. + Ok(true) + } } diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index 71150e74f70d4..3c397eb444d1d 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -10,6 +10,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(bool_to_option)] #![feature(nll)] +#![feature(never_type)] +#![feature(associated_type_bounds)] +#![feature(exhaustive_patterns)] #[macro_use] extern crate log; diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 7570d9d4b28ac..859a219c95a21 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -18,6 +18,7 @@ use crate::type_error_struct; use crate::util::common::ErrorReported; use rustc::middle::lang_items; +use rustc::mir::interpret::ErrorHandled; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::Ty; @@ -1039,11 +1040,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if element_ty.references_error() { - tcx.types.err - } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, count)) - } else { - tcx.types.err + return tcx.types.err; + } + match count { + Ok(count) => tcx.mk_ty(ty::Array(t, count)), + Err(ErrorHandled::TooGeneric) => { + self.tcx.sess.span_err( + tcx.def_span(count_def_id), + "array lengths can't depend on generic parameters", + ); + tcx.types.err + } + Err(ErrorHandled::Reported) => tcx.types.err, } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3572eda5c1399..d2a358c3e09b8 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -147,7 +147,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ), "rustc_peek" => (1, vec![param(0)], param(0)), "caller_location" => (0, vec![], tcx.caller_location_ty()), - "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()), + "panic_if_uninhabited" | "panic_if_zero_invalid" | "panic_if_any_invalid" => { + (1, Vec::new(), tcx.mk_unit()) + } "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), "forget" => (1, vec![param(0)], tcx.mk_unit()), diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params/anon-params-denied-2018.rs similarity index 100% rename from src/test/ui/anon-params-denied-2018.rs rename to src/test/ui/anon-params/anon-params-denied-2018.rs diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr similarity index 100% rename from src/test/ui/anon-params-denied-2018.stderr rename to src/test/ui/anon-params/anon-params-denied-2018.stderr diff --git a/src/test/ui/anon-params-deprecated.fixed b/src/test/ui/anon-params/anon-params-deprecated.fixed similarity index 100% rename from src/test/ui/anon-params-deprecated.fixed rename to src/test/ui/anon-params/anon-params-deprecated.fixed diff --git a/src/test/ui/anon-params-deprecated.rs b/src/test/ui/anon-params/anon-params-deprecated.rs similarity index 100% rename from src/test/ui/anon-params-deprecated.rs rename to src/test/ui/anon-params/anon-params-deprecated.rs diff --git a/src/test/ui/anon-params-deprecated.stderr b/src/test/ui/anon-params/anon-params-deprecated.stderr similarity index 100% rename from src/test/ui/anon-params-deprecated.stderr rename to src/test/ui/anon-params/anon-params-deprecated.stderr diff --git a/src/test/ui/anon-params/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/anon-params-edition-hygiene.rs new file mode 100644 index 0000000000000..14e11c5696f4a --- /dev/null +++ b/src/test/ui/anon-params/anon-params-edition-hygiene.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 +// aux-build:anon-params-edition-hygiene.rs + +#[macro_use] +extern crate anon_params_edition_hygiene; + +generate_trait_2015!(u8); + +fn main() {} diff --git a/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs new file mode 100644 index 0000000000000..aa4221becc24f --- /dev/null +++ b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs @@ -0,0 +1,12 @@ +// edition:2015 + +#[macro_export] +macro_rules! generate_trait_2015 { + ($Type: ident) => { + trait Trait { + fn method($Type) {} + } + }; +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs new file mode 100644 index 0000000000000..c5e6fe9104bc9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn foo() { + let _ = [0u64; N + 1]; + //~^ ERROR array lengths can't depend on generic parameters +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr new file mode 100644 index 0000000000000..9cdccf8407c9b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.stderr @@ -0,0 +1,16 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-62456.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: array lengths can't depend on generic parameters + --> $DIR/issue-62456.rs:5:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-int-conversion-rpass.rs b/src/test/ui/consts/const-int-conversion-rpass.rs index d52dbbae1e7b5..6484169dd9ae1 100644 --- a/src/test/ui/consts/const-int-conversion-rpass.rs +++ b/src/test/ui/consts/const-int-conversion-rpass.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_int_conversion)] - const REVERSE: u32 = 0x12345678_u32.reverse_bits(); const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs new file mode 100644 index 0000000000000..1ad5134e71c52 --- /dev/null +++ b/src/test/ui/consts/const_discriminant.rs @@ -0,0 +1,40 @@ +// run-pass +#![feature(const_discriminant)] +#![allow(dead_code)] + +use std::mem::{discriminant, Discriminant}; + +// `discriminant(const_expr)` may get const-propagated. +// As we want to check that const-eval is equal to ordinary exection, +// we wrap `const_expr` with a function which is not const to prevent this. +#[inline(never)] +fn identity(x: T) -> T { x } + +enum Test { + A(u8), + B, + C { a: u8, b: u8 }, +} + +const TEST_A: Discriminant = discriminant(&Test::A(5)); +const TEST_A_OTHER: Discriminant = discriminant(&Test::A(17)); +const TEST_B: Discriminant = discriminant(&Test::B); + +enum Void {} + +enum SingleVariant { + V, + Never(Void), +} + +const TEST_V: Discriminant = discriminant(&SingleVariant::V); + +fn main() { + assert_eq!(TEST_A, TEST_A_OTHER); + assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(identity(&Test::B))); + assert_ne!(TEST_A, TEST_B); + assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + + assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); +} diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs new file mode 100644 index 0000000000000..02f8ecaa4eec5 --- /dev/null +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -0,0 +1,170 @@ +// run-pass +// ignore-wasm32-bare compiled with panic=abort by default + +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + +#![feature(never_type)] +#![allow(deprecated, invalid_value)] + +use std::{ + mem::{self, MaybeUninit, ManuallyDrop}, + panic, + ptr::NonNull, + num, +}; + +#[allow(dead_code)] +struct Foo { + x: u8, + y: !, +} + +enum Bar {} + +#[allow(dead_code)] +enum OneVariant { Variant(i32) } + +// An enum with ScalarPair layout +#[allow(dead_code)] +enum LR { + Left(i64), + Right(i64), +} +#[allow(dead_code, non_camel_case_types)] +enum LR_NonZero { + Left(num::NonZeroI64), + Right(num::NonZeroI64), +} + +fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { + let err = panic::catch_unwind(op).err(); + assert_eq!( + err.as_ref().and_then(|a| a.downcast_ref::()).map(|s| &**s), + Some(msg) + ); +} + +fn main() { + unsafe { + // Uninhabited types + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `!`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Foo`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Bar`" + ); + + // Types that do not like zero-initialziation + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `fn()` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `fn()`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const dyn Send>(), + "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<*const dyn Send>(), + "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" + ); + + /* FIXME(#66151) we conservatively do not error here yet. + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::>(), + "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<(NonNull, u32, u32)>(), + "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::<(NonNull, u32, u32)>(), + "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ + which is invalid" + ); + */ + + // Types that can be zero, but not uninit. + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `bool` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" + ); + + // Some things that should work. + let _val = mem::zeroed::(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); + let _val = mem::zeroed::>>(); + let _val = mem::uninitialized::>(); + + // These are UB because they have not been officially blessed, but we await the resolution + // of before doing + // anything about that. + let _val = mem::uninitialized::(); + let _val = mem::uninitialized::<*const ()>(); + } +} diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs index 2c5257ce063cb..d060f26fb2a08 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -19,4 +19,5 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` fn main() { let _ = [0; B::VALUE]; + //~^ ERROR array lengths can't depend on generic parameters } diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr index 8ae0f8b804c93..c6b2b4d27a208 100644 --- a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -13,7 +13,13 @@ LL | type MyA: TraitA; LL | impl TraitB for B { | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation -error: aborting due to 2 previous errors +error: array lengths can't depend on generic parameters + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 + | +LL | let _ = [0; B::VALUE]; + | ^^^^^^^^ + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0046, E0437. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs new file mode 100644 index 0000000000000..59032ab9775c8 --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs @@ -0,0 +1,9 @@ +// build-fail + +fn main() { + Bug::V([0; !0]); //~ ERROR is too big for the current +} + +enum Bug { + V([u8; !0]), +} diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr new file mode 100644 index 0000000000000..ce9790fc94681 --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr @@ -0,0 +1,8 @@ +error: the type `[u8; 18446744073709551615]` is too big for the current architecture + --> $DIR/issue-69485-var-size-diffs-too-large.rs:4:12 + | +LL | Bug::V([0; !0]); + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs deleted file mode 100644 index e0c30160b9e94..0000000000000 --- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs +++ /dev/null @@ -1,102 +0,0 @@ -// run-pass -// ignore-wasm32-bare compiled with panic=abort by default -// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results -// in a runtime panic. - -#![feature(never_type)] -#![allow(deprecated, invalid_value)] - -use std::{mem, panic}; - -#[allow(dead_code)] -struct Foo { - x: u8, - y: !, -} - -enum Bar {} - -fn main() { - unsafe { - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - } -} diff --git a/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs new file mode 100644 index 0000000000000..1f7c060386bd0 --- /dev/null +++ b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs @@ -0,0 +1,33 @@ +// Regression test for issue #69490 + +// check-pass + +pub trait Trait { + const S: &'static str; +} + +impl Trait<()> for T +where + T: for<'a> Trait<&'a ()>, +{ + // Use of `T::S` here caused an ICE + const S: &'static str = T::S; +} + +// Some similar cases that didn't ICE: + +impl<'a, T> Trait<()> for (T,) +where + T: Trait<&'a ()>, +{ + const S: &'static str = T::S; +} + +impl Trait<()> for [T; 1] +where + T: Trait fn(&'a ())>, +{ + const S: &'static str = T::S; +} + +fn main() {} diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs new file mode 100644 index 0000000000000..59533cefea64c --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs @@ -0,0 +1,9 @@ +#![feature(or_patterns)] + +fn main() { + let 0 | (1 | 2) = 0; //~ ERROR refutable pattern in local binding + match 0 { + //~^ ERROR non-exhaustive patterns + 0 | (1 | 2) => {} + } +} diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr new file mode 100644 index 0000000000000..58286e87869a4 --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -0,0 +1,25 @@ +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9 + | +LL | let 0 | (1 | 2) = 0; + | ^^^^^^^^^^^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let 0 | (1 | 2) = 0 { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0004]: non-exhaustive patterns: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11 + | +LL | match 0 { + | ^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs new file mode 100644 index 0000000000000..1de563dedbf18 --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(or_patterns)] + +fn main() { + let 0 | (1 | _) = 0; + if let 0 | (1 | 2) = 0 {} + if let x @ 0 | x @ (1 | 2) = 0 {} +}