Skip to content

Commit 64fbe2f

Browse files
committed
Add helper method for determining the type of a discriminant
1 parent d94923e commit 64fbe2f

File tree

3 files changed

+35
-49
lines changed

3 files changed

+35
-49
lines changed

src/librustc_middle/mir/tcx.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
use crate::mir::*;
77
use crate::ty::subst::Subst;
8-
use crate::ty::util::IntTypeExt;
98
use crate::ty::{self, Ty, TyCtxt};
109
use rustc_hir as hir;
1110
use rustc_target::abi::VariantIdx;
@@ -175,15 +174,7 @@ impl<'tcx> Rvalue<'tcx> {
175174
}
176175
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
177176
Rvalue::Discriminant(ref place) => {
178-
let ty = place.ty(local_decls, tcx).ty;
179-
match ty.kind {
180-
ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
181-
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
182-
_ => {
183-
// This can only be `0`, for now, so `u8` will suffice.
184-
tcx.types.u8
185-
}
186-
}
177+
place.ty(local_decls, tcx).ty.discriminant_type(tcx)
187178
}
188179
Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
189180
Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,

src/librustc_middle/ty/sty.rs

+10
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use std::borrow::Cow;
2929
use std::cmp::Ordering;
3030
use std::marker::PhantomData;
3131
use std::ops::Range;
32+
use ty::util::IntTypeExt;
3233

3334
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
3435
#[derive(HashStable, TypeFoldable, Lift)]
@@ -2104,6 +2105,15 @@ impl<'tcx> TyS<'tcx> {
21042105
}
21052106
}
21062107

2108+
/// Returns the type of the discriminant of this type.
2109+
pub fn discriminant_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
2110+
match self.kind {
2111+
ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
2112+
ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
2113+
_ => bug!("{:?} does not have a discriminant", self),
2114+
}
2115+
}
2116+
21072117
/// When we create a closure, we record its kind (i.e., what trait
21082118
/// it implements) into its `ClosureSubsts` using a type
21092119
/// parameter. This is kind of a phantom type, except that the

src/librustc_mir/interpret/operand.rs

+24-39
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use std::fmt::Write;
77
use rustc_errors::ErrorReported;
88
use rustc_hir::def::Namespace;
99
use rustc_macros::HashStable;
10-
use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
10+
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
1111
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
1212
use rustc_middle::ty::Ty;
1313
use rustc_middle::{mir, ty};
14-
use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, Integer, LayoutOf, Size};
14+
use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
1515
use rustc_target::abi::{VariantIdx, Variants};
1616

1717
use super::{
@@ -576,9 +576,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
576576
/// Read discriminant, return the runtime value as well as the variant index.
577577
pub fn read_discriminant(
578578
&self,
579-
rval: OpTy<'tcx, M::PointerTag>,
579+
op: OpTy<'tcx, M::PointerTag>,
580580
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
581-
trace!("read_discriminant_value {:#?}", rval.layout);
581+
trace!("read_discriminant_value {:#?}", op.layout);
582+
583+
// Get type and layout of the discriminant.
584+
let discr_layout = self.layout_of(op.layout.ty.discriminant_type(*self.tcx))?;
585+
trace!("discriminant type: {:?}", discr_layout.ty);
582586

583587
// We use "discriminant" to refer to the value associated with a particualr enum variant.
584588
// This is not to be confused with its "variant index", which is just determining its position in the
@@ -587,18 +591,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
587591
// straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
588592
// Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
589593
// rather confusing.
590-
let (tag_scalar_layout, tag_kind, tag_index) = match rval.layout.variants {
594+
let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
591595
Variants::Single { index } => {
592-
let discr = match rval.layout.ty.discriminant_for_variant(*self.tcx, index) {
596+
let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
593597
Some(discr) => {
594598
// This type actually has discriminants.
595-
let discr_layout = self.layout_of(discr.ty)?;
599+
assert_eq!(discr.ty, discr_layout.ty);
596600
Scalar::from_uint(discr.val, discr_layout.size)
597601
}
598602
None => {
599-
// On a type without actual discriminants, variant is 0. Return variant idx as `u8`.
603+
// On a type without actual discriminants, variant is 0.
600604
assert_eq!(index.as_u32(), 0);
601-
let discr_layout = self.layout_of(self.tcx.types.u8)?;
602605
Scalar::from_uint(index.as_u32(), discr_layout.size)
603606
}
604607
};
@@ -609,53 +612,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
609612
}
610613
};
611614

612-
// There are *three* types/layouts that come into play here:
613-
// - The discriminant has a type for typechecking. This is `discr_ty`, and is used for
615+
// There are *three* layouts that come into play here:
616+
// - The discriminant has a type for typechecking. This is `discr_layout`, and is used for
614617
// the `Scalar` we return.
615-
// - The discriminant gets encoded as a tag/niche, with layout `tag_layout`.
616-
// This is always an integer, and used to interpret the value we read from the
617-
// tag field. For the return value, a cast to `discr_ty` is performed.
618-
// - The field storing the tag has a layout, which is very similar to
619-
// `tag_layout` but may be a pointer. This is `tag_val.layout`;
620-
// we just use it for sanity checks.
618+
// - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type,
619+
// and used to interpret the value we read from the tag field.
620+
// For the return value, a cast to `discr_layout` is performed.
621+
// - The field storing the tag has a layout, which is very similar to `tag_layout` but
622+
// may be a pointer. This is `tag_val.layout`; we just use it for sanity checks.
621623

622624
// Get layout for tag.
623625
let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
624626

625627
// Read tag and sanity-check `tag_layout`.
626-
let tag_val = self.read_immediate(self.operand_field(rval, tag_index)?)?;
628+
let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
627629
assert_eq!(tag_layout.size, tag_val.layout.size);
628630
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
629631
let tag_val = tag_val.to_scalar()?;
630632
trace!("tag value: {:?}", tag_val);
631633

632-
// Get type used by typechecking.
633-
let discr_ty = match rval.layout.ty.kind {
634-
ty::Adt(adt, _) => {
635-
let discr_int_ty = Integer::from_attr(self, adt.repr.discr_type());
636-
// The signedness of tag and discriminant is the same.
637-
discr_int_ty.to_ty(*self.tcx, tag_layout.abi.is_signed())
638-
}
639-
ty::Generator(_, substs, _) => {
640-
let substs = substs.as_generator();
641-
substs.discr_ty(*self.tcx)
642-
}
643-
_ => bug!("multiple variants for non-adt non-generator"),
644-
};
645-
trace!("discriminant type: {:?}", discr_ty);
646-
647634
// Figure out which discriminant and variant this corresponds to.
648635
Ok(match *tag_kind {
649636
DiscriminantKind::Tag => {
650637
let tag_bits = self
651638
.force_bits(tag_val, tag_layout.size)
652639
.map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
653640
// Cast bits from tag layout to discriminant layout.
654-
let discr_layout = self.layout_of(discr_ty)?;
655-
let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_ty);
641+
let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
656642
let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
657643
// Convert discriminant to variant index, and catch invalid discriminants.
658-
let index = match rval.layout.ty.kind {
644+
let index = match op.layout.ty.kind {
659645
ty::Adt(adt, _) => {
660646
adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits)
661647
}
@@ -705,7 +691,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
705691
let variant_index = variants_start
706692
.checked_add(variant_index_relative)
707693
.expect("overflow computing absolute variant idx");
708-
let variants_len = rval
694+
let variants_len = op
709695
.layout
710696
.ty
711697
.ty_adt_def()
@@ -722,8 +708,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
722708
// Compute the size of the scalar we need to return.
723709
// No need to cast, because the variant index directly serves as discriminant and is
724710
// encoded in the tag.
725-
let size = self.layout_of(discr_ty)?.size;
726-
(Scalar::from_uint(variant.as_u32(), size), variant)
711+
(Scalar::from_uint(variant.as_u32(), discr_layout.size), variant)
727712
}
728713
})
729714
}

0 commit comments

Comments
 (0)