Skip to content

Commit 6dc21b7

Browse files
committed
rustc: use monomorphic const_eval for cross-crate enum discriminants.
1 parent 63064ec commit 6dc21b7

File tree

14 files changed

+139
-149
lines changed

14 files changed

+139
-149
lines changed

src/librustc/ty/mod.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16601660
self.variants.iter().map(move |v| {
16611661
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
16621662
if let VariantDiscr::Explicit(expr_did) = v.discr {
1663-
match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
1663+
match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
16641664
Ok(ConstVal::Integral(v)) => {
16651665
discr = v;
16661666
}
@@ -1673,6 +1673,51 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16731673
})
16741674
}
16751675

1676+
/// Compute the discriminant value used by a specific variant.
1677+
/// Unlike `discriminants`, this is (amortized) constant-time,
1678+
/// only doing at most one query for evaluating an explicit
1679+
/// discriminant (the last one before the requested variant),
1680+
/// assuming there are no constant-evaluation errors there.
1681+
pub fn discriminant_for_variant(&self,
1682+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
1683+
variant_index: usize)
1684+
-> ConstInt {
1685+
let repr_type = self.repr.discr_type();
1686+
let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx());
1687+
let mut explicit_index = variant_index;
1688+
loop {
1689+
match self.variants[explicit_index].discr {
1690+
ty::VariantDiscr::Relative(0) => break,
1691+
ty::VariantDiscr::Relative(distance) => {
1692+
explicit_index -= distance;
1693+
}
1694+
ty::VariantDiscr::Explicit(expr_did) => {
1695+
match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
1696+
Ok(ConstVal::Integral(v)) => {
1697+
explicit_value = v;
1698+
break;
1699+
}
1700+
_ => {
1701+
explicit_index -= 1;
1702+
}
1703+
}
1704+
}
1705+
}
1706+
}
1707+
let discr = explicit_value.to_u128_unchecked()
1708+
.wrapping_add((variant_index - explicit_index) as u128);
1709+
match repr_type {
1710+
attr::UnsignedInt(ty) => {
1711+
ConstInt::new_unsigned_truncating(discr, ty,
1712+
tcx.sess.target.uint_type)
1713+
}
1714+
attr::SignedInt(ty) => {
1715+
ConstInt::new_signed_truncating(discr as i128, ty,
1716+
tcx.sess.target.int_type)
1717+
}
1718+
}
1719+
}
1720+
16761721
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
16771722
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
16781723
}

src/librustc_const_eval/eval.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -804,10 +804,13 @@ pub fn provide(providers: &mut Providers) {
804804
fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
805805
def_id: DefId)
806806
-> EvalResult<'tcx> {
807-
ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
808807
let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
809808

810-
let id = tcx.hir.as_local_node_id(def_id).unwrap();
811-
let body = tcx.hir.body_owned_by(id);
812-
cx.eval(&tcx.hir.body(body).value)
809+
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
810+
ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
811+
tcx.hir.body(tcx.hir.body_owned_by(id))
812+
} else {
813+
tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
814+
};
815+
cx.eval(&body.value)
813816
}

src/librustc_driver/driver.rs

+2
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
900900
let mut extern_providers = ty::maps::Providers::default();
901901
cstore::provide(&mut extern_providers);
902902
ty::provide_extern(&mut extern_providers);
903+
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
904+
rustc_const_eval::provide(&mut extern_providers);
903905

904906
TyCtxt::create_and_enter(sess,
905907
local_providers,

src/librustc_incremental/persist/dirty_clean.rs

+11
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,17 @@ impl<'a, 'tcx, 'm> intravisit::Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, '
266266
intravisit::walk_item(self, item);
267267
}
268268

269+
fn visit_variant(&mut self,
270+
variant: &'tcx hir::Variant,
271+
generics: &'tcx hir::Generics,
272+
parent_id: ast::NodeId) {
273+
if let Some(e) = variant.node.disr_expr {
274+
self.check_item(e.node_id, variant.span);
275+
}
276+
277+
intravisit::walk_variant(self, variant, generics, parent_id);
278+
}
279+
269280
fn visit_variant_data(&mut self,
270281
variant_data: &'tcx hir::VariantData,
271282
_: ast::Name,

src/librustc_metadata/decoder.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -511,25 +511,15 @@ impl<'a, 'tcx> CrateMetadata {
511511
def
512512
}
513513

514-
fn get_variant(&self,
515-
item: &Entry<'tcx>,
516-
index: DefIndex,
517-
tcx: TyCtxt<'a, 'tcx, 'tcx>)
518-
-> (ty::VariantDef, Option<DefIndex>) {
514+
fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
519515
let data = match item.kind {
520516
EntryKind::Variant(data) |
521517
EntryKind::Struct(data, _) |
522518
EntryKind::Union(data, _) => data.decode(self),
523519
_ => bug!(),
524520
};
525521

526-
if let ty::VariantDiscr::Explicit(def_id) = data.discr {
527-
// The original crate wouldn't have compiled if this is missing.
528-
let result = Ok(data.evaluated_discr.unwrap());
529-
tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
530-
}
531-
532-
(ty::VariantDef {
522+
ty::VariantDef {
533523
did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
534524
name: self.item_name(index),
535525
fields: item.children.decode(self).map(|index| {
@@ -542,7 +532,7 @@ impl<'a, 'tcx> CrateMetadata {
542532
}).collect(),
543533
discr: data.discr,
544534
ctor_kind: data.ctor_kind,
545-
}, data.struct_ctor)
535+
}
546536
}
547537

548538
pub fn get_adt_def(&self,
@@ -561,15 +551,11 @@ impl<'a, 'tcx> CrateMetadata {
561551
item.children
562552
.decode(self)
563553
.map(|index| {
564-
let (variant, struct_ctor) =
565-
self.get_variant(&self.entry(index), index, tcx);
566-
assert_eq!(struct_ctor, None);
567-
variant
554+
self.get_variant(&self.entry(index), index)
568555
})
569556
.collect()
570557
} else {
571-
let (variant, _struct_ctor) = self.get_variant(&item, item_id, tcx);
572-
vec![variant]
558+
vec![self.get_variant(&item, item_id)]
573559
};
574560
let (kind, repr) = match item.kind {
575561
EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),

src/librustc_metadata/encoder.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
269269
let data = VariantData {
270270
ctor_kind: variant.ctor_kind,
271271
discr: variant.discr,
272-
evaluated_discr: match variant.discr {
273-
ty::VariantDiscr::Explicit(def_id) => {
274-
ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
275-
}
276-
ty::VariantDiscr::Relative(_) => None
277-
},
278272
struct_ctor: None,
279273
};
280274

@@ -408,7 +402,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
408402
let data = VariantData {
409403
ctor_kind: variant.ctor_kind,
410404
discr: variant.discr,
411-
evaluated_discr: None,
412405
struct_ctor: Some(def_id.index),
413406
};
414407

@@ -697,7 +690,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
697690
EntryKind::Struct(self.lazy(&VariantData {
698691
ctor_kind: variant.ctor_kind,
699692
discr: variant.discr,
700-
evaluated_discr: None,
701693
struct_ctor: struct_ctor,
702694
}), repr_options)
703695
}
@@ -708,7 +700,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
708700
EntryKind::Union(self.lazy(&VariantData {
709701
ctor_kind: variant.ctor_kind,
710702
discr: variant.discr,
711-
evaluated_discr: None,
712703
struct_ctor: None,
713704
}), repr_options)
714705
}
@@ -1037,6 +1028,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
10371028
EntryBuilder::encode_info_for_foreign_item,
10381029
(def_id, ni));
10391030
}
1031+
fn visit_variant(&mut self,
1032+
v: &'tcx hir::Variant,
1033+
g: &'tcx hir::Generics,
1034+
id: ast::NodeId) {
1035+
intravisit::walk_variant(self, v, g, id);
1036+
1037+
if let Some(discr) = v.node.disr_expr {
1038+
let def_id = self.index.tcx.hir.body_owner_def_id(discr);
1039+
self.index.record(def_id, EntryBuilder::encode_info_for_embedded_const, def_id);
1040+
}
1041+
}
10401042
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
10411043
intravisit::walk_generics(self, generics);
10421044
self.index.encode_info_for_generics(generics);
@@ -1160,6 +1162,32 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> {
11601162
}
11611163
}
11621164

1165+
fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> {
1166+
debug!("EntryBuilder::encode_info_for_embedded_const({:?})", def_id);
1167+
let tcx = self.tcx;
1168+
let id = tcx.hir.as_local_node_id(def_id).unwrap();
1169+
let body = tcx.hir.body_owned_by(id);
1170+
1171+
Entry {
1172+
kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)),
1173+
visibility: self.lazy(&ty::Visibility::Public),
1174+
span: self.lazy(&tcx.def_span(def_id)),
1175+
attributes: LazySeq::empty(),
1176+
children: LazySeq::empty(),
1177+
stability: None,
1178+
deprecation: None,
1179+
1180+
ty: Some(self.encode_item_type(def_id)),
1181+
inherent_impls: LazySeq::empty(),
1182+
variances: LazySeq::empty(),
1183+
generics: Some(self.encode_generics(def_id)),
1184+
predicates: Some(self.encode_predicates(def_id)),
1185+
1186+
ast: Some(self.encode_body(body)),
1187+
mir: self.encode_mir(def_id),
1188+
}
1189+
}
1190+
11631191
fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
11641192
// NOTE: This must use lazy_seq_from_slice(), not lazy_seq() because
11651193
// we really on the HashStable specialization for [Attribute]

src/librustc_metadata/schema.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use rustc::hir;
1515
use rustc::hir::def::{self, CtorKind};
1616
use rustc::hir::def_id::{DefIndex, DefId};
1717
use rustc::ich::StableHashingContext;
18-
use rustc::middle::const_val::ConstVal;
1918
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
2019
use rustc::middle::lang_items;
2120
use rustc::mir;
@@ -271,9 +270,9 @@ pub enum EntryKind<'tcx> {
271270
Type,
272271
Enum(ReprOptions),
273272
Field,
274-
Variant(Lazy<VariantData<'tcx>>),
275-
Struct(Lazy<VariantData<'tcx>>, ReprOptions),
276-
Union(Lazy<VariantData<'tcx>>, ReprOptions),
273+
Variant(Lazy<VariantData>),
274+
Struct(Lazy<VariantData>, ReprOptions),
275+
Union(Lazy<VariantData>, ReprOptions),
277276
Fn(Lazy<FnData>),
278277
ForeignFn(Lazy<FnData>),
279278
Mod(Lazy<ModData>),
@@ -374,20 +373,18 @@ pub struct FnData {
374373
impl_stable_hash_for!(struct FnData { constness, arg_names });
375374

376375
#[derive(RustcEncodable, RustcDecodable)]
377-
pub struct VariantData<'tcx> {
376+
pub struct VariantData {
378377
pub ctor_kind: CtorKind,
379378
pub discr: ty::VariantDiscr,
380-
pub evaluated_discr: Option<ConstVal<'tcx>>,
381379

382380
/// If this is a struct's only variant, this
383381
/// is the index of the "struct ctor" item.
384382
pub struct_ctor: Option<DefIndex>,
385383
}
386384

387-
impl_stable_hash_for!(struct VariantData<'tcx> {
385+
impl_stable_hash_for!(struct VariantData {
388386
ctor_kind,
389387
discr,
390-
evaluated_discr,
391388
struct_ctor
392389
});
393390

src/librustc_trans/adt.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
//! used unboxed and any field can have pointers (including mutable)
4242
//! taken to it, implementing them for Rust seems difficult.
4343
44-
use super::Disr;
45-
4644
use std;
4745

4846
use llvm::{ValueRef, True, IntEQ, IntNE};
@@ -347,31 +345,31 @@ fn load_discr(bcx: &Builder, ity: layout::Integer, ptr: ValueRef,
347345

348346
/// Set the discriminant for a new value of the given case of the given
349347
/// representation.
350-
pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: Disr) {
348+
pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: ValueRef, to: u64) {
351349
let l = bcx.ccx.layout_of(t);
352350
match *l {
353351
layout::CEnum{ discr, min, max, .. } => {
354-
assert_discr_in_range(Disr(min), Disr(max), to);
355-
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
352+
assert_discr_in_range(min, max, to);
353+
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
356354
val, None);
357355
}
358356
layout::General{ discr, .. } => {
359-
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
357+
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
360358
bcx.struct_gep(val, 0), None);
361359
}
362360
layout::Univariant { .. }
363361
| layout::UntaggedUnion { .. }
364362
| layout::Vector { .. } => {
365-
assert_eq!(to, Disr(0));
363+
assert_eq!(to, 0);
366364
}
367365
layout::RawNullablePointer { nndiscr, .. } => {
368-
if to.0 != nndiscr {
366+
if to != nndiscr {
369367
let llptrty = val_ty(val).element_type();
370368
bcx.store(C_null(llptrty), val, None);
371369
}
372370
}
373371
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
374-
if to.0 != nndiscr {
372+
if to != nndiscr {
375373
if target_sets_discr_via_memset(bcx) {
376374
// Issue #34427: As workaround for LLVM bug on
377375
// 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 {
397395
bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64"
398396
}
399397

400-
pub fn assert_discr_in_range(min: Disr, max: Disr, discr: Disr) {
398+
pub fn assert_discr_in_range<D: PartialOrd>(min: D, max: D, discr: D) {
401399
if min <= max {
402400
assert!(min <= discr && discr <= max)
403401
} else {
@@ -415,7 +413,7 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
415413
/// (Not to be confused with `common::const_get_elt`, which operates on
416414
/// raw LLVM-level structs and arrays.)
417415
pub fn const_get_field<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
418-
val: ValueRef, _discr: Disr,
416+
val: ValueRef,
419417
ix: usize) -> ValueRef {
420418
let l = ccx.layout_of(t);
421419
match *l {

0 commit comments

Comments
 (0)