Skip to content

Commit 7c626a6

Browse files
committed
Add discr_index to multi-variant layouts
We relax the assumption that the discriminant is always field 0, in preparations for layouts like generators where this is not going to be the case.
1 parent b586247 commit 7c626a6

File tree

8 files changed

+67
-47
lines changed

8 files changed

+67
-47
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

+24-12
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
}
@@ -1547,11 +1554,14 @@ fn describe_enum_variant(
15471554
let (offsets, args) = if use_enum_fallback(cx) {
15481555
// If this is not a univariant enum, there is also the discriminant field.
15491556
let (discr_offset, discr_arg) = match discriminant_info {
1550-
RegularDiscriminant(_) => {
1557+
RegularDiscriminant { discr_field, .. } => {
15511558
// We have the layout of an enum variant, we need the layout of the outer enum
15521559
let enum_layout = cx.layout_of(layout.ty);
1553-
(Some(enum_layout.fields.offset(0)),
1554-
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))
15551565
}
15561566
_ => (None, None),
15571567
};
@@ -1579,8 +1589,8 @@ fn describe_enum_variant(
15791589
offsets,
15801590
args,
15811591
discriminant_type_metadata: match discriminant_info {
1582-
RegularDiscriminant(discriminant_type_metadata) => {
1583-
Some(discriminant_type_metadata)
1592+
RegularDiscriminant { discr_type_metadata, .. } => {
1593+
Some(discr_type_metadata)
15841594
}
15851595
_ => None
15861596
},
@@ -1730,6 +1740,7 @@ fn prepare_enum_metadata(
17301740
layout::Variants::Multiple {
17311741
discr_kind: layout::DiscriminantKind::Niche { .. },
17321742
ref discr,
1743+
discr_index,
17331744
..
17341745
} => {
17351746
// Find the integer type of the correct size.
@@ -1753,7 +1764,7 @@ fn prepare_enum_metadata(
17531764
UNKNOWN_LINE_NUMBER,
17541765
size.bits(),
17551766
align.abi.bits() as u32,
1756-
layout.fields.offset(0).bits(),
1767+
layout.fields.offset(discr_index).bits(),
17571768
DIFlags::FlagArtificial,
17581769
discr_metadata))
17591770
}
@@ -1762,6 +1773,7 @@ fn prepare_enum_metadata(
17621773
layout::Variants::Multiple {
17631774
discr_kind: layout::DiscriminantKind::Tag,
17641775
ref discr,
1776+
discr_index,
17651777
..
17661778
} => {
17671779
let discr_type = discr.value.to_ty(cx.tcx);
@@ -1777,7 +1789,7 @@ fn prepare_enum_metadata(
17771789
UNKNOWN_LINE_NUMBER,
17781790
size.bits(),
17791791
align.bits() as u32,
1780-
layout.fields.offset(0).bits(),
1792+
layout.fields.offset(discr_index).bits(),
17811793
DIFlags::FlagArtificial,
17821794
discr_metadata))
17831795
}

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)