Move type of discriminant to AdtDef

Previously AdtDef variants contained ConstInt for each discriminant, which did not really reflect
the actual type of the discriminants. Moving the type into AdtDef allows to easily put the type
into metadata and also saves bytes from ConstVal overhead for each discriminant.

Also arguably the code is cleaner now :)
This commit is contained in:
Simonas Kazlauskas 2017-02-01 03:38:28 +02:00
parent 98d1db7fe3
commit 24c93efbb5
10 changed files with 104 additions and 121 deletions

View File

@ -673,10 +673,12 @@ 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 def = ty::AdtDef::new(self, did, kind, variants, repr);
let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
self.global_arenas.adt_def.alloc(def)
}

View File

@ -20,7 +20,6 @@ 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;
@ -1183,10 +1182,12 @@ impl<'a, 'gcx, 'tcx> Layout {
i64::min_value(),
true);
for v in &def.variants {
let x = match v.disr_val.erase_type() {
ConstInt::InferSigned(i) => i as i64,
ConstInt::Infer(i) => i as u64 as i64,
_ => bug!()
let x = match def.discr_ty {
attr::IntType::SignedInt(IntTy::I128) |
attr::IntType::UnsignedInt(UintTy::U128) =>
bug!("128-bit discriminants not yet supported"),
attr::IntType::SignedInt(_) => v.disr_val as i64,
attr::IntType::UnsignedInt(_) => v.disr_val as u64 as i64,
};
if x == 0 { non_zero = false; }
if x < min { min = x; }
@ -1247,7 +1248,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.to_u128_unchecked() {
if i as u128 != v.disr_val {
bug!("non-C-like enum {} with specified discriminants",
tcx.item_path_str(def.did));
}

View File

@ -45,7 +45,6 @@ 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;
use hir;
@ -72,6 +71,8 @@ pub use self::context::{Lift, TypeckTables};
pub use self::trait_def::{TraitDef, TraitFlags};
use rustc_i128::u128;
pub mod adjustment;
pub mod cast;
pub mod error;
@ -96,7 +97,7 @@ mod flags;
mod structural_impls;
mod sty;
pub type Disr = ConstInt;
pub type Disr = u128;
// Data types
@ -1325,6 +1326,7 @@ pub struct FieldDef {
/// table.
pub struct AdtDef {
pub did: DefId,
pub discr_ty: attr::IntType, // Type of the discriminant
pub variants: Vec<VariantDef>,
destructor: Cell<Option<DefId>>,
flags: Cell<AdtFlags>,
@ -1387,6 +1389,7 @@ 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;
@ -1410,6 +1413,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
AdtDef {
did: did,
discr_ty: discr_ty,
variants: variants,
flags: Cell::new(flags),
destructor: Cell::new(None),

View File

@ -23,7 +23,7 @@ use ty::TypeVariants::*;
use util::nodemap::FxHashMap;
use middle::lang_items;
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc_const_math::ConstInt;
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
use std::cell::RefCell;
@ -34,14 +34,15 @@ use syntax::ast::{self, Name};
use syntax::attr::{self, SignedInt, UnsignedInt};
use syntax_pos::Span;
use rustc_i128::i128;
use hir;
pub trait IntTypeExt {
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, '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;
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
}
impl IntTypeExt for attr::IntType {
@ -62,56 +63,18 @@ impl IntTypeExt for attr::IntType {
}
}
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 initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
0
}
/// None = overflow
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
-> Option<Disr> {
-> Option<Disr> {
if let Some(val) = val {
self.assert_ty_matches(val);
(val + ConstInt::Infer(1)).ok()
match *self {
SignedInt(it) => ConstInt::new_signed(val as i128, it, tcx.sess.target.int_type),
UnsignedInt(it) => ConstInt::new_unsigned(val, it, tcx.sess.target.uint_type),
}.and_then(|l| (l + ConstInt::Infer(1)).ok()).map(|v| v.to_u128_unchecked())
} else {
Some(self.initial_discriminant(tcx))
}

View File

@ -25,8 +25,6 @@ use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc_const_math::ConstInt;
use rustc::mir::Mir;
use std::borrow::Cow;
@ -435,7 +433,7 @@ impl<'tcx> EntryKind<'tcx> {
EntryKind::Mod(_) => Def::Mod(did),
EntryKind::Variant(_) => Def::Variant(did),
EntryKind::Trait(_) => Def::Trait(did),
EntryKind::Enum(_) => Def::Enum(did),
EntryKind::Enum(..) => Def::Enum(did),
EntryKind::MacroDef(_) => Def::Macro(did),
EntryKind::ForeignMod |
@ -535,7 +533,7 @@ impl<'a, 'tcx> CrateMetadata {
vis: f.visibility.decode(self)
}
}).collect(),
disr_val: ConstInt::Infer(data.disr),
disr_val: data.disr,
ctor_kind: data.ctor_kind,
}, data.struct_ctor)
}
@ -546,6 +544,12 @@ 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),
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
};
let mut ctor_index = None;
let variants = if let EntryKind::Enum(_) = item.kind {
item.children
@ -562,13 +566,13 @@ impl<'a, 'tcx> CrateMetadata {
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, variants, repr);
let adt = tcx.alloc_adt_def(did, kind, ty, 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);

View File

@ -261,7 +261,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let data = VariantData {
ctor_kind: variant.ctor_kind,
disr: variant.disr_val.to_u128_unchecked(),
disr: variant.disr_val,
struct_ctor: None,
};
@ -388,7 +388,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let data = VariantData {
ctor_kind: variant.ctor_kind,
disr: variant.disr_val.to_u128_unchecked(),
disr: variant.disr_val,
struct_ctor: Some(def_id.index),
};
@ -661,7 +661,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
hir::ItemTy(..) => EntryKind::Type,
hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty), get_repr_options(&tcx, def_id)),
hir::ItemStruct(ref struct_def, _) => {
let variant = tcx.lookup_adt_def(def_id).struct_variant();
@ -678,7 +678,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
EntryKind::Struct(self.lazy(&VariantData {
ctor_kind: variant.ctor_kind,
disr: variant.disr_val.to_u128_unchecked(),
disr: variant.disr_val,
struct_ctor: struct_ctor,
}), repr_options)
}
@ -688,7 +688,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
EntryKind::Union(self.lazy(&VariantData {
ctor_kind: variant.ctor_kind,
disr: variant.disr_val.to_u128_unchecked(),
disr: variant.disr_val,
struct_ctor: None,
}), repr_options)
}

View File

@ -228,7 +228,7 @@ pub enum EntryKind<'tcx> {
ForeignMutStatic,
ForeignMod,
Type,
Enum(ReprOptions),
Enum(Lazy<attr::IntType>, ReprOptions),
Field,
Variant(Lazy<VariantData>),
Struct(Lazy<VariantData>, ReprOptions),

View File

@ -1473,7 +1473,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.to_u128_unchecked() as u64)
v.disr_val as u64)
}
})
.collect();

View File

@ -27,7 +27,7 @@ impl ::std::ops::BitAnd for Disr {
impl From<::rustc::ty::Disr> for Disr {
fn from(i: ::rustc::ty::Disr) -> Disr {
// FIXME: what if discr has 128 bit discr?
Disr(i.to_u128_unchecked() as u64)
Disr(i as u64)
}
}

View File

@ -1004,9 +1004,8 @@ 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,
ConstInt::Infer(0), def)];
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, variants,
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,
ReprOptions::new(&ccx.tcx, did));
if let Some(ctor_id) = ctor_id {
// Make adt definition available through constructor id as well.
@ -1023,63 +1022,69 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-> &'tcx ty::AdtDef
{
let did = ccx.tcx.hir.local_def_id(it.id);
<<<<<<< HEAD
let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)];
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, variants, ReprOptions::new(&ccx.tcx, did));
=======
let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants);
>>>>>>> b1934037e6... Move type of discriminant to AdtDef
ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
adt
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
-> Option<ty::Disr> {
let e = &ccx.tcx.hir.body(body).value;
debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
-> Option<ty::Disr> {
let e = &ccx.tcx.hir.body(body).value;
debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
let ty_hint = repr_ty.to_ty(ccx.tcx);
let print_err = |cv: ConstVal| {
struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types")
.note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
.span_label(e.span, &format!("expected '{}' type", ty_hint))
.emit();
};
let ty_hint = repr_ty.to_ty(ccx.tcx);
let print_err = |cv: ConstVal| {
struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types")
.note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
.span_label(e.span, &format!("expected '{}' type", ty_hint))
.emit();
};
let hint = UncheckedExprHint(ty_hint);
match ConstContext::new(ccx.tcx, body).eval(e, hint) {
Ok(ConstVal::Integral(i)) => {
// FIXME: eval should return an error if the hint is wrong
match (repr_ty, i) {
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
(attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
(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),
(_, i) => {
print_err(ConstVal::Integral(i));
None
},
}
},
Ok(cv) => {
print_err(cv);
None
},
// enum variant evaluation happens before the global constant check
// so we need to report the real error
Err(err) => {
let mut diag = report_const_eval_err(
ccx.tcx, &err, e.span, "enum discriminant");
diag.emit();
None
let hint = UncheckedExprHint(ty_hint);
match ConstContext::new(ccx.tcx, body).eval(e, hint) {
Ok(ConstVal::Integral(i)) => {
// FIXME: eval should return an error if the hint is wrong
match (repr_ty, i) {
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
(attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
(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.to_u128_unchecked()),
(_, i) => {
print_err(ConstVal::Integral(i));
None
},
}
},
Ok(cv) => {
print_err(cv);
None
},
// enum variant evaluation happens before the global constant check
// so we need to report the real error
Err(err) => {
let mut diag = report_const_eval_err(
ccx.tcx, &err, e.span, "enum discriminant");
diag.emit();
None
}
}
}
fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
it: &hir::Item,
@ -1093,7 +1098,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let initial = repr_type.initial_discriminant(tcx);
let mut prev_disr = None::<ty::Disr>;
let variants = def.variants.iter().map(|v| {
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrapping_add(1));
let disr = if let Some(e) = v.node.disr_expr {
evaluate_disr_expr(ccx, repr_type, e)
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
@ -1113,7 +1118,11 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data)
}).collect();
<<<<<<< HEAD
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, variants, ReprOptions::new(&ccx.tcx, did));
=======
let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants);
>>>>>>> b1934037e6... Move type of discriminant to AdtDef
tcx.adt_defs.borrow_mut().insert(did, adt);
adt
}