@@ -894,6 +894,15 @@ impl Scalar {
894
894
Scalar :: Union { .. } => true ,
895
895
}
896
896
}
897
+
898
+ /// Returns `true` if this type can be left uninit.
899
+ #[ inline]
900
+ pub fn is_uninit_valid ( & self ) -> bool {
901
+ match * self {
902
+ Scalar :: Initialized { .. } => false ,
903
+ Scalar :: Union { .. } => true ,
904
+ }
905
+ }
897
906
}
898
907
899
908
/// Describes how the fields of a type are located in memory.
@@ -1355,6 +1364,14 @@ pub struct PointeeInfo {
1355
1364
pub address_space : AddressSpace ,
1356
1365
}
1357
1366
1367
+ /// Used in `might_permit_raw_init` to indicate the kind of initialisation
1368
+ /// that is checked to be valid
1369
+ #[ derive( Copy , Clone , Debug ) ]
1370
+ pub enum InitKind {
1371
+ Zero ,
1372
+ Uninit ,
1373
+ }
1374
+
1358
1375
/// Trait that needs to be implemented by the higher-level type representation
1359
1376
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
1360
1377
pub trait TyAbiInterface < ' a , C > : Sized {
@@ -1461,26 +1478,37 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
1461
1478
1462
1479
/// Determines if this type permits "raw" initialization by just transmuting some
1463
1480
/// memory into an instance of `T`.
1464
- /// `zero` indicates if the memory is zero-initialized, or alternatively
1465
- /// left entirely uninitialized.
1481
+ ///
1482
+ /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
1483
+ ///
1484
+ /// `strict` is an opt-in debugging flag added in #97323 that enables more checks.
1485
+ ///
1466
1486
/// This is conservative: in doubt, it will answer `true`.
1467
1487
///
1468
1488
/// FIXME: Once we removed all the conservatism, we could alternatively
1469
1489
/// create an all-0/all-undef constant and run the const value validator to see if
1470
1490
/// this is a valid value for the given type.
1471
- pub fn might_permit_raw_init < C > ( self , cx : & C , zero : bool ) -> bool
1491
+ pub fn might_permit_raw_init < C > ( self , cx : & C , init_kind : InitKind , strict : bool ) -> bool
1472
1492
where
1473
1493
Self : Copy ,
1474
1494
Ty : TyAbiInterface < ' a , C > ,
1475
1495
C : HasDataLayout ,
1476
1496
{
1477
1497
let scalar_allows_raw_init = move |s : Scalar | -> bool {
1478
- if zero {
1479
- // The range must contain 0.
1480
- s. valid_range ( cx) . contains ( 0 )
1481
- } else {
1482
- // The range must include all values.
1483
- s. is_always_valid ( cx)
1498
+ match init_kind {
1499
+ InitKind :: Zero => {
1500
+ // The range must contain 0.
1501
+ s. valid_range ( cx) . contains ( 0 )
1502
+ }
1503
+ InitKind :: Uninit => {
1504
+ if strict {
1505
+ // The type must be allowed to be uninit (which means "is a union").
1506
+ s. is_uninit_valid ( )
1507
+ } else {
1508
+ // The range must include all values.
1509
+ s. is_always_valid ( cx)
1510
+ }
1511
+ }
1484
1512
}
1485
1513
} ;
1486
1514
@@ -1500,12 +1528,19 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
1500
1528
// If we have not found an error yet, we need to recursively descend into fields.
1501
1529
match & self . fields {
1502
1530
FieldsShape :: Primitive | FieldsShape :: Union { .. } => { }
1503
- FieldsShape :: Array { .. } => {
1504
- // FIXME(#66151): For now, we are conservative and do not check arrays.
1531
+ FieldsShape :: Array { count, .. } => {
1532
+ // FIXME(#66151): For now, we are conservative and do not check arrays by default.
1533
+ if strict
1534
+ && * count > 0
1535
+ && !self . field ( cx, 0 ) . might_permit_raw_init ( cx, init_kind, strict)
1536
+ {
1537
+ // Found non empty array with a type that is unhappy about this kind of initialization
1538
+ return false ;
1539
+ }
1505
1540
}
1506
1541
FieldsShape :: Arbitrary { offsets, .. } => {
1507
1542
for idx in 0 ..offsets. len ( ) {
1508
- if !self . field ( cx, idx) . might_permit_raw_init ( cx, zero ) {
1543
+ if !self . field ( cx, idx) . might_permit_raw_init ( cx, init_kind , strict ) {
1509
1544
// We found a field that is unhappy with this kind of initialization.
1510
1545
return false ;
1511
1546
}
0 commit comments