Skip to content

Commit 83f0ffb

Browse files
committed
Fix offset_of for non-absent uninhabited variants in using tagless enum representations
1 parent acc0cc7 commit 83f0ffb

File tree

38 files changed

+184
-86
lines changed

38 files changed

+184
-86
lines changed

compiler/rustc_abi/src/callconv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
140140
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
141141

142142
match &self.variants {
143-
Variants::Single { .. } | Variants::Empty => {}
143+
Variants::Single { .. } | Variants::Empty { .. } => {}
144144
Variants::Multiple { variants, .. } => {
145145
// Treat enum variants like union members.
146146
// HACK(eddyb) pretend the `enum` field (discriminant)

compiler/rustc_abi/src/layout.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
130130
element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?;
131131

132132
Ok(LayoutData {
133-
variants: Variants::Single { index: VariantIdx::new(0) },
133+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
134134
fields: FieldsShape::Array { stride: element.size, count },
135135
backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() },
136136
largest_niche: element.largest_niche.filter(|_| count != 0),
@@ -181,7 +181,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
181181
let size = size.align_to(align.abi);
182182

183183
Ok(LayoutData {
184-
variants: Variants::Single { index: VariantIdx::new(0) },
184+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
185185
fields: FieldsShape::Arbitrary {
186186
offsets: [Size::ZERO].into(),
187187
memory_index: [0].into(),
@@ -469,7 +469,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
469469
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
470470

471471
Ok(LayoutData {
472-
variants: Variants::Single { index: only_variant_idx },
472+
variants: Variants::Single { index: only_variant_idx, variants: None },
473473
fields: FieldsShape::Union(union_field_count),
474474
backend_repr,
475475
largest_niche: None,
@@ -510,7 +510,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
510510
};
511511

512512
let mut st = self.univariant(&variants[v], repr, kind)?;
513-
st.variants = Variants::Single { index: v };
513+
st.variants = Variants::Single { index: v, variants: None };
514514

515515
if is_special_no_niche {
516516
let hide_niches = |scalar: &mut _| match scalar {
@@ -617,7 +617,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
617617
.iter_enumerated()
618618
.map(|(j, v)| {
619619
let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;
620-
st.variants = Variants::Single { index: j };
620+
st.variants = Variants::Single { index: j, variants: None };
621621

622622
align = align.max(st.align);
623623
max_repr_align = max_repr_align.max(st.max_repr_align);
@@ -853,7 +853,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
853853
};
854854
let mut st = self.univariant(field_layouts, repr, struct_kind)?;
855855

856-
st.variants = Variants::Single { index: i };
856+
st.variants = Variants::Single { index: i, variants: None };
857857
// Find the first field we can't move later
858858
// to make room for a larger discriminant.
859859
for field_idx in st.fields.index_by_increasing_offset() {
@@ -1118,7 +1118,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
11181118
);
11191119
return Ok(LayoutData {
11201120
fields: FieldsShape::Arbitrary { offsets: [].into(), memory_index: [].into() },
1121-
variants: Variants::Empty,
1121+
variants: Variants::Empty { variants: Some(layout_variants) },
11221122
backend_repr: BackendRepr::Memory { sized: true },
11231123
largest_niche: None,
11241124
uninhabited: true,
@@ -1512,7 +1512,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
15121512
let seed = field_seed.wrapping_add(repr.field_shuffle_seed);
15131513

15141514
Ok(LayoutData {
1515-
variants: Variants::Single { index: VariantIdx::new(0) },
1515+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
15161516
fields: FieldsShape::Arbitrary { offsets, memory_index },
15171517
backend_repr: abi,
15181518
largest_niche,

compiler/rustc_abi/src/layout/coroutine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ pub(super) fn layout<
234234
&ReprOptions::default(),
235235
StructKind::Prefixed(prefix_size, prefix_align.abi),
236236
)?;
237-
variant.variants = Variants::Single { index };
237+
variant.variants = Variants::Single { index, variants: None };
238238

239239
let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
240240
unreachable!();

compiler/rustc_abi/src/layout/simple.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
1212
pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
1313
let dl = cx.data_layout();
1414
LayoutData {
15-
variants: Variants::Single { index: VariantIdx::new(0) },
15+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
1616
fields: FieldsShape::Arbitrary {
1717
offsets: IndexVec::new(),
1818
memory_index: IndexVec::new(),
@@ -32,7 +32,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
3232
let dl = cx.data_layout();
3333
// This is also used for uninhabited enums, so we use `Variants::Empty`.
3434
LayoutData {
35-
variants: Variants::Empty,
35+
variants: Variants::Empty { variants: None },
3636
fields: FieldsShape::Primitive,
3737
backend_repr: BackendRepr::Memory { sized: true },
3838
largest_niche: None,
@@ -74,7 +74,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
7474
.wrapping_add((range.end as u64).rotate_right(16));
7575

7676
LayoutData {
77-
variants: Variants::Single { index: VariantIdx::new(0) },
77+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
7878
fields: FieldsShape::Primitive,
7979
backend_repr: BackendRepr::Scalar(scalar),
8080
largest_niche,
@@ -104,7 +104,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
104104
let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
105105

106106
LayoutData {
107-
variants: Variants::Single { index: VariantIdx::new(0) },
107+
variants: Variants::Single { index: VariantIdx::new(0), variants: None },
108108
fields: FieldsShape::Arbitrary {
109109
offsets: [Size::ZERO, b_offset].into(),
110110
memory_index: [0, 1].into(),
@@ -120,14 +120,14 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
120120
}
121121
}
122122

123-
/// Returns a dummy layout for an uninhabited variant.
123+
/// Returns a dummy layout for an absent variant.
124124
///
125-
/// Uninhabited variants get pruned as part of the layout calculation,
125+
/// Absent variants get pruned as part of the layout calculation,
126126
/// so this can be used after the fact to reconstitute a layout.
127-
pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
127+
pub fn absent_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
128128
let dl = cx.data_layout();
129129
LayoutData {
130-
variants: Variants::Single { index },
130+
variants: Variants::Single { index, variants: None },
131131
fields: match NonZero::new(fields) {
132132
Some(fields) => FieldsShape::Union(fields),
133133
None => FieldsShape::Arbitrary {

compiler/rustc_abi/src/lib.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,12 +1852,27 @@ impl BackendRepr {
18521852
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
18531853
pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
18541854
/// A type with no valid variants. Must be uninhabited.
1855-
Empty,
1855+
///
1856+
/// We still need to hold variant layout information for `offset_of!`
1857+
/// on uninhabited enum variants with non-zero-sized fields.
1858+
Empty {
1859+
/// Always `None` for non-enums.
1860+
/// For enums, this is `None` if all variants are "absent"
1861+
/// (have no non-1-ZST fields), and is `Some` otherwise.
1862+
variants: Option<IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>>,
1863+
},
18561864

1857-
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
1865+
/// Enums with one inhabited variant and no tag, structs/tuples, unions, and all non-ADTs.
1866+
///
1867+
/// We still need to hold variant layout information for `offset_of!`
1868+
/// on uninhabited enum variants with non-zero-sized fields.
18581869
Single {
18591870
/// Always `0` for types that cannot have multiple variants.
18601871
index: VariantIdx,
1872+
/// Always `None` for non-enums.
1873+
/// For enums, this is `None` if all uninhabited variants are "absent"
1874+
/// (have no non-1-ZST fields), and is `Some` otherwise.
1875+
variants: Option<IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>>,
18611876
},
18621877

18631878
/// Enum-likes with more than one variant: each variant comes with

compiler/rustc_codegen_cranelift/src/discriminant.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
1818
return;
1919
}
2020
match layout.variants {
21-
Variants::Empty => unreachable!("we already handled uninhabited types"),
22-
Variants::Single { index } => {
21+
Variants::Empty { .. } => unreachable!("we already handled uninhabited types"),
22+
Variants::Single { index, .. } => {
2323
assert_eq!(index, variant_index);
2424
}
2525
Variants::Multiple {
@@ -86,8 +86,8 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
8686
}
8787

8888
let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
89-
Variants::Empty => unreachable!("we already handled uninhabited types"),
90-
Variants::Single { index } => {
89+
Variants::Empty { .. } => unreachable!("we already handled uninhabited types"),
90+
Variants::Single { index, .. } => {
9191
let discr_val = layout
9292
.ty
9393
.discriminant_for_variant(fx.tcx, *index)

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,11 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
213213
),
214214
|cx, enum_type_di_node| {
215215
match enum_type_and_layout.variants {
216-
Variants::Empty => {
216+
Variants::Empty { .. } => {
217217
// We don't generate any members for uninhabited types.
218218
return smallvec![];
219219
}
220-
Variants::Single { index: variant_index } => build_single_variant_union_fields(
220+
Variants::Single { index: variant_index, .. } => build_single_variant_union_fields(
221221
cx,
222222
enum_adt_def,
223223
enum_type_and_layout,
@@ -300,7 +300,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
300300
)
301301
}
302302
Variants::Single { .. }
303-
| Variants::Empty
303+
| Variants::Empty { .. }
304304
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => {
305305
bug!(
306306
"Encountered coroutine with non-direct-tag layout: {:?}",

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ fn compute_discriminant_value<'ll, 'tcx>(
392392
variant_index: VariantIdx,
393393
) -> DiscrResult {
394394
match enum_type_and_layout.layout.variants() {
395-
&Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant,
395+
&Variants::Single { .. } | &Variants::Empty { .. } => DiscrResult::NoDiscriminant,
396396
&Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
397397
enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
398398
),

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
357357

358358
match enum_or_coroutine_type_and_layout.layout.variants() {
359359
// A single-variant or no-variant enum has no discriminant.
360-
&Variants::Single { .. } | &Variants::Empty => None,
360+
&Variants::Single { .. } | &Variants::Empty { .. } => None,
361361

362362
&Variants::Multiple { tag_field, .. } => {
363363
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);

compiler/rustc_codegen_llvm/src/type_of.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ fn uncached_llvm_type<'a, 'tcx>(
3535
if !cx.sess().fewer_names() =>
3636
{
3737
let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string()));
38-
if let (&ty::Adt(def, _), &Variants::Single { index }) =
38+
if let (&ty::Adt(def, _), &Variants::Single { index, .. }) =
3939
(layout.ty.kind(), &layout.variants)
4040
{
4141
if def.is_enum() {
4242
write!(&mut name, "::{}", def.variant(index).name).unwrap();
4343
}
4444
}
45-
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
45+
if let (&ty::Coroutine(_, _), &Variants::Single { index, .. }) =
4646
(layout.ty.kind(), &layout.variants)
4747
{
4848
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
@@ -213,7 +213,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
213213

214214
// Check the cache.
215215
let variant_index = match self.variants {
216-
Variants::Single { index } => Some(index),
216+
Variants::Single { index, .. } => Some(index),
217217
_ => None,
218218
};
219219
if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {

0 commit comments

Comments
 (0)