Skip to content

Commit e96a171

Browse files
committed
rustc: move the actual values of enum discriminants into a map.
1 parent 86e4029 commit e96a171

File tree

23 files changed

+311
-147
lines changed

23 files changed

+311
-147
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub enum DepNode<D: Clone + Debug> {
114114
InherentImpls(D),
115115
TypeckTables(D),
116116
UsedTraitImports(D),
117+
MonomorphicConstEval(D),
117118

118119
// The set of impls for a given trait. Ultimately, it would be
119120
// nice to get more fine-grained here (e.g., to include a
@@ -263,6 +264,7 @@ impl<D: Clone + Debug> DepNode<D> {
263264
InherentImpls(ref d) => op(d).map(InherentImpls),
264265
TypeckTables(ref d) => op(d).map(TypeckTables),
265266
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
267+
MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
266268
TraitImpls(ref d) => op(d).map(TraitImpls),
267269
TraitItems(ref d) => op(d).map(TraitItems),
268270
ReprHints(ref d) => op(d).map(ReprHints),

src/librustc/mir/tcx.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ impl<'tcx> Rvalue<'tcx> {
173173
Rvalue::Discriminant(ref lval) => {
174174
let ty = lval.ty(mir, tcx).to_ty(tcx);
175175
if let ty::TyAdt(adt_def, _) = ty.sty {
176-
Some(adt_def.discr_ty.to_ty(tcx))
176+
let repr_hints = tcx.lookup_repr_hints(adt_def.did);
177+
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
178+
Some(repr_type.to_ty(tcx))
177179
} else {
178180
// Undefined behaviour, bug for now; may want to return something for
179181
// the `discriminant` intrinsic later.

src/librustc/ty/context.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,10 @@ pub struct GlobalCtxt<'tcx> {
507507
/// FIXME(arielb1): why is this separate from populated_external_types?
508508
pub populated_external_primitive_impls: RefCell<DefIdSet>,
509509

510+
/// Results of evaluating monomorphic constants embedded in
511+
/// other items, such as enum variant explicit discriminants.
512+
pub monomorphic_const_eval: RefCell<DepTrackingMap<maps::MonomorphicConstEval<'tcx>>>,
513+
510514
/// Maps any item's def-id to its stability index.
511515
pub stability: RefCell<stability::Index<'tcx>>,
512516

@@ -662,12 +666,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
662666
pub fn alloc_adt_def(self,
663667
did: DefId,
664668
kind: AdtKind,
665-
discr_ty: Option<attr::IntType>,
666669
variants: Vec<ty::VariantDef>,
667670
repr: ReprOptions)
668671
-> &'gcx ty::AdtDef {
669-
let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
670-
let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
672+
let def = ty::AdtDef::new(self, did, kind, variants, repr);
671673
self.global_arenas.adt_def.alloc(def)
672674
}
673675

@@ -783,6 +785,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
783785
used_trait_imports: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
784786
populated_external_types: RefCell::new(DefIdSet()),
785787
populated_external_primitive_impls: RefCell::new(DefIdSet()),
788+
monomorphic_const_eval: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
786789
stability: RefCell::new(stability),
787790
selection_cache: traits::SelectionCache::new(),
788791
evaluation_cache: traits::EvaluationCache::new(),

src/librustc/ty/layout.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
2020
use syntax::ast::{FloatTy, IntTy, UintTy};
2121
use syntax::attr;
2222
use syntax_pos::DUMMY_SP;
23+
use rustc_const_math::ConstInt;
2324

2425
use std::cmp;
2526
use std::fmt;
@@ -1181,8 +1182,12 @@ impl<'a, 'gcx, 'tcx> Layout {
11811182
let (mut min, mut max, mut non_zero) = (i64::max_value(),
11821183
i64::min_value(),
11831184
true);
1184-
for v in &def.variants {
1185-
let x = v.disr_val as i128 as i64;
1185+
for discr in def.discriminants(tcx) {
1186+
let x = match discr.erase_type() {
1187+
ConstInt::InferSigned(i) => i as i64,
1188+
ConstInt::Infer(i) => i as u64 as i64,
1189+
_ => bug!()
1190+
};
11861191
if x == 0 { non_zero = false; }
11871192
if x < min { min = x; }
11881193
if x > max { max = x; }
@@ -1240,7 +1245,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12401245
// non-empty body, explicit discriminants should have
12411246
// been rejected by a checker before this point.
12421247
for (i, v) in def.variants.iter().enumerate() {
1243-
if i as u128 != v.disr_val {
1248+
if v.discr != ty::VariantDiscr::Relative(i) {
12441249
bug!("non-C-like enum {} with specified discriminants",
12451250
tcx.item_path_str(def.did));
12461251
}
@@ -1348,7 +1353,9 @@ impl<'a, 'gcx, 'tcx> Layout {
13481353
return Err(LayoutError::SizeOverflow(ty));
13491354
}
13501355

1351-
let typeck_ity = Integer::from_attr(dl, def.discr_ty);
1356+
let repr_hints = tcx.lookup_repr_hints(def.did);
1357+
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
1358+
let typeck_ity = Integer::from_attr(dl, repr_type);
13521359
if typeck_ity < min_ity {
13531360
// It is a bug if Layout decided on a greater discriminant size than typeck for
13541361
// some reason at this point (based on values discriminant can take on). Mostly

src/librustc/ty/maps.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use dep_graph::{DepNode, DepTrackingMapConfig};
1212
use hir::def_id::DefId;
13+
use middle::const_val::ConstVal;
1314
use mir;
1415
use ty::{self, Ty};
1516
use util::nodemap::DefIdSet;
@@ -51,3 +52,4 @@ dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
5152
dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
5253
dep_map_ty! { TypeckTables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx> }
5354
dep_map_ty! { UsedTraitImports: UsedTraitImports(DefId) -> DefIdSet }
55+
dep_map_ty! { MonomorphicConstEval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()> }

src/librustc/ty/mod.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ use hir::{map as hir_map, FreevarMap, TraitMap};
2020
use middle;
2121
use hir::def::{Def, CtorKind, ExportMap};
2222
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
23+
use middle::const_val::ConstVal;
2324
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
2425
use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
2526
use middle::resolve_lifetime::ObjectLifetimeDefault;
2627
use mir::Mir;
2728
use traits;
2829
use ty;
2930
use ty::subst::{Subst, Substs};
31+
use ty::util::IntTypeExt;
3032
use ty::walk::TypeWalker;
3133
use util::common::MemoizationMap;
3234
use util::nodemap::{NodeSet, NodeMap, FxHashMap};
@@ -45,6 +47,7 @@ use syntax::ast::{self, Name, NodeId};
4547
use syntax::attr;
4648
use syntax::symbol::{Symbol, InternedString};
4749
use syntax_pos::{DUMMY_SP, Span};
50+
use rustc_const_math::ConstInt;
4851

4952
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
5053

@@ -96,8 +99,6 @@ mod flags;
9699
mod structural_impls;
97100
mod sty;
98101

99-
pub type Disr = u128;
100-
101102
// Data types
102103

103104
/// The complete set of all analyses described in this module. This is
@@ -1309,11 +1310,24 @@ pub struct VariantDef {
13091310
/// this is the DefId of the struct's ctor.
13101311
pub did: DefId,
13111312
pub name: Name, // struct's name if this is a struct
1312-
pub disr_val: Disr,
1313+
pub discr: VariantDiscr,
13131314
pub fields: Vec<FieldDef>,
13141315
pub ctor_kind: CtorKind,
13151316
}
13161317

1318+
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
1319+
pub enum VariantDiscr {
1320+
/// Explicit value for this variant, i.e. `X = 123`.
1321+
/// The `DefId` corresponds to the embedded constant.
1322+
Explicit(DefId),
1323+
1324+
/// The previous variant's discriminant plus one.
1325+
/// For efficiency reasons, the distance from the
1326+
/// last `Explicit` discriminant is being stored,
1327+
/// or `0` for the first variant, if it has none.
1328+
Relative(usize),
1329+
}
1330+
13171331
#[derive(Debug)]
13181332
pub struct FieldDef {
13191333
pub did: DefId,
@@ -1327,12 +1341,6 @@ pub struct FieldDef {
13271341
/// table.
13281342
pub struct AdtDef {
13291343
pub did: DefId,
1330-
/// Type of the discriminant
1331-
///
1332-
/// Note, that this is the type specified in `repr()` or a default type of some sort, and might
1333-
/// not match the actual type that layout algorithm decides to use when translating this type
1334-
/// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
1335-
pub discr_ty: attr::IntType,
13361344
pub variants: Vec<VariantDef>,
13371345
destructor: Cell<Option<DefId>>,
13381346
flags: Cell<AdtFlags>,
@@ -1395,7 +1403,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
13951403
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
13961404
did: DefId,
13971405
kind: AdtKind,
1398-
discr_ty: attr::IntType,
13991406
variants: Vec<VariantDef>,
14001407
repr: ReprOptions) -> Self {
14011408
let mut flags = AdtFlags::NO_ADT_FLAGS;
@@ -1419,7 +1426,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
14191426
}
14201427
AdtDef {
14211428
did: did,
1422-
discr_ty: discr_ty,
14231429
variants: variants,
14241430
flags: Cell::new(flags),
14251431
destructor: Cell::new(None),
@@ -1577,6 +1583,28 @@ impl<'a, 'gcx, 'tcx> AdtDef {
15771583
self.destructor.set(Some(dtor));
15781584
}
15791585

1586+
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
1587+
-> impl Iterator<Item=ConstInt> + 'a {
1588+
let repr_hints = tcx.lookup_repr_hints(self.did);
1589+
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
1590+
let initial = repr_type.initial_discriminant(tcx.global_tcx());
1591+
let mut prev_discr = None::<ConstInt>;
1592+
self.variants.iter().map(move |v| {
1593+
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
1594+
if let VariantDiscr::Explicit(expr_did) = v.discr {
1595+
match tcx.monomorphic_const_eval.borrow()[&expr_did] {
1596+
Ok(ConstVal::Integral(v)) => {
1597+
discr = v;
1598+
}
1599+
_ => {}
1600+
}
1601+
}
1602+
prev_discr = Some(discr);
1603+
1604+
discr
1605+
})
1606+
}
1607+
15801608
/// Returns a simpler type such that `Self: Sized` if and only
15811609
/// if that type is Sized, or `TyErr` if this type is recursive.
15821610
///

src/librustc/ty/util.rs

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ use infer::InferCtxt;
1616
use hir::map as hir_map;
1717
use traits::{self, Reveal};
1818
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
19-
use ty::{Disr, ParameterEnvironment};
19+
use ty::{ParameterEnvironment};
2020
use ty::fold::TypeVisitor;
2121
use ty::layout::{Layout, LayoutError};
2222
use ty::TypeVariants::*;
2323
use util::nodemap::FxHashMap;
2424
use middle::lang_items;
2525

26+
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
2627
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
2728

2829
use std::cell::RefCell;
@@ -35,21 +36,88 @@ use syntax_pos::Span;
3536

3637
use hir;
3738

38-
pub trait IntTypeExt {
39-
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
40-
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
41-
}
39+
type Disr = ConstInt;
40+
41+
pub trait IntTypeExt {
42+
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
43+
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
44+
-> Option<Disr>;
45+
fn assert_ty_matches(&self, val: Disr);
46+
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
47+
}
48+
4249

4350
impl IntTypeExt for attr::IntType {
44-
fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
45-
match self {
46-
SignedInt(i) => tcx.mk_mach_int(i),
47-
UnsignedInt(i) => tcx.mk_mach_uint(i),
51+
fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
52+
match *self {
53+
SignedInt(ast::IntTy::I8) => tcx.types.i8,
54+
SignedInt(ast::IntTy::I16) => tcx.types.i16,
55+
SignedInt(ast::IntTy::I32) => tcx.types.i32,
56+
SignedInt(ast::IntTy::I64) => tcx.types.i64,
57+
SignedInt(ast::IntTy::I128) => tcx.types.i128,
58+
SignedInt(ast::IntTy::Is) => tcx.types.isize,
59+
UnsignedInt(ast::UintTy::U8) => tcx.types.u8,
60+
UnsignedInt(ast::UintTy::U16) => tcx.types.u16,
61+
UnsignedInt(ast::UintTy::U32) => tcx.types.u32,
62+
UnsignedInt(ast::UintTy::U64) => tcx.types.u64,
63+
UnsignedInt(ast::UintTy::U128) => tcx.types.u128,
64+
UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
65+
}
66+
}
67+
68+
fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
69+
match *self {
70+
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
71+
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
72+
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
73+
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
74+
SignedInt(ast::IntTy::I128) => ConstInt::I128(0),
75+
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
76+
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)),
77+
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
78+
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
79+
_ => bug!(),
80+
},
81+
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
82+
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
83+
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
84+
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
85+
UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0),
86+
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
87+
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)),
88+
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
89+
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
90+
_ => bug!(),
91+
},
4892
}
4993
}
5094

51-
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
52-
0
95+
fn assert_ty_matches(&self, val: Disr) {
96+
match (*self, val) {
97+
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
98+
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
99+
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
100+
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
101+
(SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
102+
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
103+
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
104+
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
105+
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
106+
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
107+
(UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
108+
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
109+
_ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
110+
}
111+
}
112+
113+
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
114+
-> Option<Disr> {
115+
if let Some(val) = val {
116+
self.assert_ty_matches(val);
117+
(val + ConstInt::Infer(1)).ok()
118+
} else {
119+
Some(self.initial_discriminant(tcx))
120+
}
53121
}
54122
}
55123

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc::ty::subst::{Kind, Subst, Substs};
2020
use rustc::ty::util::IntTypeExt;
2121
use rustc::mir::*;
2222
use rustc::mir::transform::{Pass, MirPass, MirSource};
23-
use rustc::middle::const_val::{ConstVal, ConstInt};
23+
use rustc::middle::const_val::ConstVal;
2424
use rustc::middle::lang_items;
2525
use rustc::util::nodemap::FxHashMap;
2626
use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -639,10 +639,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
639639
let mut values = Vec::with_capacity(adt.variants.len());
640640
let mut blocks = Vec::with_capacity(adt.variants.len());
641641
let mut otherwise = None;
642-
for (variant_index, variant) in adt.variants.iter().enumerate() {
643-
let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
644-
self.tcx.sess.target.uint_type,
645-
self.tcx.sess.target.int_type).unwrap();
642+
for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() {
646643
let subpath = super::move_path_children_matching(
647644
self.move_data(), c.path, |proj| match proj {
648645
&Projection {
@@ -680,7 +677,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
680677
// Additionally, we do not want to switch on the
681678
// discriminant after it is free-ed, because that
682679
// way lies only trouble.
683-
let discr_ty = adt.discr_ty.to_ty(self.tcx);
680+
let repr_hints = self.tcx.lookup_repr_hints(adt.did);
681+
let repr_type = self.tcx.enum_repr_type(repr_hints.get(0));
682+
let discr_ty = repr_type.to_ty(self.tcx);
684683
let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
685684
let switch_block = self.patch.new_block(BasicBlockData {
686685
statements: vec![

src/librustc_const_math/int.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,6 @@ mod ibounds {
7777
}
7878

7979
impl ConstInt {
80-
pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
81-
-> Option<ConstInt> {
82-
match ty {
83-
IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
84-
IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
85-
}
86-
}
87-
8880
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
8981
/// not happen.
9082
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {

0 commit comments

Comments
 (0)