mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #69914 - Centril:rollup-wtmdinz, r=Centril
Rollup of 10 pull requests Successful merges: - #66059 (mem::zeroed/uninit: panic on types that do not permit zero-initialization) - #69373 (Stabilize const for integer {to,from}_{be,le,ne}_bytes methods) - #69591 (Use TypeRelating for instantiating query responses) - #69625 (Implement nth, last, and count for iter::Copied) - #69645 (const forget tests) - #69766 (Make Point `Copy` in arithmetic documentation) - #69825 (make `mem::discriminant` const) - #69859 (fix #62456) - #69891 (Exhaustiveness checking, `Matrix::push`: recursively expand or-patterns) - #69896 (parse: Tweak the function parameter edition check) Failed merges: r? @ghost
This commit is contained in:
commit
303d8aff60
@ -1007,6 +1007,16 @@ extern "rust-intrinsic" {
|
||||
/// This will statically either panic, or do nothing.
|
||||
pub fn panic_if_uninhabited<T>();
|
||||
|
||||
/// 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<T>();
|
||||
|
||||
/// 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<T>();
|
||||
|
||||
/// 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<T>(v: &T) -> u64;
|
||||
|
||||
/// Rust's "try catch" construct which invokes the function pointer `f` with
|
||||
|
@ -200,6 +200,18 @@ where
|
||||
{
|
||||
self.it.fold(init, copy_fold(f))
|
||||
}
|
||||
|
||||
fn nth(&mut self, n: usize) -> Option<T> {
|
||||
self.it.nth(n).copied()
|
||||
}
|
||||
|
||||
fn last(self) -> Option<T> {
|
||||
self.it.last().copied()
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
self.it.count()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_copied", since = "1.36.0")]
|
||||
|
@ -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)]
|
||||
|
@ -496,6 +496,9 @@ pub const fn needs_drop<T>() -> bool {
|
||||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_zeroed"]
|
||||
pub unsafe fn zeroed<T>() -> T {
|
||||
#[cfg(not(bootstrap))]
|
||||
intrinsics::panic_if_zero_invalid::<T>();
|
||||
#[cfg(bootstrap)]
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
intrinsics::init()
|
||||
}
|
||||
@ -529,6 +532,9 @@ pub unsafe fn zeroed<T>() -> T {
|
||||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_uninitialized"]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
#[cfg(not(bootstrap))]
|
||||
intrinsics::panic_if_any_invalid::<T>();
|
||||
#[cfg(bootstrap)]
|
||||
intrinsics::panic_if_uninhabited::<T>();
|
||||
intrinsics::uninit()
|
||||
}
|
||||
@ -864,6 +870,7 @@ impl<T> fmt::Debug for Discriminant<T> {
|
||||
/// assert_ne!(mem::discriminant(&Foo::B(3)), mem::discriminant(&Foo::C(3)));
|
||||
/// ```
|
||||
#[stable(feature = "discriminant_value", since = "1.21.0")]
|
||||
pub fn discriminant<T>(v: &T) -> Discriminant<T> {
|
||||
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
||||
pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
|
||||
Discriminant(intrinsics::discriminant_value(v), PhantomData)
|
||||
}
|
||||
|
@ -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>()] {
|
||||
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>()] {
|
||||
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::<Self>()] {
|
||||
#[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 {
|
||||
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 {
|
||||
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>()]) -> 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>()] {
|
||||
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>()] {
|
||||
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::<Self>()] {
|
||||
#[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 {
|
||||
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 {
|
||||
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>()]) -> 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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<T> {
|
||||
/// 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,
|
||||
|
@ -42,7 +42,7 @@
|
||||
//! ```rust
|
||||
//! use std::ops::{Add, Sub};
|
||||
//!
|
||||
//! #[derive(Debug, PartialEq)]
|
||||
//! #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
//! struct Point {
|
||||
//! x: i32,
|
||||
//! y: i32,
|
||||
|
@ -41,6 +41,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(leading_trailing_ones)]
|
||||
#![feature(const_forget)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
@ -129,3 +129,21 @@ fn test_discriminant_send_sync() {
|
||||
is_send_sync::<Discriminant<Regular>>();
|
||||
is_send_sync::<Discriminant<NotSendSync>>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_forget() {
|
||||
const _: () = forget(0i32);
|
||||
const _: () = forget(Vec::<Vec<Box<i32>>>::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<T>(x: Box<T>) {
|
||||
forget(x);
|
||||
}
|
||||
|
||||
// Call the forget_box at runtime,
|
||||
// as we can't const-construct a box yet.
|
||||
const_forget_box(Box::new(0i32));
|
||||
}
|
||||
|
@ -1904,36 +1904,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MaybeResult<T> {
|
||||
type Error;
|
||||
|
||||
fn from(x: Result<T, Self::Error>) -> Self;
|
||||
fn to_result(self) -> Result<T, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> MaybeResult<T> for T {
|
||||
type Error = !;
|
||||
|
||||
fn from(x: Result<T, Self::Error>) -> Self {
|
||||
let Ok(x) = x;
|
||||
x
|
||||
}
|
||||
fn to_result(self) -> Result<T, Self::Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> MaybeResult<T> for Result<T, E> {
|
||||
type Error = E;
|
||||
|
||||
fn from(x: Result<T, Self::Error>) -> Self {
|
||||
x
|
||||
}
|
||||
fn to_result(self) -> Result<T, Self::Error> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>;
|
||||
|
||||
impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
|
@ -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<Instance<'tcx>>,
|
||||
span: Span,
|
||||
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
|
||||
cleanup: Option<mir::BasicBlock>,
|
||||
) -> 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;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ macro_rules! newtype_index {
|
||||
|
||||
#[inline]
|
||||
fn index(self) -> usize {
|
||||
usize::from(self)
|
||||
self.as_usize()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<PredicateObligation<'tcx>>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -265,6 +265,7 @@ symbols! {
|
||||
derive,
|
||||
diagnostic,
|
||||
direct,
|
||||
discriminant_value,
|
||||
doc,
|
||||
doc_alias,
|
||||
doc_cfg,
|
||||
|
@ -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<TyLayout<'_, Self>>`.
|
||||
/// 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<T> {
|
||||
type Error;
|
||||
|
||||
fn from(x: Result<T, Self::Error>) -> Self;
|
||||
fn to_result(self) -> Result<T, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> MaybeResult<T> for T {
|
||||
type Error = !;
|
||||
|
||||
fn from(Ok(x): Result<T, Self::Error>) -> Self {
|
||||
x
|
||||
}
|
||||
fn to_result(self) -> Result<T, Self::Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> MaybeResult<T> for Result<T, E> {
|
||||
type Error = E;
|
||||
|
||||
fn from(x: Result<T, Self::Error>) -> Self {
|
||||
x
|
||||
}
|
||||
fn to_result(self) -> Result<T, Self::Error> {
|
||||
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<Ty=Ty, TyLayout: MaybeResult<Self>>`
|
||||
/// to allow recursion (see `might_permit_zero_init` below for an example).
|
||||
pub fn field<C>(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<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
|
||||
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<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
|
||||
where
|
||||
Self: Copy,
|
||||
Ty: TyLayoutMethods<'a, C>,
|
||||
C: LayoutOf<Ty = Ty, TyLayout: MaybeResult<Self, Error = E>> + 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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
|
10
src/test/ui/anon-params/anon-params-edition-hygiene.rs
Normal file
10
src/test/ui/anon-params/anon-params-edition-hygiene.rs
Normal file
@ -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() {}
|
@ -0,0 +1,12 @@
|
||||
// edition:2015
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! generate_trait_2015 {
|
||||
($Type: ident) => {
|
||||
trait Trait {
|
||||
fn method($Type) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
9
src/test/ui/const-generics/issues/issue-62456.rs
Normal file
9
src/test/ui/const-generics/issues/issue-62456.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
fn foo<const N: usize>() {
|
||||
let _ = [0u64; N + 1];
|
||||
//~^ ERROR array lengths can't depend on generic parameters
|
||||
}
|
||||
|
||||
fn main() {}
|
16
src/test/ui/const-generics/issues/issue-62456.stderr
Normal file
16
src/test/ui/const-generics/issues/issue-62456.stderr
Normal file
@ -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
|
||||
|
@ -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]);
|
||||
|
40
src/test/ui/consts/const_discriminant.rs
Normal file
40
src/test/ui/consts/const_discriminant.rs
Normal file
@ -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<T>(x: T) -> T { x }
|
||||
|
||||
enum Test {
|
||||
A(u8),
|
||||
B,
|
||||
C { a: u8, b: u8 },
|
||||
}
|
||||
|
||||
const TEST_A: Discriminant<Test> = discriminant(&Test::A(5));
|
||||
const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17));
|
||||
const TEST_B: Discriminant<Test> = discriminant(&Test::B);
|
||||
|
||||
enum Void {}
|
||||
|
||||
enum SingleVariant {
|
||||
V,
|
||||
Never(Void),
|
||||
}
|
||||
|
||||
const TEST_V: Discriminant<SingleVariant> = 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)));
|
||||
}
|
170
src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
Normal file
170
src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
Normal file
@ -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<T>(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::<String>()).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::<Foo>(),
|
||||
"attempted to instantiate uninhabited type `Foo`"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<Foo>(),
|
||||
"attempted to instantiate uninhabited type `Foo`"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| MaybeUninit::<Foo>::uninit().assume_init(),
|
||||
"attempted to instantiate uninhabited type `Foo`"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<Bar>(),
|
||||
"attempted to instantiate uninhabited type `Bar`"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<Bar>(),
|
||||
"attempted to instantiate uninhabited type `Bar`"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| MaybeUninit::<Bar>::uninit().assume_init(),
|
||||
"attempted to instantiate uninhabited type `Bar`"
|
||||
);
|
||||
|
||||
// Types that do not like zero-initialziation
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<fn()>(),
|
||||
"attempted to leave type `fn()` uninitialized, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<fn()>(),
|
||||
"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::<LR_NonZero>(),
|
||||
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<LR_NonZero>(),
|
||||
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to leave type `(std::ptr::NonNull<u32>, u32, u32)` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
|
||||
which is invalid"
|
||||
);
|
||||
*/
|
||||
|
||||
// Types that can be zero, but not uninit.
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<bool>(),
|
||||
"attempted to leave type `bool` uninitialized, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<LR>(),
|
||||
"attempted to leave type `LR` uninitialized, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<ManuallyDrop<LR>>(),
|
||||
"attempted to leave type `std::mem::ManuallyDrop<LR>` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
// Some things that should work.
|
||||
let _val = mem::zeroed::<bool>();
|
||||
let _val = mem::zeroed::<LR>();
|
||||
let _val = mem::zeroed::<ManuallyDrop<LR>>();
|
||||
let _val = mem::zeroed::<OneVariant>();
|
||||
let _val = mem::zeroed::<Option<&'static i32>>();
|
||||
let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
|
||||
let _val = mem::uninitialized::<MaybeUninit<bool>>();
|
||||
|
||||
// These are UB because they have not been officially blessed, but we await the resolution
|
||||
// of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
|
||||
// anything about that.
|
||||
let _val = mem::uninitialized::<i32>();
|
||||
let _val = mem::uninitialized::<*const ()>();
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type !"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<!>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().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::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type !"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::uninitialized::<Foo>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<Foo>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::MaybeUninit::<Foo>::uninit().assume_init()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Foo"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::uninitialized::<Bar>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::zeroed::<Bar>()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
panic::catch_unwind(|| {
|
||||
mem::MaybeUninit::<Bar>::uninit().assume_init()
|
||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||
s == "Attempted to instantiate uninhabited type Bar"
|
||||
})),
|
||||
Some(true)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
// Regression test for issue #69490
|
||||
|
||||
// check-pass
|
||||
|
||||
pub trait Trait<T> {
|
||||
const S: &'static str;
|
||||
}
|
||||
|
||||
impl<T> 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<T> Trait<()> for [T; 1]
|
||||
where
|
||||
T: Trait<for<'a> fn(&'a ())>,
|
||||
{
|
||||
const S: &'static str = T::S;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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) => {}
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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 {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user