Skip to content

Commit a8272f2

Browse files
committed
Auto merge of #96197 - erikdesjardins:scalarpairenum, r=oli-obk
Mark payload fields of ScalarPair enums as Scalar::Union when they're not always initialized Fixes #96158 r? `@RalfJung`
2 parents 8d68f2f + 4dcc1aa commit a8272f2

File tree

3 files changed

+795
-16
lines changed

3 files changed

+795
-16
lines changed

compiler/rustc_middle/src/ty/layout.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -1120,21 +1120,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
11201120
match st[i].abi() {
11211121
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
11221122
Abi::ScalarPair(first, second) => {
1123-
// We need to use scalar_unit to reset the
1124-
// valid range to the maximal one for that
1125-
// primitive, because only the niche is
1126-
// guaranteed to be initialised, not the
1127-
// other primitive.
1123+
// Only the niche is guaranteed to be initialised,
1124+
// so use union layout for the other primitive.
11281125
if offset.bytes() == 0 {
1129-
Abi::ScalarPair(
1130-
niche_scalar,
1131-
scalar_unit(second.primitive()),
1132-
)
1126+
Abi::ScalarPair(niche_scalar, second.to_union())
11331127
} else {
1134-
Abi::ScalarPair(
1135-
scalar_unit(first.primitive()),
1136-
niche_scalar,
1137-
)
1128+
Abi::ScalarPair(first.to_union(), niche_scalar)
11381129
}
11391130
}
11401131
_ => Abi::Aggregate { sized: true },
@@ -1329,22 +1320,30 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13291320
} else {
13301321
// Try to use a ScalarPair for all tagged enums.
13311322
let mut common_prim = None;
1323+
let mut common_prim_initialized_in_all_variants = true;
13321324
for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
13331325
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
13341326
bug!();
13351327
};
13361328
let mut fields =
13371329
iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
13381330
let (field, offset) = match (fields.next(), fields.next()) {
1339-
(None, None) => continue,
1331+
(None, None) => {
1332+
common_prim_initialized_in_all_variants = false;
1333+
continue;
1334+
}
13401335
(Some(pair), None) => pair,
13411336
_ => {
13421337
common_prim = None;
13431338
break;
13441339
}
13451340
};
13461341
let prim = match field.abi {
1347-
Abi::Scalar(scalar) => scalar.primitive(),
1342+
Abi::Scalar(scalar) => {
1343+
common_prim_initialized_in_all_variants &=
1344+
matches!(scalar, Scalar::Initialized { .. });
1345+
scalar.primitive()
1346+
}
13481347
_ => {
13491348
common_prim = None;
13501349
break;
@@ -1364,7 +1363,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13641363
}
13651364
}
13661365
if let Some((prim, offset)) = common_prim {
1367-
let pair = self.scalar_pair(tag, scalar_unit(prim));
1366+
let prim_scalar = if common_prim_initialized_in_all_variants {
1367+
scalar_unit(prim)
1368+
} else {
1369+
// Common prim might be uninit.
1370+
Scalar::Union { value: prim }
1371+
};
1372+
let pair = self.scalar_pair(tag, prim_scalar);
13681373
let pair_offsets = match pair.fields {
13691374
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
13701375
assert_eq!(memory_index, &[0, 1]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN"
2+
#![crate_type = "lib"]
3+
#![feature(rustc_attrs)]
4+
5+
use std::mem::MaybeUninit;
6+
7+
enum HasNiche {
8+
A,
9+
B,
10+
C,
11+
}
12+
13+
// This should result in ScalarPair(Initialized, Union),
14+
// since the u8 payload will be uninit for `None`.
15+
#[rustc_layout(debug)]
16+
pub enum MissingPayloadField { //~ ERROR: layout_of
17+
Some(u8),
18+
None
19+
}
20+
21+
// This should result in ScalarPair(Initialized, Initialized),
22+
// since the u8 field is present in all variants,
23+
// and hence will always be initialized.
24+
#[rustc_layout(debug)]
25+
pub enum CommonPayloadField { //~ ERROR: layout_of
26+
A(u8),
27+
B(u8),
28+
}
29+
30+
// This should result in ScalarPair(Initialized, Union),
31+
// since, though a u8-sized field is present in all variants, it might be uninit.
32+
#[rustc_layout(debug)]
33+
pub enum CommonPayloadFieldIsMaybeUninit { //~ ERROR: layout_of
34+
A(u8),
35+
B(MaybeUninit<u8>),
36+
}
37+
38+
// This should result in ScalarPair(Initialized, Union),
39+
// since only the niche field (used for the tag) is guaranteed to be initialized.
40+
#[rustc_layout(debug)]
41+
pub enum NicheFirst { //~ ERROR: layout_of
42+
A(HasNiche, u8),
43+
B,
44+
C
45+
}
46+
47+
// This should result in ScalarPair(Union, Initialized),
48+
// since only the niche field (used for the tag) is guaranteed to be initialized.
49+
#[rustc_layout(debug)]
50+
pub enum NicheSecond { //~ ERROR: layout_of
51+
A(u8, HasNiche),
52+
B,
53+
C,
54+
}

0 commit comments

Comments
 (0)