Skip to content

Commit 9a612b2

Browse files
committed
Auto merge of #59651 - tmandry:discr-index, r=eddyb
Add discr_index to multi-variant layouts We remove the assumption that the discriminant is always field 0, in preparations for layouts like generators where this is not (always) going to be the case. Specifically, upvars are going to go before the discriminant. In theory, it's possible to remove _that_ assumption instead and keep the discriminant at field index 0, but one assumption or the other had to go :) There is one place I know of in the debuginfo code where we'll still need to remove assumptions that the discriminant is the _only_ field. I was planning on doing this along with the upcoming generator change, which will also include tests that exercise the code changing in this PR. r? @eddyb cc @oli-obk cc @cramertj
2 parents 5b96425 + 7c626a6 commit 9a612b2

File tree

8 files changed

+77
-59
lines changed

8 files changed

+77
-59
lines changed

src/librustc/ty/layout.rs

+4
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
920920
niche_variants,
921921
niche_start,
922922
},
923+
discr_index: 0,
923924
variants: st,
924925
},
925926
fields: FieldPlacement::Arbitrary {
@@ -1142,6 +1143,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
11421143
variants: Variants::Multiple {
11431144
discr: tag,
11441145
discr_kind: DiscriminantKind::Tag,
1146+
discr_index: 0,
11451147
variants: layout_variants,
11461148
},
11471149
fields: FieldPlacement::Arbitrary {
@@ -1884,10 +1886,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for Variants {
18841886
Multiple {
18851887
ref discr,
18861888
ref discr_kind,
1889+
discr_index,
18871890
ref variants,
18881891
} => {
18891892
discr.hash_stable(hcx, hasher);
18901893
discr_kind.hash_stable(hcx, hasher);
1894+
discr_index.hash_stable(hcx, hasher);
18911895
variants.hash_stable(hcx, hasher);
18921896
}
18931897
}

src/librustc_codegen_llvm/debuginfo/metadata.rs

+34-24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc::hir::CodegenFnAttrFlags;
2222
use rustc::hir::def::CtorKind;
2323
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
2424
use rustc::ich::NodeIdHashingMode;
25+
use rustc::mir::Field;
2526
use rustc::mir::interpret::truncate;
2627
use rustc_data_structures::fingerprint::Fingerprint;
2728
use rustc::ty::Instance;
@@ -1306,12 +1307,15 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
13061307
}
13071308
layout::Variants::Multiple {
13081309
discr_kind: layout::DiscriminantKind::Tag,
1310+
discr_index,
13091311
ref variants,
13101312
..
13111313
} => {
13121314
let discriminant_info = if fallback {
1313-
RegularDiscriminant(self.discriminant_type_metadata
1314-
.expect(""))
1315+
RegularDiscriminant {
1316+
discr_field: Field::from(discr_index),
1317+
discr_type_metadata: self.discriminant_type_metadata.unwrap()
1318+
}
13151319
} else {
13161320
// This doesn't matter in this case.
13171321
NoDiscriminant
@@ -1358,6 +1362,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
13581362
},
13591363
ref discr,
13601364
ref variants,
1365+
discr_index,
13611366
} => {
13621367
if fallback {
13631368
let variant = self.layout.for_variant(cx, dataful_variant);
@@ -1403,8 +1408,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
14031408
}
14041409
compute_field_path(cx, &mut name,
14051410
self.layout,
1406-
self.layout.fields.offset(0),
1407-
self.layout.field(cx, 0).size);
1411+
self.layout.fields.offset(discr_index),
1412+
self.layout.field(cx, discr_index).size);
14081413
name.push_str(&adt.variants[*niche_variants.start()].ident.as_str());
14091414

14101415
// Create the (singleton) list of descriptions of union members.
@@ -1486,6 +1491,8 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
14861491
name: name.to_string(),
14871492
type_metadata: if use_enum_fallback(cx) {
14881493
match self.discriminant_type_metadata {
1494+
// Discriminant is always the first field of our variant
1495+
// when using the enum fallback.
14891496
Some(metadata) if i == 0 => metadata,
14901497
_ => type_metadata(cx, ty, self.span)
14911498
}
@@ -1504,7 +1511,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
15041511

15051512
#[derive(Copy, Clone)]
15061513
enum EnumDiscriminantInfo<'ll> {
1507-
RegularDiscriminant(&'ll DIType),
1514+
RegularDiscriminant{ discr_field: Field, discr_type_metadata: &'ll DIType },
15081515
OptimizedDiscriminant,
15091516
NoDiscriminant
15101517
}
@@ -1535,15 +1542,26 @@ fn describe_enum_variant(
15351542
unique_type_id,
15361543
Some(containing_scope));
15371544

1545+
let arg_name = |i: usize| {
1546+
if variant.ctor_kind == CtorKind::Fn {
1547+
format!("__{}", i)
1548+
} else {
1549+
variant.fields[i].ident.to_string()
1550+
}
1551+
};
1552+
15381553
// Build an array of (field name, field type) pairs to be captured in the factory closure.
15391554
let (offsets, args) = if use_enum_fallback(cx) {
15401555
// If this is not a univariant enum, there is also the discriminant field.
15411556
let (discr_offset, discr_arg) = match discriminant_info {
1542-
RegularDiscriminant(_) => {
1557+
RegularDiscriminant { discr_field, .. } => {
15431558
// We have the layout of an enum variant, we need the layout of the outer enum
15441559
let enum_layout = cx.layout_of(layout.ty);
1545-
(Some(enum_layout.fields.offset(0)),
1546-
Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
1560+
let offset = enum_layout.fields.offset(discr_field.as_usize());
1561+
let args = (
1562+
"RUST$ENUM$DISR".to_owned(),
1563+
enum_layout.field(cx, discr_field.as_usize()).ty);
1564+
(Some(offset), Some(args))
15471565
}
15481566
_ => (None, None),
15491567
};
@@ -1552,12 +1570,7 @@ fn describe_enum_variant(
15521570
layout.fields.offset(i)
15531571
})).collect(),
15541572
discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
1555-
let name = if variant.ctor_kind == CtorKind::Fn {
1556-
format!("__{}", i)
1557-
} else {
1558-
variant.fields[i].ident.to_string()
1559-
};
1560-
(name, layout.field(cx, i).ty)
1573+
(arg_name(i), layout.field(cx, i).ty)
15611574
})).collect()
15621575
)
15631576
} else {
@@ -1566,12 +1579,7 @@ fn describe_enum_variant(
15661579
layout.fields.offset(i)
15671580
}).collect(),
15681581
(0..layout.fields.count()).map(|i| {
1569-
let name = if variant.ctor_kind == CtorKind::Fn {
1570-
format!("__{}", i)
1571-
} else {
1572-
variant.fields[i].ident.to_string()
1573-
};
1574-
(name, layout.field(cx, i).ty)
1582+
(arg_name(i), layout.field(cx, i).ty)
15751583
}).collect()
15761584
)
15771585
};
@@ -1581,8 +1589,8 @@ fn describe_enum_variant(
15811589
offsets,
15821590
args,
15831591
discriminant_type_metadata: match discriminant_info {
1584-
RegularDiscriminant(discriminant_type_metadata) => {
1585-
Some(discriminant_type_metadata)
1592+
RegularDiscriminant { discr_type_metadata, .. } => {
1593+
Some(discr_type_metadata)
15861594
}
15871595
_ => None
15881596
},
@@ -1732,6 +1740,7 @@ fn prepare_enum_metadata(
17321740
layout::Variants::Multiple {
17331741
discr_kind: layout::DiscriminantKind::Niche { .. },
17341742
ref discr,
1743+
discr_index,
17351744
..
17361745
} => {
17371746
// Find the integer type of the correct size.
@@ -1755,7 +1764,7 @@ fn prepare_enum_metadata(
17551764
UNKNOWN_LINE_NUMBER,
17561765
size.bits(),
17571766
align.abi.bits() as u32,
1758-
layout.fields.offset(0).bits(),
1767+
layout.fields.offset(discr_index).bits(),
17591768
DIFlags::FlagArtificial,
17601769
discr_metadata))
17611770
}
@@ -1764,6 +1773,7 @@ fn prepare_enum_metadata(
17641773
layout::Variants::Multiple {
17651774
discr_kind: layout::DiscriminantKind::Tag,
17661775
ref discr,
1776+
discr_index,
17671777
..
17681778
} => {
17691779
let discr_type = discr.value.to_ty(cx.tcx);
@@ -1779,7 +1789,7 @@ fn prepare_enum_metadata(
17791789
UNKNOWN_LINE_NUMBER,
17801790
size.bits(),
17811791
align.bits() as u32,
1782-
layout.fields.offset(0).bits(),
1792+
layout.fields.offset(discr_index).bits(),
17831793
DIFlags::FlagArtificial,
17841794
discr_metadata))
17851795
}

src/librustc_codegen_llvm/type_of.rs

+15-19
Original file line numberDiff line numberDiff line change
@@ -452,31 +452,27 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
452452

453453
_ => {
454454
let mut data_variant = match self.variants {
455+
// Within the discriminant field, only the niche itself is
456+
// always initialized, so we only check for a pointer at its
457+
// offset.
458+
//
459+
// If the niche is a pointer, it's either valid (according
460+
// to its type), or null (which the niche field's scalar
461+
// validity range encodes). This allows using
462+
// `dereferenceable_or_null` for e.g., `Option<&T>`, and
463+
// this will continue to work as long as we don't start
464+
// using more niches than just null (e.g., the first page of
465+
// the address space, or unaligned pointers).
455466
layout::Variants::Multiple {
456467
discr_kind: layout::DiscriminantKind::Niche {
457468
dataful_variant,
458469
..
459470
},
471+
discr_index,
460472
..
461-
} => {
462-
// Only the niche itself is always initialized,
463-
// so only check for a pointer at its offset.
464-
//
465-
// If the niche is a pointer, it's either valid
466-
// (according to its type), or null (which the
467-
// niche field's scalar validity range encodes).
468-
// This allows using `dereferenceable_or_null`
469-
// for e.g., `Option<&T>`, and this will continue
470-
// to work as long as we don't start using more
471-
// niches than just null (e.g., the first page
472-
// of the address space, or unaligned pointers).
473-
if self.fields.offset(0) == offset {
474-
Some(self.for_variant(cx, dataful_variant))
475-
} else {
476-
None
477-
}
478-
}
479-
_ => Some(*self)
473+
} if self.fields.offset(discr_index) == offset =>
474+
Some(self.for_variant(cx, dataful_variant)),
475+
_ => Some(*self),
480476
};
481477

482478
if let Some(variant) = data_variant {

src/librustc_codegen_ssa/mir/place.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,19 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
216216
if self.layout.abi.is_uninhabited() {
217217
return bx.cx().const_undef(cast_to);
218218
}
219-
let (discr_scalar, discr_kind) = match self.layout.variants {
219+
let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
220220
layout::Variants::Single { index } => {
221221
let discr_val = self.layout.ty.ty_adt_def().map_or(
222222
index.as_u32() as u128,
223223
|def| def.discriminant_for_variant(bx.cx().tcx(), index).val);
224224
return bx.cx().const_uint_big(cast_to, discr_val);
225225
}
226-
layout::Variants::Multiple { ref discr, ref discr_kind, .. } => {
227-
(discr, discr_kind)
226+
layout::Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
227+
(discr, discr_kind, discr_index)
228228
}
229229
};
230230

231-
let discr = self.project_field(bx, 0);
231+
let discr = self.project_field(bx, discr_index);
232232
let lldiscr = bx.load_operand(discr).immediate();
233233
match *discr_kind {
234234
layout::DiscriminantKind::Tag => {
@@ -292,9 +292,10 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
292292
}
293293
layout::Variants::Multiple {
294294
discr_kind: layout::DiscriminantKind::Tag,
295+
discr_index,
295296
..
296297
} => {
297-
let ptr = self.project_field(bx, 0);
298+
let ptr = self.project_field(bx, discr_index);
298299
let to = self.layout.ty.ty_adt_def().unwrap()
299300
.discriminant_for_variant(bx.tcx(), variant_index)
300301
.val;
@@ -309,6 +310,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
309310
ref niche_variants,
310311
niche_start,
311312
},
313+
discr_index,
312314
..
313315
} => {
314316
if variant_index != dataful_variant {
@@ -321,7 +323,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
321323
bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
322324
}
323325

324-
let niche = self.project_field(bx, 0);
326+
let niche = self.project_field(bx, discr_index);
325327
let niche_llty = bx.cx().immediate_backend_type(niche.layout);
326328
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
327329
let niche_value = (niche_value as u128)

src/librustc_lint/types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
820820
discr_kind: layout::DiscriminantKind::Tag,
821821
ref discr,
822822
ref variants,
823+
..
823824
} => (variants, discr),
824825
_ => return,
825826
};

src/librustc_mir/interpret/operand.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -588,18 +588,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
588588
) -> EvalResult<'tcx, (u128, VariantIdx)> {
589589
trace!("read_discriminant_value {:#?}", rval.layout);
590590

591-
let discr_kind = match rval.layout.variants {
591+
let (discr_kind, discr_index) = match rval.layout.variants {
592592
layout::Variants::Single { index } => {
593593
let discr_val = rval.layout.ty.ty_adt_def().map_or(
594594
index.as_u32() as u128,
595595
|def| def.discriminant_for_variant(*self.tcx, index).val);
596596
return Ok((discr_val, index));
597597
}
598-
layout::Variants::Multiple { ref discr_kind, .. } => discr_kind,
598+
layout::Variants::Multiple { ref discr_kind, discr_index, .. } =>
599+
(discr_kind, discr_index),
599600
};
600601

601602
// read raw discriminant value
602-
let discr_op = self.operand_field(rval, 0)?;
603+
let discr_op = self.operand_field(rval, discr_index as u64)?;
603604
let discr_val = self.read_immediate(discr_op)?;
604605
let raw_discr = discr_val.to_scalar_or_undef();
605606
trace!("discr value: {:?}", raw_discr);

src/librustc_mir/interpret/place.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,7 @@ where
997997
layout::Variants::Multiple {
998998
discr_kind: layout::DiscriminantKind::Tag,
999999
ref discr,
1000+
discr_index,
10001001
..
10011002
} => {
10021003
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
@@ -1011,7 +1012,7 @@ where
10111012
let size = discr.value.size(self);
10121013
let discr_val = truncate(discr_val, size);
10131014

1014-
let discr_dest = self.place_field(dest, 0)?;
1015+
let discr_dest = self.place_field(dest, discr_index as u64)?;
10151016
self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
10161017
}
10171018
layout::Variants::Multiple {
@@ -1020,14 +1021,15 @@ where
10201021
ref niche_variants,
10211022
niche_start,
10221023
},
1024+
discr_index,
10231025
..
10241026
} => {
10251027
assert!(
10261028
variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
10271029
);
10281030
if variant_index != dataful_variant {
10291031
let niche_dest =
1030-
self.place_field(dest, 0)?;
1032+
self.place_field(dest, discr_index as u64)?;
10311033
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
10321034
let niche_value = (niche_value as u128)
10331035
.wrapping_add(niche_start);

src/librustc_target/abi/mod.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -828,12 +828,13 @@ pub enum Variants {
828828
index: VariantIdx,
829829
},
830830

831-
/// Enums with more than one inhabited variant: for each case there is
832-
/// a struct, and they all have space reserved for the discriminant,
833-
/// which is the sole field of the enum layout.
831+
/// Enum-likes with more than one inhabited variant: for each case there is
832+
/// a struct, and they all have space reserved for the discriminant.
833+
/// For enums this is the sole field of the layout.
834834
Multiple {
835835
discr: Scalar,
836836
discr_kind: DiscriminantKind,
837+
discr_index: usize,
837838
variants: IndexVec<VariantIdx, LayoutDetails>,
838839
},
839840
}
@@ -845,8 +846,9 @@ pub enum DiscriminantKind {
845846

846847
/// Niche (values invalid for a type) encoding the discriminant:
847848
/// the variant `dataful_variant` contains a niche at an arbitrary
848-
/// offset (field 0 of the enum), which for a variant with discriminant
849-
/// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)`.
849+
/// offset (field `discr_index` of the enum), which for a variant with
850+
/// discriminant `d` is set to
851+
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
850852
///
851853
/// For example, `Option<(usize, &T)>` is represented such that
852854
/// `None` has a null pointer for the second tuple field, and

0 commit comments

Comments
 (0)