Scalar::Union { .. } => true,
}
}
+
+ /// Returns `true` if this type can be left uninit.
+ #[inline]
+ pub fn is_uninit_valid(&self) -> bool {
+ match *self {
+ Scalar::Initialized { .. } => false,
+ Scalar::Union { .. } => true,
+ }
+ }
}
/// Describes how the fields of a type are located in memory.
pub address_space: AddressSpace,
}
+/// Used in `might_permit_raw_init` to indicate the kind of initialisation
+/// that is checked to be valid
+#[derive(Copy, Clone, Debug)]
+pub enum InitKind {
+ Zero,
+ Uninit,
+}
+
/// Trait that needs to be implemented by the higher-level type representation
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
pub trait TyAbiInterface<'a, C>: Sized {
/// 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.
+ ///
+ /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
+ ///
+ /// `strict` is an opt-in debugging flag added in #97323 that enables more checks.
+ ///
/// 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>(self, cx: &C, zero: bool) -> bool
+ pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind, strict: bool) -> bool
where
Self: Copy,
Ty: TyAbiInterface<'a, C>,
C: HasDataLayout,
{
let scalar_allows_raw_init = move |s: Scalar| -> bool {
- if zero {
- // The range must contain 0.
- s.valid_range(cx).contains(0)
- } else {
- // The range must include all values.
- s.is_always_valid(cx)
+ match init_kind {
+ InitKind::Zero => {
+ // The range must contain 0.
+ s.valid_range(cx).contains(0)
+ }
+ InitKind::Uninit => {
+ if strict {
+ // The type must be allowed to be uninit (which means "is a union").
+ s.is_uninit_valid()
+ } else {
+ // The range must include all values.
+ s.is_always_valid(cx)
+ }
+ }
}
};
// 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::Array { count, .. } => {
+ // FIXME(#66151): For now, we are conservative and do not check arrays by default.
+ if strict
+ && *count > 0
+ && !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict)
+ {
+ // Found non empty array with a type that is unhappy about this kind of initialization
+ return false;
+ }
}
FieldsShape::Arbitrary { offsets, .. } => {
for idx in 0..offsets.len() {
- if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
+ if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) {
// We found a field that is unhappy with this kind of initialization.
return false;
}