diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 4b565dd246f..3c1a2ea39d3 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1135,16 +1135,31 @@ pub fn might_permit_raw_init(self, cx: &C, zero: bool) -> Result 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*. + Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. - trace!("might_permit_raw_init({:?}, zero={}): not valid", self.layout, 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. + // 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. + } + FieldsShape::Arbitrary { offsets, .. } => { + for idx in 0..offsets.len() { + let field = self.field(cx, idx).to_result()?; + if !field.might_permit_raw_init(cx, zero)? { + // We found a field that is unhappy with this kind of initialization. + return Ok(false); + } + } + } + } + + // FIXME(#66151): For now, we are conservative and do not check `self.variants`. Ok(true) } } diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 02f8ecaa4ee..24474cabf1e 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -3,7 +3,7 @@ // This test checks panic emitted from `mem::{uninitialized,zeroed}`. -#![feature(never_type)] +#![feature(never_type, arbitrary_enum_discriminant)] #![allow(deprecated, invalid_value)] use std::{ @@ -24,6 +24,20 @@ enum Bar {} #[allow(dead_code)] enum OneVariant { Variant(i32) } +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + // An enum with ScalarPair layout #[allow(dead_code)] enum LR { @@ -125,6 +139,7 @@ fn main() { "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ which is invalid" ); + */ test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), @@ -136,7 +151,28 @@ fn main() { "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); - */ + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `NoNullVariant` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `NoNullVariant`, \ + which is invalid" + ); // Types that can be zero, but not uninit. test_panic_msg(