Skip to content

Commit 1c7ace8

Browse files
committed
Generalize discriminant info calls for generators and ADTs
1 parent d2906f6 commit 1c7ace8

File tree

8 files changed

+95
-51
lines changed

8 files changed

+95
-51
lines changed

src/librustc/ty/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use std::ops::Deref;
4141
use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter};
4242
use std::slice;
4343
use std::{mem, ptr};
44+
use std::ops::Range;
4445
use syntax::ast::{self, Name, Ident, NodeId};
4546
use syntax::attr;
4647
use syntax::ext::hygiene::Mark;
@@ -2418,11 +2419,17 @@ impl<'a, 'gcx, 'tcx> AdtDef {
24182419
})
24192420
}
24202421

2422+
#[inline]
2423+
pub fn variant_range(&self) -> Range<VariantIdx> {
2424+
(VariantIdx::new(0)..VariantIdx::new(self.variants.len()))
2425+
}
2426+
24212427
/// Computes the discriminant value used by a specific variant.
24222428
/// Unlike `discriminants`, this is (amortized) constant-time,
24232429
/// only doing at most one query for evaluating an explicit
24242430
/// discriminant (the last one before the requested variant),
24252431
/// assuming there are no constant-evaluation errors there.
2432+
#[inline]
24262433
pub fn discriminant_for_variant(&self,
24272434
tcx: TyCtxt<'a, 'gcx, 'tcx>,
24282435
variant_index: VariantIdx)

src/librustc/ty/sty.rs

+57-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use polonius_engine::Atom;
99
use rustc_data_structures::indexed_vec::Idx;
1010
use rustc_macros::HashStable;
1111
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, Kind, UnpackedKind};
12-
use crate::ty::{self, AdtDef, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
12+
use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
1313
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
1414
use crate::ty::layout::VariantIdx;
1515
use crate::util::captures::Captures;
@@ -18,6 +18,7 @@ use crate::mir::interpret::{Scalar, Pointer};
1818
use smallvec::SmallVec;
1919
use std::cmp::Ordering;
2020
use std::marker::PhantomData;
21+
use std::ops::Range;
2122
use rustc_target::spec::abi;
2223
use syntax::ast::{self, Ident};
2324
use syntax::symbol::{keywords, InternedString};
@@ -478,14 +479,35 @@ impl<'a, 'gcx, 'tcx> GeneratorSubsts<'tcx> {
478479
const RETURNED_NAME: &'static str = "Returned";
479480
const POISONED_NAME: &'static str = "Panicked";
480481

481-
/// The variants of this Generator.
482+
/// The valid variant indices of this Generator.
482483
#[inline]
483-
pub fn variants(&self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
484-
impl Iterator<Item = VariantIdx>
485-
{
484+
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Range<VariantIdx> {
486485
// FIXME requires optimized MIR
487486
let num_variants = self.state_tys(def_id, tcx).count();
488-
(0..num_variants).map(VariantIdx::new)
487+
(VariantIdx::new(0)..VariantIdx::new(num_variants))
488+
}
489+
490+
/// The discriminant for the given variant. Panics if the variant_index is
491+
/// out of range.
492+
#[inline]
493+
pub fn discriminant_for_variant(
494+
&self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>, variant_index: VariantIdx
495+
) -> Discr<'tcx> {
496+
// Generators don't support explicit discriminant values, so they are
497+
// the same as the variant index.
498+
assert!(self.variant_range(def_id, tcx).contains(&variant_index));
499+
Discr { val: variant_index.as_usize() as u128, ty: self.discr_ty(tcx) }
500+
}
501+
502+
/// The set of all discriminants for the Generator, enumerated with their
503+
/// variant indices.
504+
#[inline]
505+
pub fn discriminants(
506+
&'a self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>
507+
) -> impl Iterator<Item=(VariantIdx, Discr<'tcx>)> + Captures<'gcx> + 'a {
508+
self.variant_range(def_id, tcx).map(move |index| {
509+
(index, Discr { val: index.as_usize() as u128, ty: self.discr_ty(tcx) })
510+
})
489511
}
490512

491513
/// Calls `f` with a reference to the name of the enumerator for the given
@@ -503,7 +525,7 @@ impl<'a, 'gcx, 'tcx> GeneratorSubsts<'tcx> {
503525
f(name)
504526
}
505527

506-
/// The type of the state "discriminant" used in the generator type.
528+
/// The type of the state discriminant used in the generator type.
507529
#[inline]
508530
pub fn discr_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
509531
tcx.types.u32
@@ -2028,6 +2050,34 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
20282050
}
20292051
}
20302052

2053+
/// If the type contains variants, returns the valid range of variant indices.
2054+
/// FIXME This requires the optimized MIR in the case of generators.
2055+
#[inline]
2056+
pub fn variant_range(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Range<VariantIdx>> {
2057+
match self.sty {
2058+
TyKind::Adt(adt, _) => Some(adt.variant_range()),
2059+
TyKind::Generator(def_id, substs, _) => Some(substs.variant_range(def_id, tcx)),
2060+
_ => None,
2061+
}
2062+
}
2063+
2064+
/// If the type contains variants, returns the variant for `variant_index`.
2065+
/// Panics if `variant_index` is out of range.
2066+
/// FIXME This requires the optimized MIR in the case of generators.
2067+
#[inline]
2068+
pub fn discriminant_for_variant(
2069+
&self,
2070+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
2071+
variant_index: VariantIdx
2072+
) -> Option<Discr<'tcx>> {
2073+
match self.sty {
2074+
TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)),
2075+
TyKind::Generator(def_id, substs, _) =>
2076+
Some(substs.discriminant_for_variant(def_id, tcx, variant_index)),
2077+
_ => None,
2078+
}
2079+
}
2080+
20312081
/// Push onto `out` the regions directly referenced from this type (but not
20322082
/// types reachable from this type via `walk_tys`). This ignores late-bound
20332083
/// regions binders.

src/librustc_codegen_llvm/debuginfo/metadata.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -1382,12 +1382,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
13821382
variant_type_metadata,
13831383
member_descriptions);
13841384

1385-
// TODO make this into a helper
1386-
let discriminant = match &self.layout.ty.sty {
1387-
ty::Adt(adt, _) => adt.discriminant_for_variant(cx.tcx, i).val as u64,
1388-
ty::Generator(..) => i.as_usize() as u64,
1389-
_ => bug!(),
1390-
}.into();
13911385
MemberDescription {
13921386
name: if fallback {
13931387
String::new()
@@ -1399,7 +1393,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
13991393
size: self.layout.size,
14001394
align: self.layout.align.abi,
14011395
flags: DIFlags::FlagZero,
1402-
discriminant,
1396+
discriminant: Some(
1397+
self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val as u64
1398+
),
14031399
}
14041400
}).collect()
14051401
}
@@ -1722,7 +1718,7 @@ fn prepare_enum_metadata(
17221718
})
17231719
.collect(),
17241720
ty::Generator(_, substs, _) => substs
1725-
.variants(enum_def_id, cx.tcx)
1721+
.variant_range(enum_def_id, cx.tcx)
17261722
.map(|v| substs.map_variant_name(v, |name| {
17271723
let name = SmallCStr::new(name);
17281724
unsafe {

src/librustc_codegen_ssa/mir/place.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
218218
}
219219
let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
220220
layout::Variants::Single { index } => {
221-
let discr_val = self.layout.ty.ty_adt_def().map_or(
222-
index.as_u32() as u128,
223-
|def| def.discriminant_for_variant(bx.cx().tcx(), index).val);
221+
let discr_val = self.layout.ty.discriminant_for_variant(bx.cx().tcx(), index)
222+
.map_or(index.as_u32() as u128, |discr| discr.val);
224223
return bx.cx().const_uint_big(cast_to, discr_val);
225224
}
226225
layout::Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
@@ -296,15 +295,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
296295
..
297296
} => {
298297
let ptr = self.project_field(bx, discr_index);
299-
let to = match self.layout.ty.sty {
300-
ty::TyKind::Adt(adt_def, _) => adt_def
301-
.discriminant_for_variant(bx.tcx(), variant_index)
302-
.val,
303-
// Generators don't support explicit discriminant values, so
304-
// they are the same as the variant index.
305-
ty::TyKind::Generator(..) => variant_index.as_u32() as u128,
306-
_ => bug!(),
307-
};
298+
let to =
299+
self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
308300
bx.store(
309301
bx.cx().const_uint_big(bx.cx().backend_type(ptr.layout), to),
310302
ptr.llval,

src/librustc_codegen_ssa/mir/rvalue.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,12 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
271271
let ll_t_in = bx.cx().immediate_backend_type(operand.layout);
272272
match operand.layout.variants {
273273
layout::Variants::Single { index } => {
274-
if let Some(def) = operand.layout.ty.ty_adt_def() {
275-
let discr_val = def
276-
.discriminant_for_variant(bx.cx().tcx(), index)
277-
.val;
278-
let discr = bx.cx().const_uint_big(ll_t_out, discr_val);
274+
if let Some(discr) =
275+
operand.layout.ty.discriminant_for_variant(bx.tcx(), index)
276+
{
277+
let discr_val = bx.cx().const_uint_big(ll_t_out, discr.val);
279278
return (bx, OperandRef {
280-
val: OperandValue::Immediate(discr),
279+
val: OperandValue::Immediate(discr_val),
281280
layout: cast,
282281
});
283282
}

src/librustc_mir/interpret/cast.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
5454
} else {
5555
match src.layout.variants {
5656
layout::Variants::Single { index } => {
57-
if let Some(def) = src.layout.ty.ty_adt_def() {
57+
if let Some(discr) =
58+
src.layout.ty.discriminant_for_variant(*self.tcx, index)
59+
{
5860
// Cast from a univariant enum
5961
assert!(src.layout.is_zst());
60-
let discr_val = def
61-
.discriminant_for_variant(*self.tcx, index)
62-
.val;
6362
return self.write_scalar(
64-
Scalar::from_uint(discr_val, dest.layout.size),
63+
Scalar::from_uint(discr.val, dest.layout.size),
6564
dest);
6665
}
6766
}

src/librustc_mir/interpret/operand.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -566,9 +566,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
566566

567567
let (discr_kind, discr_index) = match rval.layout.variants {
568568
layout::Variants::Single { index } => {
569-
let discr_val = rval.layout.ty.ty_adt_def().map_or(
569+
let discr_val = rval.layout.ty.discriminant_for_variant(*self.tcx, index).map_or(
570570
index.as_u32() as u128,
571-
|def| def.discriminant_for_variant(*self.tcx, index).val);
571+
|discr| discr.val);
572572
return Ok((discr_val, index));
573573
}
574574
layout::Variants::Multiple { ref discr_kind, discr_index, .. } =>
@@ -603,12 +603,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
603603
bits_discr
604604
};
605605
// Make sure we catch invalid discriminants
606-
let index = rval.layout.ty
607-
.ty_adt_def()
608-
.expect("tagged layout for non adt")
609-
.discriminants(self.tcx.tcx)
610-
.find(|(_, var)| var.val == real_discr)
611-
.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?;
606+
let index = match &rval.layout.ty.sty {
607+
ty::Adt(adt, _) => adt
608+
.discriminants(self.tcx.tcx)
609+
.find(|(_, var)| var.val == real_discr),
610+
ty::Generator(def_id, substs, _) => substs
611+
.discriminants(*def_id, self.tcx.tcx)
612+
.find(|(_, var)| var.val == real_discr),
613+
_ => bug!("tagged layout for non-adt non-generator"),
614+
}.ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?;
612615
(real_discr, index.0)
613616
},
614617
layout::DiscriminantKind::Niche {

src/librustc_mir/interpret/place.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -984,11 +984,9 @@ where
984984
discr_index,
985985
..
986986
} => {
987-
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
988-
assert!(variant_index.as_usize() < adt_def.variants.len());
989-
let discr_val = adt_def
990-
.discriminant_for_variant(*self.tcx, variant_index)
991-
.val;
987+
assert!(dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index));
988+
let discr_val =
989+
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
992990

993991
// raw discriminants for enums are isize or bigger during
994992
// their computation, but the in-memory tag is the smallest possible

0 commit comments

Comments
 (0)