rustc: use monomorphic const_eval for cross-crate enum discriminants.
This commit is contained in:
parent
63064ec190
commit
6dc21b71cf
14 changed files with 139 additions and 149 deletions
|
@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
self.variants.iter().map(move |v| {
|
self.variants.iter().map(move |v| {
|
||||||
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
|
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
|
||||||
if let VariantDiscr::Explicit(expr_did) = v.discr {
|
if let VariantDiscr::Explicit(expr_did) = v.discr {
|
||||||
match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
|
match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
|
||||||
Ok(ConstVal::Integral(v)) => {
|
Ok(ConstVal::Integral(v)) => {
|
||||||
discr = v;
|
discr = v;
|
||||||
}
|
}
|
||||||
|
@ -1673,6 +1673,51 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the discriminant value used by a specific variant.
|
||||||
|
/// Unlike `discriminants`, this is (amortized) constant-time,
|
||||||
|
/// only doing at most one query for evaluating an explicit
|
||||||
|
/// discriminant (the last one before the requested variant),
|
||||||
|
/// assuming there are no constant-evaluation errors there.
|
||||||
|
pub fn discriminant_for_variant(&self,
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
variant_index: usize)
|
||||||
|
-> ConstInt {
|
||||||
|
let repr_type = self.repr.discr_type();
|
||||||
|
let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
|
||||||
|
let mut explicit_index = variant_index;
|
||||||
|
loop {
|
||||||
|
match self.variants[explicit_index].discr {
|
||||||
|
ty::VariantDiscr::Relative(0) => break,
|
||||||
|
ty::VariantDiscr::Relative(distance) => {
|
||||||
|
explicit_index -= distance;
|
||||||
|
}
|
||||||
|
ty::VariantDiscr::Explicit(expr_did) => {
|
||||||
|
match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
|
||||||
|
Ok(ConstVal::Integral(v)) => {
|
||||||
|
explicit_value = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
explicit_index -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let discr = explicit_value.to_u128_unchecked()
|
||||||
|
.wrapping_add((variant_index - explicit_index) as u128);
|
||||||
|
match repr_type {
|
||||||
|
attr::UnsignedInt(ty) => {
|
||||||
|
ConstInt::new_unsigned_truncating(discr, ty,
|
||||||
|
tcx.sess.target.uint_type)
|
||||||
|
}
|
||||||
|
attr::SignedInt(ty) => {
|
||||||
|
ConstInt::new_signed_truncating(discr as i128, ty,
|
||||||
|
tcx.sess.target.int_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
|
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
|
||||||
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
|
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
|
||||||
}
|
}
|
||||||
|
|
|
@ -804,10 +804,13 @@ pub fn provide(providers: &mut Providers) {
|
||||||
fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> EvalResult<'tcx> {
|
-> EvalResult<'tcx> {
|
||||||
ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
|
|
||||||
let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
|
let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
|
||||||
|
|
||||||
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
||||||
let body = tcx.hir.body_owned_by(id);
|
ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
|
||||||
cx.eval(&tcx.hir.body(body).value)
|
tcx.hir.body(tcx.hir.body_owned_by(id))
|
||||||
|
} else {
|
||||||
|
tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
|
||||||
|
};
|
||||||
|
cx.eval(&body.value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -900,6 +900,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||||
let mut extern_providers = ty::maps::Providers::default();
|
let mut extern_providers = ty::maps::Providers::default();
|
||||||
cstore::provide(&mut extern_providers);
|
cstore::provide(&mut extern_providers);
|
||||||
ty::provide_extern(&mut extern_providers);
|
ty::provide_extern(&mut extern_providers);
|
||||||
|
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
|
||||||
|
rustc_const_eval::provide(&mut extern_providers);
|
||||||
|
|
||||||
TyCtxt::create_and_enter(sess,
|
TyCtxt::create_and_enter(sess,
|
||||||
local_providers,
|
local_providers,
|
||||||
|
|
|
@ -266,6 +266,17 @@ impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, '
|
||||||
intravisit::walk_item(self, item);
|
intravisit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_variant(&mut self,
|
||||||
|
variant: &'tcx hir::Variant,
|
||||||
|
generics: &'tcx hir::Generics,
|
||||||
|
parent_id: ast::NodeId) {
|
||||||
|
if let Some(e) = variant.node.disr_expr {
|
||||||
|
self.check_item(e.node_id, variant.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
intravisit::walk_variant(self, variant, generics, parent_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_variant_data(&mut self,
|
fn visit_variant_data(&mut self,
|
||||||
variant_data: &'tcx hir::VariantData,
|
variant_data: &'tcx hir::VariantData,
|
||||||
_: ast::Name,
|
_: ast::Name,
|
||||||
|
|
|
@ -511,11 +511,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
def
|
def
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_variant(&self,
|
fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
|
||||||
item: &Entry<'tcx>,
|
|
||||||
index: DefIndex,
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
|
||||||
-> (ty::VariantDef, Option<DefIndex>) {
|
|
||||||
let data = match item.kind {
|
let data = match item.kind {
|
||||||
EntryKind::Variant(data) |
|
EntryKind::Variant(data) |
|
||||||
EntryKind::Struct(data, _) |
|
EntryKind::Struct(data, _) |
|
||||||
|
@ -523,13 +519,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ty::VariantDiscr::Explicit(def_id) = data.discr {
|
ty::VariantDef {
|
||||||
// The original crate wouldn't have compiled if this is missing.
|
|
||||||
let result = Ok(data.evaluated_discr.unwrap());
|
|
||||||
tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
(ty::VariantDef {
|
|
||||||
did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
|
did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
|
||||||
name: self.item_name(index),
|
name: self.item_name(index),
|
||||||
fields: item.children.decode(self).map(|index| {
|
fields: item.children.decode(self).map(|index| {
|
||||||
|
@ -542,7 +532,7 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
}).collect(),
|
}).collect(),
|
||||||
discr: data.discr,
|
discr: data.discr,
|
||||||
ctor_kind: data.ctor_kind,
|
ctor_kind: data.ctor_kind,
|
||||||
}, data.struct_ctor)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_adt_def(&self,
|
pub fn get_adt_def(&self,
|
||||||
|
@ -561,15 +551,11 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
item.children
|
item.children
|
||||||
.decode(self)
|
.decode(self)
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
let (variant, struct_ctor) =
|
self.get_variant(&self.entry(index), index)
|
||||||
self.get_variant(&self.entry(index), index, tcx);
|
|
||||||
assert_eq!(struct_ctor, None);
|
|
||||||
variant
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx);
|
vec![self.get_variant(&item, item_id)]
|
||||||
vec![variant]
|
|
||||||
};
|
};
|
||||||
let (kind, repr) = match item.kind {
|
let (kind, repr) = match item.kind {
|
||||||
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
|
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
|
||||||
|
|
|
@ -269,12 +269,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
let data = VariantData {
|
let data = VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
discr: variant.discr,
|
discr: variant.discr,
|
||||||
evaluated_discr: match variant.discr {
|
|
||||||
ty::VariantDiscr::Explicit(def_id) => {
|
|
||||||
ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
|
|
||||||
}
|
|
||||||
ty::VariantDiscr::Relative(_) => None
|
|
||||||
},
|
|
||||||
struct_ctor: None,
|
struct_ctor: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -408,7 +402,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
let data = VariantData {
|
let data = VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
discr: variant.discr,
|
discr: variant.discr,
|
||||||
evaluated_discr: None,
|
|
||||||
struct_ctor: Some(def_id.index),
|
struct_ctor: Some(def_id.index),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -697,7 +690,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
EntryKind::Struct(self.lazy(&VariantData {
|
EntryKind::Struct(self.lazy(&VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
discr: variant.discr,
|
discr: variant.discr,
|
||||||
evaluated_discr: None,
|
|
||||||
struct_ctor: struct_ctor,
|
struct_ctor: struct_ctor,
|
||||||
}), repr_options)
|
}), repr_options)
|
||||||
}
|
}
|
||||||
|
@ -708,7 +700,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
EntryKind::Union(self.lazy(&VariantData {
|
EntryKind::Union(self.lazy(&VariantData {
|
||||||
ctor_kind: variant.ctor_kind,
|
ctor_kind: variant.ctor_kind,
|
||||||
discr: variant.discr,
|
discr: variant.discr,
|
||||||
evaluated_discr: None,
|
|
||||||
struct_ctor: None,
|
struct_ctor: None,
|
||||||
}), repr_options)
|
}), repr_options)
|
||||||
}
|
}
|
||||||
|
@ -1037,6 +1028,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
|
||||||
EntryBuilder::encode_info_for_foreign_item,
|
EntryBuilder::encode_info_for_foreign_item,
|
||||||
(def_id, ni));
|
(def_id, ni));
|
||||||
}
|
}
|
||||||
|
fn visit_variant(&mut self,
|
||||||
|
v: &'tcx hir::Variant,
|
||||||
|
g: &'tcx hir::Generics,
|
||||||
|
id: ast::NodeId) {
|
||||||
|
intravisit::walk_variant(self, v, g, id);
|
||||||
|
|
||||||
|
if let Some(discr) = v.node.disr_expr {
|
||||||
|
let def_id = self.index.tcx.hir.body_owner_def_id(discr);
|
||||||
|
self.index.record(def_id, EntryBuilder::encode_info_for_embedded_const, def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
||||||
intravisit::walk_generics(self, generics);
|
intravisit::walk_generics(self, generics);
|
||||||
self.index.encode_info_for_generics(generics);
|
self.index.encode_info_for_generics(generics);
|
||||||
|
@ -1160,6 +1162,32 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> {
|
||||||
|
debug!("EntryBuilder::encode_info_for_embedded_const({:?})", def_id);
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
|
let body = tcx.hir.body_owned_by(id);
|
||||||
|
|
||||||
|
Entry {
|
||||||
|
kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)),
|
||||||
|
visibility: self.lazy(&ty::Visibility::Public),
|
||||||
|
span: self.lazy(&tcx.def_span(def_id)),
|
||||||
|
attributes: LazySeq::empty(),
|
||||||
|
children: LazySeq::empty(),
|
||||||
|
stability: None,
|
||||||
|
deprecation: None,
|
||||||
|
|
||||||
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
|
inherent_impls: LazySeq::empty(),
|
||||||
|
variances: LazySeq::empty(),
|
||||||
|
generics: Some(self.encode_generics(def_id)),
|
||||||
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
|
ast: Some(self.encode_body(body)),
|
||||||
|
mir: self.encode_mir(def_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
|
fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
|
||||||
// NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because
|
// NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because
|
||||||
// we really on the HashStable specialization for [Attribute]
|
// we really on the HashStable specialization for [Attribute]
|
||||||
|
|
|
@ -15,7 +15,6 @@ use rustc::hir;
|
||||||
use rustc::hir::def::{self, CtorKind};
|
use rustc::hir::def::{self, CtorKind};
|
||||||
use rustc::hir::def_id::{DefIndex, DefId};
|
use rustc::hir::def_id::{DefIndex, DefId};
|
||||||
use rustc::ich::StableHashingContext;
|
use rustc::ich::StableHashingContext;
|
||||||
use rustc::middle::const_val::ConstVal;
|
|
||||||
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
|
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
|
@ -271,9 +270,9 @@ pub enum EntryKind<'tcx> {
|
||||||
Type,
|
Type,
|
||||||
Enum(ReprOptions),
|
Enum(ReprOptions),
|
||||||
Field,
|
Field,
|
||||||
Variant(Lazy<VariantData<'tcx>>),
|
Variant(Lazy<VariantData>),
|
||||||
Struct(Lazy<VariantData<'tcx>>, ReprOptions),
|
Struct(Lazy<VariantData>, ReprOptions),
|
||||||
Union(Lazy<VariantData<'tcx>>, ReprOptions),
|
Union(Lazy<VariantData>, ReprOptions),
|
||||||
Fn(Lazy<FnData>),
|
Fn(Lazy<FnData>),
|
||||||
ForeignFn(Lazy<FnData>),
|
ForeignFn(Lazy<FnData>),
|
||||||
Mod(Lazy<ModData>),
|
Mod(Lazy<ModData>),
|
||||||
|
@ -374,20 +373,18 @@ pub struct FnData {
|
||||||
impl_stable_hash_for!(struct FnData { constness, arg_names });
|
impl_stable_hash_for!(struct FnData { constness, arg_names });
|
||||||
|
|
||||||
#[derive(RustcEncodable, RustcDecodable)]
|
#[derive(RustcEncodable, RustcDecodable)]
|
||||||
pub struct VariantData<'tcx> {
|
pub struct VariantData {
|
||||||
pub ctor_kind: CtorKind,
|
pub ctor_kind: CtorKind,
|
||||||
pub discr: ty::VariantDiscr,
|
pub discr: ty::VariantDiscr,
|
||||||
pub evaluated_discr: Option<ConstVal<'tcx>>,
|
|
||||||
|
|
||||||
/// If this is a struct's only variant, this
|
/// If this is a struct's only variant, this
|
||||||
/// is the index of the "struct ctor" item.
|
/// is the index of the "struct ctor" item.
|
||||||
pub struct_ctor: Option<DefIndex>,
|
pub struct_ctor: Option<DefIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_stable_hash_for!(struct VariantData<'tcx> {
|
impl_stable_hash_for!(struct VariantData {
|
||||||
ctor_kind,
|
ctor_kind,
|
||||||
discr,
|
discr,
|
||||||
evaluated_discr,
|
|
||||||
struct_ctor
|
struct_ctor
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,6 @@
|
||||||
//! used unboxed and any field can have pointers (including mutable)
|
//! used unboxed and any field can have pointers (including mutable)
|
||||||
//! taken to it, implementing them for Rust seems difficult.
|
//! taken to it, implementing them for Rust seems difficult.
|
||||||
|
|
||||||
use super::Disr;
|
|
||||||
|
|
||||||
use std;
|
use std;
|
||||||
|
|
||||||
use llvm::{ValueRef, True, IntEQ, IntNE};
|
use llvm::{ValueRef, True, IntEQ, IntNE};
|
||||||
|
@ -347,31 +345,31 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef,
|
||||||
|
|
||||||
/// Set the discriminant for a new value of the given case of the given
|
/// Set the discriminant for a new value of the given case of the given
|
||||||
/// representation.
|
/// representation.
|
||||||
pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
|
pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: u64) {
|
||||||
let l = bcx.ccx.layout_of(t);
|
let l = bcx.ccx.layout_of(t);
|
||||||
match *l {
|
match *l {
|
||||||
layout::CEnum{ discr, min, max, .. } => {
|
layout::CEnum{ discr, min, max, .. } => {
|
||||||
assert_discr_in_range(Disr(min), Disr(max), to);
|
assert_discr_in_range(min, max, to);
|
||||||
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
|
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
|
||||||
val, None);
|
val, None);
|
||||||
}
|
}
|
||||||
layout::General{ discr, .. } => {
|
layout::General{ discr, .. } => {
|
||||||
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
|
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
|
||||||
bcx.struct_gep(val, 0), None);
|
bcx.struct_gep(val, 0), None);
|
||||||
}
|
}
|
||||||
layout::Univariant { .. }
|
layout::Univariant { .. }
|
||||||
| layout::UntaggedUnion { .. }
|
| layout::UntaggedUnion { .. }
|
||||||
| layout::Vector { .. } => {
|
| layout::Vector { .. } => {
|
||||||
assert_eq!(to, Disr(0));
|
assert_eq!(to, 0);
|
||||||
}
|
}
|
||||||
layout::RawNullablePointer { nndiscr, .. } => {
|
layout::RawNullablePointer { nndiscr, .. } => {
|
||||||
if to.0 != nndiscr {
|
if to != nndiscr {
|
||||||
let llptrty = val_ty(val).element_type();
|
let llptrty = val_ty(val).element_type();
|
||||||
bcx.store(C_null(llptrty), val, None);
|
bcx.store(C_null(llptrty), val, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
|
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
|
||||||
if to.0 != nndiscr {
|
if to != nndiscr {
|
||||||
if target_sets_discr_via_memset(bcx) {
|
if target_sets_discr_via_memset(bcx) {
|
||||||
// Issue #34427: As workaround for LLVM bug on
|
// Issue #34427: As workaround for LLVM bug on
|
||||||
// ARM, use memset of 0 on whole struct rather
|
// ARM, use memset of 0 on whole struct rather
|
||||||
|
@ -397,7 +395,7 @@ fn target_sets_discr_via_memset<'a, 'tcx>(bcx: &Builder<'a, 'tcx>) -> bool {
|
||||||
bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
|
bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
|
pub fn assert_discr_in_range<D: PartialOrd>(min: D, max: D, discr: D) {
|
||||||
if min <= max {
|
if min <= max {
|
||||||
assert!(min <= discr && discr <= max)
|
assert!(min <= discr && discr <= max)
|
||||||
} else {
|
} else {
|
||||||
|
@ -415,7 +413,7 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
|
||||||
/// (Not to be confused with `common::const_get_elt`, which operates on
|
/// (Not to be confused with `common::const_get_elt`, which operates on
|
||||||
/// raw LLVM-level structs and arrays.)
|
/// raw LLVM-level structs and arrays.)
|
||||||
pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
|
||||||
val: ValueRef, _discr: Disr,
|
val: ValueRef,
|
||||||
ix: usize) -> ValueRef {
|
ix: usize) -> ValueRef {
|
||||||
let l = ccx.layout_of(t);
|
let l = ccx.layout_of(t);
|
||||||
match *l {
|
match *l {
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// 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.maps.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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::ops::BitAnd for Disr {
|
|
||||||
type Output = Disr;
|
|
||||||
fn bitand(self, other: Self) -> Self {
|
|
||||||
Disr(self.0 & other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ConstInt> for Disr {
|
|
||||||
fn from(i: ConstInt) -> Disr {
|
|
||||||
// FIXME: what if discr has 128 bit discr?
|
|
||||||
Disr(i.to_u128_unchecked() as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<usize> for Disr {
|
|
||||||
fn from(i: usize) -> Disr {
|
|
||||||
Disr(i as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Disr {
|
|
||||||
fn partial_cmp(&self, other: &Disr) -> Option<::std::cmp::Ordering> {
|
|
||||||
self.0.partial_cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Disr {
|
|
||||||
fn cmp(&self, other: &Disr) -> ::std::cmp::Ordering {
|
|
||||||
self.0.cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -67,7 +67,6 @@ pub use rustc::lint;
|
||||||
pub use rustc::util;
|
pub use rustc::util;
|
||||||
|
|
||||||
pub use base::trans_crate;
|
pub use base::trans_crate;
|
||||||
pub use disr::Disr;
|
|
||||||
|
|
||||||
pub mod back {
|
pub mod back {
|
||||||
pub use rustc::hir::svh;
|
pub use rustc::hir::svh;
|
||||||
|
@ -118,7 +117,6 @@ mod consts;
|
||||||
mod context;
|
mod context;
|
||||||
mod debuginfo;
|
mod debuginfo;
|
||||||
mod declare;
|
mod declare;
|
||||||
mod disr;
|
|
||||||
mod glue;
|
mod glue;
|
||||||
mod intrinsic;
|
mod intrinsic;
|
||||||
mod machine;
|
mod machine;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc::ty::layout::{self, LayoutTyper};
|
||||||
use rustc::ty::cast::{CastTy, IntTy};
|
use rustc::ty::cast::{CastTy, IntTy};
|
||||||
use rustc::ty::subst::{Kind, Substs, Subst};
|
use rustc::ty::subst::{Kind, Substs, Subst};
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
use {abi, adt, base, Disr, machine};
|
use {abi, adt, base, machine};
|
||||||
use callee;
|
use callee;
|
||||||
use builder::Builder;
|
use builder::Builder;
|
||||||
use common::{self, CrateContext, const_get_elt, val_ty};
|
use common::{self, CrateContext, const_get_elt, val_ty};
|
||||||
|
@ -428,7 +428,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Field(ref field, _) => {
|
mir::ProjectionElem::Field(ref field, _) => {
|
||||||
let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
|
let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
|
||||||
Disr(0), field.index());
|
field.index());
|
||||||
let llextra = if is_sized {
|
let llextra = if is_sized {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
} else {
|
} else {
|
||||||
|
@ -987,13 +987,14 @@ fn trans_const<'a, 'tcx>(
|
||||||
layout::CEnum { discr: d, min, max, .. } => {
|
layout::CEnum { discr: d, min, max, .. } => {
|
||||||
let discr = match *kind {
|
let discr = match *kind {
|
||||||
mir::AggregateKind::Adt(adt_def, _, _, _) => {
|
mir::AggregateKind::Adt(adt_def, _, _, _) => {
|
||||||
Disr::for_variant(ccx.tcx(), adt_def, variant_index)
|
adt_def.discriminant_for_variant(ccx.tcx(), variant_index)
|
||||||
|
.to_u128_unchecked() as u64
|
||||||
},
|
},
|
||||||
_ => Disr(0),
|
_ => 0,
|
||||||
};
|
};
|
||||||
assert_eq!(vals.len(), 0);
|
assert_eq!(vals.len(), 0);
|
||||||
adt::assert_discr_in_range(Disr(min), Disr(max), discr);
|
adt::assert_discr_in_range(min, max, discr);
|
||||||
C_integral(Type::from_integer(ccx, d), discr.0, true)
|
C_integral(Type::from_integer(ccx, d), discr, true)
|
||||||
}
|
}
|
||||||
layout::General { discr: d, ref variants, .. } => {
|
layout::General { discr: d, ref variants, .. } => {
|
||||||
let variant = &variants[variant_index];
|
let variant = &variants[variant_index];
|
||||||
|
|
|
@ -28,7 +28,6 @@ use type_::Type;
|
||||||
use type_of;
|
use type_of;
|
||||||
use tvec;
|
use tvec;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
use Disr;
|
|
||||||
|
|
||||||
use super::MirContext;
|
use super::MirContext;
|
||||||
use super::constant::const_scalar_checked_binop;
|
use super::constant::const_scalar_checked_binop;
|
||||||
|
@ -107,9 +106,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
||||||
match *kind {
|
match *kind {
|
||||||
mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
|
mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
|
||||||
let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
|
let discr = adt_def.discriminant_for_variant(bcx.tcx(), variant_index)
|
||||||
|
.to_u128_unchecked() as u64;
|
||||||
let dest_ty = dest.ty.to_ty(bcx.tcx());
|
let dest_ty = dest.ty.to_ty(bcx.tcx());
|
||||||
adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
|
adt::trans_set_discr(&bcx, dest_ty, dest.llval, discr);
|
||||||
for (i, operand) in operands.iter().enumerate() {
|
for (i, operand) in operands.iter().enumerate() {
|
||||||
let op = self.trans_operand(&bcx, operand);
|
let op = self.trans_operand(&bcx, operand);
|
||||||
// Do not generate stores and GEPis for zero-sized fields.
|
// Do not generate stores and GEPis for zero-sized fields.
|
||||||
|
|
|
@ -18,7 +18,6 @@ use builder::Builder;
|
||||||
use super::MirContext;
|
use super::MirContext;
|
||||||
use super::LocalRef;
|
use super::LocalRef;
|
||||||
use super::super::adt;
|
use super::super::adt;
|
||||||
use super::super::disr::Disr;
|
|
||||||
|
|
||||||
impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
pub fn trans_statement(&mut self,
|
pub fn trans_statement(&mut self,
|
||||||
|
@ -65,7 +64,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||||
adt::trans_set_discr(&bcx,
|
adt::trans_set_discr(&bcx,
|
||||||
ty,
|
ty,
|
||||||
lvalue_transed.llval,
|
lvalue_transed.llval,
|
||||||
Disr::from(variant_index));
|
variant_index as u64);
|
||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
mir::StatementKind::StorageLive(ref lvalue) => {
|
mir::StatementKind::StorageLive(ref lvalue) => {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(stmt_expr_attributes)]
|
||||||
#![crate_type="rlib"]
|
#![crate_type="rlib"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,9 +126,12 @@ enum EnumChangeValueCStyleVariant0 {
|
||||||
enum EnumChangeValueCStyleVariant0 {
|
enum EnumChangeValueCStyleVariant0 {
|
||||||
Variant1,
|
Variant1,
|
||||||
|
|
||||||
|
#[rustc_metadata_clean(cfg="cfail2")]
|
||||||
|
#[rustc_metadata_clean(cfg="cfail3")]
|
||||||
|
Variant2 =
|
||||||
#[rustc_metadata_dirty(cfg="cfail2")]
|
#[rustc_metadata_dirty(cfg="cfail2")]
|
||||||
#[rustc_metadata_clean(cfg="cfail3")]
|
#[rustc_metadata_clean(cfg="cfail3")]
|
||||||
Variant2 = 22,
|
22,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(cfail1)]
|
#[cfg(cfail1)]
|
||||||
|
|
Loading…
Reference in a new issue