From e96a171453973bad66ed9b5df3a7f6e37d9bce31 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 5 Feb 2017 07:01:48 +0200 Subject: [PATCH] rustc: move the actual values of enum discriminants into a map. --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/mir/tcx.rs | 4 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/layout.rs | 15 ++- src/librustc/ty/maps.rs | 2 + src/librustc/ty/mod.rs | 50 +++++++--- src/librustc/ty/util.rs | 90 ++++++++++++++--- .../borrowck/mir/elaborate_drops.rs | 11 +-- src/librustc_const_math/int.rs | 8 -- src/librustc_metadata/decoder.rs | 27 ++++-- src/librustc_metadata/encoder.rs | 20 ++-- src/librustc_metadata/schema.rs | 6 +- src/librustc_mir/build/matches/test.rs | 11 +-- src/librustc_trans/callee.rs | 4 +- src/librustc_trans/debuginfo/metadata.rs | 10 +- src/librustc_trans/disr.rs | 38 +++++++- src/librustc_trans/glue.rs | 7 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 6 +- src/librustc_typeck/check/mod.rs | 15 ++- src/librustc_typeck/collect.rs | 97 +++++++++++-------- src/test/compile-fail/E0081.rs | 6 +- src/test/compile-fail/issue-15524.rs | 18 ++-- 23 files changed, 311 insertions(+), 147 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 96d1a925425..8da032f5935 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -114,6 +114,7 @@ pub enum DepNode { 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 DepNode { 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), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 5c8d031caf6..527f1152770 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -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. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2f062e2e5b1..c7e7fac2759 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -507,6 +507,10 @@ pub struct GlobalCtxt<'tcx> { /// FIXME(arielb1): why is this separate from populated_external_types? pub populated_external_primitive_impls: RefCell, + /// Results of evaluating monomorphic constants embedded in + /// other items, such as enum variant explicit discriminants. + pub monomorphic_const_eval: RefCell>>, + /// Maps any item's def-id to its stability index. pub stability: RefCell>, @@ -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, variants: Vec, 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(), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index f429053d8bb..5829ae195c9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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 diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index d2c237d5db6..cedb0307495 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -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 } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1275530b1bd..be4ec881482 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, 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, destructor: Cell>, flags: Cell, @@ -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, 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 + '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::; + 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. /// diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 16492de6c3d..af259909787 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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) + -> Option; + 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) + -> Option { + if let Some(val) = val { + self.assert_ty_matches(val); + (val + ConstInt::Infer(1)).ok() + } else { + Some(self.initial_discriminant(tcx)) + } } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 5899c9f31d1..c64b25032c9 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -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![ diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index bc3809db1c6..17714f2fb2d 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -77,14 +77,6 @@ mod ibounds { } impl ConstInt { - pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy) - -> Option { - 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 { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 22fa9411cc1..88b06e29e10 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -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) { 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); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a643ed59af1..725d54c227a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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) } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index ee30063fcbd..6307d4eda30 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -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, ReprOptions), + Enum(ReprOptions), Field, Variant(Lazy), Struct(Lazy, 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, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 01c0433112b..3256bdf9c25 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -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())); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 4a8658dd2e3..9a06820115f 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -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 }; } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 11c0bf852f7..2b584344ed1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1465,10 +1465,10 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // let file_metadata = unknown_file_metadata(cx); - let variants = &enum_type.ty_adt_def().unwrap().variants; - let enumerators_metadata: Vec = variants - .iter() - .map(|v| { + let def = enum_type.ty_adt_def().unwrap(); + let enumerators_metadata: Vec = 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(); diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs index f3a62bc85b8..00c0e0d5415 100644 --- a/src/librustc_trans/disr.rs +++ b/src/librustc_trans/disr.rs @@ -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 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) } } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 9963514acd7..58e0a9e589f 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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, diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index e6cae2f9f32..6a0e05803c3 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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), }; diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 6f6d81a2535..c3dffd476e1 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -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); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d4895d638ba..6a003ef7340 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 = 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 = 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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 975a9aa9946..3f3fc40320e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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::; + + // 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 = 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 { + -> Result { 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::; + 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 } diff --git a/src/test/compile-fail/E0081.rs b/src/test/compile-fail/E0081.rs index e12eff72c7f..9911e093a89 100644 --- a/src/test/compile-fail/E0081.rs +++ b/src/test/compile-fail/E0081.rs @@ -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 } diff --git a/src/test/compile-fail/issue-15524.rs b/src/test/compile-fail/issue-15524.rs index 0d5f5fd75eb..658a0c1546b 100644 --- a/src/test/compile-fail/issue-15524.rs +++ b/src/test/compile-fail/issue-15524.rs @@ -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` }