rustc: move the actual values of enum discriminants into a map.
This commit is contained in:
parent
86e402904a
commit
e96a171453
@ -114,6 +114,7 @@ pub enum DepNode<D: Clone + Debug> {
|
||||
InherentImpls(D),
|
||||
TypeckTables(D),
|
||||
UsedTraitImports(D),
|
||||
MonomorphicConstEval(D),
|
||||
|
||||
// The set of impls for a given trait. Ultimately, it would be
|
||||
// nice to get more fine-grained here (e.g., to include a
|
||||
@ -263,6 +264,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||
TypeckTables(ref d) => op(d).map(TypeckTables),
|
||||
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
|
||||
MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
|
||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||
TraitItems(ref d) => op(d).map(TraitItems),
|
||||
ReprHints(ref d) => op(d).map(ReprHints),
|
||||
|
@ -173,7 +173,9 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
Rvalue::Discriminant(ref lval) => {
|
||||
let ty = lval.ty(mir, tcx).to_ty(tcx);
|
||||
if let ty::TyAdt(adt_def, _) = ty.sty {
|
||||
Some(adt_def.discr_ty.to_ty(tcx))
|
||||
let repr_hints = tcx.lookup_repr_hints(adt_def.did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
Some(repr_type.to_ty(tcx))
|
||||
} else {
|
||||
// Undefined behaviour, bug for now; may want to return something for
|
||||
// the `discriminant` intrinsic later.
|
||||
|
@ -507,6 +507,10 @@ pub struct GlobalCtxt<'tcx> {
|
||||
/// FIXME(arielb1): why is this separate from populated_external_types?
|
||||
pub populated_external_primitive_impls: RefCell<DefIdSet>,
|
||||
|
||||
/// Results of evaluating monomorphic constants embedded in
|
||||
/// other items, such as enum variant explicit discriminants.
|
||||
pub monomorphic_const_eval: RefCell<DepTrackingMap<maps::MonomorphicConstEval<'tcx>>>,
|
||||
|
||||
/// Maps any item's def-id to its stability index.
|
||||
pub stability: RefCell<stability::Index<'tcx>>,
|
||||
|
||||
@ -662,12 +666,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn alloc_adt_def(self,
|
||||
did: DefId,
|
||||
kind: AdtKind,
|
||||
discr_ty: Option<attr::IntType>,
|
||||
variants: Vec<ty::VariantDef>,
|
||||
repr: ReprOptions)
|
||||
-> &'gcx ty::AdtDef {
|
||||
let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
|
||||
let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
|
||||
let def = ty::AdtDef::new(self, did, kind, variants, repr);
|
||||
self.global_arenas.adt_def.alloc(def)
|
||||
}
|
||||
|
||||
@ -783,6 +785,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
used_trait_imports: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
populated_external_types: RefCell::new(DefIdSet()),
|
||||
populated_external_primitive_impls: RefCell::new(DefIdSet()),
|
||||
monomorphic_const_eval: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
|
||||
stability: RefCell::new(stability),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
|
@ -20,6 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
use syntax::attr;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
@ -1181,8 +1182,12 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
let (mut min, mut max, mut non_zero) = (i64::max_value(),
|
||||
i64::min_value(),
|
||||
true);
|
||||
for v in &def.variants {
|
||||
let x = v.disr_val as i128 as i64;
|
||||
for discr in def.discriminants(tcx) {
|
||||
let x = match discr.erase_type() {
|
||||
ConstInt::InferSigned(i) => i as i64,
|
||||
ConstInt::Infer(i) => i as u64 as i64,
|
||||
_ => bug!()
|
||||
};
|
||||
if x == 0 { non_zero = false; }
|
||||
if x < min { min = x; }
|
||||
if x > max { max = x; }
|
||||
@ -1240,7 +1245,7 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
// non-empty body, explicit discriminants should have
|
||||
// been rejected by a checker before this point.
|
||||
for (i, v) in def.variants.iter().enumerate() {
|
||||
if i as u128 != v.disr_val {
|
||||
if v.discr != ty::VariantDiscr::Relative(i) {
|
||||
bug!("non-C-like enum {} with specified discriminants",
|
||||
tcx.item_path_str(def.did));
|
||||
}
|
||||
@ -1348,7 +1353,9 @@ impl<'a, 'gcx, 'tcx> Layout {
|
||||
return Err(LayoutError::SizeOverflow(ty));
|
||||
}
|
||||
|
||||
let typeck_ity = Integer::from_attr(dl, def.discr_ty);
|
||||
let repr_hints = tcx.lookup_repr_hints(def.did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let typeck_ity = Integer::from_attr(dl, repr_type);
|
||||
if typeck_ity < min_ity {
|
||||
// It is a bug if Layout decided on a greater discriminant size than typeck for
|
||||
// some reason at this point (based on values discriminant can take on). Mostly
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use dep_graph::{DepNode, DepTrackingMapConfig};
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::ConstVal;
|
||||
use mir;
|
||||
use ty::{self, Ty};
|
||||
use util::nodemap::DefIdSet;
|
||||
@ -51,3 +52,4 @@ dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
|
||||
dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
|
||||
dep_map_ty! { TypeckTables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx> }
|
||||
dep_map_ty! { UsedTraitImports: UsedTraitImports(DefId) -> DefIdSet }
|
||||
dep_map_ty! { MonomorphicConstEval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()> }
|
||||
|
@ -20,6 +20,7 @@ use hir::{map as hir_map, FreevarMap, TraitMap};
|
||||
use middle;
|
||||
use hir::def::{Def, CtorKind, ExportMap};
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
|
||||
use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
|
||||
use middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
@ -27,6 +28,7 @@ use mir::Mir;
|
||||
use traits;
|
||||
use ty;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::util::IntTypeExt;
|
||||
use ty::walk::TypeWalker;
|
||||
use util::common::MemoizationMap;
|
||||
use util::nodemap::{NodeSet, NodeMap, FxHashMap};
|
||||
@ -45,6 +47,7 @@ use syntax::ast::{self, Name, NodeId};
|
||||
use syntax::attr;
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||
|
||||
@ -96,8 +99,6 @@ mod flags;
|
||||
mod structural_impls;
|
||||
mod sty;
|
||||
|
||||
pub type Disr = u128;
|
||||
|
||||
// Data types
|
||||
|
||||
/// The complete set of all analyses described in this module. This is
|
||||
@ -1309,11 +1310,24 @@ pub struct VariantDef {
|
||||
/// this is the DefId of the struct's ctor.
|
||||
pub did: DefId,
|
||||
pub name: Name, // struct's name if this is a struct
|
||||
pub disr_val: Disr,
|
||||
pub discr: VariantDiscr,
|
||||
pub fields: Vec<FieldDef>,
|
||||
pub ctor_kind: CtorKind,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||
pub enum VariantDiscr {
|
||||
/// Explicit value for this variant, i.e. `X = 123`.
|
||||
/// The `DefId` corresponds to the embedded constant.
|
||||
Explicit(DefId),
|
||||
|
||||
/// The previous variant's discriminant plus one.
|
||||
/// For efficiency reasons, the distance from the
|
||||
/// last `Explicit` discriminant is being stored,
|
||||
/// or `0` for the first variant, if it has none.
|
||||
Relative(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldDef {
|
||||
pub did: DefId,
|
||||
@ -1327,12 +1341,6 @@ pub struct FieldDef {
|
||||
/// table.
|
||||
pub struct AdtDef {
|
||||
pub did: DefId,
|
||||
/// Type of the discriminant
|
||||
///
|
||||
/// Note, that this is the type specified in `repr()` or a default type of some sort, and might
|
||||
/// not match the actual type that layout algorithm decides to use when translating this type
|
||||
/// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
|
||||
pub discr_ty: attr::IntType,
|
||||
pub variants: Vec<VariantDef>,
|
||||
destructor: Cell<Option<DefId>>,
|
||||
flags: Cell<AdtFlags>,
|
||||
@ -1395,7 +1403,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
did: DefId,
|
||||
kind: AdtKind,
|
||||
discr_ty: attr::IntType,
|
||||
variants: Vec<VariantDef>,
|
||||
repr: ReprOptions) -> Self {
|
||||
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
||||
@ -1419,7 +1426,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
}
|
||||
AdtDef {
|
||||
did: did,
|
||||
discr_ty: discr_ty,
|
||||
variants: variants,
|
||||
flags: Cell::new(flags),
|
||||
destructor: Cell::new(None),
|
||||
@ -1577,6 +1583,28 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
self.destructor.set(Some(dtor));
|
||||
}
|
||||
|
||||
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> impl Iterator<Item=ConstInt> + 'a {
|
||||
let repr_hints = tcx.lookup_repr_hints(self.did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let initial = repr_type.initial_discriminant(tcx.global_tcx());
|
||||
let mut prev_discr = None::<ConstInt>;
|
||||
self.variants.iter().map(move |v| {
|
||||
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
|
||||
if let VariantDiscr::Explicit(expr_did) = v.discr {
|
||||
match tcx.monomorphic_const_eval.borrow()[&expr_did] {
|
||||
Ok(ConstVal::Integral(v)) => {
|
||||
discr = v;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
prev_discr = Some(discr);
|
||||
|
||||
discr
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a simpler type such that `Self: Sized` if and only
|
||||
/// if that type is Sized, or `TyErr` if this type is recursive.
|
||||
///
|
||||
|
@ -16,13 +16,14 @@ use infer::InferCtxt;
|
||||
use hir::map as hir_map;
|
||||
use traits::{self, Reveal};
|
||||
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
||||
use ty::{Disr, ParameterEnvironment};
|
||||
use ty::{ParameterEnvironment};
|
||||
use ty::fold::TypeVisitor;
|
||||
use ty::layout::{Layout, LayoutError};
|
||||
use ty::TypeVariants::*;
|
||||
use util::nodemap::FxHashMap;
|
||||
use middle::lang_items;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
|
||||
|
||||
use std::cell::RefCell;
|
||||
@ -35,21 +36,88 @@ use syntax_pos::Span;
|
||||
|
||||
use hir;
|
||||
|
||||
pub trait IntTypeExt {
|
||||
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
|
||||
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
|
||||
}
|
||||
type Disr = ConstInt;
|
||||
|
||||
pub trait IntTypeExt {
|
||||
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
|
||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
|
||||
-> Option<Disr>;
|
||||
fn assert_ty_matches(&self, val: Disr);
|
||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
|
||||
}
|
||||
|
||||
|
||||
impl IntTypeExt for attr::IntType {
|
||||
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||
match self {
|
||||
SignedInt(i) => tcx.mk_mach_int(i),
|
||||
UnsignedInt(i) => tcx.mk_mach_uint(i),
|
||||
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => tcx.types.i8,
|
||||
SignedInt(ast::IntTy::I16) => tcx.types.i16,
|
||||
SignedInt(ast::IntTy::I32) => tcx.types.i32,
|
||||
SignedInt(ast::IntTy::I64) => tcx.types.i64,
|
||||
SignedInt(ast::IntTy::I128) => tcx.types.i128,
|
||||
SignedInt(ast::IntTy::Is) => tcx.types.isize,
|
||||
UnsignedInt(ast::UintTy::U8) => tcx.types.u8,
|
||||
UnsignedInt(ast::UintTy::U16) => tcx.types.u16,
|
||||
UnsignedInt(ast::UintTy::U32) => tcx.types.u32,
|
||||
UnsignedInt(ast::UintTy::U64) => tcx.types.u64,
|
||||
UnsignedInt(ast::UintTy::U128) => tcx.types.u128,
|
||||
UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
|
||||
0
|
||||
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
|
||||
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
|
||||
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
|
||||
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
|
||||
SignedInt(ast::IntTy::I128) => ConstInt::I128(0),
|
||||
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
|
||||
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)),
|
||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
|
||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
|
||||
_ => bug!(),
|
||||
},
|
||||
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
|
||||
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
|
||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
|
||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
|
||||
UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0),
|
||||
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
|
||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)),
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
|
||||
_ => bug!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_ty_matches(&self, val: Disr) {
|
||||
match (*self, val) {
|
||||
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
|
||||
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
|
||||
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
|
||||
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
|
||||
(SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
|
||||
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
|
||||
_ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
|
||||
}
|
||||
}
|
||||
|
||||
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
|
||||
-> Option<Disr> {
|
||||
if let Some(val) = val {
|
||||
self.assert_ty_matches(val);
|
||||
(val + ConstInt::Infer(1)).ok()
|
||||
} else {
|
||||
Some(self.initial_discriminant(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::transform::{Pass, MirPass, MirSource};
|
||||
use rustc::middle::const_val::{ConstVal, ConstInt};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||
@ -639,10 +639,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
let mut values = Vec::with_capacity(adt.variants.len());
|
||||
let mut blocks = Vec::with_capacity(adt.variants.len());
|
||||
let mut otherwise = None;
|
||||
for (variant_index, variant) in adt.variants.iter().enumerate() {
|
||||
let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
|
||||
self.tcx.sess.target.uint_type,
|
||||
self.tcx.sess.target.int_type).unwrap();
|
||||
for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() {
|
||||
let subpath = super::move_path_children_matching(
|
||||
self.move_data(), c.path, |proj| match proj {
|
||||
&Projection {
|
||||
@ -680,7 +677,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
// Additionally, we do not want to switch on the
|
||||
// discriminant after it is free-ed, because that
|
||||
// way lies only trouble.
|
||||
let discr_ty = adt.discr_ty.to_ty(self.tcx);
|
||||
let repr_hints = self.tcx.lookup_repr_hints(adt.did);
|
||||
let repr_type = self.tcx.enum_repr_type(repr_hints.get(0));
|
||||
let discr_ty = repr_type.to_ty(self.tcx);
|
||||
let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
|
||||
let switch_block = self.patch.new_block(BasicBlockData {
|
||||
statements: vec![
|
||||
|
@ -77,14 +77,6 @@ mod ibounds {
|
||||
}
|
||||
|
||||
impl ConstInt {
|
||||
pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
|
||||
-> Option<ConstInt> {
|
||||
match ty {
|
||||
IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
|
||||
IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
|
||||
/// not happen.
|
||||
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
|
||||
|
@ -515,7 +515,8 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
|
||||
fn get_variant(&self,
|
||||
item: &Entry<'tcx>,
|
||||
index: DefIndex)
|
||||
index: DefIndex,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
||||
-> (ty::VariantDef, Option<DefIndex>) {
|
||||
let data = match item.kind {
|
||||
EntryKind::Variant(data) |
|
||||
@ -524,6 +525,11 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
if let ty::VariantDiscr::Explicit(def_id) = data.discr {
|
||||
let result = data.evaluated_discr.map_or(Err(()), Ok);
|
||||
tcx.monomorphic_const_eval.borrow_mut().insert(def_id, result);
|
||||
}
|
||||
|
||||
(ty::VariantDef {
|
||||
did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
|
||||
name: self.item_name(index),
|
||||
@ -535,7 +541,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
vis: f.visibility.decode(self)
|
||||
}
|
||||
}).collect(),
|
||||
disr_val: data.disr,
|
||||
discr: data.discr,
|
||||
ctor_kind: data.ctor_kind,
|
||||
}, data.struct_ctor)
|
||||
}
|
||||
@ -546,10 +552,10 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
-> &'tcx ty::AdtDef {
|
||||
let item = self.entry(item_id);
|
||||
let did = self.local_def_id(item_id);
|
||||
let (kind, ty) = match item.kind {
|
||||
EntryKind::Enum(dt, _) => (ty::AdtKind::Enum, Some(dt.decode(self))),
|
||||
EntryKind::Struct(_, _) => (ty::AdtKind::Struct, None),
|
||||
EntryKind::Union(_, _) => (ty::AdtKind::Union, None),
|
||||
let kind = match item.kind {
|
||||
EntryKind::Enum(_) => ty::AdtKind::Enum,
|
||||
EntryKind::Struct(_, _) => ty::AdtKind::Struct,
|
||||
EntryKind::Union(_, _) => ty::AdtKind::Union,
|
||||
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
||||
};
|
||||
let mut ctor_index = None;
|
||||
@ -557,24 +563,25 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
item.children
|
||||
.decode(self)
|
||||
.map(|index| {
|
||||
let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
|
||||
let (variant, struct_ctor) =
|
||||
self.get_variant(&self.entry(index), index, tcx);
|
||||
assert_eq!(struct_ctor, None);
|
||||
variant
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
let (variant, struct_ctor) = self.get_variant(&item, item_id);
|
||||
let (variant, struct_ctor) = self.get_variant(&item, item_id, tcx);
|
||||
ctor_index = struct_ctor;
|
||||
vec![variant]
|
||||
};
|
||||
let (kind, repr) = match item.kind {
|
||||
EntryKind::Enum(_, repr) => (ty::AdtKind::Enum, repr),
|
||||
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
|
||||
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
|
||||
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
|
||||
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
|
||||
};
|
||||
|
||||
let adt = tcx.alloc_adt_def(did, kind, ty, variants, repr);
|
||||
let adt = tcx.alloc_adt_def(did, kind, variants, repr);
|
||||
if let Some(ctor_index) = ctor_index {
|
||||
// Make adt definition available through constructor id as well.
|
||||
tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
|
||||
|
@ -261,7 +261,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
|
||||
let data = VariantData {
|
||||
ctor_kind: variant.ctor_kind,
|
||||
disr: variant.disr_val,
|
||||
discr: variant.discr,
|
||||
evaluated_discr: match variant.discr {
|
||||
ty::VariantDiscr::Explicit(def_id) => {
|
||||
tcx.monomorphic_const_eval.borrow()[&def_id].clone().ok()
|
||||
}
|
||||
ty::VariantDiscr::Relative(_) => None
|
||||
},
|
||||
struct_ctor: None,
|
||||
};
|
||||
|
||||
@ -388,7 +394,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
|
||||
let data = VariantData {
|
||||
ctor_kind: variant.ctor_kind,
|
||||
disr: variant.disr_val,
|
||||
discr: variant.discr,
|
||||
evaluated_discr: None,
|
||||
struct_ctor: Some(def_id.index),
|
||||
};
|
||||
|
||||
@ -644,8 +651,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
}
|
||||
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
|
||||
hir::ItemTy(..) => EntryKind::Type,
|
||||
hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty),
|
||||
get_repr_options(&tcx, def_id)),
|
||||
hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
|
||||
hir::ItemStruct(ref struct_def, _) => {
|
||||
let variant = tcx.lookup_adt_def(def_id).struct_variant();
|
||||
|
||||
@ -662,7 +668,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
|
||||
EntryKind::Struct(self.lazy(&VariantData {
|
||||
ctor_kind: variant.ctor_kind,
|
||||
disr: variant.disr_val,
|
||||
discr: variant.discr,
|
||||
evaluated_discr: None,
|
||||
struct_ctor: struct_ctor,
|
||||
}), repr_options)
|
||||
}
|
||||
@ -672,7 +679,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
|
||||
EntryKind::Union(self.lazy(&VariantData {
|
||||
ctor_kind: variant.ctor_kind,
|
||||
disr: variant.disr_val,
|
||||
discr: variant.discr,
|
||||
evaluated_discr: None,
|
||||
struct_ctor: None,
|
||||
}), repr_options)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use index;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def::{self, CtorKind};
|
||||
use rustc::hir::def_id::{DefIndex, DefId};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::mir;
|
||||
@ -227,7 +228,7 @@ pub enum EntryKind<'tcx> {
|
||||
ForeignMutStatic,
|
||||
ForeignMod,
|
||||
Type,
|
||||
Enum(Lazy<attr::IntType>, ReprOptions),
|
||||
Enum(ReprOptions),
|
||||
Field,
|
||||
Variant(Lazy<VariantData>),
|
||||
Struct(Lazy<VariantData>, ReprOptions),
|
||||
@ -264,7 +265,8 @@ pub struct FnData {
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
pub struct VariantData {
|
||||
pub ctor_kind: CtorKind,
|
||||
pub disr: u128,
|
||||
pub discr: ty::VariantDiscr,
|
||||
pub evaluated_discr: Option<ConstVal>,
|
||||
|
||||
/// If this is a struct's only variant, this
|
||||
/// is the index of the "struct ctor" item.
|
||||
|
@ -20,7 +20,7 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
|
||||
use hair::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
use rustc::middle::const_val::{ConstVal, ConstInt};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::mir::*;
|
||||
@ -191,11 +191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let mut targets = Vec::with_capacity(used_variants + 1);
|
||||
let mut values = Vec::with_capacity(used_variants);
|
||||
let tcx = self.hir.tcx();
|
||||
for (idx, variant) in adt_def.variants.iter().enumerate() {
|
||||
for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
|
||||
target_blocks.place_back() <- if variants.contains(idx) {
|
||||
let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
|
||||
tcx.sess.target.uint_type,
|
||||
tcx.sess.target.int_type).unwrap();
|
||||
values.push(discr);
|
||||
*(targets.place_back() <- self.cfg.start_new_block())
|
||||
} else {
|
||||
@ -212,7 +209,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
|
||||
num_enum_variants, values, variants);
|
||||
let discr_ty = adt_def.discr_ty.to_ty(tcx);
|
||||
let repr_hints = tcx.lookup_repr_hints(adt_def.did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let discr_ty = repr_type.to_ty(tcx);
|
||||
let discr = self.temp(discr_ty);
|
||||
self.cfg.push_assign(block, source_info, &discr,
|
||||
Rvalue::Discriminant(lvalue.clone()));
|
||||
|
@ -93,9 +93,9 @@ impl<'tcx> Callee<'tcx> {
|
||||
|
||||
// FIXME(eddyb) Detect ADT constructors more efficiently.
|
||||
if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
|
||||
if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
|
||||
if let Some(i) = adt_def.variants.iter().position(|v| def_id == v.did) {
|
||||
return Callee {
|
||||
data: NamedTupleConstructor(Disr::from(v.disr_val)),
|
||||
data: NamedTupleConstructor(Disr::for_variant(tcx, adt_def, i)),
|
||||
ty: fn_ty
|
||||
};
|
||||
}
|
||||
|
@ -1465,10 +1465,10 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
// <unknown>
|
||||
let file_metadata = unknown_file_metadata(cx);
|
||||
|
||||
let variants = &enum_type.ty_adt_def().unwrap().variants;
|
||||
let enumerators_metadata: Vec<DIDescriptor> = variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let def = enum_type.ty_adt_def().unwrap();
|
||||
let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx())
|
||||
.zip(&def.variants)
|
||||
.map(|(discr, v)| {
|
||||
let token = v.name.as_str();
|
||||
let name = CString::new(token.as_bytes()).unwrap();
|
||||
unsafe {
|
||||
@ -1476,7 +1476,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
DIB(cx),
|
||||
name.as_ptr(),
|
||||
// FIXME: what if enumeration has i128 discriminant?
|
||||
v.disr_val as u64)
|
||||
discr.to_u128_unchecked() as u64)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -8,10 +8,42 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
pub struct Disr(pub u64);
|
||||
|
||||
impl Disr {
|
||||
pub fn for_variant(tcx: TyCtxt,
|
||||
def: &ty::AdtDef,
|
||||
variant_index: usize) -> Self {
|
||||
let mut explicit_index = variant_index;
|
||||
let mut explicit_value = Disr(0);
|
||||
loop {
|
||||
match def.variants[explicit_index].discr {
|
||||
ty::VariantDiscr::Relative(0) => break,
|
||||
ty::VariantDiscr::Relative(distance) => {
|
||||
explicit_index -= distance;
|
||||
}
|
||||
ty::VariantDiscr::Explicit(expr_did) => {
|
||||
match tcx.monomorphic_const_eval.borrow()[&expr_did] {
|
||||
Ok(ConstVal::Integral(v)) => {
|
||||
explicit_value = Disr::from(v);
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
explicit_index -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let distance = variant_index - explicit_index;
|
||||
explicit_value.wrapping_add(Disr::from(distance))
|
||||
}
|
||||
|
||||
pub fn wrapping_add(self, other: Self) -> Self {
|
||||
Disr(self.0.wrapping_add(other.0))
|
||||
}
|
||||
@ -24,10 +56,10 @@ impl ::std::ops::BitAnd for Disr {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::rustc::ty::Disr> for Disr {
|
||||
fn from(i: ::rustc::ty::Disr) -> Disr {
|
||||
impl From<ConstInt> for Disr {
|
||||
fn from(i: ConstInt) -> Disr {
|
||||
// FIXME: what if discr has 128 bit discr?
|
||||
Disr(i as u64)
|
||||
Disr(i.to_u128_unchecked() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,11 +521,10 @@ fn drop_structural_ty<'a, 'tcx>(
|
||||
let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
|
||||
let next_cx = cx.build_sibling_block("enum-iter-next");
|
||||
|
||||
for (i, variant) in adt.variants.iter().enumerate() {
|
||||
let variant_cx_name = format!("enum-iter-variant-{}",
|
||||
&variant.disr_val.to_string());
|
||||
for (i, discr) in adt.discriminants(cx.tcx()).enumerate() {
|
||||
let variant_cx_name = format!("enum-iter-variant-{}", i);
|
||||
let variant_cx = cx.build_sibling_block(&variant_cx_name);
|
||||
let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
|
||||
let case_val = adt::trans_case(&cx, t, Disr::from(discr));
|
||||
variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
|
||||
ptr.ty = LvalueTy::Downcast {
|
||||
adt_def: adt,
|
||||
|
@ -1001,7 +1001,7 @@ fn trans_const<'a, 'tcx>(
|
||||
layout::CEnum { discr: d, min, max, .. } => {
|
||||
let discr = match *kind {
|
||||
mir::AggregateKind::Adt(adt_def, _, _, _) => {
|
||||
Disr::from(adt_def.variants[variant_index].disr_val)
|
||||
Disr::for_variant(ccx.tcx(), adt_def, variant_index)
|
||||
},
|
||||
_ => Disr(0),
|
||||
};
|
||||
|
@ -106,9 +106,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
||||
match *kind {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
|
||||
let disr = Disr::from(adt_def.variants[variant_index].disr_val);
|
||||
let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
|
||||
let dest_ty = dest.ty.to_ty(bcx.tcx());
|
||||
adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(disr));
|
||||
adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
let op = self.trans_operand(&bcx, operand);
|
||||
// Do not generate stores and GEPis for zero-sized fields.
|
||||
@ -119,7 +119,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
val.ty = LvalueTy::Downcast {
|
||||
adt_def: adt_def,
|
||||
substs: self.monomorphize(&substs),
|
||||
variant_index: disr.0 as usize,
|
||||
variant_index: variant_index,
|
||||
};
|
||||
let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index);
|
||||
self.store_operand(&bcx, lldest_i, align.to_align(), op);
|
||||
|
@ -124,6 +124,7 @@ use rustc::hir::{self, PatKind};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc_back::slice;
|
||||
use rustc_const_eval::eval_length;
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
mod assoc;
|
||||
mod autoderef;
|
||||
@ -1323,14 +1324,12 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
|
||||
let def_id = ccx.tcx.hir.local_def_id(id);
|
||||
|
||||
let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
|
||||
let mut disr_vals: Vec<ty::Disr> = Vec::new();
|
||||
for (v, variant) in vs.iter().zip(variants.iter()) {
|
||||
let current_disr_val = variant.disr_val;
|
||||
|
||||
let def = ccx.tcx.lookup_adt_def(def_id);
|
||||
let mut disr_vals: Vec<ConstInt> = Vec::new();
|
||||
for (discr, v) in def.discriminants(ccx.tcx).zip(vs) {
|
||||
// Check for duplicate discriminant values
|
||||
if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
|
||||
let variant_i_node_id = ccx.tcx.hir.as_local_node_id(variants[i].did).unwrap();
|
||||
if let Some(i) = disr_vals.iter().position(|&x| x == discr) {
|
||||
let variant_i_node_id = ccx.tcx.hir.as_local_node_id(def.variants[i].did).unwrap();
|
||||
let variant_i = ccx.tcx.hir.expect_variant(variant_i_node_id);
|
||||
let i_span = match variant_i.node.disr_expr {
|
||||
Some(expr) => ccx.tcx.hir.span(expr.node_id),
|
||||
@ -1346,7 +1345,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
.span_label(span , &format!("enum already has `{}`", disr_vals[i]))
|
||||
.emit();
|
||||
}
|
||||
disr_vals.push(current_disr_val);
|
||||
disr_vals.push(discr);
|
||||
}
|
||||
|
||||
check_representable(ccx.tcx, sp, def_id);
|
||||
|
@ -875,8 +875,36 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
def: &'tcx ty::AdtDef,
|
||||
ty: Ty<'tcx>,
|
||||
variants: &[hir::Variant]) {
|
||||
// fill the field types
|
||||
let tcx = ccx.tcx;
|
||||
let repr_hints = tcx.lookup_repr_hints(def.did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let initial = repr_type.initial_discriminant(tcx);
|
||||
let mut prev_discr = None::<ConstInt>;
|
||||
|
||||
// fill the discriminant values and field types
|
||||
for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
|
||||
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
|
||||
prev_discr = Some(if let Some(e) = variant.node.disr_expr {
|
||||
let result = evaluate_disr_expr(ccx, repr_type, e);
|
||||
|
||||
let expr_did = tcx.hir.local_def_id(e.node_id);
|
||||
tcx.monomorphic_const_eval.borrow_mut()
|
||||
.insert(expr_did, result.map(ConstVal::Integral));
|
||||
|
||||
result.ok()
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
Some(discr)
|
||||
} else {
|
||||
struct_span_err!(tcx.sess, variant.span, E0370,
|
||||
"enum discriminant overflowed")
|
||||
.span_label(variant.span, &format!("overflowed on value after {}",
|
||||
prev_discr.unwrap()))
|
||||
.note(&format!("explicitly set `{} = {}` if that is desired outcome",
|
||||
variant.node.name, wrapped_discr))
|
||||
.emit();
|
||||
None
|
||||
}.unwrap_or(wrapped_discr));
|
||||
|
||||
for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
|
||||
convert_field(ccx, f, ty_f)
|
||||
}
|
||||
@ -890,7 +918,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
did: DefId,
|
||||
name: ast::Name,
|
||||
disr_val: ty::Disr,
|
||||
discr: ty::VariantDiscr,
|
||||
def: &hir::VariantData)
|
||||
-> ty::VariantDef {
|
||||
let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap();
|
||||
@ -918,7 +946,7 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
ty::VariantDef {
|
||||
did: did,
|
||||
name: name,
|
||||
disr_val: disr_val,
|
||||
discr: discr,
|
||||
fields: fields,
|
||||
ctor_kind: CtorKind::from_hir(def),
|
||||
}
|
||||
@ -932,8 +960,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
let did = ccx.tcx.hir.local_def_id(it.id);
|
||||
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
|
||||
let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
|
||||
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)];
|
||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants,
|
||||
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
|
||||
ty::VariantDiscr::Relative(0), def)];
|
||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants,
|
||||
ReprOptions::new(&ccx.tcx, did));
|
||||
if let Some(ctor_id) = ctor_id {
|
||||
// Make adt definition available through constructor id as well.
|
||||
@ -950,15 +979,16 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
-> &'tcx ty::AdtDef
|
||||
{
|
||||
let did = ccx.tcx.hir.local_def_id(it.id);
|
||||
let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
|
||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants,
|
||||
ReprOptions::new(&ccx.tcx, did));
|
||||
let variants = vec![convert_struct_variant(ccx, did, it.name,
|
||||
ty::VariantDiscr::Relative(0), def)];
|
||||
|
||||
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did));
|
||||
ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
|
||||
adt
|
||||
}
|
||||
|
||||
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
|
||||
-> Option<ConstInt> {
|
||||
-> Result<ConstInt, ()> {
|
||||
let e = &ccx.tcx.hir.body(body).value;
|
||||
debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
|
||||
|
||||
@ -987,17 +1017,16 @@ fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId
|
||||
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
|
||||
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) =>
|
||||
Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Ok(i),
|
||||
(_, i) => {
|
||||
print_err(ConstVal::Integral(i));
|
||||
None
|
||||
Err(())
|
||||
},
|
||||
}
|
||||
},
|
||||
Ok(cv) => {
|
||||
print_err(cv);
|
||||
None
|
||||
Err(())
|
||||
},
|
||||
// enum variant evaluation happens before the global constant check
|
||||
// so we need to report the real error
|
||||
@ -1005,7 +1034,7 @@ fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId
|
||||
let mut diag = report_const_eval_err(
|
||||
ccx.tcx, &err, e.span, "enum discriminant");
|
||||
diag.emit();
|
||||
None
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1016,36 +1045,22 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
-> &'tcx ty::AdtDef
|
||||
{
|
||||
let tcx = ccx.tcx;
|
||||
let did = tcx.hir.local_def_id(it.id);
|
||||
let repr_hints = tcx.lookup_repr_hints(did);
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type,
|
||||
tcx.sess.target.uint_type, tcx.sess.target.int_type)
|
||||
.unwrap();
|
||||
let mut prev_disr = None::<ConstInt>;
|
||||
let mut distance_from_explicit = 0;
|
||||
let variants = def.variants.iter().map(|v| {
|
||||
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
|
||||
let disr = if let Some(e) = v.node.disr_expr {
|
||||
// FIXME: i128 discriminants
|
||||
evaluate_disr_expr(ccx, repr_type, e)
|
||||
} else if let Some(disr) = prev_disr.map_or(Some(initial),
|
||||
|v| (v + ConstInt::Infer(1)).ok()) {
|
||||
Some(disr)
|
||||
} else {
|
||||
struct_span_err!(tcx.sess, v.span, E0370,
|
||||
"enum discriminant overflowed")
|
||||
.span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
|
||||
.note(&format!("explicitly set `{} = {}` if that is desired outcome",
|
||||
v.node.name, wrapped_disr))
|
||||
.emit();
|
||||
None
|
||||
}.unwrap_or(wrapped_disr);
|
||||
prev_disr = Some(disr);
|
||||
let did = tcx.hir.local_def_id(v.node.data.id());
|
||||
convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data)
|
||||
let discr = if let Some(e) = v.node.disr_expr {
|
||||
distance_from_explicit = 0;
|
||||
ty::VariantDiscr::Explicit(tcx.hir.local_def_id(e.node_id))
|
||||
} else {
|
||||
ty::VariantDiscr::Relative(distance_from_explicit)
|
||||
};
|
||||
distance_from_explicit += 1;
|
||||
|
||||
convert_struct_variant(ccx, did, v.node.name, discr, &v.node.data)
|
||||
}).collect();
|
||||
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants,
|
||||
ReprOptions::new(&ccx.tcx, did));
|
||||
|
||||
let did = tcx.hir.local_def_id(it.id);
|
||||
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did));
|
||||
tcx.adt_defs.borrow_mut().insert(did, adt);
|
||||
adt
|
||||
}
|
||||
|
@ -9,10 +9,10 @@
|
||||
// except according to those terms.
|
||||
|
||||
enum Enum {
|
||||
P = 3, //~ NOTE first use of `3`
|
||||
P = 3, //~ NOTE first use of `3isize`
|
||||
X = 3,
|
||||
//~^ ERROR discriminant value `3` already exists
|
||||
//~| NOTE enum already has `3`
|
||||
//~^ ERROR discriminant value `3isize` already exists
|
||||
//~| NOTE enum already has `3isize`
|
||||
Y = 5
|
||||
}
|
||||
|
||||
|
@ -12,20 +12,20 @@ const N: isize = 1;
|
||||
|
||||
enum Foo {
|
||||
A = 1,
|
||||
//~^ NOTE first use of `1`
|
||||
//~| NOTE first use of `1`
|
||||
//~| NOTE first use of `1`
|
||||
//~^ NOTE first use of `1isize`
|
||||
//~| NOTE first use of `1isize`
|
||||
//~| NOTE first use of `1isize`
|
||||
B = 1,
|
||||
//~^ ERROR discriminant value `1` already exists
|
||||
//~| NOTE enum already has `1`
|
||||
//~^ ERROR discriminant value `1isize` already exists
|
||||
//~| NOTE enum already has `1isize`
|
||||
C = 0,
|
||||
D,
|
||||
//~^ ERROR discriminant value `1` already exists
|
||||
//~| NOTE enum already has `1`
|
||||
//~^ ERROR discriminant value `1isize` already exists
|
||||
//~| NOTE enum already has `1isize`
|
||||
|
||||
E = N,
|
||||
//~^ ERROR discriminant value `1` already exists
|
||||
//~| NOTE enum already has `1`
|
||||
//~^ ERROR discriminant value `1isize` already exists
|
||||
//~| NOTE enum already has `1isize`
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user