mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
change might_permit_raw_init to fully detect LLVM UB, but not more than that
This commit is contained in:
parent
02cd79afb8
commit
a0131f0a36
@ -32,7 +32,6 @@ extern crate rustc_middle;
|
||||
pub mod const_eval;
|
||||
mod errors;
|
||||
pub mod interpret;
|
||||
mod might_permit_raw_init;
|
||||
pub mod transform;
|
||||
pub mod util;
|
||||
|
||||
@ -61,7 +60,6 @@ pub fn provide(providers: &mut Providers) {
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
providers.permits_uninit_init =
|
||||
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit);
|
||||
providers.permits_zero_init =
|
||||
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero);
|
||||
|tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
|
||||
providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
use crate::const_eval::CompileTimeInterpreter;
|
||||
use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
use rustc_middle::ty::layout::LayoutCx;
|
||||
use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::InitKind;
|
||||
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: TyAndLayout<'tcx>,
|
||||
kind: InitKind,
|
||||
) -> bool {
|
||||
let strict = tcx.sess.opts.unstable_opts.strict_init_checks;
|
||||
|
||||
if strict {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
/*can_access_statics:*/ false,
|
||||
/*check_alignment:*/ true,
|
||||
);
|
||||
|
||||
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
|
||||
|
||||
let allocated = cx
|
||||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
if kind == InitKind::Zero {
|
||||
cx.write_bytes_ptr(
|
||||
allocated.ptr,
|
||||
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
|
||||
)
|
||||
.expect("failed to write bytes for zero valid check");
|
||||
}
|
||||
|
||||
let ot: OpTy<'_, _> = allocated.into();
|
||||
|
||||
// Assume that if it failed, it's a validation failure.
|
||||
cx.validate_operand(&ot).is_ok()
|
||||
} else {
|
||||
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
|
||||
ty.might_permit_raw_init(&layout_cx, kind)
|
||||
}
|
||||
}
|
151
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
Normal file
151
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
Normal file
@ -0,0 +1,151 @@
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
|
||||
|
||||
use crate::const_eval::CompileTimeInterpreter;
|
||||
use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
|
||||
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
|
||||
/// instance of `T`.
|
||||
///
|
||||
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized. We assume
|
||||
/// uninitialized memory is mitigated by filling it with 0x01, which reduces the chance of causing
|
||||
/// LLVM UB.
|
||||
///
|
||||
/// By default we check whether that operation would cause *LLVM UB*, i.e., whether the LLVM IR we
|
||||
/// generate has UB or not. This is a mitigation strategy, which is why we are okay with accepting
|
||||
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
|
||||
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
|
||||
/// to the full uninit check).
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: TyAndLayout<'tcx>,
|
||||
kind: InitKind,
|
||||
) -> bool {
|
||||
if tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(ty, tcx, kind)
|
||||
} else {
|
||||
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
|
||||
might_permit_raw_init_lax(ty, &layout_cx, kind)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for
|
||||
/// details.
|
||||
fn might_permit_raw_init_strict<'tcx>(
|
||||
ty: TyAndLayout<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: InitKind,
|
||||
) -> bool {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
/*can_access_statics:*/ false,
|
||||
/*check_alignment:*/ true,
|
||||
);
|
||||
|
||||
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
|
||||
|
||||
let allocated = cx
|
||||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
if kind == InitKind::Zero {
|
||||
cx.write_bytes_ptr(
|
||||
allocated.ptr,
|
||||
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
|
||||
)
|
||||
.expect("failed to write bytes for zero valid check");
|
||||
}
|
||||
|
||||
let ot: OpTy<'_, _> = allocated.into();
|
||||
|
||||
// Assume that if it failed, it's a validation failure.
|
||||
// This does *not* actually check that references are dereferenceable, but since all types that
|
||||
// require dereferenceability also require non-null, we don't actually get any false negatives
|
||||
// due to this.
|
||||
cx.validate_operand(&ot).is_ok()
|
||||
}
|
||||
|
||||
/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
|
||||
/// details.
|
||||
fn might_permit_raw_init_lax<'tcx>(
|
||||
this: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
init_kind: InitKind,
|
||||
) -> bool {
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
}
|
||||
InitKind::UninitMitigated0x01Fill => {
|
||||
// The range must include an 0x01-filled buffer.
|
||||
let mut val: u128 = 0x01;
|
||||
for _ in 1..s.size(cx).bytes() {
|
||||
// For sizes >1, repeat the 0x01.
|
||||
val = (val << 8) | 0x01;
|
||||
}
|
||||
s.valid_range(cx).contains(val)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Check the ABI.
|
||||
let valid = match this.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, // Fields are checked below.
|
||||
};
|
||||
if !valid {
|
||||
// This is definitely not okay.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special magic check for references and boxes (i.e., special pointer types).
|
||||
if let Some(pointee) = this.ty.builtin_deref(false) {
|
||||
let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
|
||||
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
|
||||
if pointee.align.abi.bytes() > 1 {
|
||||
// 0x01-filling is not aligned.
|
||||
return false;
|
||||
}
|
||||
if pointee.size.bytes() > 0 {
|
||||
// A 'fake' integer pointer is not sufficiently dereferenceable.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have not found an error yet, we need to recursively descend into fields.
|
||||
match &this.fields {
|
||||
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
|
||||
FieldsShape::Array { .. } => {
|
||||
// Arrays never have scalar layout in LLVM, so if the array is not actually
|
||||
// accessed, there is no LLVM UB -- therefore we can skip this.
|
||||
}
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
for idx in 0..offsets.len() {
|
||||
if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
|
||||
// We found a field that is unhappy with this kind of initialization.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match &this.variants {
|
||||
Variants::Single { .. } => {
|
||||
// All fields of this single variant have already been checked above, there is nothing
|
||||
// else to do.
|
||||
}
|
||||
Variants::Multiple { .. } => {
|
||||
// We cannot tell LLVM anything about the details of this multi-variant layout, so
|
||||
// invalid values "hidden" inside the variant cannot cause LLVM trouble.
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
@ -3,8 +3,10 @@ mod alignment;
|
||||
mod call_kind;
|
||||
pub mod collect_writes;
|
||||
mod find_self_call;
|
||||
mod might_permit_raw_init;
|
||||
|
||||
pub use self::aggregate::expand_aggregate;
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
pub use self::might_permit_raw_init::might_permit_raw_init;
|
||||
|
@ -1392,7 +1392,7 @@ pub struct PointeeInfo {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InitKind {
|
||||
Zero,
|
||||
Uninit,
|
||||
UninitMitigated0x01Fill,
|
||||
}
|
||||
|
||||
/// Trait that needs to be implemented by the higher-level type representation
|
||||
@ -1498,72 +1498,4 @@ impl<'a, Ty> TyAndLayout<'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`.
|
||||
///
|
||||
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
|
||||
///
|
||||
/// This code is intentionally conservative, and will not detect
|
||||
/// * zero init of an enum whose 0 variant does not allow zero initialization
|
||||
/// * making uninitialized types who have a full valid range (ints, floats, raw pointers)
|
||||
/// * Any form of invalid value being made inside an array (unless the value is uninhabited)
|
||||
///
|
||||
/// A strict form of these checks that uses const evaluation exists in
|
||||
/// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
|
||||
/// stricter is <https://github.com/rust-lang/rust/issues/66151>.
|
||||
///
|
||||
/// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
|
||||
/// we can use the const evaluation checks always instead.
|
||||
pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind) -> bool
|
||||
where
|
||||
Self: Copy,
|
||||
Ty: TyAbiInterface<'a, C>,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
}
|
||||
InitKind::Uninit => {
|
||||
// The range must include all values.
|
||||
s.is_always_valid(cx)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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, // Fields are checked below.
|
||||
};
|
||||
if !valid {
|
||||
// This is definitely not okay.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have not found an error yet, we need to recursively descend into fields.
|
||||
match &self.fields {
|
||||
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
|
||||
FieldsShape::Array { .. } => {
|
||||
// FIXME(#66151): For now, we are conservative and do not check arrays by default.
|
||||
}
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
for idx in 0..offsets.len() {
|
||||
if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) {
|
||||
// We found a field that is unhappy with this kind of initialization.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(#66151): For now, we are conservative and do not check `self.variants`.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,15 @@ fn main() {
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
const _BAD1: () = unsafe {
|
||||
MaybeUninit::<!>::uninit().assume_init();
|
||||
intrinsics::assert_inhabited::<!>(); //~ERROR: any use of this value will cause an error
|
||||
//~^WARN: previously accepted
|
||||
};
|
||||
const _BAD2: () = {
|
||||
intrinsics::assert_uninit_valid::<bool>();
|
||||
intrinsics::assert_uninit_valid::<!>(); //~ERROR: any use of this value will cause an error
|
||||
//~^WARN: previously accepted
|
||||
};
|
||||
const _BAD3: () = {
|
||||
intrinsics::assert_zero_valid::<&'static i32>();
|
||||
intrinsics::assert_zero_valid::<&'static i32>(); //~ERROR: any use of this value will cause an error
|
||||
//~^WARN: previously accepted
|
||||
};
|
||||
}
|
||||
|
@ -3,26 +3,26 @@ error: any use of this value will cause an error
|
||||
|
|
||||
LL | const _BAD1: () = unsafe {
|
||||
| ---------------
|
||||
LL | MaybeUninit::<!>::uninit().assume_init();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
LL | intrinsics::assert_inhabited::<!>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:17:9
|
||||
--> $DIR/assert-type-intrinsics.rs:18:9
|
||||
|
|
||||
LL | const _BAD2: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
|
||||
LL | intrinsics::assert_uninit_valid::<!>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:20:9
|
||||
--> $DIR/assert-type-intrinsics.rs:22:9
|
||||
|
|
||||
LL | const _BAD3: () = {
|
||||
| ---------------
|
||||
@ -40,8 +40,8 @@ error: any use of this value will cause an error
|
||||
|
|
||||
LL | const _BAD1: () = unsafe {
|
||||
| ---------------
|
||||
LL | MaybeUninit::<!>::uninit().assume_init();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
LL | intrinsics::assert_inhabited::<!>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
@ -49,12 +49,12 @@ LL | MaybeUninit::<!>::uninit().assume_init();
|
||||
|
||||
Future breakage diagnostic:
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:17:9
|
||||
--> $DIR/assert-type-intrinsics.rs:18:9
|
||||
|
|
||||
LL | const _BAD2: () = {
|
||||
| ---------------
|
||||
LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
|
||||
LL | intrinsics::assert_uninit_valid::<!>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
|
||||
@ -62,7 +62,7 @@ LL | intrinsics::assert_uninit_valid::<bool>();
|
||||
|
||||
Future breakage diagnostic:
|
||||
error: any use of this value will cause an error
|
||||
--> $DIR/assert-type-intrinsics.rs:20:9
|
||||
--> $DIR/assert-type-intrinsics.rs:22:9
|
||||
|
|
||||
LL | const _BAD3: () = {
|
||||
| ---------------
|
||||
|
@ -34,6 +34,12 @@ enum OneVariant_NonZero {
|
||||
DeadVariant(Bar),
|
||||
}
|
||||
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
enum OneVariant_Ref {
|
||||
Variant(&'static i32),
|
||||
DeadVariant(Bar),
|
||||
}
|
||||
|
||||
// An `Aggregate` abi enum where 0 is not a valid discriminant.
|
||||
#[allow(dead_code)]
|
||||
#[repr(i32)]
|
||||
@ -63,6 +69,7 @@ enum ZeroIsValid {
|
||||
One(NonNull<()>) = 1,
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
|
||||
let err = panic::catch_unwind(op).err();
|
||||
assert_eq!(
|
||||
@ -71,6 +78,15 @@ fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
|
||||
);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn test_panic_msg_only_if_strict<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::<&str>()),
|
||||
if cfg!(strict) { Some(&msg) } else { None },
|
||||
);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
// Uninhabited types
|
||||
@ -139,57 +155,68 @@ fn main() {
|
||||
"attempted to instantiate uninhabited type `[Bar; 2]`"
|
||||
);
|
||||
|
||||
// Types that do not like zero-initialziation
|
||||
// Types that don't allow either.
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<fn()>(),
|
||||
"attempted to leave type `fn()` uninitialized, which is invalid"
|
||||
|| mem::zeroed::<&i32>(),
|
||||
"attempted to zero-initialize type `&i32`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<fn()>(),
|
||||
"attempted to zero-initialize type `fn()`, which is invalid"
|
||||
|| mem::uninitialized::<&i32>(),
|
||||
"attempted to leave type `&i32` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<*const dyn Send>(),
|
||||
"attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
|
||||
|| mem::zeroed::<Box<[i32; 0]>>(),
|
||||
"attempted to zero-initialize type `alloc::boxed::Box<[i32; 0]>`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<Box<[i32; 0]>>(),
|
||||
"attempted to leave type `alloc::boxed::Box<[i32; 0]>` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<Box<u8>>(),
|
||||
"attempted to zero-initialize type `alloc::boxed::Box<u8>`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<Box<u8>>(),
|
||||
"attempted to leave type `alloc::boxed::Box<u8>` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&[i32]>(),
|
||||
"attempted to zero-initialize type `&[i32]`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<&[i32]>(),
|
||||
"attempted to leave type `&[i32]` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&(u8, [u8])>(),
|
||||
"attempted to zero-initialize type `&(u8, [u8])`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<&(u8, [u8])>(),
|
||||
"attempted to leave type `&(u8, [u8])` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&dyn Send>(),
|
||||
"attempted to zero-initialize type `&dyn core::marker::Send`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<&dyn Send>(),
|
||||
"attempted to leave type `&dyn core::marker::Send` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<*const dyn Send>(),
|
||||
"attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<OneVariant_NonZero>(),
|
||||
"attempted to leave type `OneVariant_NonZero` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<OneVariant_NonZero>(),
|
||||
"attempted to zero-initialize type `OneVariant_NonZero`, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<LR_NonZero>(),
|
||||
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \
|
||||
which is invalid"
|
||||
|| mem::uninitialized::<*const dyn Send>(),
|
||||
"attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
@ -197,34 +224,147 @@ fn main() {
|
||||
"attempted to leave type `NoNullVariant` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<NoNullVariant>(),
|
||||
"attempted to zero-initialize type `NoNullVariant`, \
|
||||
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"
|
||||
|| mem::zeroed::<OneVariant_Ref>(),
|
||||
"attempted to zero-initialize type `OneVariant_Ref`, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<OneVariant_Ref>(),
|
||||
"attempted to leave type `OneVariant_Ref` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
// Types where both are invalid, but we allow uninit since the 0x01-filling is not LLVM UB.
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<fn()>(),
|
||||
"attempted to zero-initialize type `fn()`, which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<fn()>(),
|
||||
"attempted to leave type `fn()` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&()>(),
|
||||
"attempted to zero-initialize type `&()`, which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<&()>(),
|
||||
"attempted to leave type `&()` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&[u8]>(),
|
||||
"attempted to zero-initialize type `&[u8]`, which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<&[u8]>(),
|
||||
"attempted to leave type `&[u8]` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<&str>(),
|
||||
"attempted to zero-initialize type `&str`, which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<&str>(),
|
||||
"attempted to leave type `&str` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
|
||||
"attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<OneVariant_NonZero>(),
|
||||
"attempted to zero-initialize type `OneVariant_NonZero`, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<OneVariant_NonZero>(),
|
||||
"attempted to leave type `OneVariant_NonZero` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
// Types where both are invalid but we allow the zeroed form since it is not LLVM UB.
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::zeroed::<LR_NonZero>(),
|
||||
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<LR_NonZero>(),
|
||||
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
|
||||
which is invalid"
|
||||
);
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \
|
||||
which is invalid"
|
||||
);
|
||||
|
||||
// Some strict-only things
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<i32>(),
|
||||
"attempted to leave type `i32` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<*const ()>(),
|
||||
"attempted to leave type `*const ()` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<[i32; 1]>(),
|
||||
"attempted to leave type `[i32; 1]` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::zeroed::<[NonNull<()>; 1]>(),
|
||||
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
|
||||
);
|
||||
|
||||
// Types that can be zero, but not uninit (though some are mitigated).
|
||||
let _val = mem::zeroed::<LR>();
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<LR>(),
|
||||
"attempted to leave type `LR` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
let _val = mem::zeroed::<ManuallyDrop<LR>>();
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<ManuallyDrop<LR>>(),
|
||||
"attempted to leave type `core::mem::manually_drop::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>>();
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<bool>(),
|
||||
"attempted to leave type `bool` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
let _val = mem::zeroed::<OneVariant>();
|
||||
test_panic_msg_only_if_strict(
|
||||
|| mem::uninitialized::<OneVariant>(),
|
||||
"attempted to leave type `OneVariant` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
// Some things that are actually allowed.
|
||||
let _val = mem::zeroed::<Option<&'static i32>>();
|
||||
let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
|
||||
let _val = mem::zeroed::<[!; 0]>();
|
||||
@ -233,59 +373,5 @@ fn main() {
|
||||
let _val = mem::uninitialized::<[!; 0]>();
|
||||
let _val = mem::uninitialized::<()>();
|
||||
let _val = mem::uninitialized::<ZeroSized>();
|
||||
|
||||
if cfg!(strict) {
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<i32>(),
|
||||
"attempted to leave type `i32` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<*const ()>(),
|
||||
"attempted to leave type `*const ()` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<[i32; 1]>(),
|
||||
"attempted to leave type `[i32; 1]` uninitialized, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<NonNull<()>>(),
|
||||
"attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<[NonNull<()>; 1]>(),
|
||||
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
|
||||
);
|
||||
|
||||
// FIXME(#66151) we conservatively do not error here yet (by default).
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<LR_NonZero>(),
|
||||
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
|
||||
);
|
||||
|
||||
test_panic_msg(
|
||||
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
|
||||
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
|
||||
which is invalid"
|
||||
);
|
||||
} else {
|
||||
// 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 ()>();
|
||||
|
||||
// These are UB, but best to test them to ensure we don't become unintentionally
|
||||
// stricter.
|
||||
|
||||
// It's currently unchecked to create invalid enums and values inside arrays.
|
||||
let _val = mem::zeroed::<LR_NonZero>();
|
||||
let _val = mem::zeroed::<[LR_NonZero; 1]>();
|
||||
let _val = mem::zeroed::<[NonNull<()>; 1]>();
|
||||
let _val = mem::uninitialized::<[NonNull<()>; 1]>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ fn main() {
|
||||
let _val: NonNull<i32> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: NonNull<i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
let _val: (NonZeroU32, i32) = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: (NonZeroU32, i32) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
@ -133,7 +136,7 @@ fn main() {
|
||||
let _val: Result<i32, i32> = mem::zeroed();
|
||||
let _val: Result<i32, i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
// Some things that happen to work due to rustc implementation details,
|
||||
// Some things that happen to be UB-free due to rustc implementation details,
|
||||
// but are not guaranteed to keep working.
|
||||
let _val: OneFruit = mem::zeroed();
|
||||
let _val: OneFruit = mem::uninitialized();
|
||||
|
@ -315,8 +315,30 @@ LL | let _val: NonNull<i32> = mem::uninitialized();
|
||||
|
|
||||
= note: `std::ptr::NonNull<i32>` must be non-null
|
||||
|
||||
error: the type `(NonZeroU32, i32)` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:91:39
|
||||
|
|
||||
LL | let _val: (NonZeroU32, i32) = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
| |
|
||||
| this code causes undefined behavior when executed
|
||||
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
||||
|
|
||||
= note: `std::num::NonZeroU32` must be non-null
|
||||
|
||||
error: the type `(NonZeroU32, i32)` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:92:39
|
||||
|
|
||||
LL | let _val: (NonZeroU32, i32) = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| this code causes undefined behavior when executed
|
||||
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
||||
|
|
||||
= note: `std::num::NonZeroU32` must be non-null
|
||||
|
||||
error: the type `*const dyn Send` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:91:37
|
||||
--> $DIR/invalid_value.rs:94:37
|
||||
|
|
||||
LL | let _val: *const dyn Send = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -327,7 +349,7 @@ LL | let _val: *const dyn Send = mem::zeroed();
|
||||
= note: the vtable of a wide raw pointer must be non-null
|
||||
|
||||
error: the type `*const dyn Send` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:92:37
|
||||
--> $DIR/invalid_value.rs:95:37
|
||||
|
|
||||
LL | let _val: *const dyn Send = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -338,7 +360,7 @@ LL | let _val: *const dyn Send = mem::uninitialized();
|
||||
= note: the vtable of a wide raw pointer must be non-null
|
||||
|
||||
error: the type `[fn(); 2]` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:94:31
|
||||
--> $DIR/invalid_value.rs:97:31
|
||||
|
|
||||
LL | let _val: [fn(); 2] = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -349,7 +371,7 @@ LL | let _val: [fn(); 2] = mem::zeroed();
|
||||
= note: function pointers must be non-null
|
||||
|
||||
error: the type `[fn(); 2]` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:95:31
|
||||
--> $DIR/invalid_value.rs:98:31
|
||||
|
|
||||
LL | let _val: [fn(); 2] = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -360,7 +382,7 @@ LL | let _val: [fn(); 2] = mem::uninitialized();
|
||||
= note: function pointers must be non-null
|
||||
|
||||
error: the type `TwoUninhabited` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:97:36
|
||||
--> $DIR/invalid_value.rs:100:36
|
||||
|
|
||||
LL | let _val: TwoUninhabited = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -375,7 +397,7 @@ LL | enum TwoUninhabited {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: the type `TwoUninhabited` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:98:36
|
||||
--> $DIR/invalid_value.rs:101:36
|
||||
|
|
||||
LL | let _val: TwoUninhabited = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -390,7 +412,7 @@ LL | enum TwoUninhabited {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: the type `OneFruitNonZero` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:100:37
|
||||
--> $DIR/invalid_value.rs:103:37
|
||||
|
|
||||
LL | let _val: OneFruitNonZero = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -405,7 +427,7 @@ LL | Banana(NonZeroU32),
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the type `OneFruitNonZero` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:101:37
|
||||
--> $DIR/invalid_value.rs:104:37
|
||||
|
|
||||
LL | let _val: OneFruitNonZero = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -420,7 +442,7 @@ LL | Banana(NonZeroU32),
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the type `bool` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:105:26
|
||||
--> $DIR/invalid_value.rs:108:26
|
||||
|
|
||||
LL | let _val: bool = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -431,7 +453,7 @@ LL | let _val: bool = mem::uninitialized();
|
||||
= note: booleans must be either `true` or `false`
|
||||
|
||||
error: the type `Wrap<char>` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:108:32
|
||||
--> $DIR/invalid_value.rs:111:32
|
||||
|
|
||||
LL | let _val: Wrap<char> = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -446,7 +468,7 @@ LL | struct Wrap<T> { wrapped: T }
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the type `NonBig` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:111:28
|
||||
--> $DIR/invalid_value.rs:114:28
|
||||
|
|
||||
LL | let _val: NonBig = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -457,7 +479,7 @@ LL | let _val: NonBig = mem::uninitialized();
|
||||
= note: `NonBig` must be initialized inside its custom valid range
|
||||
|
||||
error: the type `Fruit` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:114:27
|
||||
--> $DIR/invalid_value.rs:117:27
|
||||
|
|
||||
LL | let _val: Fruit = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -472,7 +494,7 @@ LL | enum Fruit {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: the type `[bool; 2]` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:117:31
|
||||
--> $DIR/invalid_value.rs:120:31
|
||||
|
|
||||
LL | let _val: [bool; 2] = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -483,7 +505,7 @@ LL | let _val: [bool; 2] = mem::uninitialized();
|
||||
= note: booleans must be either `true` or `false`
|
||||
|
||||
error: the type `i32` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:120:25
|
||||
--> $DIR/invalid_value.rs:123:25
|
||||
|
|
||||
LL | let _val: i32 = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -494,7 +516,7 @@ LL | let _val: i32 = mem::uninitialized();
|
||||
= note: integers must not be uninitialized
|
||||
|
||||
error: the type `f32` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:123:25
|
||||
--> $DIR/invalid_value.rs:126:25
|
||||
|
|
||||
LL | let _val: f32 = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -505,7 +527,7 @@ LL | let _val: f32 = mem::uninitialized();
|
||||
= note: floats must not be uninitialized
|
||||
|
||||
error: the type `*const ()` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:126:31
|
||||
--> $DIR/invalid_value.rs:129:31
|
||||
|
|
||||
LL | let _val: *const () = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -516,7 +538,7 @@ LL | let _val: *const () = mem::uninitialized();
|
||||
= note: raw pointers must not be uninitialized
|
||||
|
||||
error: the type `*const [()]` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:129:33
|
||||
--> $DIR/invalid_value.rs:132:33
|
||||
|
|
||||
LL | let _val: *const [()] = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -527,7 +549,7 @@ LL | let _val: *const [()] = mem::uninitialized();
|
||||
= note: raw pointers must not be uninitialized
|
||||
|
||||
error: the type `Result<i32, i32>` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:134:38
|
||||
--> $DIR/invalid_value.rs:137:38
|
||||
|
|
||||
LL | let _val: Result<i32, i32> = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@ -542,7 +564,7 @@ LL | pub enum Result<T, E> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: the type `&i32` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:142:34
|
||||
--> $DIR/invalid_value.rs:145:34
|
||||
|
|
||||
LL | let _val: &'static i32 = mem::transmute(0usize);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -553,7 +575,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize);
|
||||
= note: references must be non-null
|
||||
|
||||
error: the type `&[i32]` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:143:36
|
||||
--> $DIR/invalid_value.rs:146:36
|
||||
|
|
||||
LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -564,7 +586,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
|
||||
= note: references must be non-null
|
||||
|
||||
error: the type `NonZeroU32` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:144:32
|
||||
--> $DIR/invalid_value.rs:147:32
|
||||
|
|
||||
LL | let _val: NonZeroU32 = mem::transmute(0);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
@ -575,7 +597,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0);
|
||||
= note: `std::num::NonZeroU32` must be non-null
|
||||
|
||||
error: the type `NonNull<i32>` does not permit zero-initialization
|
||||
--> $DIR/invalid_value.rs:147:34
|
||||
--> $DIR/invalid_value.rs:150:34
|
||||
|
|
||||
LL | let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -586,7 +608,7 @@ LL | let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
|
||||
= note: `std::ptr::NonNull<i32>` must be non-null
|
||||
|
||||
error: the type `NonNull<i32>` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:148:34
|
||||
--> $DIR/invalid_value.rs:151:34
|
||||
|
|
||||
LL | let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -597,7 +619,7 @@ LL | let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
|
||||
= note: `std::ptr::NonNull<i32>` must be non-null
|
||||
|
||||
error: the type `bool` does not permit being left uninitialized
|
||||
--> $DIR/invalid_value.rs:149:26
|
||||
--> $DIR/invalid_value.rs:152:26
|
||||
|
|
||||
LL | let _val: bool = MaybeUninit::uninit().assume_init();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -607,5 +629,5 @@ LL | let _val: bool = MaybeUninit::uninit().assume_init();
|
||||
|
|
||||
= note: booleans must be either `true` or `false`
|
||||
|
||||
error: aborting due to 48 previous errors
|
||||
error: aborting due to 50 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user