we cannot short-circuit just becuase the Abi seems harmless

also add tests for ScalarPair enums
This commit is contained in:
Ralf Jung 2020-02-17 09:21:02 +01:00
parent 6e66f586a0
commit 729f4cd9ae
2 changed files with 59 additions and 52 deletions

View File

@ -1045,7 +1045,7 @@ pub fn is_zst(&self) -> bool {
/// 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 vonst value validator to see if
/// 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
@ -1067,59 +1067,22 @@ pub fn might_permit_raw_init<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
}
};
// Abi is the most informative here.
let res = match &self.abi {
// 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 { .. } => {
match self.variants {
Variants::Multiple { .. } => {
if zero {
// FIXME(#66151):
// could we identify the variant with discriminant 0, check that?
true
} else {
// FIXME(#66151): This needs to have some sort of discriminant,
// which cannot be undef. But for now we are conservative.
true
}
}
Variants::Single { .. } => {
// For aggregates, recurse.
match self.fields {
FieldPlacement::Union(..) => true, // An all-0 unit is fine.
FieldPlacement::Array { .. } =>
// FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
// with any element type, so let us not (yet) complain about that.
/* count == 0 ||
self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
{
true
}
FieldPlacement::Arbitrary { .. } => {
// FIXME(#66151) cargo depends on sized-chunks 0.3.0 which
// has some illegal zero-initialization, so let us not (yet)
// complain about aggregates either.
/* let mut res = true;
// Check that all fields accept zero-init.
for idx in 0..offsets.len() {
let field = self.field(cx, idx).to_result()?;
if !field.might_permit_raw_init(cx, zero)? {
res = false;
break;
}
}
res */
true
}
}
}
}
}
Abi::Aggregate { .. } => true, // Cannot be excluded *right now*.
};
trace!("might_permit_raw_init({:?}, zero={}) = {}", self.details, zero, res);
Ok(res)
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)
}
}

View File

@ -7,9 +7,10 @@
#![allow(deprecated, invalid_value)]
use std::{
mem::{self, MaybeUninit},
mem::{self, MaybeUninit, ManuallyDrop},
panic,
ptr::NonNull,
num,
};
#[allow(dead_code)]
@ -23,6 +24,18 @@ 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!(
@ -33,7 +46,7 @@ fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
fn main() {
unsafe {
// Uninitialized types
// Uninhabited types
test_panic_msg(
|| mem::uninitialized::<!>(),
"attempted to instantiate uninhabited type `!`"
@ -93,6 +106,26 @@ fn main() {
);
/* 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, \
@ -105,13 +138,24 @@ fn main() {
);
*/
// 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>>>();