From 49a8fe52fa978a328bb5007494a6c864071fcb42 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:12:54 +0100 Subject: [PATCH 001/115] Add a variant to ConstVal for storing miri results --- src/librustc/ich/impls_ty.rs | 24 +++++++++++ src/librustc/lib.rs | 1 + src/librustc/middle/const_val.rs | 3 ++ src/librustc/mir/interpret/mod.rs | 11 ++++-- src/librustc/mir/interpret/value.rs | 8 ++-- src/librustc/mir/mod.rs | 3 +- src/librustc/ty/context.rs | 19 +++++++++ src/librustc/ty/flags.rs | 1 + src/librustc/ty/instance.rs | 4 +- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/structural_impls.rs | 2 + src/librustc/ty/walk.rs | 1 + src/librustc/ty/wf.rs | 1 + src/librustc_const_eval/pattern.rs | 1 + src/librustc_metadata/decoder.rs | 46 +++++++++++++++++++++- src/librustc_metadata/encoder.rs | 39 +++++++++++++++++- src/librustc_mir/interpret/eval_context.rs | 23 +++++------ src/librustc_trans/mir/constant.rs | 1 + 18 files changed, 165 insertions(+), 25 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 107779ec3fa15..ddeef856dd071 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -21,6 +21,7 @@ use std::mem; use middle::region; use traits; use ty; +use mir; impl<'gcx, T> HashStable> for &'gcx ty::Slice @@ -367,6 +368,9 @@ for ::middle::const_val::ConstVal<'gcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } + Value(ref value) => { + value.hash_stable(hcx, hasher); + } } } } @@ -375,6 +379,26 @@ impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> { data }); +impl_stable_hash_for!(enum mir::interpret::Value { + ByVal(v), + ByValPair(a, b), + ByRef(ptr, align) +}); + +impl_stable_hash_for!(struct mir::interpret::MemoryPointer { + alloc_id, + offset +}); + +impl_stable_hash_for!(tuple_struct mir::interpret::AllocId{id}); +impl_stable_hash_for!(struct mir::interpret::Pointer{primval}); + +impl_stable_hash_for!(enum mir::interpret::PrimVal { + Bytes(b), + Ptr(p), + Undef +}); + impl_stable_hash_for!(struct ty::Const<'tcx> { ty, val diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index db6863d6dadc2..259f294238699 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -48,6 +48,7 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(dyn_trait)] +#![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] #![feature(i128)] diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 440af39a0d469..2309131c57a9f 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,6 +14,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; +use mir::interpret::Value; use graphviz::IntoCow; use errors::DiagnosticBuilder; @@ -38,6 +39,8 @@ pub enum ConstVal<'tcx> { Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), + /// A miri value, currently only produced if old ctfe fails, but miri succeeds + Value(Value), } #[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)] diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 8ffea62f6be51..b10f3ae9291d3 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -41,7 +41,7 @@ pub enum AccessKind { } /// Uniquely identifies a specific constant or static. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct GlobalId<'tcx> { /// For a constant or static, the `Instance` of the item itself. /// For a promoted global, the `Instance` of the function they belong to. @@ -101,7 +101,7 @@ pub trait PointerArithmetic: layout::HasDataLayout { impl PointerArithmetic for T {} -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub struct MemoryPointer { pub alloc_id: AllocId, pub offset: u64, @@ -148,13 +148,16 @@ impl<'tcx> MemoryPointer { #[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] pub struct AllocId(pub u64); +impl ::rustc_serialize::UseSpecializedEncodable for AllocId {} +impl ::rustc_serialize::UseSpecializedDecodable for AllocId {} + impl fmt::Display for AllocId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } -#[derive(Debug, Eq, PartialEq, Hash)] +#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer @@ -188,7 +191,7 @@ impl Allocation { type Block = u64; const BLOCK_SIZE: u64 = 64; -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { blocks: Vec, len: u64, diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 0bfff2a80e678..8d67856c0df8d 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -29,7 +29,7 @@ pub fn bytes_to_f64(bits: u128) -> ConstFloat { /// For optimization of a few very common cases, there is also a representation for a pair of /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary /// operations and fat pointers. This idea was taken from rustc's trans. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub enum Value { ByRef(Pointer, Align), ByVal(PrimVal), @@ -43,9 +43,9 @@ pub enum Value { /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just /// the representation of pointers. Also all the sites that convert between primvals and pointers /// are explicit now (and rare!) -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub struct Pointer { - primval: PrimVal, + pub primval: PrimVal, } impl<'tcx> Pointer { @@ -138,7 +138,7 @@ impl ::std::convert::From for Pointer { /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes /// of a simple value, a pointer into another `Allocation`, or be undefined. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub enum PrimVal { /// The raw bytes of a simple value. Bytes(u128), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d82691f882c73..097f422b940ea 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1782,7 +1782,8 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), - Unevaluated(..) => write!(fmt, "{:?}", const_val) + Unevaluated(..) => write!(fmt, "{:?}", const_val), + Value(val) => write!(fmt, "{:?}", val), } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..d1949267c9aea 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -904,6 +904,11 @@ pub struct InterpretInterner<'tcx> { /// Allows obtaining const allocs via a unique identifier alloc_by_id: FxHashMap, + /// Reverse map of `alloc_cache` + /// + /// Multiple globals may share the same memory + global_cache: FxHashMap>>, + /// The AllocId to assign to the next new regular allocation. /// Always incremented, never gets smaller. next_id: interpret::AllocId, @@ -954,11 +959,25 @@ impl<'tcx> InterpretInterner<'tcx> { global_id: interpret::GlobalId<'tcx>, ptr: interpret::AllocId, ) { + if let interpret::PrimVal::Ptr(ptr) = ptr.primval { + assert!(ptr.offset == 0); + } + self.global_cache.entry(ptr).or_default().push(global_id); if let Some(old) = self.alloc_cache.insert(global_id, ptr) { bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old); } } + pub fn get_globals( + &self, + ptr: interpret::Pointer, + ) -> &[interpret::GlobalId<'tcx>] { + match self.global_cache.get(&ptr) { + Some(v) => v, + None => &[], + } + } + pub fn intern_at_reserved( &mut self, id: interpret::AllocId, diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 2889322a1ce77..60bf4afc2fc88 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -224,6 +224,7 @@ impl FlagComputation { ConstVal::ByteStr(_) | ConstVal::Bool(_) | ConstVal::Char(_) | + ConstVal::Value(_) | ConstVal::Variant(_) => {} ConstVal::Function(_, substs) => { self.add_substs(substs); diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 63bf52a9bdf78..37041a975b437 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -17,13 +17,13 @@ use util::ppaux; use std::fmt; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Instance<'tcx> { pub def: InstanceDef<'tcx>, pub substs: &'tcx Substs<'tcx>, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum InstanceDef<'tcx> { Item(DefId), Intrinsic(DefId), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 63b91ff110161..b352723b8864a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -342,7 +342,7 @@ impl AddAssign for Size { /// Each field is a power of two, giving the alignment a maximum /// value of 2(28 - 1), which is limited by LLVM to a i32, with /// a maximum capacity of 231 - 1 or 2147483647. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Align { abi: u8, pref: u8, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0dc1338fff860..d53b3a80ae9aa 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1278,6 +1278,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { ConstVal::ByteStr(b) => ConstVal::ByteStr(b), ConstVal::Bool(b) => ConstVal::Bool(b), ConstVal::Char(c) => ConstVal::Char(c), + ConstVal::Value(v) => ConstVal::Value(v), ConstVal::Variant(def_id) => ConstVal::Variant(def_id), ConstVal::Function(def_id, substs) => { ConstVal::Function(def_id, substs.fold_with(folder)) @@ -1333,6 +1334,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { ConstVal::ByteStr(_) | ConstVal::Bool(_) | ConstVal::Char(_) | + ConstVal::Value(_) | ConstVal::Variant(_) => false, ConstVal::Function(_, substs) => substs.visit_with(visitor), ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 45f0ad1cf1a5f..4ef7706c45e3e 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -146,6 +146,7 @@ fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const ConstVal::ByteStr(_) | ConstVal::Bool(_) | ConstVal::Char(_) | + ConstVal::Value(_) | ConstVal::Variant(_) => {} ConstVal::Function(_, substs) => { stack.extend(substs.types().rev()); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index ce44448ef794e..78fa1e1ed9148 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -228,6 +228,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ConstVal::Bool(_) | ConstVal::Char(_) | ConstVal::Variant(_) | + ConstVal::Value(_) | ConstVal::Function(..) => {} ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { for &(_, v) in fields { diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index e0b3929e32a8d..5ea2b98d1d156 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -121,6 +121,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::Variant(_) | ConstVal::Function(..) | ConstVal::Aggregate(_) | + ConstVal::Value(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 06728b2e6257c..ca6fa04cefcb4 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -22,12 +22,13 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::ich::Fingerprint; use rustc::middle::lang_items; -use rustc::mir; +use rustc::mir::{self, interpret}; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; use rustc::util::nodemap::DefIdSet; use rustc::mir::Mir; +use rustc::util::nodemap::FxHashMap; use std::cell::Ref; use std::collections::BTreeMap; @@ -54,6 +55,9 @@ pub struct DecodeContext<'a, 'tcx: 'a> { last_filemap_index: usize, lazy_state: LazyState, + + // interpreter allocation cache + interpret_alloc_cache: FxHashMap, } /// Abstract over the various ways one can create metadata decoders. @@ -72,6 +76,7 @@ pub trait Metadata<'a, 'tcx>: Copy { tcx, last_filemap_index: 0, lazy_state: LazyState::NoNode, + interpret_alloc_cache: FxHashMap::default(), } } } @@ -268,6 +273,45 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + const MAX1: usize = usize::max_value() - 1; + let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut(); + let pos = self.position(); + match self.read_usize()? { + ::std::usize::MAX => { + let allocation = interpret::Allocation::decode(self)?; + let id = interpret_interner.reserve(); + let allocation = self.tcx.unwrap().intern_const_alloc(allocation); + interpret_interner.intern_at_reserved(id, allocation); + let id = interpret::AllocId(id); + self.interpret_alloc_cache.insert(pos, id); + + let num = usize::decode(self)?; + let ptr = interpret::Pointer { + primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { + alloc_id: id, + offset: 0, + }), + }; + for _ in 0..num { + let glob = interpret::GlobalId::decode(self)?; + interpret_interner.cache(glob, ptr); + } + + Ok(id) + }, + MAX1 => { + let instance = ty::Instance::decode(self)?; + let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance)); + self.interpret_alloc_cache.insert(pos, id); + Ok(id) + }, + shorthand => Ok(self.interpret_alloc_cache[&shorthand]), + } + } +} + impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { let tag = u8::decode(self)?; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 78578ca179c82..2a32a05342b5c 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -21,7 +21,7 @@ use rustc::hir::map::definitions::DefPathTable; use rustc::ich::Fingerprint; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; -use rustc::mir; +use rustc::mir::{self, interpret}; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt, ReprOptions}; use rustc::ty::codec::{self as ty_codec, TyEncoder}; @@ -58,6 +58,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { lazy_state: LazyState, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + interpret_alloc_shorthands: FxHashMap, // This is used to speed up Span encoding. filemap_cache: Rc, @@ -185,6 +186,41 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { + return self.emit_usize(shorthand); + } + let start = self.position(); + let interpret_interner = self.tcx.interpret_interner.borrow(); + if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + usize::max_value().encode(self)?; + alloc.encode(self)?; + let globals = interpret_interner.get_globals(interpret::Pointer { + primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { + alloc_id: *alloc_id, + offset: 0, + }), + }); + globals.len().encode(self)?; + for glob in globals { + glob.encode(self)?; + } + } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + (usize::max_value() - 1).encode(self)?; + fn_instance.encode(self)?; + } else { + bug!("alloc id without corresponding allocation: {}", alloc_id.0); + } + let len = self.position() - start * 7; + // Check that the shorthand is a not longer than the + // full encoding itself, i.e. it's an obvious win. + assert!(len >= 64 || (start as u64) < (1 << len)); + self.interpret_alloc_shorthands.insert(*alloc_id, start); + Ok(()) + } +} + impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>) @@ -1683,6 +1719,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, type_shorthands: Default::default(), predicate_shorthands: Default::default(), filemap_cache: tcx.sess.codemap().files()[0].clone(), + interpret_alloc_shorthands: Default::default(), }; // Encode the rustc version string in a predictable location. diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 02fcb69fef5ac..568eb78d40a02 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -241,24 +241,24 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { - use rustc::middle::const_val::ConstVal::*; + use rustc::middle::const_val::ConstVal; let primval = match *const_val { - Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()), + ConstVal::Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()), - Float(val) => PrimVal::Bytes(val.bits), + ConstVal::Float(val) => PrimVal::Bytes(val.bits), - Bool(b) => PrimVal::from_bool(b), - Char(c) => PrimVal::from_char(c), + ConstVal::Bool(b) => PrimVal::from_bool(b), + ConstVal::Char(c) => PrimVal::from_char(c), - Str(ref s) => return self.str_to_value(s), + ConstVal::Str(ref s) => return self.str_to_value(s), - ByteStr(ref bs) => { + ConstVal::ByteStr(ref bs) => { let ptr = self.memory.allocate_cached(bs.data); PrimVal::Ptr(ptr) } - Unevaluated(def_id, substs) => { + ConstVal::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(self.read_global_as_value(GlobalId { instance, @@ -266,10 +266,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }, self.layout_of(ty)?)); } - Aggregate(..) | - Variant(_) => bug!("should not have aggregate or variant constants in MIR"), + ConstVal::Aggregate(..) | + ConstVal::Variant(_) => bug!("should not have aggregate or variant constants in MIR"), // function items are zero sized and thus have no readable value - Function(..) => PrimVal::Undef, + ConstVal::Function(..) => PrimVal::Undef, + ConstVal::Value(val) => return Ok(val), }; Ok(Value::ByVal(primval)) diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index cd1975488a24a..c6744f1ad3f3f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -108,6 +108,7 @@ impl<'a, 'tcx> Const<'tcx> { ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } + ConstVal::Value(_) => unimplemented!(), }; assert!(!ty.has_erasable_regions()); From bb583949eeb5fcd25f3d6e7b24c345095463be87 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:13:50 +0100 Subject: [PATCH 002/115] Add miri errors to the const eval error enum --- src/librustc/ich/impls_ty.rs | 170 ++++++++++++++++++++++++++++ src/librustc/middle/const_val.rs | 8 ++ src/librustc/mir/interpret/error.rs | 16 +-- src/librustc/ty/structural_impls.rs | 112 ++++++++++++++++++ 4 files changed, 294 insertions(+), 12 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index ddeef856dd071..48a1902095c8c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -449,6 +449,7 @@ for ::middle::const_val::ErrKind<'gcx> { ErroneousReferencedConstant(ref const_val) => { const_val.hash_stable(hcx, hasher); } + Miri(ref err) => err.hash_stable(hcx, hasher), } } } @@ -462,6 +463,175 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { predicates }); +impl<'gcx> HashStable> +for ::mir::interpret::EvalError<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + use mir::interpret::EvalErrorKind::*; + + mem::discriminant(&self.kind).hash_stable(hcx, hasher); + + match self.kind { + DanglingPointerDeref | + DoubleFree | + InvalidMemoryAccess | + InvalidFunctionPointer | + InvalidBool | + InvalidDiscriminant | + InvalidNullPointerUsage | + ReadPointerAsBytes | + ReadBytesAsPointer | + InvalidPointerMath | + ReadUndefBytes | + DeadLocal | + ExecutionTimeLimitReached | + StackFrameLimitReached | + OutOfTls | + TlsOutOfBounds | + CalledClosureAsFunction | + VtableForArgumentlessMethod | + ModifiedConstantMemory | + AssumptionNotHeld | + InlineAsm | + ReallocateNonBasePtr | + DeallocateNonBasePtr | + HeapAllocZeroBytes | + Unreachable | + Panic | + ReadFromReturnPointer | + UnimplementedTraitSelection | + TypeckError | + DerefFunctionPointer | + ExecuteMemory | + OverflowingMath => {} + MachineError(ref err) => err.hash_stable(hcx, hasher), + FunctionPointerTyMismatch(a, b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher) + }, + NoMirFor(ref s) => s.hash_stable(hcx, hasher), + UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher), + PointerOutOfBounds { + ptr, + access, + allocation_size, + } => { + ptr.hash_stable(hcx, hasher); + access.hash_stable(hcx, hasher); + allocation_size.hash_stable(hcx, hasher) + }, + InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher), + Unimplemented(ref s) => s.hash_stable(hcx, hasher), + ArrayIndexOutOfBounds(sp, a, b) => { + sp.hash_stable(hcx, hasher); + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher) + }, + Math(sp, ref err) => { + sp.hash_stable(hcx, hasher); + err.hash_stable(hcx, hasher) + }, + Intrinsic(ref s) => s.hash_stable(hcx, hasher), + InvalidChar(c) => c.hash_stable(hcx, hasher), + OutOfMemory { + allocation_size, + memory_size, + memory_usage, + } => { + allocation_size.hash_stable(hcx, hasher); + memory_size.hash_stable(hcx, hasher); + memory_usage.hash_stable(hcx, hasher) + }, + AbiViolation(ref s) => s.hash_stable(hcx, hasher), + AlignmentCheckFailed { + required, + has, + } => { + required.hash_stable(hcx, hasher); + has.hash_stable(hcx, hasher) + }, + MemoryLockViolation { + ptr, + len, + frame, + access, + ref lock, + } => { + ptr.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + frame.hash_stable(hcx, hasher); + access.hash_stable(hcx, hasher); + lock.hash_stable(hcx, hasher) + }, + MemoryAcquireConflict { + ptr, + len, + kind, + ref lock, + } => { + ptr.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + lock.hash_stable(hcx, hasher) + }, + InvalidMemoryLockRelease { + ptr, + len, + frame, + ref lock, + } => { + ptr.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + frame.hash_stable(hcx, hasher); + lock.hash_stable(hcx, hasher) + }, + DeallocatedLockedMemory { + ptr, + ref lock, + } => { + ptr.hash_stable(hcx, hasher); + lock.hash_stable(hcx, hasher) + }, + ValidationFailure(ref s) => s.hash_stable(hcx, hasher), + TypeNotPrimitive(ty) => ty.hash_stable(hcx, hasher), + ReallocatedWrongMemoryKind(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher) + }, + DeallocatedWrongMemoryKind(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher) + }, + IncorrectAllocationInformation(a, b, c, d) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + c.hash_stable(hcx, hasher); + d.hash_stable(hcx, hasher) + }, + Layout(lay) => lay.hash_stable(hcx, hasher), + HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher), + PathNotFound(ref v) => v.hash_stable(hcx, hasher), + } + } +} + +impl_stable_hash_for!(enum mir::interpret::Lock { + NoLock, + WriteLock(dl), + ReadLock(v) +}); + +impl_stable_hash_for!(struct mir::interpret::DynamicLifetime { + frame, + region +}); + +impl_stable_hash_for!(enum mir::interpret::AccessKind { + Read, + Write +}); + impl_stable_hash_for!(enum ty::Variance { Covariant, Invariant, diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 2309131c57a9f..589890947cd5a 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -111,6 +111,13 @@ pub enum ErrKind<'tcx> { TypeckError, CheckMatchError, + Miri(::mir::interpret::EvalError<'tcx>), +} + +impl<'tcx> From<::mir::interpret::EvalError<'tcx>> for ErrKind<'tcx> { + fn from(err: ::mir::interpret::EvalError<'tcx>) -> ErrKind<'tcx> { + ErrKind::Miri(err) + } } impl<'tcx> From for ErrKind<'tcx> { @@ -173,6 +180,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { TypeckError => simple!("type-checking failed"), CheckMatchError => simple!("match-checking failed"), + Miri(ref err) => simple!("miri failed: {}", err), } } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 9ebfe25c107a9..6386de5952f99 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -12,7 +12,7 @@ use rustc_const_math::ConstMathErr; use syntax::codemap::Span; use backtrace::Backtrace; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct EvalError<'tcx> { pub kind: EvalErrorKind<'tcx>, pub backtrace: Option, @@ -31,11 +31,11 @@ impl<'tcx> From> for EvalError<'tcx> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum EvalErrorKind<'tcx> { /// This variant is used by machines to signal their own errors that do not /// match an existing variant - MachineError(Box), + MachineError(String), FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), NoMirFor(String), UnterminatedCString(MemoryPointer), @@ -132,7 +132,7 @@ impl<'tcx> Error for EvalError<'tcx> { fn description(&self) -> &str { use self::EvalErrorKind::*; match self.kind { - MachineError(ref inner) => inner.description(), + MachineError(ref inner) => inner, FunctionPointerTyMismatch(..) => "tried to call a function through a function pointer of a different type", InvalidMemoryAccess => @@ -247,14 +247,6 @@ impl<'tcx> Error for EvalError<'tcx> { "encountered constants with type errors, stopping evaluation", } } - - fn cause(&self) -> Option<&Error> { - use self::EvalErrorKind::*; - match self.kind { - MachineError(ref inner) => Some(&**inner), - _ => None, - } - } } impl<'tcx> fmt::Display for EvalError<'tcx> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d53b3a80ae9aa..33a1fd951514c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -19,6 +19,7 @@ use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use mir::interpret; use std::rc::Rc; @@ -606,6 +607,116 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { + type Lifted = interpret::EvalError<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + use mir::interpret::EvalErrorKind::*; + let kind = match self.kind { + MachineError(ref err) => MachineError(err.clone()), + FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( + tcx.lift(&a)?, + tcx.lift(&b)?, + ), + NoMirFor(ref s) => NoMirFor(s.clone()), + UnterminatedCString(ptr) => UnterminatedCString(ptr), + DanglingPointerDeref => DanglingPointerDeref, + DoubleFree => DoubleFree, + InvalidMemoryAccess => InvalidMemoryAccess, + InvalidFunctionPointer => InvalidFunctionPointer, + InvalidBool => InvalidBool, + InvalidDiscriminant => InvalidDiscriminant, + PointerOutOfBounds { + ptr, + access, + allocation_size, + } => PointerOutOfBounds { ptr, access, allocation_size }, + InvalidNullPointerUsage => InvalidNullPointerUsage, + ReadPointerAsBytes => ReadPointerAsBytes, + ReadBytesAsPointer => ReadBytesAsPointer, + InvalidPointerMath => InvalidPointerMath, + ReadUndefBytes => ReadUndefBytes, + DeadLocal => DeadLocal, + InvalidBoolOp(bop) => InvalidBoolOp(bop), + Unimplemented(ref s) => Unimplemented(s.clone()), + DerefFunctionPointer => DerefFunctionPointer, + ExecuteMemory => ExecuteMemory, + ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b), + Math(sp, ref err) => Math(sp, err.clone()), + Intrinsic(ref s) => Intrinsic(s.clone()), + OverflowingMath => OverflowingMath, + InvalidChar(c) => InvalidChar(c), + OutOfMemory { + allocation_size, + memory_size, + memory_usage, + } => OutOfMemory { allocation_size, memory_size, memory_usage }, + ExecutionTimeLimitReached => ExecutionTimeLimitReached, + StackFrameLimitReached => StackFrameLimitReached, + OutOfTls => OutOfTls, + TlsOutOfBounds => TlsOutOfBounds, + AbiViolation(ref s) => AbiViolation(s.clone()), + AlignmentCheckFailed { + required, + has, + } => AlignmentCheckFailed { required, has }, + MemoryLockViolation { + ptr, + len, + frame, + access, + ref lock, + } => MemoryLockViolation { ptr, len, frame, access, lock: lock.clone() }, + MemoryAcquireConflict { + ptr, + len, + kind, + ref lock, + } => MemoryAcquireConflict { ptr, len, kind, lock: lock.clone() }, + InvalidMemoryLockRelease { + ptr, + len, + frame, + ref lock, + } => InvalidMemoryLockRelease { ptr, len, frame, lock: lock.clone() }, + DeallocatedLockedMemory { + ptr, + ref lock, + } => DeallocatedLockedMemory { ptr, lock: lock.clone() }, + ValidationFailure(ref s) => ValidationFailure(s.clone()), + CalledClosureAsFunction => CalledClosureAsFunction, + VtableForArgumentlessMethod => VtableForArgumentlessMethod, + ModifiedConstantMemory => ModifiedConstantMemory, + AssumptionNotHeld => AssumptionNotHeld, + InlineAsm => InlineAsm, + TypeNotPrimitive(ty) => TypeNotPrimitive(tcx.lift(&ty)?), + ReallocatedWrongMemoryKind(ref a, ref b) => { + ReallocatedWrongMemoryKind(a.clone(), b.clone()) + }, + DeallocatedWrongMemoryKind(ref a, ref b) => { + DeallocatedWrongMemoryKind(a.clone(), b.clone()) + }, + ReallocateNonBasePtr => ReallocateNonBasePtr, + DeallocateNonBasePtr => DeallocateNonBasePtr, + IncorrectAllocationInformation(a, b, c, d) => { + IncorrectAllocationInformation(a, b, c, d) + }, + Layout(lay) => Layout(tcx.lift(&lay)?), + HeapAllocZeroBytes => HeapAllocZeroBytes, + HeapAllocNonPowerOfTwoAlignment(n) => HeapAllocNonPowerOfTwoAlignment(n), + Unreachable => Unreachable, + Panic => Panic, + ReadFromReturnPointer => ReadFromReturnPointer, + PathNotFound(ref v) => PathNotFound(v.clone()), + UnimplementedTraitSelection => UnimplementedTraitSelection, + TypeckError => TypeckError, + }; + Some(interpret::EvalError { + kind, + backtrace: self.backtrace.clone(), + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { type Lifted = const_val::ErrKind<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -635,6 +746,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { TypeckError => TypeckError, CheckMatchError => CheckMatchError, + Miri(ref e) => return tcx.lift(e).map(Miri), }) } } From 13e580880430df0151f8e016f03287e013b81966 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:24:38 +0100 Subject: [PATCH 003/115] Produce instead of pointers --- src/libcore/cmp.rs | 4 +- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/middle/const_val.rs | 39 +- src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/mem_categorization.rs | 3 +- src/librustc/mir/interpret/value.rs | 10 + src/librustc/mir/mod.rs | 80 ++++- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 14 +- src/librustc/ty/context.rs | 39 +- src/librustc/ty/error.rs | 11 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/maps/config.rs | 1 + src/librustc/ty/maps/keys.rs | 1 + src/librustc/ty/maps/on_disk_cache.rs | 9 +- src/librustc/ty/mod.rs | 28 ++ src/librustc/ty/relate.rs | 9 + src/librustc/ty/structural_impls.rs | 55 +++ src/librustc/ty/util.rs | 2 + src/librustc/util/ppaux.rs | 4 + src/librustc_const_eval/_match.rs | 180 ++++++++-- src/librustc_const_eval/eval.rs | 180 +++++----- src/librustc_const_eval/pattern.rs | 335 +++++++++++------- src/librustc_data_structures/stable_hasher.rs | 8 + src/librustc_lint/types.rs | 11 + src/librustc_metadata/decoder.rs | 38 +- src/librustc_metadata/encoder.rs | 14 +- .../borrow_check/nll/type_check/mod.rs | 47 ++- src/librustc_mir/build/expr/as_rvalue.rs | 21 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 69 +++- src/librustc_mir/build/misc.rs | 19 +- src/librustc_mir/hair/cx/expr.rs | 48 ++- src/librustc_mir/hair/cx/mod.rs | 178 +++++++++- src/librustc_mir/interpret/const_eval.rs | 153 ++++++-- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/operator.rs | 5 + src/librustc_mir/interpret/place.rs | 43 ++- src/librustc_mir/interpret/terminator/mod.rs | 4 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_mir/shim.rs | 29 +- src/librustc_mir/transform/generator.rs | 9 +- src/librustc_mir/transform/inline.rs | 7 + src/librustc_mir/transform/qualify_consts.rs | 2 +- .../transform/simplify_branches.rs | 4 +- src/librustc_mir/util/elaborate_drops.rs | 15 +- src/librustc_passes/consts.rs | 23 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/analyze.rs | 19 +- src/librustc_trans/mir/block.rs | 9 +- src/librustc_trans/mir/constant.rs | 110 ++++-- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/op.rs | 8 +- src/librustc_typeck/collect.rs | 13 + src/librustc_typeck/lib.rs | 1 + src/test/mir-opt/end_region_2.rs | 2 +- src/test/mir-opt/end_region_3.rs | 2 +- src/test/mir-opt/end_region_9.rs | 2 +- src/test/mir-opt/end_region_cyclic.rs | 2 +- src/test/mir-opt/issue-38669.rs | 2 +- src/test/mir-opt/match_false_edges.rs | 8 +- src/test/mir-opt/nll/region-liveness-basic.rs | 2 +- src/test/mir-opt/simplify_if.rs | 2 +- src/test/ui/const-eval-overflow-2.rs | 3 +- src/test/ui/const-eval-overflow-2.stderr | 6 +- src/test/ui/const-eval-overflow-4.rs | 3 +- src/test/ui/const-eval-overflow-4.stderr | 10 +- src/test/ui/const-eval/issue-43197.rs | 2 - src/test/ui/const-eval/issue-43197.stderr | 18 +- src/test/ui/const-expr-addr-operator.rs | 3 +- src/test/ui/const-expr-addr-operator.stderr | 14 - src/test/ui/const-fn-error.rs | 13 +- src/test/ui/const-fn-error.stderr | 22 +- .../ui/const-len-underflow-separate-spans.rs | 3 +- .../const-len-underflow-separate-spans.stderr | 20 +- .../ui/const-pattern-not-const-evaluable.rs | 4 +- .../const-pattern-not-const-evaluable.stderr | 14 - src/test/ui/feature-gate-const-indexing.rs | 3 +- .../ui/feature-gate-const-indexing.stderr | 8 - src/test/ui/issue-38875/issue_38875.rs | 1 + src/test/ui/issue-38875/issue_38875.stderr | 14 - src/test/ui/union/union-const-eval.rs | 9 +- src/test/ui/union/union-const-eval.stderr | 16 - 89 files changed, 1494 insertions(+), 659 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 266cae3c122f4..9a37970b34da2 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,6 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` +#[cfg_attr(not(stage0), lang = "ord")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -596,7 +597,8 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[lang = "ord"] +#[cfg_attr(stage0, lang = "ord")] +#[cfg_attr(not(stage0), lang = "partial_ord")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..e01946e0f3db5 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,6 +63,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; +use mir; use ich::Fingerprint; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 589890947cd5a..cf322010e05c3 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; -use mir::interpret::Value; +use mir::interpret::{Value, PrimVal}; use graphviz::IntoCow; use errors::DiagnosticBuilder; @@ -39,7 +39,7 @@ pub enum ConstVal<'tcx> { Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), - /// A miri value, currently only produced if old ctfe fails, but miri succeeds + /// A miri value, currently only produced if --miri is enabled Value(Value), } @@ -71,12 +71,37 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> { } impl<'tcx> ConstVal<'tcx> { - pub fn to_const_int(&self) -> Option { + pub fn to_u128(&self) -> Option { match *self { - ConstVal::Integral(i) => Some(i), - ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), - ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), - _ => None + ConstVal::Integral(i) => i.to_u128(), + ConstVal::Bool(b) => Some(b as u128), + ConstVal::Char(ch) => Some(ch as u32 as u128), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + Some(b) + }, + _ => None, + } + } + pub fn unwrap_u64(&self) -> u64 { + match self.to_u128() { + Some(val) => { + assert_eq!(val as u64 as u128, val); + val as u64 + }, + None => bug!("expected constant u64, got {:#?}", self), + } + } + pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { + match *self { + ConstVal::Integral(ConstInt::Usize(i)) => i, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u64 as u128, b); + match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { + Ok(val) => val, + Err(e) => bug!("{:#?} is not a usize {:?}", self, e), + } + }, + _ => bug!("expected constant u64, got {:#?}", self), } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 447ce46ee5c5c..3b37031cf4614 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -280,6 +280,7 @@ language_item_table! { GeneratorTraitLangItem, "generator", gen_trait; EqTraitLangItem, "eq", eq_trait; + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait; OrdTraitLangItem, "ord", ord_trait; // A number of panic-related lang items. The `panic` item corresponds to diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 45b595adfe7b8..a33ddd5844d2b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -912,8 +912,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if - len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, + ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8d67856c0df8d..c00956c0a8570 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,7 @@ #![allow(unknown_lints)] use ty::layout::{Align, HasDataLayout}; +use ty; use super::{EvalResult, MemoryPointer, PointerArithmetic}; use syntax::ast::FloatTy; @@ -36,6 +37,15 @@ pub enum Value { ByValPair(PrimVal, PrimVal), } +impl<'tcx> ty::TypeFoldable<'tcx> for Value { + fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. /// This type clears up a few APIs where having a `PrimVal` argument for something that is /// potentially an integer pointer or a pointer to an allocation was unclear. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 097f422b940ea..d542f2a9f72b4 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; +use rustc_const_math::{ConstUsize, ConstMathErr}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; @@ -24,9 +24,11 @@ use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; use mir::visit::MirVisitable; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::TypeAndMut; use util::ppaux; use std::slice; use hir::{self, InlineAsm}; @@ -694,7 +696,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [ConstInt]>, + values: Cow<'tcx, [u128]>, /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 @@ -826,7 +828,7 @@ impl<'tcx> Terminator<'tcx> { impl<'tcx> TerminatorKind<'tcx> { pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; + static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, @@ -1055,12 +1057,16 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, .. } => { + SwitchInt { ref values, switch_ty, .. } => { values.iter() - .map(|const_val| { - let mut buf = String::new(); - fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap(); - buf.into() + .map(|&u| { + let mut s = String::new(); + print_miri_value( + Value::ByVal(PrimVal::Bytes(u)), + switch_ty, + &mut s, + ).unwrap(); + s.into() }) .chain(iter::once(String::from("otherwise").into())) .collect() @@ -1434,7 +1440,12 @@ impl<'tcx> Operand<'tcx> { ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + }, ty }) }, @@ -1754,7 +1765,7 @@ impl<'tcx> Debug for Literal<'tcx> { match *self { Value { value } => { write!(fmt, "const ")?; - fmt_const_val(fmt, &value.val) + fmt_const_val(fmt, value) } Promoted { index } => { write!(fmt, "{:?}", index) @@ -1764,9 +1775,9 @@ impl<'tcx> Debug for Literal<'tcx> { } /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { +fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { use middle::const_val::ConstVal::*; - match *const_val { + match const_val.val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), Str(s) => write!(fmt, "{:?}", s), @@ -1783,7 +1794,41 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => write!(fmt, "{:?}", val), + Value(val) => print_miri_value(val, const_val.ty, fmt), + } +} + +fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { + use ty::TypeVariants::*; + use rustc_const_math::ConstFloat; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) => + write!(f, "{}", ConstFloat { bits, ty: fty }), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) => + write!(f, "{}", item_path_str(did)), + (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut { + ty: &ty::TyS { sty: TyStr, .. }, .. + })) => { + ty::tls::with(|tcx| { + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + write!(f, "{:?}", s) + }) + }, + _ => write!(f, "{:?}:{}", value, ty), } } @@ -2367,6 +2412,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> } } +impl<'tcx> TypeFoldable<'tcx> for Field { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { Constant { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 53607764b3984..4a7bdacb70fca 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 57ed41f2f06e6..c6a04a52dd588 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -243,12 +243,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_int(&mut self, - const_int: &ConstInt, - _: Location) { - self.super_const_int(const_int); - } - fn visit_const_usize(&mut self, const_usize: & $($mutability)* ConstUsize, _: Location) { @@ -426,13 +420,10 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { ref $($mutability)* discr, ref $($mutability)* switch_ty, - ref values, + values: _, ref targets } => { self.visit_operand(discr, source_location); self.visit_ty(switch_ty, TyContext::Location(source_location)); - for value in &values[..] { - self.visit_const_int(value, source_location); - } for &target in targets { self.visit_branch(block, target); } @@ -792,9 +783,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_int(&mut self, _const_int: &ConstInt) { - } - fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d1949267c9aea..9fab7b9ebd786 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{Mir, interpret}; +use mir::{self, Mir, interpret}; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; @@ -1266,6 +1267,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_lang_items(LOCAL_CRATE) } + pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> { + let items = self.lang_items(); + let def_id = Some(def_id); + if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else { None } + } + pub fn stability(self) -> Rc> { self.stability_index(LOCAL_CRATE) } @@ -2016,7 +2047,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(n)), + val: if self.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))) + } else { + ConstVal::Integral(ConstInt::Usize(n)) + }, ty: self.types.usize }))) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 583612f9590f1..269a536821b88 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -12,6 +12,7 @@ use hir::def_id::DefId; use infer::type_variable; use middle::const_val::ConstVal; use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt}; +use mir::interpret::{Value, PrimVal}; use std::fmt; use syntax::abi; @@ -193,10 +194,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - format!("array of {} elements", n) - } else { - "array".to_string() + match n.val { + ConstVal::Integral(ConstInt::Usize(n)) => + format!("array of {} elements", n), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => + format!("array of {} elements", n), + _ => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 93e4cd9adf888..bfaa661b2432d 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_const_int().and_then(|i| i.to_u64()) { + match len.val.to_u128() { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b352723b8864a..9e110d2c74cc8 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. + /// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized. MaybeUnsized, /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag). Prefixed(Size, Align), @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.to_const_int().unwrap().to_u64().unwrap(); + let count = count.val.unwrap_u64(); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..44609adefccbb 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -13,6 +13,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; +use mir; use std::hash::Hash; use syntax_pos::symbol::InternedString; diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b7b64c9761a8e..3dd482ad16401 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; +use mir; use std::fmt::Debug; use std::hash::Hash; diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 56ed0f9106f30..24256934099c6 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; -use mir; +use mir::{self, interpret}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, @@ -543,6 +543,13 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + unimplemented!() + } +} + impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc8..438b08e235b61 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,6 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; +use mir::interpret::{Value, PrimVal}; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits; @@ -1793,6 +1794,19 @@ impl<'a, 'gcx, 'tcx> AdtDef { Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { discr = v; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + discr = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), @@ -1834,6 +1848,20 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value = v; break; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + explicit_value = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + break; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index a6c72728a5125..9ff9f1ebda7f1 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -20,6 +20,7 @@ use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; +use mir::interpret::{Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -481,6 +482,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { match x.val { ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(Reveal::UserFacing); @@ -490,6 +492,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { return Ok(x.to_u64().unwrap()); } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + assert_eq!(b as u64 as u128, b); + return Ok(b as u64); + } _ => {} } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 33a1fd951514c..d6c536e689530 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -890,6 +890,61 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use ty::InstanceDef::*; + Self { + substs: self.substs.fold_with(folder), + def: match self.def { + Item(did) => Item(did.fold_with(folder)), + Intrinsic(did) => Intrinsic(did.fold_with(folder)), + FnPtrShim(did, ty) => FnPtrShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + Virtual(did, i) => Virtual( + did.fold_with(folder), + i, + ), + ClosureOnceShim { call_once } => ClosureOnceShim { + call_once: call_once.fold_with(folder), + }, + DropGlue(did, ty) => DropGlue( + did.fold_with(folder), + ty.fold_with(folder), + ), + CloneShim(did, ty) => CloneShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + }, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use ty::InstanceDef::*; + self.substs.visit_with(visitor) || + match self.def { + Item(did) => did.visit_with(visitor), + Intrinsic(did) => did.visit_with(visitor), + FnPtrShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + Virtual(did, _) => did.visit_with(visitor), + ClosureOnceShim { call_once } => call_once.visit_with(visitor), + DropGlue(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + CloneShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 34f05232adcab..713ca85998a1d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -23,6 +23,7 @@ use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; +use mir::interpret::{Value, PrimVal}; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -760,6 +761,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> self.hash_discriminant_u8(&n.val); match n.val { ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), _ => bug!("arrays should not have {:?} as length", n) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515b5..2ec060aa2016e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,6 +21,7 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; +use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -1163,6 +1164,9 @@ define_print! { ConstVal::Integral(ConstInt::Usize(sz)) => { write!(f, "{}", sz)?; } + ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { + write!(f, "{}", sz)?; + } ConstVal::Unevaluated(_def_id, substs) => { write!(f, "", &substs[..])?; } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index a7c382eba5091..78e3ae9e0b551 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -28,6 +28,7 @@ use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::Field; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::common::ErrorReported; use syntax_pos::{Span, DUMMY_SP}; @@ -195,6 +196,41 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } })).collect() } + box PatternKind::Constant { + value: &ty::Const { val: ConstVal::Value(b), ty } + } => { + match b { + Value::ByVal(PrimVal::Ptr(ptr)) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + assert_eq!(ptr.offset, 0); + // FIXME: check length + alloc.bytes.iter().map(|b| { + &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal( + PrimVal::Bytes(*b as u128), + )), + ty: tcx.types.u8 + }) + } + }) + }).collect() + }, + _ => bug!("not a byte str: {:?}", b), + } + } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) } }).clone() @@ -422,13 +458,17 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyBool => { [true, false].iter().map(|&b| { ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Bool(b), + val: if cx.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))) + } else { + ConstVal::Bool(b) + }, ty: cx.tcx.types.bool })) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => { + let len = len.val.unwrap_u64(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -461,7 +501,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( - _cx: &mut MatchCheckCtxt<'a, 'tcx>, + cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 where I: Iterator> { @@ -538,6 +578,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); } + PatternKind::Constant { + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), + ty, + } + } => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + if is_array_ptr { + let alloc = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } + } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); @@ -581,7 +640,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; - debug!("is_useful({:?}, {:?})", matrix, v); + debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. @@ -626,10 +685,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) }; - debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); + debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:?}", constructors); + debug!("is_useful - expanding constructors: {:#?}", constructors); constructors.into_iter().map(|c| is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) ).find(|result| result.is_useful()).unwrap_or(NotUseful) @@ -639,9 +698,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let used_ctors: Vec = rows.iter().flat_map(|row| { pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) }).collect(); - debug!("used_ctors = {:?}", used_ctors); + debug!("used_ctors = {:#?}", used_ctors); let all_ctors = all_constructors(cx, pcx); - debug!("all_ctors = {:?}", all_ctors); + debug!("all_ctors = {:#?}", all_ctors); let missing_ctors: Vec = all_ctors.iter().filter(|c| { !used_ctors.contains(*c) }).cloned().collect(); @@ -669,7 +728,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", + debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", missing_ctors, is_privately_empty, is_declared_nonexhaustive); // For privately empty and non-exhaustive enums, we work as if there were an "extra" @@ -769,7 +828,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( lty: Ty<'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { - debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty); + debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { Pattern { @@ -821,7 +880,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { ty::TyArray(_, length) => Some(vec![ - Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) + Slice(length.val.unwrap_u64()) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -842,7 +901,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { - debug!("constructor_arity({:?}, {:?})", ctor, ty); + debug!("constructor_arity({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TySlice(..) | ty::TyArray(..) => match *ctor { @@ -866,12 +925,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor, ty: Ty<'tcx>) -> Vec> { - debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); + debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], + Single => vec![ty], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], @@ -880,6 +940,9 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs[0].as_type().unwrap()] } else { + if let ConstantValue(_) = *ctor { + return vec![]; + } adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); @@ -901,14 +964,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, +fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, ctor: &Constructor, prefix: &[Pattern], slice: &Option, suffix: &[Pattern]) -> Result { - let data = match *ctor { + let data: &[u8] = match *ctor { ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, + ConstantValue(&ty::Const { val: ConstVal::Value( + Value::ByVal(PrimVal::Ptr(ptr)) + ), ty }) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .as_ref() + } _ => bug!() }; @@ -928,6 +1007,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, return Ok(false); } }, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); + } + } _ => span_bug!(pat.span, "bad const u8 {:?}", value) }, _ => {} @@ -937,32 +1022,43 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(tcx: TyCtxt, span: Span, - ctor: &Constructor, +fn constructor_covered_by_range(ctor: &Constructor, from: &ConstVal, to: &ConstVal, - end: RangeEnd) + end: RangeEnd, + ty: Ty) -> Result { - let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); + trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); + let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + .map(|res| res != Ordering::Less); + let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + macro_rules! some_or_ok { + ($e:expr) => { + match $e { + Some(to) => to, + None => return Ok(false), // not char or int + } + }; + } match *ctor { ConstantValue(value) => { - let to = cmp_to(&value.val)?; + let to = some_or_ok!(cmp_to(&value.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&value.val)? && end) + Ok(some_or_ok!(cmp_from(&value.val)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) } + Variant(_) | Single => Ok(true), _ => bug!(), } @@ -979,7 +1075,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( result[subpat.field.index()] = &subpat.pattern; } - debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result); + debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); result } @@ -994,7 +1090,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( fn specialize<'p, 'a: 'p, 'tcx: 'a>( cx: &mut MatchCheckCtxt<'a, 'tcx>, r: &[&'p Pattern<'tcx>], - constructor: &Constructor, + constructor: &Constructor<'tcx>, wild_patterns: &[&'p Pattern<'tcx>]) -> Option>> { @@ -1031,12 +1127,32 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( None } } + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + let is_array_ptr = value.ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + assert!(is_array_ptr); + let data_len = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .len(); + if wild_patterns.len() == data_len { + Some(cx.lower_byte_str_pattern(pat)) + } else { + None + } + } _ => span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) }, _ => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included + constructor, &value.val, &value.val, RangeEnd::Included, + value.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1048,7 +1164,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() + constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1092,7 +1208,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } } }; - debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head); + debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); head.map(|mut head| { head.extend_from_slice(&r[1 ..]); diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14bae..70d5854986de3 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -26,7 +26,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use rustc::hir::{self, Expr}; -use syntax_pos::Span; use std::cmp::Ordering; @@ -104,60 +103,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::ExprUnary(hir::UnNeg, ref inner) => { // unary neg literals already got their sign during creation if let hir::ExprLit(ref lit) = inner.node { - use syntax::ast::*; - use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128; - const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128; - const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; - const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; - const I128_OVERFLOW: u128 = i128::min_value() as u128; - let negated = match (&lit.node, &ty.sty) { - (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | - (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - Some(I8(i8::min_value())) - }, - (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | - (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - Some(I16(i16::min_value())) - }, - (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | - (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - Some(I32(i32::min_value())) - }, - (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | - (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - Some(I64(i64::min_value())) - }, - (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | - (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { - Some(I128(i128::min_value())) - }, - (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) | - (&LitKind::Int(n, Signed(IntTy::Isize)), _) => { - match tcx.sess.target.isize_ty { - IntTy::I16 => if n == I16_OVERFLOW { - Some(Isize(Is16(i16::min_value()))) - } else { - None - }, - IntTy::I32 => if n == I32_OVERFLOW { - Some(Isize(Is32(i32::min_value()))) - } else { - None - }, - IntTy::I64 => if n == I64_OVERFLOW { - Some(Isize(Is64(i64::min_value()))) - } else { - None - }, - _ => span_bug!(e.span, "typeck error") - } - }, - _ => None + return match lit_to_const(&lit.node, tcx, ty, true) { + Ok(val) => Ok(mk_const(val)), + Err(err) => signal!(e, err), }; - if let Some(i) = negated { - return Ok(mk_const(Integral(i))); - } } mk_const(match cx.eval(inner)?.val { Float(f) => Float(-f), @@ -377,7 +326,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }; callee_cx.eval(&body.value)? }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) { + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) { Ok(val) => mk_const(val), Err(err) => signal!(e, err), }, @@ -438,7 +387,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprRepeat(ref elem, _) => { let n = match ty.sty { - ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(), + ty::TyArray(_, n) => n.val.unwrap_u64(), _ => span_bug!(e.span, "typeck error") }; mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) @@ -447,7 +396,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { fields[index.node] } else { - signal!(base, ExpectedConstTuple); + span_bug!(base.span, "{:#?}", cx.eval(base)?.val); + //signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { @@ -557,7 +507,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { ty::TyArray(ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); if ty == tcx.types.u8 && n == b.data.len() as u64 { Ok(val) } else { @@ -583,13 +533,66 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, +pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut ty: Ty<'tcx>) + mut ty: Ty<'tcx>, + neg: bool) -> Result, ErrKind<'tcx>> { use syntax::ast::*; use syntax::ast::LitIntType::*; + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Ok(ConstVal::Value(lit)); + } + if let ty::TyAdt(adt, _) = ty.sty { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(tcx) @@ -604,26 +607,38 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, match (&ty.sty, hint) { (&ty::TyInt(ity), _) | (_, Signed(ity)) => { - Ok(Integral(ConstInt::new_signed_truncating(n as i128, + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, ity, tcx.sess.target.isize_ty))) } (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, + Ok(Integral(ConstInt::new_unsigned_truncating(n, uty, tcx.sess.target.usize_ty))) } _ => bug!() } } LitKind::Float(n, fty) => { - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::Bool(b) => Ok(Bool(b)), LitKind::Char(c) => Ok(Char(c)), @@ -638,36 +653,31 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) }) } -pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) - -> Result -{ - let result = match (a, b) { +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), - (&Float(a), &Float(b)) => a.try_cmp(b).ok(), - (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), - (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), - (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)), (&Char(a), &Char(b)) => Some(a.cmp(&b)), + (&Value(Value::ByVal(PrimVal::Bytes(a))), + &Value(Value::ByVal(PrimVal::Bytes(b)))) => { + Some(if ty.is_signed() { + (a as i128).cmp(&(b as i128)) + } else { + a.cmp(&b) + }) + }, + _ if a == b => Some(Ordering::Equal), _ => None, - }; - - match result { - Some(result) => Ok(result), - None => { - // FIXME: can this ever be reached? - tcx.sess.delay_span_bug(span, - &format!("type mismatch comparing {:?} and {:?}", a, b)); - Err(ErrorReported) - } } } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn compare_lit_exprs(&self, - span: Span, a: &'tcx Expr, - b: &'tcx Expr) -> Result { + b: &'tcx Expr) -> Result, ErrorReported> { let tcx = self.tcx; + let ty = self.tables.expr_ty(a); let a = match self.eval(a) { Ok(a) => a, Err(e) => { @@ -682,6 +692,6 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { return Err(ErrorReported); } }; - compare_const_vals(tcx, span, &a.val, &b.val) + Ok(compare_const_vals(&a.val, &b.val, ty)) } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 5ea2b98d1d156..f388808ab1d00 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -10,8 +10,9 @@ use eval; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -110,22 +111,35 @@ pub enum PatternKind<'tcx> { }, } -fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { - match *value { +fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { + match value.val { ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Integral(ref i) => write!(f, "{}", i), ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Value(v) => print_miri_value(v, value.ty, f), ConstVal::Variant(_) | ConstVal::Function(..) | ConstVal::Aggregate(_) | - ConstVal::Value(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } +fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { + use rustc::ty::TypeVariants::*; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + _ => bug!("{:?}: {} not printable in a pattern", value, ty), + } +} + impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -233,15 +247,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - print_const_val(&value.val, f) + print_const_val(value, f) } PatternKind::Range { lo, hi, end } => { - print_const_val(&lo.val, f)?; + print_const_val(lo, f)?; match end { RangeEnd::Included => write!(f, "...")?, RangeEnd::Excluded => write!(f, "..")?, } - print_const_val(&hi.val, f) + print_const_val(hi, f) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -362,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); + return self.lower_path(qpath, pat.hir_id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -581,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -632,7 +646,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, - pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); @@ -644,29 +657,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { - Some((def_id, substs)) => { - // Enter the inlined constant's tables&substs temporarily. - let old_tables = self.tables; - let old_substs = self.substs; - self.tables = self.tcx.typeck_tables_of(def_id); - self.substs = substs; - let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) - } else { - self.tcx.extern_const_body(def_id).body - }; - let pat = self.lower_const_expr(&body.value, pat_id, span); - self.tables = old_tables; - self.substs = old_substs; - return pat; - } - None => { - self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) - } else { - PatternError::StaticInPattern(span) - }); + match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { + Ok(value) => { + if self.tcx.sess.opts.debugging_opts.miri { + if let ConstVal::Value(_) = value.val {} else { + panic!("const eval produced non-miri value: {:#?}", value); + } + } + let instance = ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ).unwrap(); + return self.const_to_pat(instance, value, span) + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(e)); PatternKind::Wild } } @@ -682,6 +689,52 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { + if self.tcx.sess.opts.debugging_opts.miri { + return match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + } + } let const_cx = eval::ConstContext::new(self.tcx, self.param_env.and(self.substs), self.tables); @@ -701,118 +754,156 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_const_expr(&mut self, - expr: &'tcx hir::Expr, - pat_id: ast::NodeId, - span: Span) - -> Pattern<'tcx> { - let pat_ty = self.tables.expr_ty(expr); - debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); - match pat_ty.sty { + fn const_to_pat( + &self, + instance: ty::Instance<'tcx>, + cv: &'tcx ty::Const<'tcx>, + span: Span, + ) -> Pattern<'tcx> { + debug!("const_to_pat: cv={:#?}", cv); + let kind = match cv.ty.sty { ty::TyFloat(_) => { self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); + PatternKind::Wild } ty::TyAdt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); + PatternKind::Wild } + ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + let msg = format!("to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + self.tcx.item_path_str(adt_def.did), + self.tcx.item_path_str(adt_def.did)); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + }, + ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { + match cv.val { + ConstVal::Value(val) => { + let discr = self.tcx.const_discr(self.param_env.and(( + instance, val, cv.ty + ))).unwrap(); + let variant_index = adt_def + .discriminants(self.tcx) + .position(|var| var.to_u128_unchecked() == discr) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect(), + } + }, + ConstVal::Variant(var_did) => { + let variant_index = adt_def + .variants + .iter() + .position(|var| var.did == var_did) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: Vec::new(), + } + } + _ => return Pattern { + span, + ty: cv.ty, + kind: Box::new(PatternKind::Constant { + value: cv, + }), + } + } + }, ty::TyAdt(adt_def, _) => { - if !self.tcx.has_attr(adt_def.did, "structural_match") { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); - self.tcx.sess.span_err(span, &msg); + let struct_var = adt_def.struct_variant(); + PatternKind::Leaf { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { + consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 + }, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - _ => { } - } - let kind = match expr.node { - hir::ExprTup(ref exprs) => { + ty::TyTuple(fields, _) => { PatternKind::Leaf { - subpatterns: exprs.iter().enumerate().map(|(i, expr)| { + subpatterns: (0..fields.len()).map(|i| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) + field, + pattern: self.const_to_pat(instance, val, span), } }).collect() } } - - hir::ExprCall(ref callee, ref args) => { - let qpath = match callee.node { - hir::ExprPath(ref qpath) => qpath, - _ => bug!() - }; - let ty = self.tables.node_id_to_type(callee.hir_id); - let def = self.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), - _ => { - let subpatterns = args.iter().enumerate().map(|(i, expr)| { - FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) - } - }).collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) - } + ty::TyArray(_, n) => { + PatternKind::Leaf { + subpatterns: (0..n.val.unwrap_u64()).map(|i| { + let i = i as usize; + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], + ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - - hir::ExprStruct(ref qpath, ref fields, None) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - expr.span, - "struct expr without ADT type"); - } - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.name.node); - let index = index.unwrap_or_else(|| { - span_bug!( - expr.span, - "no field with name {:?}", - field.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.lower_const_expr(&field.expr, pat_id, span), - } - }) - .collect(); - - self.lower_variant_or_leaf(def, pat_ty, subpatterns) - } - - hir::ExprArray(ref exprs) => { - let pats = exprs.iter() - .map(|expr| self.lower_const_expr(expr, pat_id, span)) - .collect(); - PatternKind::Array { - prefix: pats, - slice: None, - suffix: vec![] + _ => { + PatternKind::Constant { + value: cv, } - } - - hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, expr.hir_id, pat_id, span); - } - - _ => self.lower_lit(expr) + }, }; Pattern { span, - ty: pat_ty, + ty: cv.ty, kind: Box::new(kind), } } diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index d82b712b5b14b..70733bc6aeda0 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -259,6 +259,14 @@ impl HashStable for f64 { } } +impl HashStable for ::std::cmp::Ordering { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (*self as i8).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for (T1,) { fn hash_stable(&self, ctx: &mut CTX, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e7e4119b9999b..acb214173a5e6 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,6 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; +use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -123,6 +124,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { .map(|i| i >= bits) .unwrap_or(true) } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + ty, + }) => { + if ty.is_signed() { + (b as i128) < 0 + } else { + b >= bits as u128 + } + } _ => false, } }; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ca6fa04cefcb4..0c780812bde99 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -276,38 +276,54 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; - let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut(); + let tcx = self.tcx; + let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut(); let pos = self.position(); - match self.read_usize()? { + match usize::decode(self)? { ::std::usize::MAX => { + let id = interpret_interner().reserve(); + let alloc_id = interpret::AllocId(id); + trace!("creating alloc id {:?} at {}", alloc_id, pos); + // insert early to allow recursive allocs + self.interpret_alloc_cache.insert(pos, alloc_id); + let allocation = interpret::Allocation::decode(self)?; - let id = interpret_interner.reserve(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner.intern_at_reserved(id, allocation); - let id = interpret::AllocId(id); - self.interpret_alloc_cache.insert(pos, id); + interpret_interner().intern_at_reserved(id, allocation); let num = usize::decode(self)?; let ptr = interpret::Pointer { primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id: id, + alloc_id, offset: 0, }), }; for _ in 0..num { let glob = interpret::GlobalId::decode(self)?; - interpret_interner.cache(glob, ptr); + interpret_interner().cache(glob, ptr); } - Ok(id) + Ok(alloc_id) }, MAX1 => { + trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; - let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance)); + trace!("decoded fn alloc instance: {:?}", instance); + let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance)); + trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) }, - shorthand => Ok(self.interpret_alloc_cache[&shorthand]), + shorthand => { + trace!("loading shorthand {}", shorthand); + if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) { + return Ok(alloc_id); + } + trace!("shorthand {} not cached, loading entire allocation", shorthand); + // need to load allocation + self.with_position(shorthand, |this| interpret::AllocId::decode(this)) + }, } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2a32a05342b5c..f57fad27f014f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -188,12 +188,18 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + trace!("encoding {:?} at {}", alloc_id, self.position()); if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { - return self.emit_usize(shorthand); + trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand); + return shorthand.encode(self); } let start = self.position(); + // cache the allocation shorthand now, because the allocation itself might recursively + // point to itself. + self.interpret_alloc_shorthands.insert(*alloc_id, start); let interpret_interner = self.tcx.interpret_interner.borrow(); if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; let globals = interpret_interner.get_globals(interpret::Pointer { @@ -207,16 +213,12 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx glob.encode(self)?; } } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id.0); } - let len = self.position() - start * 7; - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - assert!(len >= 64 || (start as u64) < (1 << len)); - self.interpret_alloc_shorthands.insert(*alloc_id, start); Ok(()) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index c0c680a4ddcbc..ca6e598b402ec 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -26,6 +26,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use std::fmt; @@ -258,7 +259,24 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - if let ConstVal::Function(def_id, ..) = value.val { + let did = match value.val { + ConstVal::Function(def_id, ..) => Some(def_id), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + self.tcx() + .interpret_interner + .borrow() + .get_fn(p.alloc_id.0) + .map(|instance| instance.def_id()) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match value.ty.sty { + ty::TyFnDef(ty_def_id, _) => Some(ty_def_id), + _ => None, + } + }, + _ => None, + }; + if let Some(def_id) = did { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -436,7 +454,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) @@ -1018,13 +1036,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Literal::Value { value: &ty::Const { - val: ConstVal::Function(def_id, _), - .. + val, + ty, }, .. }, .. - }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), + }) => match val { + ConstVal::Function(def_id, _) => { + Some(def_id) == self.tcx().lang_items().box_free_fn() + }, + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0); + inst.map_or(false, |inst| { + Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() + }) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match ty.sty { + ty::TyFnDef(ty_def_id, _) => { + Some(ty_def_id) == self.tcx().lang_items().box_free_fn() + } + _ => false, + } + } + _ => false, + } _ => false, } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d3cc952759058..b5b8f8d7e78b0 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use syntax::ast; use syntax_pos::Span; @@ -203,7 +204,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: this.hir.tcx().types.u32, literal: Literal::Value { value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(0)), + val: if this.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(ConstInt::U32(0)) + }, ty: this.hir.tcx().types.u32 }), }, @@ -401,7 +406,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -439,7 +448,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes( + val.to_u128_unchecked() + ))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 6cb9217776648..5459a40ea156d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -338,7 +338,7 @@ enum TestKind<'tcx> { // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec<&'tcx ty::Const<'tcx>>, + options: Vec, indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index bdcbfc0bdd85e..fafdee5b1e1b9 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::hir::RangeEnd; use syntax_pos::Span; use std::cmp::Ordering; @@ -112,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec<&'tcx ty::Const<'tcx>>, + options: &mut Vec, indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { @@ -128,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { indices.entry(value) .or_insert_with(|| { - options.push(value); + options.push(value.val.to_u128().expect("switching on int")); options.len() - 1 }); true @@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { target_blocks.place_back() <- if variants.contains(idx) { - values.push(discr); + values.push(discr.to_u128_unchecked()); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { @@ -266,9 +267,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - let ret = match options[0].val { - ConstVal::Bool(true) => vec![true_bb, false_bb], - ConstVal::Bool(false) => vec![false_bb, true_bb], + let ret = match options[0] { + 1 => vec![true_bb, false_bb], + 0 => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), @@ -282,13 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .chain(Some(otherwise)) .collect(); - let values: Vec<_> = options.iter().map(|v| - v.val.to_const_int().expect("switching on integral") - ).collect(); (targets.clone(), TerminatorKind::SwitchInt { discr: Operand::Copy(place.clone()), switch_ty, - values: From::from(values), + values: options.clone().into(), targets, }) }; @@ -300,14 +298,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); let mut val = Operand::Copy(place.clone()); + let bytes = match value.val { + ConstVal::ByteStr(bytes) => Some(bytes.data), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == self.hir.tcx().types.u8); + if is_array_ptr { + self.hir + .tcx() + .interpret_interner + .borrow() + .get_alloc(p.alloc_id.0) + .map(|alloc| &alloc.bytes[..]) + } else { + None + } + }, + _ => None, + }; // If we're using b"..." as a pattern, we need to insert an // unsizing coercion, as the byte string has the type &[u8; N]. // // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val { - let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64); + let expect = if let Some(bytes) = bytes { + let tcx = self.hir.tcx(); + + // Unsize the place to &[u8], too, if necessary. + if let ty::TyRef(region, mt) = ty.sty { + if let ty::TyArray(_, _) = mt.ty.sty { + ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); + let val_slice = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &val_slice, + Rvalue::Cast(CastKind::Unsize, val, ty)); + val = Operand::Move(val_slice); + } + } + + assert!(ty.is_slice()); + + let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64); let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value @@ -324,11 +357,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. let fail = self.cfg.start_new_block(); - let ty = expect.ty(&self.local_decls, tcx); - if let ty::TyRef(_, mt) = ty.sty { - assert!(ty.is_slice()); + let str_or_bytestr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|tam| match tam.ty.sty { + ty::TyStr => Some(tam.ty), + ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty), + _ => None, + }); + if let Some(ty) = str_or_bytestr { let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); - let ty = mt.ty; let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a3350cb1671d2..efb367201189b 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -16,6 +16,7 @@ use build::Builder; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax::ast; @@ -62,7 +63,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyChar => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Char('\0'), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Char('\0') + }, ty }) } @@ -83,7 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -104,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 317b038c48295..15722b64517cc 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,13 +10,13 @@ use hair::*; use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc::ty::{self, AdtKind, VariantDef, Ty}; +use rustc::mir::interpret::{Value, PrimVal}; +use rustc::ty::{self, AdtKind, VariantDef, Ty, TyCtxt}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -99,7 +99,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Deref { arg: expr.to_ref() } } Adjust::Deref(Some(deref)) => { - let call = deref.method_call(cx.tcx, expr.ty); + let call = deref.method_call(cx.tcx(), expr.ty); expr = Expr { temp_lifetime, @@ -313,7 +313,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, + hir::ExprLit(ref lit) => ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + }, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { @@ -399,9 +401,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { - // FIXME runtime-overflow - if let hir::ExprLit(_) = arg.node { - ExprKind::Literal { literal: cx.const_eval_literal(expr) } + if let hir::ExprLit(ref lit) = arg.node { + ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + } } else { ExprKind::Unary { op: UnOp::Neg, @@ -508,8 +511,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, - Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), + Ok(cv) => cv.val.unwrap_usize(cx.tcx), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; @@ -633,8 +635,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + value: cx.tcx().mk_const(ty::Const { + val: const_fn(cx.tcx, def_id, substs), ty }), }, @@ -659,6 +661,28 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) } } +fn const_fn<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, +) -> ConstVal<'tcx> { + if tcx.sess.opts.debugging_opts.miri { + /* + let inst = ty::Instance::new(def_id, substs); + let ptr = tcx + .interpret_interner + .borrow_mut() + .create_fn_alloc(inst); + let ptr = MemoryPointer::new(AllocId(ptr), 0); + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) + */ + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + } +} + fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) @@ -672,7 +696,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: const_fn(cx.tcx.global_tcx(), def_id, substs), ty: cx.tables().node_id_to_type(expr.hir_id) }), }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 725a1b845e7ea..1d305e61bb8d4 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,7 +17,6 @@ use hair::*; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use rustc_const_eval::ConstContext; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -31,6 +30,7 @@ use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; +use rustc::mir::interpret::{Value, PrimVal}; use std::rc::Rc; #[derive(Clone)] @@ -119,7 +119,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { Ok(val) => { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(val)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))) + } else { + ConstVal::Integral(ConstInt::Usize(val)) + }, ty: self.tcx.types.usize }) } @@ -139,7 +143,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(true), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))) + } else { + ConstVal::Bool(true) + }, ty: self.tcx.types.bool }) } @@ -148,20 +156,161 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(false), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Bool(false) + }, ty: self.tcx.types.bool }) } } - pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { + pub fn const_eval_literal( + &mut self, + lit: &'tcx ast::LitKind, + ty: Ty<'tcx>, + sp: Span, + neg: bool, + ) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - let const_cx = ConstContext::new(tcx, - self.param_env.and(self.identity_substs), - self.tables()); - match const_cx.eval(tcx.hir.expect_expr(e.id)) { - Ok(value) => Literal::Value { value }, - Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") + + let mut repr_ty = ty; + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + repr_ty = adt.repr.discr_type().to_ty(tcx) + } + } + + let parse_float = |num: &str, fty| -> ConstFloat { + ConstFloat::from_str(num, fty).unwrap_or_else(|_| { + // FIXME(#31407) this is only necessary because float parsing is buggy + tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); + }) + }; + + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = self.tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = self.tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: Value(lit), + ty, + }), + }; + } + + use syntax::ast::*; + use syntax::ast::LitIntType::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::ConstInt::*; + use rustc::ty::util::IntTypeExt; + use rustc::middle::const_val::ByteArray; + use rustc_const_math::ConstFloat; + + let lit = match *lit { + LitKind::Str(ref s, _) => Ok(Str(s.as_str())), + LitKind::ByteStr(ref data) => { + let data: &'tcx [u8] = data; + Ok(ByteStr(ByteArray { data })) + }, + LitKind::Byte(n) => Ok(Integral(U8(n))), + LitKind::Int(n, hint) => { + match (&repr_ty.sty, hint) { + (&ty::TyInt(ity), _) | + (_, Signed(ity)) => { + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, + ity, tcx.sess.target.isize_ty))) + } + (&ty::TyUint(uty), _) | + (_, Unsigned(uty)) => { + Ok(Integral(ConstInt::new_unsigned_truncating(n, + uty, tcx.sess.target.usize_ty))) + } + _ => bug!() + } + } + LitKind::Float(n, fty) => { + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::Bool(b) => Ok(Bool(b)), + LitKind::Char(c) => Ok(Char(c)), + }; + + match lit { + Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const { + val: value, + ty, + }) }, + Err(kind) => self.fatal_const_eval_err(&ConstEvalErr { + span: sp, + kind, + }, sp, "expression") } } @@ -203,7 +352,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { return (method_ty, Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Function(item.def_id, substs), + val: if self.tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(item.def_id, substs) + }, ty: method_ty }), }); diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index d3b084fde6ab8..dddf447375068 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -13,14 +13,13 @@ use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory}; use rustc_const_math::ConstInt; use std::fmt; use std::error::Error; - pub fn mk_eval_cx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, @@ -45,7 +44,7 @@ pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); @@ -82,7 +81,13 @@ pub fn eval_body<'a, 'tcx>( while ecx.step()? {} } let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - Ok((MemoryPointer::new(alloc, 0).into(), instance_ty)) + let align = ecx.layout_of(instance_ty)?.align; + let ptr = MemoryPointer::new(alloc, 0).into(); + let value = match ecx.try_read_value(ptr, align, instance_ty)? { + Some(val) => val, + _ => Value::ByRef(ptr, align), + }; + Ok((value, ptr, instance_ty)) } pub fn eval_body_as_integer<'a, 'tcx>( @@ -90,11 +95,9 @@ pub fn eval_body_as_integer<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, instance: Instance<'tcx>, ) -> EvalResult<'tcx, ConstInt> { - let ptr_ty = eval_body(tcx, instance, param_env); - let (ptr, ty) = ptr_ty?; - let ecx = mk_eval_cx(tcx, instance, param_env)?; - let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { - Some(Value::ByVal(prim)) => prim.to_bytes()?, + let (value, _, ty) = eval_body(tcx, instance, param_env)?; + let prim = match value { + Value::ByVal(prim) => prim.to_bytes()?, _ => return err!(TypeNotPrimitive(ty)), }; use syntax::ast::{IntTy, UintTy}; @@ -133,7 +136,7 @@ pub struct CompileTimeEvaluator; impl<'tcx> Into> for ConstEvalError { fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() + EvalErrorKind::MachineError(self.to_string()).into() } } @@ -193,7 +196,6 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -302,6 +304,70 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } } +pub fn const_val_field<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::middle::const_val::EvalResult<'tcx> { + trace!("const_val_field: {:#?}", key); + match const_val_field_inner(tcx, key) { + Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(field), + ty, + })), + Err(err) => Err(ConstEvalErr { + span: tcx.def_span(key.value.0.def_id()), + kind: err.into(), + }), + } +} + +fn const_val_field_inner<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { + trace!("const_val_field: {:#?}", key); + let (instance, field, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (mut field, ty) = match value { + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), + Value::ByRef(ptr, align) => { + let place = Place::from_primval_ptr(ptr, align); + let layout = ecx.layout_of(ty)?; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + (Value::ByRef(ptr, align), layout.ty) + } + }; + if let Value::ByRef(ptr, align) = field { + if let Some(val) = ecx.try_read_value(ptr, align, ty)? { + field = val; + } + } + Ok((field, ty)) +} + +pub fn const_discr<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>, +) -> EvalResult<'tcx, u128> { + trace!("const_discr: {:#?}", key); + let (instance, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (ptr, align) = match value { + Value::ByValPair(..) | Value::ByVal(_) => { + let layout = ecx.layout_of(ty)?; + use super::MemoryKind; + let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr: Pointer = ptr.into(); + ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; + (ptr, layout.align) + }, + Value::ByRef(ptr, align) => (ptr, align), + }; + let place = Place::from_primval_ptr(ptr, align); + ecx.read_discriminant_value(place, ty) +} + pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, @@ -340,35 +406,48 @@ pub fn const_eval_provider<'a, 'tcx>( return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) } + + let instance = ty::Instance::new(def_id, substs); + if tcx.sess.opts.debugging_opts.miri { + return match ::interpret::eval_body(tcx, instance, key.param_env) { + Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(miri_value), + ty: miri_ty, + })), + Err(err) => { + Err(ConstEvalErr { span: body.value.span, kind: err.into() }) + } + }; + } + trace!("running old const eval"); let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); trace!("old const eval produced {:?}", old_result); - if tcx.sess.opts.debugging_opts.miri { - let instance = ty::Instance::new(def_id, substs); - trace!("const eval instance: {:?}, {:?}", instance, key.param_env); - let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); - match (miri_result, old_result) { - (Err(err), Ok(ok)) => { - trace!("miri failed, ctfe returned {:?}", ok); - tcx.sess.span_warn( - tcx.def_span(key.value.0), - "miri failed to eval, while ctfe succeeded", - ); - let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let () = unwrap_miri(&ecx, Err(err)); - Ok(ok) - }, - (_, Err(err)) => Err(err), - (Ok((miri_val, miri_ty)), Ok(ctfe)) => { - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let layout = ecx.layout_of(miri_ty).unwrap(); - let miri_place = Place::from_primval_ptr(miri_val, layout.align); - check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); - Ok(ctfe) - } + trace!("const eval instance: {:?}, {:?}", instance, key.param_env); + let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); + match (miri_result, old_result) { + (Err(err), Ok(ok)) => { + trace!("miri failed, ctfe returned {:?}", ok); + tcx.sess.span_warn( + tcx.def_span(key.value.0), + "miri failed to eval, while ctfe succeeded", + ); + let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let () = unwrap_miri(&ecx, Err(err)); + Ok(ok) + }, + (Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + })), + (Err(_), Err(err)) => Err(err), + (Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => { + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let layout = ecx.layout_of(miri_ty).unwrap(); + let miri_place = Place::from_primval_ptr(miri_ptr, layout.align); + check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); + Ok(ctfe) } - } else { - old_result } } @@ -451,7 +530,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( } }, TyArray(elem_ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 568eb78d40a02..a8b3864ea87c2 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), + ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -1382,7 +1382,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = self.into_ptr(src)?; // u64 cast is from usize to u64, which is always good let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), + value: ptr.to_value_with_len(length.val.unwrap_u64() ), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index fee62c8a82e2f..a6ebdd45968fc 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider}; +pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr}; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 6ab1aec38b863..b20540b00ceae 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -248,10 +248,15 @@ pub fn unary_op<'tcx>( (Not, I64) => !(bytes as i64) as u128, (Not, I128) => !(bytes as i128) as u128, + (Neg, I8) if bytes == i8::min_value() as u128 => return err!(OverflowingMath), (Neg, I8) => -(bytes as i8) as u128, + (Neg, I16) if bytes == i16::min_value() as u128 => return err!(OverflowingMath), (Neg, I16) => -(bytes as i16) as u128, + (Neg, I32) if bytes == i32::min_value() as u128 => return err!(OverflowingMath), (Neg, I32) => -(bytes as i32) as u128, + (Neg, I64) if bytes == i64::min_value() as u128 => return err!(OverflowingMath), (Neg, I64) => -(bytes as i64) as u128, + (Neg, I128) if bytes == i128::min_value() as u128 => return err!(OverflowingMath), (Neg, I128) => -(bytes as i128) as u128, (Neg, F32) => (-bytes_to_f32(bytes)).bits, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 701b7a07ac988..c5e4eeab86709 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -71,7 +71,7 @@ impl<'tcx> Place { pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), + ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), ty::TySlice(elem) => { match self { @@ -115,6 +115,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } + pub fn read_field( + &self, + base: Value, + field: mir::Field, + base_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> { + let base_layout = self.layout_of(base_ty)?; + let field_index = field.index(); + let field = base_layout.field(self, field_index)?; + let offset = base_layout.fields.offset(field_index); + match base { + // the field covers the entire type + Value::ByValPair(..) | + Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))), + // split fat pointers, 2 element tuples, ... + Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { + let val = [a, b][field_index]; + Ok(Some((Value::ByVal(val), field.ty))) + }, + _ => Ok(None), + } + } + fn try_read_place_projection( &mut self, proj: &mir::PlaceProjection<'tcx>, @@ -126,23 +149,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let base_ty = self.place_ty(&proj.base); match proj.elem { - Field(field, _) => { - let base_layout = self.layout_of(base_ty)?; - let field_index = field.index(); - let field = base_layout.field(&self, field_index)?; - let offset = base_layout.fields.offset(field_index); - match base { - // the field covers the entire type - Value::ByValPair(..) | - Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)), - // split fat pointers, 2 element tuples, ... - Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { - let val = [a, b][field_index]; - Ok(Some(Value::ByVal(val))) - }, - _ => Ok(None), - } - }, + Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index c8a0dbdd90308..b083a81022487 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -45,8 +45,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets[targets.len() - 1]; - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); + for (index, &const_int) in values.iter().enumerate() { + let prim = PrimVal::Bytes(const_int); if discr_prim.to_bytes()? == prim.to_bytes()? { target_block = targets[index]; break; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 86a4dd4a31f8c..738111e7275e2 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -354,7 +354,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push('['); self.push_type_name(inner_type, output); write!(output, "; {}", - len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap(); + len.val.unwrap_u64()).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 42ffcc194ca8c..48cbf54a56920 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; use rustc_const_math::{ConstInt, ConstUsize}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +304,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), ty::TyArray(ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -443,7 +444,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: func_ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(self.def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(self.def_id, substs) + }, ty: func_ty }), }, @@ -501,13 +507,20 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } fn make_usize(&self, value: u64) -> Box> { - let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap(); box Constant { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(value)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) + } else { + let value = ConstUsize::new( + value, + self.tcx.sess.target.usize_ty, + ).unwrap(); + ConstVal::Integral(ConstInt::Usize(value)) + }, ty: self.tcx.types.usize, }) } @@ -736,8 +749,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, - Substs::identity_for_item(tcx, def_id)), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id)) + }, ty }), }, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 812665f5fa498..8b05ea4969503 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -80,6 +80,7 @@ use transform::simplify; use transform::no_landing_pads::no_landing_pads; use dataflow::{do_dataflow, DebugFormatted, state_for_location}; use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; +use rustc::mir::interpret::{Value, PrimVal}; pub struct StateTransform; @@ -181,7 +182,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty: self.tcx.types.u32, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(state_disc)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))) + } else { + ConstVal::Integral(ConstInt::U32(state_disc)) + }, ty: self.tcx.types.u32 }), }, @@ -534,7 +539,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let switch = TerminatorKind::SwitchInt { discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)), switch_ty: tcx.types.u32, - values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::>()), + values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::>()), targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), }; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index ceea97e3ed3b0..901393be7ca0b 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -206,6 +206,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } + // Do not inline {u,i}128 lang items, trans const eval depends + // on detecting calls to these lang items and intercepting them + if tcx.is_binop_lang_item(callsite.callee).is_some() { + debug!(" not inlining 128bit integer lang item"); + return false; + } + let attrs = tcx.get_attrs(callsite.callee); let hint = attr::find_inline_attr(None, &attrs[..]); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index da76adfd48f3f..061728186a6f6 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -611,7 +611,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { _ => false } } else if let ty::TyArray(_, len) = ty.sty { - len.val.to_const_int().unwrap().to_u64().unwrap() == 0 && + len.val.unwrap_u64() == 0 && self.mode == Mode::Fn } else { false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 20c33bab1aacb..1e1004c4569a8 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -40,10 +40,10 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(ref constint) = value.val.to_const_int() { + if let Some(constint) = value.val.to_u128() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (v, t) in values.iter().zip(targets.iter()) { + for (&v, t) in values.iter().zip(targets.iter()) { if v == constint { ret = TerminatorKind::Goto { target: *t }; break; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 6577106801499..666cf30136514 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,13 +11,14 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::{ConstInt, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; +use rustc::mir::interpret::{Value, PrimVal}; use std::{iter, u32}; @@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path, &adt.variants[variant_index], substs); - values.push(discr); + values.push(discr.to_u128().unwrap()); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original // drop ladder, because this breaks the @@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn adt_switch_block(&mut self, adt: &'tcx ty::AdtDef, blocks: Vec, - values: &[ConstInt], + values: &[u128], succ: BasicBlock, unwind: Unwind) -> BasicBlock { @@ -799,7 +800,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_const_int().and_then(|v| v.to_u64())), + ety, size.val.to_u128().map(|i| i as u64)), ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -945,7 +946,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty: self.tcx().types.usize, literal: Literal::Value { value: self.tcx().mk_const(ty::Const { - val: ConstVal::Integral(self.tcx().const_usize(val)), + val: if self.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))) + } else { + ConstVal::Integral(self.tcx().const_usize(val)) + }, ty: self.tcx().types.usize }) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 6df860492f05a..9ded3a5a0e5de 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -129,6 +129,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } fn check_const_eval(&self, expr: &'gcx hir::Expr) { + if self.tcx.sess.opts.debugging_opts.miri { + return; + } if let Err(err) = self.const_cx().eval(expr) { match err.kind { UnimplementedConstVal(_) => {} @@ -220,28 +223,30 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(lit); } PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) => {} - Ok(Ordering::Equal) | - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) => {} + Ok(Some(Ordering::Equal)) | + Ok(Some(Ordering::Greater)) => { span_err!(self.tcx.sess, start.span, E0579, "lower range bound must be less than upper"); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } PatKind::Range(ref start, ref end, RangeEnd::Included) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) | - Ok(Ordering::Equal) => {} - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) | + Ok(Some(Ordering::Equal)) => {} + Ok(Some(Ordering::Greater)) => { struct_span_err!(self.tcx.sess, start.span, E0030, "lower range bound must be less than or equal to upper") .span_label(start.span, "lower bound larger than upper bound") .emit(); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } @@ -298,7 +303,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.promotable = false; } - if self.in_fn && self.promotable { + if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri { match self.const_cx().eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 466a86e7ea558..d886be1f953ab 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -196,7 +196,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, len.val.unwrap_u64()) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 62ba91840d95e..6111b243720ff 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong + len.val.unwrap_u64() as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6490d109f2936..a88eb9ae35471 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap())); + output.push_str(&format!("; {}", len.val.unwrap_u64())); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index bf82e1d50c473..3514cf5056dee 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir::traversal; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty; use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; @@ -109,15 +110,26 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { - match *kind { + let check = match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(box mir::Constant { literal: Literal::Value { - value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. + value: &ty::Const { val, ty }, .. }, .. }), ref args, .. - } if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => { + } => match val { + ConstVal::Function(def_id, _) => Some((def_id, args)), + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), + _ => None, + }, + _ => None, + } + _ => None, + }; + if let Some((def_id, args)) = check { + if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() { // box_free(x) shares with `drop x` the property that it // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. @@ -125,7 +137,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { self.visit_place(place, PlaceContext::Drop, location); } } - _ => {} } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index af1e30a4b19a6..fe16b3bca64f6 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::traits; @@ -196,17 +196,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if switch_ty == bx.tcx().types.bool { let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [ConstInt::U8(0)] = values[..] { + if let [0] = values[..] { bx.cond_br(discr.immediate(), llfalse, lltrue); } else { + assert_eq!(&values[..], &[1]); bx.cond_br(discr.immediate(), lltrue, llfalse); } } else { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); - for (value, target) in values.iter().zip(targets) { - let val = Const::from_constint(bx.cx, value); + for (&value, target) in values.iter().zip(targets) { + let val = Const::from_bytes(bx.cx, value, switch_ty); let llbb = llblock(self, *target); bx.add_case(switch, val.llval, llbb) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c6744f1ad3f3f..9f8d1ddeb4164 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::traits; use rustc::mir; +use rustc::mir::interpret::{Value as MiriValue, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -38,6 +39,7 @@ use value::Value; use syntax_pos::Span; use syntax::ast; +use syntax::symbol::Symbol; use std::fmt; use std::ptr; @@ -81,12 +83,46 @@ impl<'a, 'tcx> Const<'tcx> { Const { llval: llval, ty: ty } } + pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { + let llval = match ty.sty { + ty::TyInt(ast::IntTy::I128) | + ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b), + ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64), + ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64), + ty::TyBool => { + assert!(b <= 1); + C_bool(ccx, b == 1) + }, + ty::TyChar => { + assert_eq!(b as u32 as u128, b); + let c = b as u32; + assert!(::std::char::from_u32(c).is_some()); + C_uint(Type::char(ccx), c as u64) + }, + ty::TyFloat(fty) => { + let llty = ccx.layout_of(ty).llvm_type(ccx); + let bits = match fty { + ast::FloatTy::F32 => C_u32(ccx, b as u32), + ast::FloatTy::F64 => C_u64(ccx, b as u64), + }; + consts::bitcast(bits, llty) + }, + ty::TyAdt(adt, _) if adt.is_enum() => { + use rustc::ty::util::IntTypeExt; + Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval + }, + _ => bug!("from_bytes({}, {})", b, ty), + }; + Const { llval, ty } + } + /// Translate ConstVal into a LLVM constant value. pub fn from_constval(cx: &CodegenCx<'a, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>) -> Const<'tcx> { let llty = cx.layout_of(ty).llvm_type(cx); + trace!("from_constval: {:#?}: {}", cv, ty); let val = match *cv { ConstVal::Float(v) => { let bits = match v.ty { @@ -108,7 +144,41 @@ impl<'a, 'tcx> Const<'tcx> { ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Value(_) => unimplemented!(), + ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), + ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { + match ty.sty { + ty::TyRef(_, ref tam) => match tam.ty.sty { + ty::TyStr => {}, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + }, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + } + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + C_str_slice(ccx, Symbol::intern(s).as_str()) + }, + ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(), + ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) => + return Const::from_bytes(ccx, b, ty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => { + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + let data = &alloc.bytes[(ptr.offset as usize)..]; + consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") + } }; assert!(!ty.has_erasable_regions()); @@ -239,7 +309,7 @@ impl<'tcx> ConstPlace<'tcx> { pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { match self.ty.sty { ty::TyArray(_, n) => { - C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, n.val.unwrap_u64()) } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); @@ -316,7 +386,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tcx = self.cx.tcx; let mut bb = mir::START_BLOCK; - // Make sure to evaluate all statemenets to + // Make sure to evaluate all statements to // report as many errors as we possibly can. let mut failure = Ok(()); @@ -392,6 +462,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; + trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args); let mut arg_vals = IndexVec::with_capacity(args.len()); for arg in args { @@ -419,7 +490,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } _ => span_bug!(span, "{:?} in constant", terminator.kind) } - } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) { + } else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) { (||{ assert_eq!(arg_vals.len(), 2); let rhs = arg_vals.pop().unwrap()?; @@ -470,37 +541,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } - fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> { - let tcx = self.cx.tcx; - let items = tcx.lang_items(); - let def_id = Some(def_id); - if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else { None } - } - fn store(&mut self, dest: &mir::Place<'tcx>, value: Result, ConstEvalErr<'tcx>>, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index d1bc4fe90014c..38df7ce30fdd3 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -493,7 +493,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1a285cd869aec..bacc7b4bd7677 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -384,7 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 363d4a9dc0cd3..3ee48c8997a27 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4030,9 +4030,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_const_int().and_then(|count| { - count.to_u64().map(|count| count <= 1) - }).unwrap_or(false); + let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 0698e3ecb6edd..97d6d96c87ad2 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -411,10 +411,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiBitOr => ("bitor", lang.bitor_trait()), hir::BiShl => ("shl", lang.shl_trait()), hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), + hir::BiLt => ("lt", lang.partial_ord_trait()), + hir::BiLe => ("le", lang.partial_ord_trait()), + hir::BiGe => ("ge", lang.partial_ord_trait()), + hir::BiGt => ("gt", lang.partial_ord_trait()), hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7a91827faef83..6aa65231aaba9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -36,6 +36,7 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; +use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashMap; use rustc_const_math::ConstInt; @@ -535,6 +536,18 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match result { Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + use syntax::attr::IntType; + Some(match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }) + } _ => None } } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bd7e200d620e6..7937a20304de1 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,6 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(i128_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index 56c3e2a38a0ed..c184a1e9a287f 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -46,7 +46,7 @@ fn main() { // _3 = &'23_1rs _2; // StorageLive(_5); // _5 = _2; -// switchInt(move _5) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _5) -> [false: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 8c0d56eba7828..8e336a16c130b 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -48,7 +48,7 @@ fn main() { // _3 = &'26_1rs _1; // StorageLive(_5); // _5 = _1; -// switchInt(move _5) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _5) -> [false: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index b313e296ac99c..b8532f91f2e96 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -64,7 +64,7 @@ fn main() { // bb1: { // StorageLive(_7); // _7 = _1; -// switchInt(move _7) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _7) -> [false: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 37a6229febabb..4743b6a711553 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -100,7 +100,7 @@ fn query() -> bool { true } // _11 = const query() -> [return: bb5, unwind: bb2]; // } // bb5: { -// switchInt(move _11) -> [0u8: bb7, otherwise: bb6]; +// switchInt(move _11) -> [false: bb7, otherwise: bb6]; // } // bb6: { // _0 = (); diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index b5c188cf834a9..59916f4b60e01 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -31,7 +31,7 @@ fn main() { // bb1: { // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _4) -> [false: bb3, otherwise: bb2]; // } // // bb2: { diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 1f892b0f9587a..2c732376712bf 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -92,7 +92,7 @@ fn main() { // _6 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _6) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _6) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -155,7 +155,7 @@ fn main() { // _6 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _6) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _6) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb6, imaginary: bb5]; @@ -216,7 +216,7 @@ fn main() { // _8 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { //end of guard -// switchInt(move _8) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _8) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -237,7 +237,7 @@ fn main() { // } // bb14: { // end of guard2 // StorageDead(_11); -// switchInt(move _10) -> [0u8: bb15, otherwise: bb3]; +// switchInt(move _10) -> [false: bb15, otherwise: bb3]; // } // bb15: { // to pre_binding4 // falseEdges -> [real: bb7, imaginary: bb7]; diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index e9834305550c3..19d733d4f6b6a 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -41,7 +41,7 @@ fn main() { // | Live variables on entry to bb2[0]: [_1, _3] // _2 = &'_#2r _1[_3]; // | Live variables on entry to bb2[1]: [_2] -// switchInt(const true) -> [0u8: bb4, otherwise: bb3]; +// switchInt(const true) -> [false: bb4, otherwise: bb3]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 35786643648eb..52d5892e6560b 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyBranches-initial.before.mir // bb0: { -// switchInt(const false) -> [0u8: bb3, otherwise: bb2]; +// switchInt(const false) -> [false: bb3, otherwise: bb2]; // } // END rustc.main.SimplifyBranches-initial.before.mir // START rustc.main.SimplifyBranches-initial.after.mir diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs index 6b7f631ff4c8d..885edb55ed86c 100644 --- a/src/test/ui/const-eval-overflow-2.rs +++ b/src/test/ui/const-eval-overflow-2.rs @@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error -//~| attempt to negate with overflow +//~^ ERROR E0080 fn main() { match -128i8 { diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr index a9d29d0107192..eed00244041db 100644 --- a/src/test/ui/const-eval-overflow-2.stderr +++ b/src/test/ui/const-eval-overflow-2.stderr @@ -2,12 +2,12 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-2.rs:21:25 | 21 | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ attempt to negate with overflow + | ^^^^^^^^ miri failed: attempted to do overflowing math | note: for pattern here - --> $DIR/const-eval-overflow-2.rs:27:9 + --> $DIR/const-eval-overflow-2.rs:26:9 | -27 | NEG_NEG_128 => println!("A"), +26 | NEG_NEG_128 => println!("A"), | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs index 4423fdec33a85..a1b90f623cdae 100644 --- a/src/test/ui/const-eval-overflow-4.rs +++ b/src/test/ui/const-eval-overflow-4.rs @@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR constant evaluation error - //~| WARNING constant evaluation error + //~^ ERROR E0080 = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr index 98c6ae1b9bcac..6cd2dd52edeae 100644 --- a/src/test/ui/const-eval-overflow-4.stderr +++ b/src/test/ui/const-eval-overflow-4.stderr @@ -1,16 +1,8 @@ -warning: constant evaluation error: attempt to add with overflow - --> $DIR/const-eval-overflow-4.rs:23:13 - | -23 | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[warn(const_err)] on by default - error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-4.rs:23:13 | 23 | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: Overflow(Add) at $DIR/const-eval-overflow-4.rs:23:13: 23:34 error: aborting due to previous error diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index 85ab2a0052164..86c5e873df866 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -16,8 +16,6 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0-1; //~ ERROR constant evaluation error - //~^ WARN constant evaluation error const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - //~^ WARN constant evaluation error println!("{} {}", X, Y); } diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 82baab620ffab..f624fc03cd871 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -1,17 +1,3 @@ -warning: constant evaluation error: attempt to subtract with overflow - --> $DIR/issue-43197.rs:18:20 - | -18 | const X: u32 = 0-1; //~ ERROR constant evaluation error - | ^^^ - | - = note: #[warn(const_err)] on by default - -warning: constant evaluation error: attempt to subtract with overflow - --> $DIR/issue-43197.rs:20:20 - | -20 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - | ^^^^^^^^ - error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:18:20 | @@ -19,9 +5,9 @@ error[E0080]: constant evaluation error | ^^^ attempt to subtract with overflow error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:20:24 + --> $DIR/issue-43197.rs:19:24 | -20 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error +19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error | ^^^ attempt to subtract with overflow error: aborting due to 2 previous errors diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs index 24d4457f01d70..bfd6a4090649b 100644 --- a/src/test/ui/const-expr-addr-operator.rs +++ b/src/test/ui/const-expr-addr-operator.rs @@ -9,10 +9,11 @@ // except according to those terms. // Encountered while testing #44614. +// must-compile-successfully pub fn main() { // Constant of generic type (int) - const X: &'static u32 = &22; //~ ERROR constant evaluation error + const X: &'static u32 = &22; assert_eq!(0, match &22 { X => 0, _ => 1, diff --git a/src/test/ui/const-expr-addr-operator.stderr b/src/test/ui/const-expr-addr-operator.stderr index f6587c703bd7f..e69de29bb2d1d 100644 --- a/src/test/ui/const-expr-addr-operator.stderr +++ b/src/test/ui/const-expr-addr-operator.stderr @@ -1,14 +0,0 @@ -error[E0080]: constant evaluation error - --> $DIR/const-expr-addr-operator.rs:15:29 - | -15 | const X: &'static u32 = &22; //~ ERROR constant evaluation error - | ^^^ unimplemented constant expression: address operator - | -note: for pattern here - --> $DIR/const-expr-addr-operator.rs:17:9 - | -17 | X => 0, - | ^ - -error: aborting due to previous error - diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs index ac1c2fe5432de..dc1526a7079d4 100644 --- a/src/test/ui/const-fn-error.rs +++ b/src/test/ui/const-fn-error.rs @@ -13,17 +13,18 @@ const X : usize = 2; const fn f(x: usize) -> usize { - let mut sum = 0; //~ ERROR blocks in constant functions are limited - for i in 0..x { //~ ERROR calls in constant functions - //~| ERROR constant function contains unimplemented + let mut sum = 0; + //~^ ERROR E0016 + for i in 0..x { + //~^ ERROR E0015 + //~| ERROR E0019 sum += i; } - sum //~ ERROR E0080 - //~| non-constant path in constant + sum } #[allow(unused_variables)] fn main() { let a : [i32; f(X)]; - //~^ WARNING constant evaluation error: non-constant path + //~^ ERROR E0080 } diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index 4f4f8b5ad0093..e313128aa7803 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -1,15 +1,7 @@ -warning: constant evaluation error: non-constant path in constant expression - --> $DIR/const-fn-error.rs:27:19 - | -27 | let a : [i32; f(X)]; - | ^^^^ - | - = note: #[warn(const_err)] on by default - error[E0016]: blocks in constant functions are limited to items and tail expressions --> $DIR/const-fn-error.rs:16:19 | -16 | let mut sum = 0; //~ ERROR blocks in constant functions are limited +16 | let mut sum = 0; | ^ error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors @@ -25,16 +17,10 @@ error[E0019]: constant function contains unimplemented expression type | ^^^^ error[E0080]: constant evaluation error - --> $DIR/const-fn-error.rs:21:5 - | -21 | sum //~ ERROR E0080 - | ^^^ non-constant path in constant expression - | -note: for constant expression here - --> $DIR/const-fn-error.rs:27:13 + --> $DIR/const-fn-error.rs:28:19 | -27 | let a : [i32; f(X)]; - | ^^^^^^^^^^^ +28 | let a : [i32; f(X)]; + | ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `>::into_iter`" error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs index 823cc988947cb..7582d0efa812e 100644 --- a/src/test/ui/const-len-underflow-separate-spans.rs +++ b/src/test/ui/const-len-underflow-separate-spans.rs @@ -15,9 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR constant evaluation error [E0080] -//~| WARN attempt to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); +//~^ ERROR E0080 } diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 6e6c2130e1ccd..77a41258b3435 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -1,22 +1,8 @@ -warning: constant evaluation error: attempt to subtract with overflow - --> $DIR/const-len-underflow-separate-spans.rs:17:20 - | -17 | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ - | - = note: #[warn(const_err)] on by default - error[E0080]: constant evaluation error - --> $DIR/const-len-underflow-separate-spans.rs:17:20 - | -17 | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ attempt to subtract with overflow - | -note: for constant expression here - --> $DIR/const-len-underflow-separate-spans.rs:22:12 + --> $DIR/const-len-underflow-separate-spans.rs:20:17 | -22 | let a: [i8; LEN] = unimplemented!(); - | ^^^^^^^^^ +20 | let a: [i8; LEN] = unimplemented!(); + | ^^^ miri failed: Overflow(Sub) at $DIR/const-len-underflow-separate-spans.rs:17:20: 17:29 error: aborting due to previous error diff --git a/src/test/ui/const-pattern-not-const-evaluable.rs b/src/test/ui/const-pattern-not-const-evaluable.rs index 263c0bdc64c6f..09b24d1ffa208 100644 --- a/src/test/ui/const-pattern-not-const-evaluable.rs +++ b/src/test/ui/const-pattern-not-const-evaluable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + #![feature(const_fn)] #[derive(PartialEq, Eq)] @@ -20,8 +22,6 @@ use Cake::*; struct Pair(A, B); const BOO: Pair = Pair(Marmor, BlackForest); -//~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { diff --git a/src/test/ui/const-pattern-not-const-evaluable.stderr b/src/test/ui/const-pattern-not-const-evaluable.stderr index 5441937e4dd60..e69de29bb2d1d 100644 --- a/src/test/ui/const-pattern-not-const-evaluable.stderr +++ b/src/test/ui/const-pattern-not-const-evaluable.stderr @@ -1,14 +0,0 @@ -error[E0080]: constant evaluation error - --> $DIR/const-pattern-not-const-evaluable.rs:22:31 - | -22 | const BOO: Pair = Pair(Marmor, BlackForest); - | ^^^^ unimplemented constant expression: tuple struct constructors - | -note: for pattern here - --> $DIR/const-pattern-not-const-evaluable.rs:37:9 - | -37 | FOO => println!("hi"), - | ^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate-const-indexing.rs b/src/test/ui/feature-gate-const-indexing.rs index 0d61878cd8073..eb5f746774cf1 100644 --- a/src/test/ui/feature-gate-const-indexing.rs +++ b/src/test/ui/feature-gate-const-indexing.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully fn main() { const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; const IDX: usize = 3; const VAL: i32 = ARR[IDX]; - const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error + const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; } diff --git a/src/test/ui/feature-gate-const-indexing.stderr b/src/test/ui/feature-gate-const-indexing.stderr index bc4b687800d75..e69de29bb2d1d 100644 --- a/src/test/ui/feature-gate-const-indexing.stderr +++ b/src/test/ui/feature-gate-const-indexing.stderr @@ -1,8 +0,0 @@ -error[E0080]: constant evaluation error - --> $DIR/feature-gate-const-indexing.rs:16:24 - | -16 | const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error - | ^^^^^^ the index operation on const values is unstable - -error: aborting due to previous error - diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs index 42e3c05a38c7e..24cd20a84a9fe 100644 --- a/src/test/ui/issue-38875/issue_38875.rs +++ b/src/test/ui/issue-38875/issue_38875.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:issue_38875_b.rs +// must-compile-successfully extern crate issue_38875_b; diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr index d49741f25b9f5..e69de29bb2d1d 100644 --- a/src/test/ui/issue-38875/issue_38875.stderr +++ b/src/test/ui/issue-38875/issue_38875.stderr @@ -1,14 +0,0 @@ -error[E0080]: constant evaluation error - --> $DIR/auxiliary/issue_38875_b.rs:11:24 - | -11 | pub const FOO: usize = *&0; - | ^^^ unimplemented constant expression: deref operation - | -note: for constant expression here - --> $DIR/issue_38875.rs:16:22 - | -16 | let test_x = [0; issue_38875_b::FOO]; - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs index a4c969ba20c46..aeafb45e6a552 100644 --- a/src/test/ui/union/union-const-eval.rs +++ b/src/test/ui/union/union-const-eval.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + union U { a: usize, b: usize, @@ -16,9 +18,6 @@ union U { const C: U = U { a: 10 }; fn main() { - unsafe { - let a: [u8; C.a]; // OK - let b: [u8; C.b]; //~ ERROR constant evaluation error - //~| WARNING constant evaluation error - } + let a: [u8; unsafe { C.a }]; + let b: [u8; unsafe { C.b }]; } diff --git a/src/test/ui/union/union-const-eval.stderr b/src/test/ui/union/union-const-eval.stderr index 3c98b5cdc6cdc..e69de29bb2d1d 100644 --- a/src/test/ui/union/union-const-eval.stderr +++ b/src/test/ui/union/union-const-eval.stderr @@ -1,16 +0,0 @@ -warning: constant evaluation error: nonexistent struct field - --> $DIR/union-const-eval.rs:21:21 - | -21 | let b: [u8; C.b]; //~ ERROR constant evaluation error - | ^^^ - | - = note: #[warn(const_err)] on by default - -error[E0080]: constant evaluation error - --> $DIR/union-const-eval.rs:21:21 - | -21 | let b: [u8; C.b]; //~ ERROR constant evaluation error - | ^^^ nonexistent struct field - -error: aborting due to previous error - From ff0e2efa9697ff9b61832c08671030a9f32239a5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 27 Dec 2017 21:32:01 +0100 Subject: [PATCH 004/115] Move librustc_const_eval to librustc_mir --- src/doc/rustc-ux-guidelines.md | 1 - src/librustc/dep_graph/dep_node.rs | 1 - src/librustc/ty/maps/config.rs | 1 - src/librustc_const_eval/Cargo.toml | 19 - src/librustc_const_eval/diagnostics.rs | 571 ------------------ src/librustc_const_eval/lib.rs | 60 -- src/librustc_driver/Cargo.toml | 1 - src/librustc_driver/driver.rs | 3 +- src/librustc_driver/lib.rs | 2 - src/librustc_lint/Cargo.toml | 2 +- src/librustc_lint/lib.rs | 2 +- src/librustc_lint/types.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_mir/build/mod.rs | 2 +- .../const_eval}/_match.rs | 6 +- .../const_eval}/check_match.rs | 8 +- .../const_eval}/eval.rs | 0 src/librustc_mir/const_eval/mod.rs | 18 + .../const_eval}/pattern.rs | 29 +- src/librustc_mir/diagnostics.rs | 550 +++++++++++++++++ src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/interpret/const_eval.rs | 34 +- src/librustc_mir/lib.rs | 6 +- src/librustc_passes/Cargo.toml | 2 +- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/lib.rs | 2 +- 26 files changed, 626 insertions(+), 702 deletions(-) delete mode 100644 src/librustc_const_eval/Cargo.toml delete mode 100644 src/librustc_const_eval/diagnostics.rs delete mode 100644 src/librustc_const_eval/lib.rs rename src/{librustc_const_eval => librustc_mir/const_eval}/_match.rs (99%) rename src/{librustc_const_eval => librustc_mir/const_eval}/check_match.rs (99%) rename src/{librustc_const_eval => librustc_mir/const_eval}/eval.rs (100%) create mode 100644 src/librustc_mir/const_eval/mod.rs rename src/{librustc_const_eval => librustc_mir/const_eval}/pattern.rs (97%) diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index 323d49e469120..b62762ef69e01 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -64,7 +64,6 @@ for details on how to format and write long error codes. [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/diagnostics.rs), [libsyntax](https://github.com/rust-lang/rust/blob/master/src/libsyntax/diagnostics.rs), [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/diagnostics.rs), - [librustc_const_eval](https://github.com/rust-lang/rust/blob/master/src/librustc_const_eval/diagnostics.rs), [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/diagnostics.rs), [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/diagnostics.rs), [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs), diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e01946e0f3db5..4034055d04155 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,7 +63,6 @@ use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; -use mir; use ich::Fingerprint; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 44609adefccbb..eb07876b05f26 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -13,7 +13,6 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; -use mir; use std::hash::Hash; use syntax_pos::symbol::InternedString; diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml deleted file mode 100644 index 53b8402ab2ad5..0000000000000 --- a/src/librustc_const_eval/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_const_eval" -version = "0.0.0" - -[lib] -name = "rustc_const_eval" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -arena = { path = "../libarena" } -log = "0.4" -rustc = { path = "../librustc" } -rustc_const_math = { path = "../librustc_const_math" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs deleted file mode 100644 index d01b3c45f7fd1..0000000000000 --- a/src/librustc_const_eval/diagnostics.rs +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_snake_case)] - -// Error messages for EXXXX errors. -// Each message should start and end with a new line, and be wrapped to 80 characters. -// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. -register_long_diagnostics! { - -E0001: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error suggests that the expression arm corresponding to the noted pattern -will never be reached as for all possible values of the expression being -matched, one of the preceding patterns will match. - -This means that perhaps some of the preceding patterns are too general, this -one is too specific or the ordering is incorrect. - -For example, the following `match` block has too many arms: - -``` -match Some(0) { - Some(bar) => {/* ... */} - x => {/* ... */} // This handles the `None` case - _ => {/* ... */} // All possible cases have already been handled -} -``` - -`match` blocks have their patterns matched in order, so, for example, putting -a wildcard arm above a more specific arm will make the latter arm irrelevant. - -Ensure the ordering of the match arm is correct and remove any superfluous -arms. -"##, - -E0002: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error indicates that an empty match expression is invalid because the type -it is matching on is non-empty (there exist values of this type). In safe code -it is impossible to create an instance of an empty type, so empty match -expressions are almost never desired. This error is typically fixed by adding -one or more cases to the match expression. - -An example of an empty type is `enum Empty { }`. So, the following will work: - -``` -enum Empty {} - -fn foo(x: Empty) { - match x { - // empty - } -} -``` - -However, this won't: - -```compile_fail -fn foo(x: Option) { - match x { - // empty - } -} -``` -"##, - -E0003: r##" -#### Note: this error code is no longer emitted by the compiler. - -Not-a-Number (NaN) values cannot be compared for equality and hence can never -match the input to a match expression. So, the following will not compile: - -```compile_fail -const NAN: f32 = 0.0 / 0.0; - -let number = 0.1f32; - -match number { - NAN => { /* ... */ }, - _ => {} -} -``` - -To match against NaN values, you should instead use the `is_nan()` method in a -guard, like so: - -``` -let number = 0.1f32; - -match number { - x if x.is_nan() => { /* ... */ } - _ => {} -} -``` -"##, - -E0004: r##" -This error indicates that the compiler cannot guarantee a matching pattern for -one or more possible inputs to a match expression. Guaranteed matches are -required in order to assign values to match expressions, or alternatively, -determine the flow of execution. Erroneous code example: - -```compile_fail,E0004 -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered - Terminator::TalkToMyHand => {} -} -``` - -If you encounter this error you must alter your patterns so that every possible -value of the input type is matched. For types with a small number of variants -(like enums) you should probably cover all cases explicitly. Alternatively, the -underscore `_` wildcard pattern can be added after all other patterns to match -"anything else". Example: - -``` -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { - Terminator::TalkToMyHand => {} - Terminator::HastaLaVistaBaby => {} -} - -// or: - -match x { - Terminator::TalkToMyHand => {} - _ => {} -} -``` -"##, - -E0005: r##" -Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. Erroneous code example: - -```compile_fail,E0005 -let x = Some(1); -let Some(y) = x; -// error: refutable pattern in local binding: `None` not covered -``` - -If you encounter this error you probably need to use a `match` or `if let` to -deal with the possibility of failure. Example: - -``` -let x = Some(1); - -match x { - Some(y) => { - // do something - }, - None => {} -} - -// or: - -if let Some(y) = x { - // do something -} -``` -"##, - -E0007: r##" -This error indicates that the bindings in a match arm would require a value to -be moved into more than one location, thus violating unique ownership. Code -like the following is invalid as it requires the entire `Option` to be -moved into a variable called `op_string` while simultaneously requiring the -inner `String` to be moved into a variable called `s`. - -```compile_fail,E0007 -let x = Some("s".to_string()); - -match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings - None => {}, -} -``` - -See also the error E0303. -"##, - -E0008: r##" -Names bound in match arms retain their type in pattern guards. As such, if a -name is bound by move in a pattern, it should also be moved to wherever it is -referenced in the pattern guard code. Doing so however would prevent the name -from being available in the body of the match arm. Consider the following: - -```compile_fail,E0008 -match Some("hi".to_string()) { - Some(s) if s.len() == 0 => {}, // use s. - _ => {}, -} -``` - -The variable `s` has type `String`, and its use in the guard is as a variable of -type `String`. The guard code effectively executes in a separate scope to the -body of the arm, so the value would be moved into this anonymous scope and -therefore becomes unavailable in the body of the arm. - -The problem above can be solved by using the `ref` keyword. - -``` -match Some("hi".to_string()) { - Some(ref s) if s.len() == 0 => {}, - _ => {}, -} -``` - -Though this example seems innocuous and easy to solve, the problem becomes clear -when it encounters functions which consume the value: - -```compile_fail,E0008 -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a { - Some(y) if y.consume() > 0 => {} - _ => {} - } -} -``` - -In this situation, even the `ref` keyword cannot solve it, since borrowed -content cannot be moved. This problem cannot be solved generally. If the value -can be cloned, here is a not-so-specific solution: - -``` -#[derive(Clone)] -struct A{} - -impl A { - fn consume(self) -> usize { - 0 - } -} - -fn main() { - let a = Some(A{}); - match a{ - Some(ref y) if y.clone().consume() > 0 => {} - _ => {} - } -} -``` - -If the value will be consumed in the pattern guard, using its clone will not -move its ownership, so the code works. -"##, - -E0009: r##" -In a pattern, all values that don't implement the `Copy` trait have to be bound -the same way. The goal here is to avoid binding simultaneously by-move and -by-ref. - -This limitation may be removed in a future version of Rust. - -Erroneous code example: - -```compile_fail,E0009 -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the - // same pattern - None => panic!() -} -``` - -You have two solutions: - -Solution #1: Bind the pattern's values the same way. - -``` -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((ref y, ref z)) => {}, - // or Some((y, z)) => {} - None => panic!() -} -``` - -Solution #2: Implement the `Copy` trait for the `X` structure. - -However, please keep in mind that the first solution should be preferred. - -``` -#[derive(Clone, Copy)] -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, - None => panic!() -} -``` -"##, - -E0158: r##" -`const` and `static` mean different things. A `const` is a compile-time -constant, an alias for a literal value. This property means you can match it -directly within a pattern. - -The `static` keyword, on the other hand, guarantees a fixed location in memory. -This does not always mean that the value is constant. For example, a global -mutex can be declared `static` as well. - -If you want to match against a `static`, consider using a guard instead: - -``` -static FORTY_TWO: i32 = 42; - -match Some(42) { - Some(x) if x == FORTY_TWO => {} - _ => {} -} -``` -"##, - -E0162: r##" -An if-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding instead. For instance: - -```compile_fail,E0162 -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -if let Irrefutable(x) = irr { - // This body will always be executed. - // ... -} -``` - -Try this instead: - -``` -struct Irrefutable(i32); -let irr = Irrefutable(0); - -let Irrefutable(x) = irr; -println!("{}", x); -``` -"##, - -E0165: r##" -A while-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding inside a `loop` instead. For instance: - -```compile_fail,E0165 -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -while let Irrefutable(x) = irr { - // ... -} -``` - -Try this instead: - -```no_run -struct Irrefutable(i32); -let irr = Irrefutable(0); - -loop { - let Irrefutable(x) = irr; - // ... -} -``` -"##, - -E0170: r##" -Enum variants are qualified by default. For example, given this type: - -``` -enum Method { - GET, - POST, -} -``` - -You would match it using: - -``` -enum Method { - GET, - POST, -} - -let m = Method::GET; - -match m { - Method::GET => {}, - Method::POST => {}, -} -``` - -If you don't qualify the names, the code will bind new variables named "GET" and -"POST" instead. This behavior is likely not what you want, so `rustc` warns when -that happens. - -Qualified names are good practice, and most code works well with them. But if -you prefer them unqualified, you can import the variants into scope: - -``` -use Method::*; -enum Method { GET, POST } -# fn main() {} -``` - -If you want others to be able to import variants from your module directly, use -`pub use`: - -``` -pub use Method::*; -pub enum Method { GET, POST } -# fn main() {} -``` -"##, - - -E0297: r##" -#### Note: this error code is no longer emitted by the compiler. - -Patterns used to bind names must be irrefutable. That is, they must guarantee -that a name will be extracted in all cases. Instead of pattern matching the -loop variable, consider using a `match` or `if let` inside the loop body. For -instance: - -```compile_fail,E0005 -let xs : Vec> = vec![Some(1), None]; - -// This fails because `None` is not covered. -for Some(x) in xs { - // ... -} -``` - -Match inside the loop instead: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - match item { - Some(x) => {}, - None => {}, - } -} -``` - -Or use `if let`: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - if let Some(x) = item { - // ... - } -} -``` -"##, - -E0301: r##" -Mutable borrows are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if mutable -borrows were allowed: - -```compile_fail,E0301 -match Some(()) { - None => { }, - option if option.take().is_none() => { - /* impossible, option is `Some` */ - }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0302: r##" -Assignments are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if assignments -were allowed: - -```compile_fail,E0302 -match Some(()) { - None => { }, - option if { option = None; false } => { }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0303: r##" -In certain cases it is possible for sub-bindings to violate memory safety. -Updates to the borrow checker in a future version of Rust may remove this -restriction, but for now patterns must be rewritten without sub-bindings. - -Before: - -```compile_fail,E0303 -match Some("hi".to_string()) { - ref op_string_ref @ Some(s) => {}, - None => {}, -} -``` - -After: - -``` -match Some("hi".to_string()) { - Some(ref s) => { - let op_string_ref = &Some(s); - // ... - }, - None => {}, -} -``` - -The `op_string_ref` binding has type `&Option<&String>` in both cases. - -See also https://github.com/rust-lang/rust/issues/14587 -"##, - -} - - -register_diagnostics! { -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0471, // constant evaluation error (in pattern) -} diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs deleted file mode 100644 index b4563f6cf2e75..0000000000000 --- a/src/librustc_const_eval/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! constant evaluation on the HIR and code to validate patterns/matches -//! -//! # Note -//! -//! This API is completely unstable and subject to change. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] - -#![feature(rustc_diagnostic_macros)] -#![feature(slice_patterns)] -#![feature(box_patterns)] -#![feature(box_syntax)] -#![feature(i128_type)] -#![feature(from_ref)] - -extern crate arena; -#[macro_use] extern crate syntax; -#[macro_use] extern crate log; -#[macro_use] extern crate rustc; -extern crate rustc_const_math; -extern crate rustc_data_structures; -extern crate rustc_errors; -extern crate syntax_pos; - -// NB: This module needs to be declared first so diagnostics are -// registered before they are used. -mod diagnostics; - -mod eval; -mod _match; -pub mod check_match; -pub mod pattern; - -pub use eval::*; - -use rustc::ty::maps::Providers; - -pub fn provide(providers: &mut Providers) { - *providers = Providers { - check_match: check_match::check_match, - ..*providers - }; -} - -// Build the diagnostics array at the end so that the metadata includes error use sites. -#[cfg(not(stage0))] // remove after the next snapshot -__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 18493b8bb3940..1514acfcb212b 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -17,7 +17,6 @@ rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_back = { path = "../librustc_back" } rustc_borrowck = { path = "../librustc_borrowck" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 50c19b5a99a54..be0eab4d799a8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,7 @@ use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats}; -use rustc_const_eval::{self, check_match}; +use rustc_mir::const_eval::check_match; use super::Compilation; use serialize::json; @@ -922,7 +922,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) { ty::provide(providers); traits::provide(providers); reachable::provide(providers); - rustc_const_eval::provide(providers); rustc_passes::provide(providers); middle::region::provide(providers); cstore::provide(providers); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 05dcaf731352a..9522edd044da8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,7 +35,6 @@ extern crate rustc; extern crate rustc_allocator; extern crate rustc_back; extern crate rustc_borrowck; -extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_passes; @@ -1497,7 +1496,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry { // FIXME: need to figure out a way to get these back in here // all_errors.extend_from_slice(get_trans(sess).diagnostics()); all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 9fee2d54e4752..5ff891202dbc5 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -12,6 +12,6 @@ test = false [dependencies] log = "0.4" rustc = { path = "../librustc" } -rustc_const_eval = { path = "../librustc_const_eval" } +rustc_mir = { path = "../librustc_mir"} syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 699765dde03ff..80241665914fe 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -39,7 +39,7 @@ extern crate syntax; extern crate rustc; #[macro_use] extern crate log; -extern crate rustc_const_eval; +extern crate rustc_mir; extern crate syntax_pos; use rustc::lint; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index acb214173a5e6..6831ff919566d 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -15,7 +15,7 @@ use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; -use rustc_const_eval::ConstContext; +use rustc_mir::const_eval::ConstContext; use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index ea05a513f7e7d..90a0f18aba367 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -9,13 +9,13 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +arena = { path = "../libarena" } bitflags = "1.0" graphviz = { path = "../libgraphviz" } log = "0.4" log_settings = "0.1.1" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 57059cd31a1bc..4b73484306029 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -21,7 +21,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; use rustc_back::PanicStrategy; -use rustc_const_eval::pattern::{BindingMode, PatternKind}; +use const_eval::pattern::{BindingMode, PatternKind}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use shim; use std::mem; diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_mir/const_eval/_match.rs similarity index 99% rename from src/librustc_const_eval/_match.rs rename to src/librustc_mir/const_eval/_match.rs index 78e3ae9e0b551..ce14650e80cc5 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -13,15 +13,15 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc::middle::const_val::ConstVal; -use eval::{compare_const_vals}; +use const_eval::eval::{compare_const_vals}; use rustc_const_math::ConstInt; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; -use pattern::{FieldPattern, Pattern, PatternKind}; -use pattern::{PatternFoldable, PatternFolder}; +use const_eval::pattern::{FieldPattern, Pattern, PatternKind}; +use const_eval::pattern::{PatternFoldable, PatternFolder}; use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_mir/const_eval/check_match.rs similarity index 99% rename from src/librustc_const_eval/check_match.rs rename to src/librustc_mir/const_eval/check_match.rs index ae53ed0e1140d..ba8865f50fa6a 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_mir/const_eval/check_match.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; -use _match::Usefulness::*; -use _match::WitnessPreference::*; +use const_eval::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; +use const_eval::_match::Usefulness::*; +use const_eval::_match::WitnessPreference::*; -use pattern::{Pattern, PatternContext, PatternError, PatternKind}; +use const_eval::pattern::{Pattern, PatternContext, PatternError, PatternKind}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs similarity index 100% rename from src/librustc_const_eval/eval.rs rename to src/librustc_mir/const_eval/eval.rs diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs new file mode 100644 index 0000000000000..27356c2b0821f --- /dev/null +++ b/src/librustc_mir/const_eval/mod.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! constant evaluation on the HIR and code to validate patterns/matches + +mod eval; +mod _match; +pub mod check_match; +pub mod pattern; + +pub use self::eval::*; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs similarity index 97% rename from src/librustc_const_eval/pattern.rs rename to src/librustc_mir/const_eval/pattern.rs index f388808ab1d00..eff6897a3b2e3 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use eval; +use const_eval::eval; +use interpret::{const_val_field, const_discr}; use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; use rustc::mir::{Field, BorrowKind, Mutability}; @@ -693,7 +694,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { return match expr.node { hir::ExprLit(ref lit) => { let ty = self.tables.expr_ty(expr); - match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) { Ok(value) => PatternKind::Constant { value: self.tcx.mk_const(ty::Const { ty, @@ -716,7 +717,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { hir::ExprLit(ref lit) => lit, _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; - match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) { Ok(value) => PatternKind::Constant { value: self.tcx.mk_const(ty::Const { ty, @@ -782,9 +783,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { match cv.val { ConstVal::Value(val) => { - let discr = self.tcx.const_discr(self.param_env.and(( - instance, val, cv.ty - ))).unwrap(); + let discr = const_discr( + self.tcx, self.param_env, instance, val, cv.ty + ).unwrap(); let variant_index = adt_def .discriminants(self.tcx) .position(|var| var.to_u128_unchecked() == discr) @@ -801,8 +802,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { .map(|(i, _)| { let field = Field::new(i); let val = match cv.val { - ConstVal::Value(miri) => self.tcx.const_val_field( - self.param_env.and((instance, field, miri, cv.ty)), + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -844,8 +845,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 }, - ConstVal::Value(miri) => self.tcx.const_val_field( - self.param_env.and((instance, field, miri, cv.ty)), + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -862,8 +863,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], - ConstVal::Value(miri) => self.tcx.const_val_field( - self.param_env.and((instance, field, miri, cv.ty)), + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -882,8 +883,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let val = match cv.val { ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, - ConstVal::Value(miri) => self.tcx.const_val_field( - self.param_env.and((instance, field, miri, cv.ty)), + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 619c0dc847ebc..65d8922459f78 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -12,6 +12,553 @@ register_long_diagnostics! { + +E0001: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this +one is too specific or the ordering is incorrect. + +For example, the following `match` block has too many arms: + +``` +match Some(0) { + Some(bar) => {/* ... */} + x => {/* ... */} // This handles the `None` case + _ => {/* ... */} // All possible cases have already been handled +} +``` + +`match` blocks have their patterns matched in order, so, for example, putting +a wildcard arm above a more specific arm will make the latter arm irrelevant. + +Ensure the ordering of the match arm is correct and remove any superfluous +arms. +"##, + +E0002: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error indicates that an empty match expression is invalid because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. So, the following will work: + +``` +enum Empty {} + +fn foo(x: Empty) { + match x { + // empty + } +} +``` + +However, this won't: + +```compile_fail +fn foo(x: Option) { + match x { + // empty + } +} +``` +"##, + +E0003: r##" +#### Note: this error code is no longer emitted by the compiler. + +Not-a-Number (NaN) values cannot be compared for equality and hence can never +match the input to a match expression. So, the following will not compile: + +```compile_fail +const NAN: f32 = 0.0 / 0.0; + +let number = 0.1f32; + +match number { + NAN => { /* ... */ }, + _ => {} +} +``` + +To match against NaN values, you should instead use the `is_nan()` method in a +guard, like so: + +``` +let number = 0.1f32; + +match number { + x if x.is_nan() => { /* ... */ } + _ => {} +} +``` +"##, + +E0004: r##" +This error indicates that the compiler cannot guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. Erroneous code example: + +```compile_fail,E0004 +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered + Terminator::TalkToMyHand => {} +} +``` + +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". Example: + +``` +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { + Terminator::TalkToMyHand => {} + Terminator::HastaLaVistaBaby => {} +} + +// or: + +match x { + Terminator::TalkToMyHand => {} + _ => {} +} +``` +"##, + +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee +that a name will be extracted in all cases. Erroneous code example: + +```compile_fail,E0005 +let x = Some(1); +let Some(y) = x; +// error: refutable pattern in local binding: `None` not covered +``` + +If you encounter this error you probably need to use a `match` or `if let` to +deal with the possibility of failure. Example: + +``` +let x = Some(1); + +match x { + Some(y) => { + // do something + }, + None => {} +} + +// or: + +if let Some(y) = x { + // do something +} +``` +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code +like the following is invalid as it requires the entire `Option` to be +moved into a variable called `op_string` while simultaneously requiring the +inner `String` to be moved into a variable called `s`. + +```compile_fail,E0007 +let x = Some("s".to_string()); + +match x { + op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + None => {}, +} +``` + +See also the error E0303. +"##, + +E0008: r##" +Names bound in match arms retain their type in pattern guards. As such, if a +name is bound by move in a pattern, it should also be moved to wherever it is +referenced in the pattern guard code. Doing so however would prevent the name +from being available in the body of the match arm. Consider the following: + +```compile_fail,E0008 +match Some("hi".to_string()) { + Some(s) if s.len() == 0 => {}, // use s. + _ => {}, +} +``` + +The variable `s` has type `String`, and its use in the guard is as a variable of +type `String`. The guard code effectively executes in a separate scope to the +body of the arm, so the value would be moved into this anonymous scope and +therefore becomes unavailable in the body of the arm. + +The problem above can be solved by using the `ref` keyword. + +``` +match Some("hi".to_string()) { + Some(ref s) if s.len() == 0 => {}, + _ => {}, +} +``` + +Though this example seems innocuous and easy to solve, the problem becomes clear +when it encounters functions which consume the value: + +```compile_fail,E0008 +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a { + Some(y) if y.consume() > 0 => {} + _ => {} + } +} +``` + +In this situation, even the `ref` keyword cannot solve it, since borrowed +content cannot be moved. This problem cannot be solved generally. If the value +can be cloned, here is a not-so-specific solution: + +``` +#[derive(Clone)] +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a{ + Some(ref y) if y.clone().consume() > 0 => {} + _ => {} + } +} +``` + +If the value will be consumed in the pattern guard, using its clone will not +move its ownership, so the code works. +"##, + +E0009: r##" +In a pattern, all values that don't implement the `Copy` trait have to be bound +the same way. The goal here is to avoid binding simultaneously by-move and +by-ref. + +This limitation may be removed in a future version of Rust. + +Erroneous code example: + +```compile_fail,E0009 +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the + // same pattern + None => panic!() +} +``` + +You have two solutions: + +Solution #1: Bind the pattern's values the same way. + +``` +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((ref y, ref z)) => {}, + // or Some((y, z)) => {} + None => panic!() +} +``` + +Solution #2: Implement the `Copy` trait for the `X` structure. + +However, please keep in mind that the first solution should be preferred. + +``` +#[derive(Clone, Copy)] +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, + None => panic!() +} +``` +"##, + +E0158: r##" +`const` and `static` mean different things. A `const` is a compile-time +constant, an alias for a literal value. This property means you can match it +directly within a pattern. + +The `static` keyword, on the other hand, guarantees a fixed location in memory. +This does not always mean that the value is constant. For example, a global +mutex can be declared `static` as well. + +If you want to match against a `static`, consider using a guard instead: + +``` +static FORTY_TWO: i32 = 42; + +match Some(42) { + Some(x) if x == FORTY_TWO => {} + _ => {} +} +``` +"##, + +E0162: r##" +An if-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding instead. For instance: + +```compile_fail,E0162 +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +if let Irrefutable(x) = irr { + // This body will always be executed. + // ... +} +``` + +Try this instead: + +``` +struct Irrefutable(i32); +let irr = Irrefutable(0); + +let Irrefutable(x) = irr; +println!("{}", x); +``` +"##, + +E0165: r##" +A while-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding inside a `loop` instead. For instance: + +```compile_fail,E0165 +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +while let Irrefutable(x) = irr { + // ... +} +``` + +Try this instead: + +```no_run +struct Irrefutable(i32); +let irr = Irrefutable(0); + +loop { + let Irrefutable(x) = irr; + // ... +} +``` +"##, + +E0170: r##" +Enum variants are qualified by default. For example, given this type: + +``` +enum Method { + GET, + POST, +} +``` + +You would match it using: + +``` +enum Method { + GET, + POST, +} + +let m = Method::GET; + +match m { + Method::GET => {}, + Method::POST => {}, +} +``` + +If you don't qualify the names, the code will bind new variables named "GET" and +"POST" instead. This behavior is likely not what you want, so `rustc` warns when +that happens. + +Qualified names are good practice, and most code works well with them. But if +you prefer them unqualified, you can import the variants into scope: + +``` +use Method::*; +enum Method { GET, POST } +# fn main() {} +``` + +If you want others to be able to import variants from your module directly, use +`pub use`: + +``` +pub use Method::*; +pub enum Method { GET, POST } +# fn main() {} +``` +"##, + + +E0297: r##" +#### Note: this error code is no longer emitted by the compiler. + +Patterns used to bind names must be irrefutable. That is, they must guarantee +that a name will be extracted in all cases. Instead of pattern matching the +loop variable, consider using a `match` or `if let` inside the loop body. For +instance: + +```compile_fail,E0005 +let xs : Vec> = vec![Some(1), None]; + +// This fails because `None` is not covered. +for Some(x) in xs { + // ... +} +``` + +Match inside the loop instead: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + match item { + Some(x) => {}, + None => {}, + } +} +``` + +Or use `if let`: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + if let Some(x) = item { + // ... + } +} +``` +"##, + +E0301: r##" +Mutable borrows are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if mutable +borrows were allowed: + +```compile_fail,E0301 +match Some(()) { + None => { }, + option if option.take().is_none() => { + /* impossible, option is `Some` */ + }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0302: r##" +Assignments are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if assignments +were allowed: + +```compile_fail,E0302 +match Some(()) { + None => { }, + option if { option = None; false } => { }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +Before: + +```compile_fail,E0303 +match Some("hi".to_string()) { + ref op_string_ref @ Some(s) => {}, + None => {}, +} +``` + +After: + +``` +match Some("hi".to_string()) { + Some(ref s) => { + let op_string_ref = &Some(s); + // ... + }, + None => {}, +} +``` + +The `op_string_ref` binding has type `&Option<&String>` in both cases. + +See also https://github.com/rust-lang/rust/issues/14587 +"##, + E0010: r##" The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on @@ -1771,6 +2318,9 @@ b.resume(); } register_diagnostics! { +// E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) // E0385, // {} in an aliasable location E0493, // destructors cannot be evaluated at compile-time E0524, // two closures require unique access to `..` at the same time diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 09a31f9ab8fa5..329365c4415e8 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -27,7 +27,7 @@ use self::cx::Cx; pub mod cx; -pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; +pub use const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; #[derive(Copy, Clone, Debug)] pub enum LintLevel { diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index dddf447375068..a36f5ed6ebc59 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId; use rustc::mir; use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError}; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use rustc_const_eval::{lookup_const_by_id, ConstContext}; +use const_eval::{lookup_const_by_id, ConstContext}; use rustc::mir::Field; use rustc_data_structures::indexed_vec::Idx; @@ -306,16 +306,19 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { pub fn const_val_field<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, + param_env: ty::ParamEnv<'tcx>, + instance: ty::Instance<'tcx>, + field: mir::Field, + val: Value, + ty: Ty<'tcx>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { - trace!("const_val_field: {:#?}", key); - match const_val_field_inner(tcx, key) { + match const_val_field_inner(tcx, param_env, instance, field, val, ty) { Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { val: ConstVal::Value(field), ty, })), Err(err) => Err(ConstEvalErr { - span: tcx.def_span(key.value.0.def_id()), + span: tcx.def_span(instance.def_id()), kind: err.into(), }), } @@ -323,11 +326,14 @@ pub fn const_val_field<'a, 'tcx>( fn const_val_field_inner<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, + param_env: ty::ParamEnv<'tcx>, + instance: ty::Instance<'tcx>, + field: mir::Field, + value: Value, + ty: Ty<'tcx>, ) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { - trace!("const_val_field: {:#?}", key); - let (instance, field, value, ty) = key.value; - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); + let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let (mut field, ty) = match value { Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), Value::ByRef(ptr, align) => { @@ -348,11 +354,13 @@ fn const_val_field_inner<'a, 'tcx>( pub fn const_discr<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>, + param_env: ty::ParamEnv<'tcx>, + instance: ty::Instance<'tcx>, + value: Value, + ty: Ty<'tcx>, ) -> EvalResult<'tcx, u128> { - trace!("const_discr: {:#?}", key); - let (instance, value, ty) = key.value; - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty); + let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let (ptr, align) = match value { Value::ByValPair(..) | Value::ByVal(_) => { let layout = ecx.layout_of(ty)?; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 1699ad0f19cf6..aa6bc2639aaec 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -16,6 +16,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![deny(warnings)] +#![feature(slice_patterns)] +#![feature(from_ref)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] @@ -38,6 +40,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nonzero)] #![feature(underscore_lifetimes)] +extern crate arena; #[macro_use] extern crate bitflags; #[macro_use] extern crate log; @@ -52,7 +55,6 @@ extern crate syntax; extern crate syntax_pos; extern crate rustc_back; extern crate rustc_const_math; -extern crate rustc_const_eval; extern crate core; // for NonZero extern crate log_settings; extern crate rustc_apfloat; @@ -69,6 +71,7 @@ pub mod transform; pub mod util; pub mod interpret; pub mod monomorphize; +pub mod const_eval; use rustc::ty::maps::Providers; @@ -77,6 +80,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); providers.const_eval = interpret::const_eval_provider; + providers.check_match = const_eval::check_match::check_match; } #[cfg(not(stage0))] // remove after the next snapshot diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 776f330a58bdd..3f25c08aff537 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] log = "0.4" rustc = { path = "../librustc" } -rustc_const_eval = { path = "../librustc_const_eval" } +rustc_mir = { path = "../librustc_mir"} rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 9ded3a5a0e5de..f3462f60b3967 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -25,7 +25,7 @@ // by borrowck::gather_loans use rustc::ty::cast::CastKind; -use rustc_const_eval::ConstContext; +use rustc_mir::const_eval::ConstContext; use rustc::middle::const_val::ConstEvalErr; use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll}; use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 73c71ec0b2f00..2bb4cfcbe5231 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -23,7 +23,7 @@ #[macro_use] extern crate rustc; -extern crate rustc_const_eval; +extern crate rustc_mir; extern crate rustc_const_math; #[macro_use] From 0bd448b691b1dc28e723753efbfc48a68da8a236 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:26:37 +0100 Subject: [PATCH 005/115] Resolve variant field access --- src/librustc_mir/const_eval/pattern.rs | 8 ++++---- src/librustc_mir/interpret/const_eval.rs | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index eff6897a3b2e3..8fe5e1ee453c0 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -803,7 +803,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, field, miri, cv.ty, + self.tcx, self.param_env, instance, Some(variant_index), field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -846,7 +846,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 }, ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, field, miri, cv.ty, + self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -864,7 +864,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let val = match cv.val { ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, field, miri, cv.ty, + self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -884,7 +884,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, field, miri, cv.ty, + self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index a36f5ed6ebc59..3cb5d0a28790f 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -13,7 +13,7 @@ use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory, PlaceExtra}; use rustc_const_math::ConstInt; @@ -308,11 +308,12 @@ pub fn const_val_field<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, + variant: Option, field: mir::Field, val: Value, ty: Ty<'tcx>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { - match const_val_field_inner(tcx, param_env, instance, field, val, ty) { + match const_val_field_inner(tcx, param_env, instance, variant, field, val, ty) { Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { val: ConstVal::Value(field), ty, @@ -328,6 +329,7 @@ fn const_val_field_inner<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, + variant: Option, field: mir::Field, value: Value, ty: Ty<'tcx>, @@ -337,7 +339,11 @@ fn const_val_field_inner<'a, 'tcx>( let (mut field, ty) = match value { Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), Value::ByRef(ptr, align) => { - let place = Place::from_primval_ptr(ptr, align); + let place = Place::Ptr { + ptr, + align, + extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), + }; let layout = ecx.layout_of(ty)?; let (place, layout) = ecx.place_field(place, field, layout)?; let (ptr, align) = place.to_ptr_align(); From 15fac98f105579865e2609355230f2172e00c90c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:28:27 +0100 Subject: [PATCH 006/115] Nuke the entire ctfe from orbit, it's the only way to be sure --- src/librustc/ich/impls_ty.rs | 43 -- src/librustc/lint/builtin.rs | 14 + src/librustc/middle/const_val.rs | 38 +- src/librustc/mir/mod.rs | 26 +- src/librustc/ty/context.rs | 21 +- src/librustc/ty/error.rs | 4 - src/librustc/ty/flags.rs | 28 +- src/librustc/ty/mod.rs | 7 - src/librustc/ty/relate.rs | 4 - src/librustc/ty/structural_impls.rs | 69 +- src/librustc/ty/util.rs | 1 - src/librustc/ty/walk.rs | 28 +- src/librustc/ty/wf.rs | 26 +- src/librustc/util/ppaux.rs | 4 - src/librustc_driver/driver.rs | 7 + src/librustc_lint/builtin.rs | 71 -- src/librustc_lint/lib.rs | 2 - src/librustc_lint/types.rs | 87 +-- src/librustc_metadata/decoder.rs | 15 +- src/librustc_metadata/encoder.rs | 13 +- .../borrow_check/nll/type_check/mod.rs | 8 +- src/librustc_mir/build/expr/as_rvalue.rs | 22 +- src/librustc_mir/build/matches/test.rs | 3 +- src/librustc_mir/build/misc.rs | 55 +- src/librustc_mir/const_eval/_match.rs | 46 +- src/librustc_mir/const_eval/check.rs | 167 +++++ src/librustc_mir/const_eval/eval.rs | 707 +++--------------- src/librustc_mir/const_eval/mod.rs | 1 + src/librustc_mir/const_eval/pattern.rs | 215 +++--- src/librustc_mir/diagnostics.rs | 36 + src/librustc_mir/hair/cx/expr.rs | 36 +- src/librustc_mir/hair/cx/mod.rs | 174 +---- src/librustc_mir/interpret/const_eval.rs | 397 ++-------- src/librustc_mir/interpret/eval_context.rs | 33 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/place.rs | 8 +- src/librustc_mir/shim.rs | 26 +- src/librustc_mir/transform/elaborate_drops.rs | 3 +- src/librustc_mir/transform/generator.rs | 9 +- .../transform/simplify_branches.rs | 8 +- src/librustc_mir/util/elaborate_drops.rs | 6 +- src/librustc_passes/consts.rs | 103 +-- src/librustc_passes/diagnostics.rs | 35 - src/librustc_trans/mir/analyze.rs | 1 - src/librustc_trans/mir/constant.rs | 45 +- src/librustc_typeck/collect.rs | 1 - src/test/compile-fail/issue-31109.rs | 3 +- src/test/compile-fail/issue-39559-2.rs | 6 +- src/test/compile-fail/issue-41255.rs | 18 +- .../compile-fail/lint-exceeding-bitshifts.rs | 2 +- src/test/compile-fail/lint-type-overflow2.rs | 1 - .../rfc1445/match-forbidden-without-eq.rs | 3 +- src/test/compile-fail/thread-local-in-ctfe.rs | 2 - src/test/ui/const-eval-overflow-2.stderr | 2 +- 54 files changed, 633 insertions(+), 2059 deletions(-) create mode 100644 src/librustc_mir/const_eval/check.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 48a1902095c8c..e1434e9da7276 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -317,53 +317,10 @@ for ::middle::const_val::ConstVal<'gcx> { hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { use middle::const_val::ConstVal::*; - use middle::const_val::ConstAggregate::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { - Integral(ref value) => { - value.hash_stable(hcx, hasher); - } - Float(ref value) => { - value.hash_stable(hcx, hasher); - } - Str(ref value) => { - value.hash_stable(hcx, hasher); - } - ByteStr(ref value) => { - value.hash_stable(hcx, hasher); - } - Bool(value) => { - value.hash_stable(hcx, hasher); - } - Char(value) => { - value.hash_stable(hcx, hasher); - } - Variant(def_id) => { - def_id.hash_stable(hcx, hasher); - } - Function(def_id, substs) => { - def_id.hash_stable(hcx, hasher); - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - substs.hash_stable(hcx, hasher); - }); - } - Aggregate(Struct(ref name_values)) => { - let mut values = name_values.to_vec(); - values.sort_unstable_by_key(|&(ref name, _)| name.clone()); - values.hash_stable(hcx, hasher); - } - Aggregate(Tuple(ref value)) => { - value.hash_stable(hcx, hasher); - } - Aggregate(Array(ref value)) => { - value.hash_stable(hcx, hasher); - } - Aggregate(Repeat(ref value, times)) => { - value.hash_stable(hcx, hasher); - times.hash_stable(hcx, hasher); - } Unevaluated(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 0577800f3f411..bd6236b442bb6 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -16,6 +16,12 @@ use lint::{LintPass, LateLintPass, LintArray}; +declare_lint! { + pub EXCEEDING_BITSHIFTS, + Deny, + "shift exceeds the type's number of bits" +} + declare_lint! { pub CONST_ERR, Warn, @@ -252,6 +258,12 @@ declare_lint! { "hidden lifetime parameters are deprecated, try `Foo<'_>`" } +declare_lint! { + pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + Warn, + "floating-point literals cannot be used in patterns" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -260,6 +272,8 @@ pub struct HardwiredLints; impl LintPass for HardwiredLints { fn get_lints(&self) -> LintArray { lint_array!( + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + EXCEEDING_BITSHIFTS, UNUSED_IMPORTS, UNUSED_EXTERN_CRATES, UNUSED_QUALIFICATIONS, diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index cf322010e05c3..dd99305809c28 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -18,9 +18,7 @@ use mir::interpret::{Value, PrimVal}; use graphviz::IntoCow; use errors::DiagnosticBuilder; -use serialize::{self, Encodable, Encoder, Decodable, Decoder}; -use syntax::symbol::InternedString; -use syntax::ast; +use serialize; use syntax_pos::Span; use std::borrow::Cow; @@ -29,17 +27,7 @@ pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { - Integral(ConstInt), - Float(ConstFloat), - Str(InternedString), - ByteStr(ByteArray<'tcx>), - Bool(bool), - Char(char), - Variant(DefId), - Function(DefId, &'tcx Substs<'tcx>), - Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), - /// A miri value, currently only produced if --miri is enabled Value(Value), } @@ -50,32 +38,9 @@ pub struct ByteArray<'tcx> { impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {} -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub enum ConstAggregate<'tcx> { - Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]), - Tuple(&'tcx [&'tcx ty::Const<'tcx>]), - Array(&'tcx [&'tcx ty::Const<'tcx>]), - Repeat(&'tcx ty::Const<'tcx>, u64), -} - -impl<'tcx> Encodable for ConstAggregate<'tcx> { - fn encode(&self, _: &mut S) -> Result<(), S::Error> { - bug!("should never encode ConstAggregate::{:?}", self) - } -} - -impl<'tcx> Decodable for ConstAggregate<'tcx> { - fn decode(_: &mut D) -> Result { - bug!("should never decode ConstAggregate") - } -} - impl<'tcx> ConstVal<'tcx> { pub fn to_u128(&self) -> Option { match *self { - ConstVal::Integral(i) => i.to_u128(), - ConstVal::Bool(b) => Some(b as u128), - ConstVal::Char(ch) => Some(ch as u32 as u128), ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { Some(b) }, @@ -93,7 +58,6 @@ impl<'tcx> ConstVal<'tcx> { } pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { match *self { - ConstVal::Integral(ConstInt::Usize(i)) => i, ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { assert_eq!(b as u64 as u128, b); match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d542f2a9f72b4..2c95aebe0735b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -32,7 +32,6 @@ use ty::TypeAndMut; use util::ppaux; use std::slice; use hir::{self, InlineAsm}; -use std::ascii; use std::borrow::{Cow}; use std::cell::Ref; use std::fmt::{self, Debug, Formatter, Write}; @@ -1440,12 +1439,8 @@ impl<'tcx> Operand<'tcx> { ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: if tcx.sess.opts.debugging_opts.miri { - // ZST function type - ConstVal::Value(Value::ByVal(PrimVal::Undef)) - } else { - ConstVal::Function(def_id, substs) - }, + // ZST function type + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty }) }, @@ -1778,21 +1773,6 @@ impl<'tcx> Debug for Literal<'tcx> { fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { use middle::const_val::ConstVal::*; match const_val.val { - Float(f) => write!(fmt, "{:?}", f), - Integral(n) => write!(fmt, "{}", n), - Str(s) => write!(fmt, "{:?}", s), - ByteStr(bytes) => { - let escaped: String = bytes.data - .iter() - .flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char)) - .collect(); - write!(fmt, "b\"{}\"", escaped) - } - Bool(b) => write!(fmt, "{:?}", b), - Char(c) => write!(fmt, "{:?}", c), - Variant(def_id) | - Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), - Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Unevaluated(..) => write!(fmt, "{:?}", const_val), Value(val) => print_miri_value(val, const_val.ty, fmt), } @@ -1819,7 +1799,7 @@ fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { let alloc = tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .expect("miri alloc not found"); assert_eq!(len as usize as u128, len); let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 9fab7b9ebd786..7cd776c7ba584 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -54,7 +54,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; use arena::{TypedArena, DroplessArena}; -use rustc_const_math::{ConstInt, ConstUsize}; +use rustc_const_math::ConstUsize; use rustc_data_structures::indexed_vec::IndexVec; use std::any::Any; use std::borrow::Borrow; @@ -908,7 +908,7 @@ pub struct InterpretInterner<'tcx> { /// Reverse map of `alloc_cache` /// /// Multiple globals may share the same memory - global_cache: FxHashMap>>, + global_cache: FxHashMap>>, /// The AllocId to assign to the next new regular allocation. /// Always incremented, never gets smaller. @@ -958,20 +958,17 @@ impl<'tcx> InterpretInterner<'tcx> { pub fn cache( &mut self, global_id: interpret::GlobalId<'tcx>, - ptr: interpret::AllocId, + alloc_id: interpret::AllocId, ) { - if let interpret::PrimVal::Ptr(ptr) = ptr.primval { - assert!(ptr.offset == 0); - } - self.global_cache.entry(ptr).or_default().push(global_id); - if let Some(old) = self.alloc_cache.insert(global_id, ptr) { + self.global_cache.entry(alloc_id).or_default().push(global_id); + if let Some(old) = self.alloc_cache.insert(global_id, alloc_id) { bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old); } } pub fn get_globals( &self, - ptr: interpret::Pointer, + ptr: interpret::AllocId, ) -> &[interpret::GlobalId<'tcx>] { match self.global_cache.get(&ptr) { Some(v) => v, @@ -2047,11 +2044,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: if self.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))) - } else { - ConstVal::Integral(ConstInt::Usize(n)) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))), ty: self.types.usize }))) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 269a536821b88..5e5ae961cae6c 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -20,8 +20,6 @@ use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::Span; -use rustc_const_math::ConstInt; - use hir; #[derive(Clone, Copy, Debug)] @@ -195,8 +193,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { match n.val { - ConstVal::Integral(ConstInt::Usize(n)) => - format!("array of {} elements", n), ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => format!("array of {} elements", n), _ => "array".to_string(), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 60bf4afc2fc88..f067789771c59 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_val::{ConstVal, ConstAggregate}; +use middle::const_val::ConstVal; use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; @@ -218,31 +218,7 @@ impl FlagComputation { fn add_const(&mut self, constant: &ty::Const) { self.add_ty(constant.ty); match constant.val { - ConstVal::Integral(_) | - ConstVal::Float(_) | - ConstVal::Str(_) | - ConstVal::ByteStr(_) | - ConstVal::Bool(_) | - ConstVal::Char(_) | - ConstVal::Value(_) | - ConstVal::Variant(_) => {} - ConstVal::Function(_, substs) => { - self.add_substs(substs); - } - ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { - for &(_, v) in fields { - self.add_const(v); - } - } - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | - ConstVal::Aggregate(ConstAggregate::Array(fields)) => { - for v in fields { - self.add_const(v); - } - } - ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { - self.add_const(v); - } + ConstVal::Value(_) => {} ConstVal::Unevaluated(_, substs) => { self.add_flags(TypeFlags::HAS_PROJECTION); self.add_substs(substs); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 438b08e235b61..38f17cc8623ef 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1791,9 +1791,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); match tcx.const_eval(param_env.and((expr_did, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { - discr = v; - } Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. @@ -1844,10 +1841,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { ty::VariantDiscr::Explicit(expr_did) => { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); match tcx.const_eval(param_env.and((expr_did, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { - explicit_value = v; - break; - } Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 9ff9f1ebda7f1..38af96e49246a 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -481,7 +481,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, assert_eq!(sz_b.ty, tcx.types.usize); let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { match x.val { - ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. @@ -489,9 +488,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, match tcx.lift_to_global(&substs) { Some(substs) => { match tcx.const_eval(param_env.and((def_id, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { - return Ok(x.to_u64().unwrap()); - } Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d6c536e689530..ce56eda0c4d40 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -14,7 +14,7 @@ //! `BraceStructLiftImpl!`) to help with the tedium. use infer::type_variable; -use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr}; +use middle::const_val::{self, ConstVal, ConstEvalErr}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -1439,54 +1439,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ConstVal::Integral(i) => ConstVal::Integral(i), - ConstVal::Float(f) => ConstVal::Float(f), - ConstVal::Str(s) => ConstVal::Str(s), - ConstVal::ByteStr(b) => ConstVal::ByteStr(b), - ConstVal::Bool(b) => ConstVal::Bool(b), - ConstVal::Char(c) => ConstVal::Char(c), ConstVal::Value(v) => ConstVal::Value(v), - ConstVal::Variant(def_id) => ConstVal::Variant(def_id), - ConstVal::Function(def_id, substs) => { - ConstVal::Function(def_id, substs.fold_with(folder)) - } - ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { - let new_fields: Vec<_> = fields.iter().map(|&(name, v)| { - (name, v.fold_with(folder)) - }).collect(); - let fields = if new_fields == fields { - fields - } else { - folder.tcx().alloc_name_const_slice(&new_fields) - }; - ConstVal::Aggregate(ConstAggregate::Struct(fields)) - } - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => { - let new_fields: Vec<_> = fields.iter().map(|v| { - v.fold_with(folder) - }).collect(); - let fields = if new_fields == fields { - fields - } else { - folder.tcx().alloc_const_slice(&new_fields) - }; - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) - } - ConstVal::Aggregate(ConstAggregate::Array(fields)) => { - let new_fields: Vec<_> = fields.iter().map(|v| { - v.fold_with(folder) - }).collect(); - let fields = if new_fields == fields { - fields - } else { - folder.tcx().alloc_const_slice(&new_fields) - }; - ConstVal::Aggregate(ConstAggregate::Array(fields)) - } - ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => { - let v = v.fold_with(folder); - ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) - } ConstVal::Unevaluated(def_id, substs) => { ConstVal::Unevaluated(def_id, substs.fold_with(folder)) } @@ -1495,25 +1448,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - ConstVal::Integral(_) | - ConstVal::Float(_) | - ConstVal::Str(_) | - ConstVal::ByteStr(_) | - ConstVal::Bool(_) | - ConstVal::Char(_) | - ConstVal::Value(_) | - ConstVal::Variant(_) => false, - ConstVal::Function(_, substs) => substs.visit_with(visitor), - ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { - fields.iter().any(|&(_, v)| v.visit_with(visitor)) - } - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | - ConstVal::Aggregate(ConstAggregate::Array(fields)) => { - fields.iter().any(|v| v.visit_with(visitor)) - } - ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { - v.visit_with(visitor) - } + ConstVal::Value(_) => false, ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor), } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 713ca85998a1d..4348324b2b989 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -760,7 +760,6 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyArray(_, n) => { self.hash_discriminant_u8(&n.val); match n.val { - ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), _ => bug!("arrays should not have {:?} as length", n) diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 4ef7706c45e3e..722fdfe773a98 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -11,7 +11,7 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use middle::const_val::{ConstVal, ConstAggregate}; +use middle::const_val::ConstVal; use ty::{self, Ty}; use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -140,31 +140,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) { match constant.val { - ConstVal::Integral(_) | - ConstVal::Float(_) | - ConstVal::Str(_) | - ConstVal::ByteStr(_) | - ConstVal::Bool(_) | - ConstVal::Char(_) | - ConstVal::Value(_) | - ConstVal::Variant(_) => {} - ConstVal::Function(_, substs) => { - stack.extend(substs.types().rev()); - } - ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { - for &(_, v) in fields.iter().rev() { - push_const(stack, v); - } - } - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | - ConstVal::Aggregate(ConstAggregate::Array(fields)) => { - for v in fields.iter().rev() { - push_const(stack, v); - } - } - ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { - push_const(stack, v); - } + ConstVal::Value(_) => {} ConstVal::Unevaluated(_, substs) => { stack.extend(substs.types().rev()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 78fa1e1ed9148..46f58c6a37d5d 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use middle::const_val::{ConstVal, ConstAggregate}; +use middle::const_val::ConstVal; use infer::InferCtxt; use ty::subst::Substs; use traits; @@ -221,29 +221,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { self.require_sized(constant.ty, traits::ConstSized); match constant.val { - ConstVal::Integral(_) | - ConstVal::Float(_) | - ConstVal::Str(_) | - ConstVal::ByteStr(_) | - ConstVal::Bool(_) | - ConstVal::Char(_) | - ConstVal::Variant(_) | - ConstVal::Value(_) | - ConstVal::Function(..) => {} - ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { - for &(_, v) in fields { - self.compute_const(v); - } - } - ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | - ConstVal::Aggregate(ConstAggregate::Array(fields)) => { - for v in fields { - self.compute_const(v); - } - } - ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { - self.compute_const(v); - } + ConstVal::Value(_) => {} ConstVal::Unevaluated(def_id, substs) => { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2ec060aa2016e..0fa85b5045ea1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -27,7 +27,6 @@ use std::cell::Cell; use std::fmt; use std::usize; -use rustc_const_math::ConstInt; use rustc_data_structures::indexed_vec::Idx; use syntax::abi::Abi; use syntax::ast::CRATE_NODE_ID; @@ -1161,9 +1160,6 @@ define_print! { TyArray(ty, sz) => { print!(f, cx, write("["), print(ty), write("; "))?; match sz.val { - ConstVal::Integral(ConstInt::Usize(sz)) => { - write!(f, "{}", sz)?; - } ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { write!(f, "{}", sz)?; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index be0eab4d799a8..4478e0ea4fe2b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1072,6 +1072,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, stability::check_unused_or_stable_features(tcx) }); + + time(time_passes, + "MIR linting", + || for def_id in tcx.body_owners() { + mir::const_eval::check::check(tcx, def_id) + }); + time(time_passes, "lint checking", || lint::check_crate(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index de55710bdf3d0..b82014e873f27 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -682,77 +682,6 @@ impl EarlyLintPass for DeprecatedAttr { } } -declare_lint! { - pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - Warn, - "floating-point literals cannot be used in patterns" -} - -/// Checks for floating point literals in patterns. -#[derive(Clone)] -pub struct IllegalFloatLiteralPattern; - -impl LintPass for IllegalFloatLiteralPattern { - fn get_lints(&self) -> LintArray { - lint_array!(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN) - } -} - -fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) { - use self::ast::{ExprKind, LitKind}; - match expr.node { - ExprKind::Lit(ref l) => { - match l.node { - LitKind::FloatUnsuffixed(..) | - LitKind::Float(..) => { - cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - l.span, - "floating-point literals cannot be used in patterns"); - }, - _ => (), - } - } - // These may occur in patterns - // and can maybe contain float literals - ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f), - // Other kinds of exprs can't occur in patterns so we don't have to check them - // (ast_validation will emit an error if they occur) - _ => (), - } -} - -impl EarlyLintPass for IllegalFloatLiteralPattern { - fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) { - use self::ast::PatKind; - pat.walk(&mut |p| { - match p.node { - // Wildcard patterns and paths are uninteresting for the lint - PatKind::Wild | - PatKind::Path(..) => (), - - // The walk logic recurses inside these - PatKind::Ident(..) | - PatKind::Struct(..) | - PatKind::Tuple(..) | - PatKind::TupleStruct(..) | - PatKind::Ref(..) | - PatKind::Box(..) | - PatKind::Slice(..) => (), - - // Extract the expressions and check them - PatKind::Lit(ref e) => fl_lit_check_expr(cx, e), - PatKind::Range(ref st, ref en, _) => { - fl_lit_check_expr(cx, st); - fl_lit_check_expr(cx, en); - }, - - PatKind::Mac(_) => bug!("lint must run post-expansion"), - } - true - }); - } -} - declare_lint! { pub UNUSED_DOC_COMMENT, Warn, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 80241665914fe..4ccbc5d14704e 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -43,7 +43,6 @@ extern crate rustc_mir; extern crate syntax_pos; use rustc::lint; -use rustc::middle; use rustc::session; use rustc::util; @@ -107,7 +106,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedParens, UnusedImportBraces, AnonymousParameters, - IllegalFloatLiteralPattern, UnusedDocComment, ); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 6831ff919566d..1a00d97610756 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -14,9 +14,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; -use middle::const_val::ConstVal; -use rustc_mir::const_eval::ConstContext; -use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -44,12 +41,6 @@ declare_lint! { "literal out of range for its type" } -declare_lint! { - EXCEEDING_BITSHIFTS, - Deny, - "shift exceeds the type's number of bits" -} - declare_lint! { VARIANT_SIZE_DIFFERENCES, Allow, @@ -71,8 +62,7 @@ impl TypeLimits { impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_COMPARISONS, - OVERFLOWING_LITERALS, - EXCEEDING_BITSHIFTS) + OVERFLOWING_LITERALS) } } @@ -91,59 +81,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { e.span, "comparison is useless due to type limits"); } - - if binop.node.is_shift() { - let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty { - ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)), - ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)), - _ => None, - }; - - if let Some(bits) = opt_ty_bits { - let exceeding = if let hir::ExprLit(ref lit) = r.node { - if let ast::LitKind::Int(shift, _) = lit.node { - shift as u64 >= bits - } else { - false - } - } else { - // HACK(eddyb) This might be quite inefficient. - // This would be better left to MIR constant propagation, - // perhaps even at trans time (like is the case already - // when the value being shifted is *also* constant). - let parent_item = cx.tcx.hir.get_parent(e.id); - let parent_def_id = cx.tcx.hir.local_def_id(parent_item); - let substs = Substs::identity_for_item(cx.tcx, parent_def_id); - let const_cx = ConstContext::new(cx.tcx, - cx.param_env.and(substs), - cx.tables); - match const_cx.eval(&r) { - Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => { - i.is_negative() || - i.to_u64() - .map(|i| i >= bits) - .unwrap_or(true) - } - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - ty, - }) => { - if ty.is_signed() { - (b as i128) < 0 - } else { - b >= bits as u128 - } - } - _ => false, - } - }; - if exceeding { - cx.span_lint(EXCEEDING_BITSHIFTS, - e.span, - "bitshift exceeds the type's number of bits"); - } - }; - } } hir::ExprLit(ref lit) => { match cx.tables.node_id_to_type(e.hir_id).sty { @@ -261,28 +198,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } - fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 { - match int_ty { - ast::IntTy::Isize => int_ty_bits(isize_ty, isize_ty), - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16 as u64, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - } - } - - fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 { - match uint_ty { - ast::UintTy::Usize => uint_ty_bits(usize_ty, usize_ty), - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - } - } - fn check_limits(cx: &LateContext, binop: hir::BinOp, l: &hir::Expr, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0c780812bde99..427cd4a0ce976 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -281,8 +281,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx let pos = self.position(); match usize::decode(self)? { ::std::usize::MAX => { - let id = interpret_interner().reserve(); - let alloc_id = interpret::AllocId(id); + let alloc_id = interpret_interner().reserve(); trace!("creating alloc id {:?} at {}", alloc_id, pos); // insert early to allow recursive allocs self.interpret_alloc_cache.insert(pos, alloc_id); @@ -290,18 +289,12 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx let allocation = interpret::Allocation::decode(self)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner().intern_at_reserved(id, allocation); + interpret_interner().intern_at_reserved(alloc_id, allocation); let num = usize::decode(self)?; - let ptr = interpret::Pointer { - primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id, - offset: 0, - }), - }; for _ in 0..num { let glob = interpret::GlobalId::decode(self)?; - interpret_interner().cache(glob, ptr); + interpret_interner().cache(glob, alloc_id); } Ok(alloc_id) @@ -310,7 +303,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; trace!("decoded fn alloc instance: {:?}", instance); - let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance)); + let id = interpret_interner().create_fn_alloc(instance); trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index f57fad27f014f..ccdf1f3ca5cd8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -198,26 +198,21 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx // point to itself. self.interpret_alloc_shorthands.insert(*alloc_id, start); let interpret_interner = self.tcx.interpret_interner.borrow(); - if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + if let Some(alloc) = interpret_interner.get_alloc(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - let globals = interpret_interner.get_globals(interpret::Pointer { - primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id: *alloc_id, - offset: 0, - }), - }); + let globals = interpret_interner.get_globals(*alloc_id); globals.len().encode(self)?; for glob in globals { glob.encode(self)?; } - } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; } else { - bug!("alloc id without corresponding allocation: {}", alloc_id.0); + bug!("alloc id without corresponding allocation: {}", alloc_id); } Ok(()) } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ca6e598b402ec..2b0d5764958a2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -260,12 +260,11 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // would be lost if we just look at the normalized // value. let did = match value.val { - ConstVal::Function(def_id, ..) => Some(def_id), ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { self.tcx() .interpret_interner .borrow() - .get_fn(p.alloc_id.0) + .get_fn(p.alloc_id) .map(|instance| instance.def_id()) }, ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { @@ -1043,11 +1042,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }, .. }) => match val { - ConstVal::Function(def_id, _) => { - Some(def_id) == self.tcx().lang_items().box_free_fn() - }, ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { - let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0); + let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id); inst.map_or(false, |inst| { Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() }) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b5b8f8d7e78b0..ca6e7c2c41580 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -204,11 +204,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: this.hir.tcx().types.u32, literal: Literal::Value { value: this.hir.tcx().mk_const(ty::Const { - val: if this.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) - } else { - ConstVal::Integral(ConstInt::U32(0)) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), ty: this.hir.tcx().types.u32 }), }, @@ -406,11 +402,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: if self.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))) - } else { - ConstVal::Integral(val) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))), ty }) } @@ -448,13 +440,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: if self.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes( - val.to_u128_unchecked() - ))) - } else { - ConstVal::Integral(val) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes( + val.to_u128_unchecked() + ))), ty }) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index fafdee5b1e1b9..30c70ac30a70b 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -299,7 +299,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut val = Operand::Copy(place.clone()); let bytes = match value.val { - ConstVal::ByteStr(bytes) => Some(bytes.data), ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { let is_array_ptr = ty .builtin_deref(true, ty::NoPreference) @@ -310,7 +309,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .tcx() .interpret_interner .borrow() - .get_alloc(p.alloc_id.0) + .get_alloc(p.alloc_id) .map(|alloc| &alloc.bytes[..]) } else { None diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index efb367201189b..78c7004ef6034 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -13,13 +13,11 @@ use build::Builder; -use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; -use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -63,61 +61,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyChar => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: if self.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) - } else { - ConstVal::Char('\0') - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), ty }) } } - ty::TyUint(ity) => { - let val = match ity { - ast::UintTy::U8 => ConstInt::U8(0), - ast::UintTy::U16 => ConstInt::U16(0), - ast::UintTy::U32 => ConstInt::U32(0), - ast::UintTy::U64 => ConstInt::U64(0), - ast::UintTy::U128 => ConstInt::U128(0), - ast::UintTy::Usize => { - let uint_ty = self.hir.tcx().sess.target.usize_ty; - let val = ConstUsize::new(0, uint_ty).unwrap(); - ConstInt::Usize(val) - } - }; - - Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: if self.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) - } else { - ConstVal::Integral(val) - }, - ty - }) - } - } - ty::TyInt(ity) => { - let val = match ity { - ast::IntTy::I8 => ConstInt::I8(0), - ast::IntTy::I16 => ConstInt::I16(0), - ast::IntTy::I32 => ConstInt::I32(0), - ast::IntTy::I64 => ConstInt::I64(0), - ast::IntTy::I128 => ConstInt::I128(0), - ast::IntTy::Isize => { - let int_ty = self.hir.tcx().sess.target.isize_ty; - let val = ConstIsize::new(0, int_ty).unwrap(); - ConstInt::Isize(val) - } - }; - + ty::TyUint(_) | + ty::TyInt(_) => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: if self.hir.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) - } else { - ConstVal::Integral(val) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), ty }) } diff --git a/src/librustc_mir/const_eval/_match.rs b/src/librustc_mir/const_eval/_match.rs index ce14650e80cc5..974338393bfd1 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -15,8 +15,6 @@ use self::WitnessPreference::*; use rustc::middle::const_val::ConstVal; use const_eval::eval::{compare_const_vals}; -use rustc_const_math::ConstInt; - use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -182,20 +180,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { let tcx = self.tcx; self.byte_array_map.entry(pat).or_insert_with(|| { match pat.kind { - box PatternKind::Constant { - value: &ty::Const { val: ConstVal::ByteStr(b), .. } - } => { - b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern { - ty: tcx.types.u8, - span: pat.span, - kind: box PatternKind::Constant { - value: tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U8(b)), - ty: tcx.types.u8 - }) - } - })).collect() - } box PatternKind::Constant { value: &ty::Const { val: ConstVal::Value(b), ty } } => { @@ -209,7 +193,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { let alloc = tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .unwrap(); assert_eq!(ptr.offset, 0); // FIXME: check length @@ -458,11 +442,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyBool => { [true, false].iter().map(|&b| { ConstantValue(cx.tcx.mk_const(ty::Const { - val: if cx.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))) - } else { - ConstVal::Bool(b) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))), ty: cx.tcx.types.bool })) }).collect() @@ -575,9 +555,6 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( for row in patterns { match *row.kind { - PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { - max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); - } PatternKind::Constant { value: &ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), @@ -592,7 +569,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( let alloc = cx.tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .unwrap(); max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); } @@ -971,7 +948,6 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, suffix: &[Pattern]) -> Result { let data: &[u8] = match *ctor { - ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, ConstantValue(&ty::Const { val: ConstVal::Value( Value::ByVal(PrimVal::Ptr(ptr)) ), ty }) => { @@ -983,7 +959,7 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .unwrap() .bytes .as_ref() @@ -1002,11 +978,6 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, { match pat.kind { box PatternKind::Constant { value } => match value.val { - ConstVal::Integral(ConstInt::U8(u)) => { - if u != *ch { - return Ok(false); - } - }, ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { assert_eq!(b as u8 as u128, b); if b as u8 != *ch { @@ -1120,13 +1091,6 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Constant { value } => { match *constructor { Slice(..) => match value.val { - ConstVal::ByteStr(b) => { - if wild_patterns.len() == b.data.len() { - Some(cx.lower_byte_str_pattern(pat)) - } else { - None - } - } ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { let is_array_ptr = value.ty .builtin_deref(true, ty::NoPreference) @@ -1136,7 +1100,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( let data_len = cx.tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .unwrap() .bytes .len(); diff --git a/src/librustc_mir/const_eval/check.rs b/src/librustc_mir/const_eval/check.rs new file mode 100644 index 0000000000000..70435c16ff72e --- /dev/null +++ b/src/librustc_mir/const_eval/check.rs @@ -0,0 +1,167 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Lints statically known runtime failures + +use rustc::mir::*; +use rustc::mir::visit::Visitor; +use rustc::mir::interpret::{Value, PrimVal}; +use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind}; +use rustc::traits; +use interpret::{eval_body_as_integer, check_body}; +use rustc::ty::{TyCtxt, ParamEnv, self}; +use rustc::ty::Instance; +use rustc::ty::layout::LayoutOf; +use rustc::hir::def_id::DefId; + +pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { + if tcx.is_closure(def_id) { + return; + } + let generics = tcx.generics_of(def_id); + // FIXME: miri should be able to eval stuff that doesn't need info + // from the generics + if generics.parent_types as usize + generics.types.len() > 0 { + return; + } + let mir = &tcx.optimized_mir(def_id); + ConstErrVisitor { + tcx, + def_id, + mir, + }.visit_mir(mir); + let param_env = ParamEnv::empty(traits::Reveal::All); + let instance = Instance::mono(tcx, def_id); + for i in 0.. mir.promoted.len() { + use rustc_data_structures::indexed_vec::Idx; + check_body(tcx, instance, Some(Promoted::new(i)), param_env); + } +} + +struct ConstErrVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> { + fn eval_op(&self, op: &Operand<'tcx>) -> Option { + let op = match *op { + Operand::Constant(ref c) => c, + _ => return None, + }; + let param_env = ParamEnv::empty(traits::Reveal::All); + let val = match op.literal { + Literal::Value { value } => match value.val { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => b, + _ => return None, + }, + Literal::Promoted { index } => { + let instance = Instance::mono(self.tcx, self.def_id); + eval_body_as_integer(self.tcx, param_env, instance, Some(index)).unwrap() + } + }; + Some(val) + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstErrVisitor<'a, 'tcx> { + fn visit_terminator(&mut self, + block: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location) { + self.super_terminator(block, terminator, location); + match terminator.kind { + TerminatorKind::Assert { cond: Operand::Constant(box Constant { + literal: Literal::Value { + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))), + .. } + }, .. + }), expected, ref msg, .. } if (cond == 1) != expected => { + assert!(cond <= 1); + // If we know we always panic, and the error message + // is also constant, then we can produce a warning. + + let kind = match *msg { + AssertMessage::BoundsCheck { ref len, ref index } => { + let len = match self.eval_op(len) { + Some(val) => val, + None => return, + }; + let index = match self.eval_op(index) { + Some(val) => val, + None => return, + }; + ErrKind::IndexOutOfBounds { + len: len as u64, + index: index as u64 + } + } + AssertMessage::Math(ref err) => ErrKind::Math(err.clone()), + AssertMessage::GeneratorResumedAfterReturn | + // FIXME(oli-obk): can we report a const_err warning here? + AssertMessage::GeneratorResumedAfterPanic => return, + }; + let span = terminator.source_info.span; + let msg = ConstEvalErr{ span, kind }; + let scope_info = match self.mir.visibility_scope_info { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return, + }; + let node_id = scope_info[terminator.source_info.scope].lint_root; + self.tcx.lint_node(::rustc::lint::builtin::CONST_ERR, + node_id, + msg.span, + &msg.description().into_oneline().into_owned()); + }, + _ => {}, + } + } + fn visit_rvalue(&mut self, + rvalue: &Rvalue<'tcx>, + location: Location) { + self.super_rvalue(rvalue, location); + use rustc::mir::BinOp; + match *rvalue { + Rvalue::BinaryOp(BinOp::Shr, ref lop, ref rop) | + Rvalue::BinaryOp(BinOp::Shl, ref lop, ref rop) => { + let val = match self.eval_op(rop) { + Some(val) => val, + None => return, + }; + let ty = lop.ty(self.mir, self.tcx); + let param_env = ParamEnv::empty(traits::Reveal::All); + let bits = (self.tcx, param_env).layout_of(ty).unwrap().size.bits(); + if val >= bits as u128 { + let data = &self.mir[location.block]; + let stmt_idx = location.statement_index; + let source_info = if stmt_idx < data.statements.len() { + data.statements[stmt_idx].source_info + } else { + data.terminator().source_info + }; + let span = source_info.span; + let scope_info = match self.mir.visibility_scope_info { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return, + }; + let node_id = scope_info[source_info.scope].lint_root; + self.tcx.lint_node( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + node_id, + span, + "bitshift exceeds the type's number of bits"); + } + } + _ => {} + } + } +} diff --git a/src/librustc_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs index 70d5854986de3..370b8681ba648 100644 --- a/src/librustc_mir/const_eval/eval.rs +++ b/src/librustc_mir/const_eval/eval.rs @@ -9,41 +9,18 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; -use rustc::middle::const_val::ConstAggregate::*; use rustc::middle::const_val::ErrKind::*; -use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind}; +use rustc::middle::const_val::{ConstVal, ErrKind}; -use rustc::hir::map::blocks::FnLikeNode; -use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::util::IntTypeExt; -use rustc::ty::subst::{Substs, Subst}; -use rustc::util::common::ErrorReported; -use rustc::util::nodemap::NodeMap; +use rustc::ty::subst::Substs; -use syntax::abi::Abi; use syntax::ast; -use syntax::attr; -use rustc::hir::{self, Expr}; use std::cmp::Ordering; use rustc_const_math::*; -macro_rules! signal { - ($e:expr, $exn:expr) => { - return Err(ConstEvalErr { span: $e.span, kind: $exn }) - } -} - -macro_rules! math { - ($e:expr, $op:expr) => { - match $op { - Ok(val) => val, - Err(e) => signal!($e, ErrKind::from(e)), - } - } -} /// * `DefId` is the id of the constant. /// * `Substs` is the monomorphized substitutions for the expression. @@ -58,591 +35,94 @@ pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ).map(|instance| (instance.def_id(), instance.substs)) } -pub struct ConstContext<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - tables: &'a ty::TypeckTables<'tcx>, - param_env: ty::ParamEnv<'tcx>, - substs: &'tcx Substs<'tcx>, - fn_args: Option>> -} - -impl<'a, 'tcx> ConstContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, - tables: &'a ty::TypeckTables<'tcx>) - -> Self { - ConstContext { - tcx, - param_env: param_env_and_substs.param_env, - tables, - substs: param_env_and_substs.value, - fn_args: None - } - } - - /// Evaluate a constant expression in a context where the expression isn't - /// guaranteed to be evaluable. - pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> { - if self.tables.tainted_by_errors { - signal!(e, TypeckError); - } - eval_const_expr_partial(self, e) - } -} - -type CastResult<'tcx> = Result, ErrKind<'tcx>>; - -fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, - e: &'tcx Expr) -> EvalResult<'tcx> { - trace!("eval_const_expr_partial: {:?}", e); - let tcx = cx.tcx; - let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs); - let mk_const = |val| tcx.mk_const(ty::Const { val, ty }); - - let result = match e.node { - hir::ExprUnary(hir::UnNeg, ref inner) => { - // unary neg literals already got their sign during creation - if let hir::ExprLit(ref lit) = inner.node { - return match lit_to_const(&lit.node, tcx, ty, true) { - Ok(val) => Ok(mk_const(val)), - Err(err) => signal!(e, err), - }; - } - mk_const(match cx.eval(inner)?.val { - Float(f) => Float(-f), - Integral(i) => Integral(math!(e, -i)), - _ => signal!(e, TypeckError) - }) - } - hir::ExprUnary(hir::UnNot, ref inner) => { - mk_const(match cx.eval(inner)?.val { - Integral(i) => Integral(math!(e, !i)), - Bool(b) => Bool(!b), - _ => signal!(e, TypeckError) - }) - } - hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")), - hir::ExprBinary(op, ref a, ref b) => { - // technically, if we don't have type hints, but integral eval - // gives us a type through a type-suffix, cast or const def type - // we need to re-eval the other value of the BinOp if it was - // not inferred - mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) { - (Float(a), Float(b)) => { - use std::cmp::Ordering::*; - match op.node { - hir::BiAdd => Float(math!(e, a + b)), - hir::BiSub => Float(math!(e, a - b)), - hir::BiMul => Float(math!(e, a * b)), - hir::BiDiv => Float(math!(e, a / b)), - hir::BiRem => Float(math!(e, a % b)), - hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal), - hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less), - hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater), - hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), - hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), - hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), - _ => span_bug!(e.span, "typeck error"), - } - } - (Integral(a), Integral(b)) => { - use std::cmp::Ordering::*; - match op.node { - hir::BiAdd => Integral(math!(e, a + b)), - hir::BiSub => Integral(math!(e, a - b)), - hir::BiMul => Integral(math!(e, a * b)), - hir::BiDiv => Integral(math!(e, a / b)), - hir::BiRem => Integral(math!(e, a % b)), - hir::BiBitAnd => Integral(math!(e, a & b)), - hir::BiBitOr => Integral(math!(e, a | b)), - hir::BiBitXor => Integral(math!(e, a ^ b)), - hir::BiShl => Integral(math!(e, a << b)), - hir::BiShr => Integral(math!(e, a >> b)), - hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal), - hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less), - hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater), - hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal), - hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less), - hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater), - _ => span_bug!(e.span, "typeck error"), - } - } - (Bool(a), Bool(b)) => { - Bool(match op.node { - hir::BiAnd => a && b, - hir::BiOr => a || b, - hir::BiBitXor => a ^ b, - hir::BiBitAnd => a & b, - hir::BiBitOr => a | b, - hir::BiEq => a == b, - hir::BiNe => a != b, - hir::BiLt => a < b, - hir::BiLe => a <= b, - hir::BiGe => a >= b, - hir::BiGt => a > b, - _ => span_bug!(e.span, "typeck error"), - }) - } - (Char(a), Char(b)) => { - Bool(match op.node { - hir::BiEq => a == b, - hir::BiNe => a != b, - hir::BiLt => a < b, - hir::BiLe => a <= b, - hir::BiGe => a >= b, - hir::BiGt => a > b, - _ => span_bug!(e.span, "typeck error"), - }) - } - - _ => signal!(e, MiscBinaryOp), - }) - } - hir::ExprCast(ref base, _) => { - let base_val = cx.eval(base)?; - let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs); - if ty == base_ty { - base_val - } else { - match cast_const(tcx, base_val.val, ty) { - Ok(val) => mk_const(val), - Err(kind) => signal!(e, kind), - } - } - } - hir::ExprPath(ref qpath) => { - let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs); - match cx.tables.qpath_def(qpath, e.hir_id) { - Def::Const(def_id) | - Def::AssociatedConst(def_id) => { - let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env); - match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - }, - Def::VariantCtor(variant_def, CtorKind::Const) => { - mk_const(Variant(variant_def)) - } - Def::VariantCtor(_, CtorKind::Fn) => { - signal!(e, UnimplementedConstVal("enum variants")); - } - Def::StructCtor(_, CtorKind::Const) => { - mk_const(Aggregate(Struct(&[]))) - } - Def::StructCtor(_, CtorKind::Fn) => { - signal!(e, UnimplementedConstVal("tuple struct constructors")) - } - Def::Local(id) => { - debug!("Def::Local({:?}): {:?}", id, cx.fn_args); - if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) { - val - } else { - signal!(e, NonConstPath); - } - }, - Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)), - Def::Err => span_bug!(e.span, "typeck error"), - _ => signal!(e, NonConstPath), - } - } - hir::ExprCall(ref callee, ref args) => { - let (def_id, substs) = match cx.eval(callee)?.val { - Function(def_id, substs) => (def_id, substs), - _ => signal!(e, TypeckError), - }; - - if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { - let layout_of = |ty: Ty<'tcx>| { - let ty = tcx.erase_regions(&ty); - tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| { - ConstEvalErr { span: e.span, kind: LayoutError(err) } - }) - }; - match &tcx.item_name(def_id)[..] { - "size_of" => { - let size = layout_of(substs.type_at(0))?.size.bytes(); - return Ok(mk_const(Integral(Usize(ConstUsize::new(size, - tcx.sess.target.usize_ty).unwrap())))); - } - "min_align_of" => { - let align = layout_of(substs.type_at(0))?.align.abi(); - return Ok(mk_const(Integral(Usize(ConstUsize::new(align, - tcx.sess.target.usize_ty).unwrap())))); - } - "type_id" => { - let type_id = tcx.type_id_hash(substs.type_at(0)); - return Ok(mk_const(Integral(U64(type_id)))); - } - _ => signal!(e, TypeckError) - } - } - - let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { - if fn_like.constness() == hir::Constness::Const { - tcx.hir.body(fn_like.body()) - } else { - signal!(e, TypeckError) - } - } else { - signal!(e, TypeckError) - } - } else { - if tcx.is_const_fn(def_id) { - tcx.extern_const_body(def_id).body - } else { - signal!(e, TypeckError) - } - }; - - let arg_ids = body.arguments.iter().map(|arg| match arg.pat.node { - hir::PatKind::Binding(_, canonical_id, _, _) => Some(canonical_id), - _ => None - }).collect::>(); - assert_eq!(arg_ids.len(), args.len()); - - let mut call_args = NodeMap(); - for (arg, arg_expr) in arg_ids.into_iter().zip(args.iter()) { - let arg_val = cx.eval(arg_expr)?; - debug!("const call arg: {:?}", arg); - if let Some(id) = arg { - assert!(call_args.insert(id, arg_val).is_none()); - } - } - debug!("const call({:?})", call_args); - let callee_cx = ConstContext { - tcx, - param_env: cx.param_env, - tables: tcx.typeck_tables_of(def_id), - substs, - fn_args: Some(call_args) - }; - callee_cx.eval(&body.value)? - }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) { - Ok(val) => mk_const(val), - Err(err) => signal!(e, err), - }, - hir::ExprBlock(ref block) => { - match block.expr { - Some(ref expr) => cx.eval(expr)?, - None => mk_const(Aggregate(Tuple(&[]))), - } - } - hir::ExprType(ref e, _) => cx.eval(e)?, - hir::ExprTup(ref fields) => { - let values = fields.iter().map(|e| cx.eval(e)).collect::, _>>()?; - mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values)))) - } - hir::ExprStruct(_, ref fields, _) => { - mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| { - cx.eval(&f.expr).map(|v| (f.name.node, v)) - }).collect::, _>>()?)))) - } - hir::ExprIndex(ref arr, ref idx) => { - if !tcx.sess.features.borrow().const_indexing { - signal!(e, IndexOpFeatureGated); - } - let arr = cx.eval(arr)?; - let idx = match cx.eval(idx)?.val { - Integral(Usize(i)) => i.as_u64(), - _ => signal!(idx, IndexNotUsize), - }; - assert_eq!(idx as usize as u64, idx); - match arr.val { - Aggregate(Array(v)) => { - if let Some(&elem) = v.get(idx as usize) { - elem - } else { - let n = v.len() as u64; - signal!(e, IndexOutOfBounds { len: n, index: idx }) - } - } - - Aggregate(Repeat(.., n)) if idx >= n => { - signal!(e, IndexOutOfBounds { len: n, index: idx }) - } - Aggregate(Repeat(elem, _)) => elem, - - ByteStr(b) if idx >= b.data.len() as u64 => { - signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx }) - } - ByteStr(b) => { - mk_const(Integral(U8(b.data[idx as usize]))) - }, - - _ => signal!(e, IndexedNonVec), - } - } - hir::ExprArray(ref v) => { - let values = v.iter().map(|e| cx.eval(e)).collect::, _>>()?; - mk_const(Aggregate(Array(tcx.alloc_const_slice(&values)))) - } - hir::ExprRepeat(ref elem, _) => { - let n = match ty.sty { - ty::TyArray(_, n) => n.val.unwrap_u64(), - _ => span_bug!(e.span, "typeck error") - }; - mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) - }, - hir::ExprTupField(ref base, index) => { - if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { - fields[index.node] - } else { - span_bug!(base.span, "{:#?}", cx.eval(base)?.val); - //signal!(base, ExpectedConstTuple); - } - } - hir::ExprField(ref base, field_name) => { - if let Aggregate(Struct(fields)) = cx.eval(base)?.val { - if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) { - f - } else { - signal!(e, MissingStructField); - } - } else { - signal!(base, ExpectedConstStruct); - } - } - hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")), - _ => signal!(e, MiscCatchAll) - }; - - Ok(result) -} - -fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - val: ConstInt, - ty: Ty<'tcx>) - -> CastResult<'tcx> { - let v = val.to_u128_unchecked(); - match ty.sty { - ty::TyBool if v == 0 => Ok(Bool(false)), - ty::TyBool if v == 1 => Ok(Bool(true)), - ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))), - ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))), - ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))), - ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))), - ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))), - ty::TyInt(ast::IntTy::Isize) => { - Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty)))) - }, - ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))), - ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))), - ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))), - ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))), - ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))), - ty::TyUint(ast::UintTy::Usize) => { - Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty)))) - }, - ty::TyFloat(fty) => { - if let Some(i) = val.to_u128() { - Ok(Float(ConstFloat::from_u128(i, fty))) - } else { - // The value must be negative, go through signed integers. - let i = val.to_u128_unchecked() as i128; - Ok(Float(ConstFloat::from_i128(i, fty))) - } - } - ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), - ty::TyChar => match val { - U8(u) => Ok(Char(u as char)), - _ => bug!(), - }, - _ => Err(CannotCast), - } -} - -fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - val: ConstFloat, - ty: Ty<'tcx>) -> CastResult<'tcx> { - let int_width = |ty| { - ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize - }; - match ty.sty { - ty::TyInt(ity) => { - if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) { - cast_const_int(tcx, I128(i), ty) - } else { - Err(CannotCast) - } - } - ty::TyUint(uty) => { - if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) { - cast_const_int(tcx, U128(i), ty) - } else { - Err(CannotCast) - } - } - ty::TyFloat(fty) => Ok(Float(val.convert(fty))), - _ => Err(CannotCast), - } -} - -fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - val: ConstVal<'tcx>, - ty: Ty<'tcx>) - -> CastResult<'tcx> { - match val { - Integral(i) => cast_const_int(tcx, i, ty), - Bool(b) => cast_const_int(tcx, U8(b as u8), ty), - Float(f) => cast_const_float(tcx, f, ty), - Char(c) => cast_const_int(tcx, U32(c as u32), ty), - Variant(v) => { - let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap()); - let idx = adt.variant_index_with_id(v); - cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) - } - Function(..) => Err(UnimplementedConstVal("casting fn pointers")), - ByteStr(b) => match ty.sty { - ty::TyRawPtr(_) => { - Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) - }, - ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { - ty::TyArray(ty, n) => { - let n = n.val.unwrap_u64(); - if ty == tcx.types.u8 && n == b.data.len() as u64 { - Ok(val) - } else { - Err(CannotCast) - } - } - ty::TySlice(_) => { - Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")) - }, - _ => Err(CannotCast), - }, - _ => Err(CannotCast), - }, - Str(s) => match ty.sty { - ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")), - ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { - ty::TyStr => Ok(Str(s)), - _ => Err(CannotCast), - }, - _ => Err(CannotCast), - }, - _ => Err(CannotCast), - } -} - pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut ty: Ty<'tcx>, + ty: Ty<'tcx>, neg: bool) -> Result, ErrKind<'tcx>> { use syntax::ast::*; - use syntax::ast::LitIntType::*; - if tcx.sess.opts.debugging_opts.miri { - use rustc::mir::interpret::*; - let lit = match *lit { - LitKind::Str(ref s, _) => { - let s = s.as_str(); - let id = tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(AllocId(id), 0); - Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - ) - }, - LitKind::ByteStr(ref data) => { - let id = tcx.allocate_cached(data); - let ptr = MemoryPointer::new(AllocId(id), 0); - Value::ByVal(PrimVal::Ptr(ptr)) - }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), - LitKind::Int(n, _) if neg => { - let n = n as i128; - let n = n.overflowing_neg().0; - Value::ByVal(PrimVal::Bytes(n as u128)) - }, - LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)), - LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::FloatUnsuffixed(n) => { - let fty = match ty.sty { - ty::TyFloat(fty) => fty, - _ => bug!() - }; - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), - }; - return Ok(ConstVal::Value(lit)); - } - - if let ty::TyAdt(adt, _) = ty.sty { - if adt.is_enum() { - ty = adt.repr.discr_type().to_ty(tcx) - } - } - - match *lit { - LitKind::Str(ref s, _) => Ok(Str(s.as_str())), - LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })), - LitKind::Byte(n) => Ok(Integral(U8(n))), - LitKind::Int(n, hint) => { - match (&ty.sty, hint) { - (&ty::TyInt(ity), _) | - (_, Signed(ity)) => { - let mut n = n as i128; - if neg { - n = n.overflowing_neg().0; - } - Ok(Integral(ConstInt::new_signed_truncating(n, - ity, tcx.sess.target.isize_ty))) - } - (&ty::TyUint(uty), _) | - (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n, - uty, tcx.sess.target.usize_ty))) - } - _ => bug!() - } - } + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(id, 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(id, 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) => { + enum Int { + Signed(IntTy), + Unsigned(UintTy), + } + let ty = match ty.sty { + ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty), + ty::TyInt(other) => Int::Signed(other), + ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), + ty::TyUint(other) => Int::Unsigned(other), + _ => bug!(), + }; + let n = match ty { + // FIXME(oli-obk): are these casts correct? + Int::Signed(IntTy::I8) if neg => + (n as i128 as i8).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I16) if neg => + (n as i128 as i16).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I32) if neg => + (n as i128 as i32).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I64) if neg => + (n as i128 as i64).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I128) if neg => + (n as i128).overflowing_neg().0 as u128, + Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, + Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, + Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, + Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, + Int::Signed(IntTy::I128) => n, + Int::Unsigned(UintTy::U8) => n as u8 as u128, + Int::Unsigned(UintTy::U16) => n as u16 as u128, + Int::Unsigned(UintTy::U32) => n as u32 as u128, + Int::Unsigned(UintTy::U64) => n as u64 as u128, + Int::Unsigned(UintTy::U128) => n, + _ => bug!(), + }; + Value::ByVal(PrimVal::Bytes(n)) + }, LitKind::Float(n, fty) => { - let mut f = parse_float(&n.as_str(), fty)?; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; if neg { f = -f; } - Ok(Float(f)) + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - let mut f = parse_float(&n.as_str(), fty)?; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; if neg { f = -f; } - Ok(Float(f)) + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) } - LitKind::Bool(b) => Ok(Bool(b)), - LitKind::Char(c) => Ok(Char(c)), - } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + Ok(ConstVal::Value(lit)) } fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) @@ -657,41 +137,26 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option a.try_cmp(b).ok(), - (&Char(a), &Char(b)) => Some(a.cmp(&b)), (&Value(Value::ByVal(PrimVal::Bytes(a))), &Value(Value::ByVal(PrimVal::Bytes(b)))) => { - Some(if ty.is_signed() { - (a as i128).cmp(&(b as i128)) - } else { - a.cmp(&b) - }) + match ty.sty { + ty::TyFloat(ty) => { + let l = ConstFloat { + bits: a, + ty, + }; + let r = ConstFloat { + bits: b, + ty, + }; + // FIXME(oli-obk): report cmp errors? + l.try_cmp(r).ok() + }, + ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), + _ => Some(a.cmp(&b)), + } }, _ if a == b => Some(Ordering::Equal), _ => None, } } - -impl<'a, 'tcx> ConstContext<'a, 'tcx> { - pub fn compare_lit_exprs(&self, - a: &'tcx Expr, - b: &'tcx Expr) -> Result, ErrorReported> { - let tcx = self.tcx; - let ty = self.tables.expr_ty(a); - let a = match self.eval(a) { - Ok(a) => a, - Err(e) => { - e.report(tcx, a.span, "expression"); - return Err(ErrorReported); - } - }; - let b = match self.eval(b) { - Ok(b) => b, - Err(e) => { - e.report(tcx, b.span, "expression"); - return Err(ErrorReported); - } - }; - Ok(compare_const_vals(&a.val, &b.val, ty)) - } -} diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index 27356c2b0821f..f47dc61c27c4d 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -14,5 +14,6 @@ mod eval; mod _match; pub mod check_match; pub mod pattern; +pub mod check; pub use self::eval::*; diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 8fe5e1ee453c0..e657a280e7f5c 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use const_eval::eval; use interpret::{const_val_field, const_discr}; -use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; @@ -19,6 +18,7 @@ use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; +use const_eval::eval::compare_const_vals; use rustc_data_structures::indexed_vec::Idx; @@ -114,16 +114,7 @@ pub enum PatternKind<'tcx> { fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { match value.val { - ConstVal::Float(ref x) => write!(f, "{}", x), - ConstVal::Integral(ref i) => write!(f, "{}", i), - ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), - ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), - ConstVal::Bool(b) => write!(f, "{:?}", b), - ConstVal::Char(c) => write!(f, "{:?}", c), ConstVal::Value(v) => print_miri_value(v, value.ty, f), - ConstVal::Variant(_) | - ConstVal::Function(..) | - ConstVal::Aggregate(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } @@ -366,10 +357,27 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Lit(ref value) => self.lower_lit(value), - PatKind::Range(ref lo, ref hi, end) => { - match (self.lower_lit(lo), self.lower_lit(hi)) { + PatKind::Range(ref lo_expr, ref hi_expr, end) => { + match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { + use std::cmp::Ordering; + match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { + (RangeEnd::Excluded, Ordering::Less) => {}, + (RangeEnd::Excluded, _) => span_err!( + self.tcx.sess, + lo_expr.span, + E0579, + "lower range bound must be less than upper", + ), + (RangeEnd::Included, Ordering::Greater) => { + struct_span_err!(self.tcx.sess, lo_expr.span, E0030, + "lower range bound must be less than or equal to upper") + .span_label(lo_expr.span, "lower bound larger than upper bound") + .emit(); + }, + (RangeEnd::Included, _) => {} + } PatternKind::Range { lo, hi, end } } _ => PatternKind::Wild @@ -487,7 +495,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { pattern: self.lower_pattern(field), }) .collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) + self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) } PatKind::Struct(ref qpath, ref fields, _) => { @@ -519,7 +527,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }) .collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) + self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) } }; @@ -610,6 +618,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_variant_or_leaf( &mut self, def: Def, + span: Span, ty: Ty<'tcx>, subpatterns: Vec>) -> PatternKind<'tcx> @@ -640,7 +649,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Leaf { subpatterns: subpatterns } } - _ => bug!() + _ => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span, + kind: ErrKind::NonConstPath, + })); + PatternKind::Wild + } } } @@ -660,18 +675,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let substs = self.tables.node_substs(id); match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { Ok(value) => { - if self.tcx.sess.opts.debugging_opts.miri { - if let ConstVal::Value(_) = value.val {} else { - panic!("const eval produced non-miri value: {:#?}", value); - } - } let instance = ty::Instance::resolve( self.tcx, self.param_env, def_id, substs, ).unwrap(); - return self.const_to_pat(instance, value, span) + return self.const_to_pat(instance, value, id, span) }, Err(e) => { self.errors.push(PatternError::ConstEval(e)); @@ -679,7 +689,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } } - _ => self.lower_variant_or_leaf(def, ty, vec![]), + _ => self.lower_variant_or_leaf(def, span, ty, vec![]), }; Pattern { @@ -690,68 +700,51 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { - if self.tcx.sess.opts.debugging_opts.miri { - return match expr.node { - hir::ExprLit(ref lit) => { - let ty = self.tables.expr_ty(expr); - match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) { - Ok(value) => PatternKind::Constant { - value: self.tcx.mk_const(ty::Const { - ty, - val: value, - }), - }, - Err(e) => { - self.errors.push(PatternError::ConstEval(ConstEvalErr { - span: lit.span, - kind: e, - })); - PatternKind::Wild - }, - } - }, - hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, - hir::ExprUnary(hir::UnNeg, ref expr) => { - let ty = self.tables.expr_ty(expr); - let lit = match expr.node { - hir::ExprLit(ref lit) => lit, - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - }; - match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) { - Ok(value) => PatternKind::Constant { - value: self.tcx.mk_const(ty::Const { - ty, - val: value, - }), - }, - Err(e) => { - self.errors.push(PatternError::ConstEval(ConstEvalErr { - span: lit.span, - kind: e, - })); - PatternKind::Wild - }, - } + match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(val) => { + let instance = ty::Instance::new( + self.tables.local_id_root.expect("literal outside any scope"), + self.substs, + ); + let cv = self.tcx.mk_const(ty::Const { val, ty }); + *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, } - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - } - } - let const_cx = eval::ConstContext::new(self.tcx, - self.param_env.and(self.substs), - self.tables); - match const_cx.eval(expr) { - Ok(value) => { - if let ConstVal::Variant(def_id) = value.val { - let ty = self.tables.expr_ty(expr); - self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) - } else { - PatternKind::Constant { value } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, } } - Err(e) => { - self.errors.push(PatternError::ConstEval(e)); - PatternKind::Wild - } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), } } @@ -759,14 +752,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { &self, instance: ty::Instance<'tcx>, cv: &'tcx ty::Const<'tcx>, + id: hir::HirId, span: Span, ) -> Pattern<'tcx> { debug!("const_to_pat: cv={:#?}", cv); let kind = match cv.ty.sty { ty::TyFloat(_) => { - self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); - PatternKind::Wild - } + let id = self.tcx.hir.hir_to_node_id(id); + self.tcx.lint_node( + ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + "floating-point types cannot be used in patterns", + ); + PatternKind::Constant { + value: cv, + } + }, ty::TyAdt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); @@ -803,30 +805,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, Some(variant_index), field, miri, cv.ty, + self.tcx, self.param_env, instance, + Some(variant_index), field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; FieldPattern { field, - pattern: self.const_to_pat(instance, val, span), + pattern: self.const_to_pat(instance, val, id, span), } }).collect(), } }, - ConstVal::Variant(var_did) => { - let variant_index = adt_def - .variants - .iter() - .position(|var| var.did == var_did) - .unwrap(); - PatternKind::Variant { - adt_def, - substs, - variant_index, - subpatterns: Vec::new(), - } - } _ => return Pattern { span, ty: cv.ty, @@ -839,12 +829,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyAdt(adt_def, _) => { let struct_var = adt_def.struct_variant(); PatternKind::Leaf { - subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| { let field = Field::new(i); let val = match cv.val { - ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { - consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 - }, ConstVal::Value(miri) => const_val_field( self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), @@ -852,7 +839,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; FieldPattern { field, - pattern: self.const_to_pat(instance, val, span), + pattern: self.const_to_pat(instance, val, id, span), } }).collect() } @@ -862,7 +849,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { subpatterns: (0..fields.len()).map(|i| { let field = Field::new(i); let val = match cv.val { - ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], ConstVal::Value(miri) => const_val_field( self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), @@ -870,29 +856,26 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; FieldPattern { field, - pattern: self.const_to_pat(instance, val, span), + pattern: self.const_to_pat(instance, val, id, span), } }).collect() } } ty::TyArray(_, n) => { - PatternKind::Leaf { - subpatterns: (0..n.val.unwrap_u64()).map(|i| { + PatternKind::Array { + prefix: (0..n.val.unwrap_u64()).map(|i| { let i = i as usize; let field = Field::new(i); let val = match cv.val { - ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], - ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, ConstVal::Value(miri) => const_val_field( self.tcx, self.param_env, instance, None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, span), - } - }).collect() + self.const_to_pat(instance, val, id, span) + }).collect(), + slice: None, + suffix: Vec::new(), } } _ => { diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 65d8922459f78..58814cf171010 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -325,6 +325,24 @@ match x { ``` "##, +E0030: r##" +When matching against a range, the compiler verifies that the range is +non-empty. Range patterns include both end-points, so this is equivalent to +requiring the start of the range to be less than or equal to the end of the +range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 ... 1 => {} + // This range is empty, and the compiler can tell. + 1000 ... 5 => {} +} +``` +"##, + E0158: r##" `const` and `static` mean different things. A `const` is a compile-time constant, an alias for a literal value. This property means you can match it @@ -2160,6 +2178,24 @@ fn main() { ``` "##, +E0579: r##" +When matching against an exclusive range, the compiler verifies that the range +is non-empty. Exclusive range patterns include the start point but not the end +point, so this is equivalent to requiring the start of the range to be less +than the end of the range. + +For example: + +```compile_fail +match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} +} +``` +"##, + E0595: r##" Closures cannot mutate immutable captured variables. diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 15722b64517cc..47ed60b011367 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -16,7 +16,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::mir::interpret::{Value, PrimVal}; -use rustc::ty::{self, AdtKind, VariantDef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -636,7 +636,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, kind: ExprKind::Literal { literal: Literal::Value { value: cx.tcx().mk_const(ty::Const { - val: const_fn(cx.tcx, def_id, substs), + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty }), }, @@ -661,28 +661,6 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) } } -fn const_fn<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, -) -> ConstVal<'tcx> { - if tcx.sess.opts.debugging_opts.miri { - /* - let inst = ty::Instance::new(def_id, substs); - let ptr = tcx - .interpret_interner - .borrow_mut() - .create_fn_alloc(inst); - let ptr = MemoryPointer::new(AllocId(ptr), 0); - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) - */ - // ZST function type - ConstVal::Value(Value::ByVal(PrimVal::Undef)) - } else { - ConstVal::Function(def_id, substs) - } -} - fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) @@ -690,13 +668,13 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let substs = cx.tables().node_substs(expr.hir_id); match def { // A regular function, constructor function or a constant. - Def::Fn(def_id) | - Def::Method(def_id) | - Def::StructCtor(def_id, CtorKind::Fn) | - Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { + Def::Fn(_) | + Def::Method(_) | + Def::StructCtor(_, CtorKind::Fn) | + Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { value: cx.tcx.mk_const(ty::Const { - val: const_fn(cx.tcx.global_tcx(), def_id, substs), + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty: cx.tables().node_id_to_type(expr.hir_id) }), }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 1d305e61bb8d4..1cba20db63aa4 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -25,11 +25,11 @@ use rustc::infer::InferCtxt; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; -use syntax::ast; +use syntax::ast::{self, LitKind}; use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; -use rustc_const_math::{ConstInt, ConstUsize}; +use rustc_const_math::{ConstUsize, ConstFloat}; use rustc::mir::interpret::{Value, PrimVal}; use std::rc::Rc; @@ -119,11 +119,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { Ok(val) => { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))) - } else { - ConstVal::Integral(ConstInt::Usize(val)) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.as_u64() as u128))), ty: self.tcx.types.usize }) } @@ -143,11 +139,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))) - } else { - ConstVal::Bool(true) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))), ty: self.tcx.types.bool }) } @@ -156,11 +148,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) - } else { - ConstVal::Bool(false) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), ty: self.tcx.types.bool }) } @@ -175,13 +163,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - let mut repr_ty = ty; - if let ty::TyAdt(adt, _) = ty.sty { - if adt.is_enum() { - repr_ty = adt.repr.discr_type().to_ty(tcx) - } - } - let parse_float = |num: &str, fty| -> ConstFloat { ConstFloat::from_str(num, fty).unwrap_or_else(|_| { // FIXME(#31407) this is only necessary because float parsing is buggy @@ -189,128 +170,59 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { }) }; - if tcx.sess.opts.debugging_opts.miri { - use rustc::mir::interpret::*; - let lit = match *lit { - LitKind::Str(ref s, _) => { - let s = s.as_str(); - let id = self.tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(AllocId(id), 0); - Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - ) - }, - LitKind::ByteStr(ref data) => { - let id = self.tcx.allocate_cached(data); - let ptr = MemoryPointer::new(AllocId(id), 0); - Value::ByVal(PrimVal::Ptr(ptr)) - }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), - LitKind::Int(n, _) if neg => { - let n = n as i128; - let n = n.overflowing_neg().0; - Value::ByVal(PrimVal::Bytes(n as u128)) - }, - LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), - LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty); - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::FloatUnsuffixed(n) => { - let fty = match ty.sty { - ty::TyFloat(fty) => fty, - _ => bug!() - }; - let n = n.as_str(); - let mut f = parse_float(&n, fty); - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), - }; - return Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: Value(lit), - ty, - }), - }; - } - - use syntax::ast::*; - use syntax::ast::LitIntType::*; - use rustc::middle::const_val::ConstVal::*; - use rustc_const_math::ConstInt::*; - use rustc::ty::util::IntTypeExt; - use rustc::middle::const_val::ByteArray; - use rustc_const_math::ConstFloat; - + use rustc::mir::interpret::*; let lit = match *lit { - LitKind::Str(ref s, _) => Ok(Str(s.as_str())), + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = self.tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(id, 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, LitKind::ByteStr(ref data) => { - let data: &'tcx [u8] = data; - Ok(ByteStr(ByteArray { data })) + let id = self.tcx.allocate_cached(data); + let ptr = MemoryPointer::new(id, 0); + Value::ByVal(PrimVal::Ptr(ptr)) }, - LitKind::Byte(n) => Ok(Integral(U8(n))), - LitKind::Int(n, hint) => { - match (&repr_ty.sty, hint) { - (&ty::TyInt(ity), _) | - (_, Signed(ity)) => { - let mut n = n as i128; - if neg { - n = n.overflowing_neg().0; - } - Ok(Integral(ConstInt::new_signed_truncating(n, - ity, tcx.sess.target.isize_ty))) - } - (&ty::TyUint(uty), _) | - (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n, - uty, tcx.sess.target.usize_ty))) - } - _ => bug!() - } - } + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), LitKind::Float(n, fty) => { - let mut f = parse_float(&n.as_str(), fty); + let n = n.as_str(); + let mut f = parse_float(&n, fty); if neg { f = -f; } - Ok(ConstVal::Float(f)) + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - let mut f = parse_float(&n.as_str(), fty); + let n = n.as_str(); + let mut f = parse_float(&n, fty); if neg { f = -f; } - Ok(ConstVal::Float(f)) + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) } - LitKind::Bool(b) => Ok(Bool(b)), - LitKind::Char(c) => Ok(Char(c)), + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), }; - - match lit { - Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const { - val: value, + Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Value(lit), ty, - }) }, - Err(kind) => self.fatal_const_eval_err(&ConstEvalErr { - span: sp, - kind, - }, sp, "expression") + }), } } @@ -352,12 +264,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { return (method_ty, Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - // ZST function type - ConstVal::Value(Value::ByVal(PrimVal::Undef)) - } else { - ConstVal::Function(item.def_id, substs) - }, + // ZST function type + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty: method_ty }), }); diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 3cb5d0a28790f..b53069791d510 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -5,17 +5,13 @@ use rustc::hir::def_id::DefId; use rustc::mir; use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError}; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use const_eval::{lookup_const_by_id, ConstContext}; -use rustc::mir::Field; -use rustc_data_structures::indexed_vec::Idx; +use const_eval::lookup_const_by_id; use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory, PlaceExtra}; - -use rustc_const_math::ConstInt; +use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra}; use std::fmt; use std::error::Error; @@ -43,93 +39,89 @@ pub fn mk_eval_cx<'a, 'tcx>( pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, + promoted: Option, param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { + eval_body_and_ecx(tcx, instance, promoted, param_env).0 +} + +pub fn check_body<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>, + promoted: Option, + param_env: ty::ParamEnv<'tcx>, +) { + let (res, ecx) = eval_body_and_ecx(tcx, instance, promoted, param_env); + if let Err(mut err) = res { + ecx.report(&mut err); + } +} + +fn eval_body_and_ecx<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>, + promoted: Option, + param_env: ty::ParamEnv<'tcx>, +) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'tcx, CompileTimeEvaluator>) { debug!("eval_body: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); let cid = GlobalId { instance, - promoted: None, + promoted, }; - if ecx.tcx.has_attr(instance.def_id(), "linkage") { - return Err(ConstEvalError::NotConst("extern global".to_string()).into()); - } - let instance_ty = instance.ty(tcx); - if tcx.interpret_interner.borrow().get_cached(cid).is_none() { - let mir = ecx.load_mir(instance.def)?; - let layout = ecx.layout_of(instance_ty)?; - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); - let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); - let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); - trace!("const_eval: pushing stack frame for global: {}", name); - ecx.push_stack_frame( - instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup.clone(), - )?; - - while ecx.step()? {} - } - let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - let align = ecx.layout_of(instance_ty)?.align; - let ptr = MemoryPointer::new(alloc, 0).into(); - let value = match ecx.try_read_value(ptr, align, instance_ty)? { - Some(val) => val, - _ => Value::ByRef(ptr, align), - }; - Ok((value, ptr, instance_ty)) + let res = (|| { + if ecx.tcx.has_attr(instance.def_id(), "linkage") { + return Err(ConstEvalError::NotConst("extern global".to_string()).into()); + } + let instance_ty = instance.ty(tcx); + if tcx.interpret_interner.borrow().get_cached(cid).is_none() { + let mir = ecx.load_mir(instance.def)?; + let layout = ecx.layout_of(instance_ty)?; + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); + let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); + let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); + trace!("const_eval: pushing stack frame for global: {}", name); + ecx.push_stack_frame( + instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup.clone(), + )?; + + while ecx.step()? {} + } + let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); + let align = ecx.layout_of(instance_ty)?.align; + let ptr = MemoryPointer::new(alloc, 0).into(); + let value = match ecx.try_read_value(ptr, align, instance_ty)? { + Some(val) => val, + _ => Value::ByRef(ptr, align), + }; + Ok((value, ptr, instance_ty)) + })(); + (res, ecx) } pub fn eval_body_as_integer<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: Instance<'tcx>, -) -> EvalResult<'tcx, ConstInt> { - let (value, _, ty) = eval_body(tcx, instance, param_env)?; - let prim = match value { - Value::ByVal(prim) => prim.to_bytes()?, - _ => return err!(TypeNotPrimitive(ty)), - }; - use syntax::ast::{IntTy, UintTy}; - use rustc::ty::TypeVariants::*; - use rustc_const_math::{ConstIsize, ConstUsize}; - Ok(match ty.sty { - TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8), - TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16), - TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32), - TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64), - TyInt(IntTy::I128) => ConstInt::I128(prim as i128), - TyInt(IntTy::Isize) => ConstInt::Isize( - ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty) - .expect("miri should already have errored"), - ), - TyUint(UintTy::U8) => ConstInt::U8(prim as u8), - TyUint(UintTy::U16) => ConstInt::U16(prim as u16), - TyUint(UintTy::U32) => ConstInt::U32(prim as u32), - TyUint(UintTy::U64) => ConstInt::U64(prim as u64), - TyUint(UintTy::U128) => ConstInt::U128(prim), - TyUint(UintTy::Usize) => ConstInt::Usize( - ConstUsize::new(prim as u64, tcx.sess.target.usize_ty) - .expect("miri should already have errored"), - ), - _ => { - return Err( - ConstEvalError::NeedsRfc( - "evaluating anything other than isize/usize during typeck".to_string(), - ).into(), - ) - } - }) + promoted: Option, +) -> EvalResult<'tcx, u128> { + let (value, _, ty) = eval_body(tcx, instance, promoted, param_env)?; + match value { + Value::ByVal(prim) => prim.to_bytes(), + _ => err!(TypeNotPrimitive(ty)), + } } pub struct CompileTimeEvaluator; @@ -337,7 +329,7 @@ fn const_val_field_inner<'a, 'tcx>( trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let (mut field, ty) = match value { - Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), Value::ByRef(ptr, align) => { let place = Place::Ptr { ptr, @@ -422,248 +414,13 @@ pub fn const_eval_provider<'a, 'tcx>( let instance = ty::Instance::new(def_id, substs); - if tcx.sess.opts.debugging_opts.miri { - return match ::interpret::eval_body(tcx, instance, key.param_env) { - Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(miri_value), - ty: miri_ty, - })), - Err(err) => { - Err(ConstEvalErr { span: body.value.span, kind: err.into() }) - } - }; - } - - trace!("running old const eval"); - let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); - trace!("old const eval produced {:?}", old_result); - trace!("const eval instance: {:?}, {:?}", instance, key.param_env); - let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); - match (miri_result, old_result) { - (Err(err), Ok(ok)) => { - trace!("miri failed, ctfe returned {:?}", ok); - tcx.sess.span_warn( - tcx.def_span(key.value.0), - "miri failed to eval, while ctfe succeeded", - ); - let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let () = unwrap_miri(&ecx, Err(err)); - Ok(ok) - }, - (Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(value), - ty, + match ::interpret::eval_body(tcx, instance, None, key.param_env) { + Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(miri_value), + ty: miri_ty, })), - (Err(_), Err(err)) => Err(err), - (Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => { - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let layout = ecx.layout_of(miri_ty).unwrap(); - let miri_place = Place::from_primval_ptr(miri_ptr, layout.align); - check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); - Ok(ctfe) - } - } -} - -fn check_ctfe_against_miri<'a, 'tcx>( - ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, - miri_place: Place, - miri_ty: Ty<'tcx>, - ctfe: ConstVal<'tcx>, -) { - use rustc::middle::const_val::ConstAggregate::*; - use rustc_const_math::ConstFloat; - use rustc::ty::TypeVariants::*; - let miri_val = ValTy { - value: ecx.read_place(miri_place).unwrap(), - ty: miri_ty - }; - match miri_ty.sty { - TyInt(int_ty) => { - let prim = get_prim(ecx, miri_val); - let c = ConstInt::new_signed_truncating(prim as i128, - int_ty, - ecx.tcx.sess.target.isize_ty); - let c = ConstVal::Integral(c); - assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); - }, - TyUint(uint_ty) => { - let prim = get_prim(ecx, miri_val); - let c = ConstInt::new_unsigned_truncating(prim, - uint_ty, - ecx.tcx.sess.target.usize_ty); - let c = ConstVal::Integral(c); - assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); - }, - TyFloat(ty) => { - let prim = get_prim(ecx, miri_val); - let f = ConstVal::Float(ConstFloat { bits: prim, ty }); - assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe); - }, - TyBool => { - let bits = get_prim(ecx, miri_val); - if bits > 1 { - bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe); - } - let b = ConstVal::Bool(bits == 1); - assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe); - }, - TyChar => { - let bits = get_prim(ecx, miri_val); - if let Some(cm) = ::std::char::from_u32(bits as u32) { - assert_eq!( - ConstVal::Char(cm), ctfe, - "miri evaluated to {:?}, but expected {:?}", cm, ctfe, - ); - } else { - bug!("miri evaluated to {}, but expected a char {:?}", bits, ctfe); - } - }, - TyStr => { - let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty); - if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value { - let bytes = ecx - .memory - .read_bytes(ptr.into(), len as u64) - .expect("bad miri memory for str"); - if let Ok(s) = ::std::str::from_utf8(bytes) { - if let ConstVal::Str(s2) = ctfe { - assert_eq!(s, s2, "miri produced {:?}, but expected {:?}", s, s2); - } else { - bug!("miri produced {:?}, but expected {:?}", s, ctfe); - } - } else { - bug!( - "miri failed to produce valid utf8 {:?}, while ctfe produced {:?}", - bytes, - ctfe, - ); - } - } else { - bug!("miri evaluated to {:?}, but expected a str {:?}", value, ctfe); - } - }, - TyArray(elem_ty, n) => { - let n = n.val.unwrap_u64(); - let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { - ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { - (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) - }).collect(), - ConstVal::Aggregate(Array(v)) => { - v.iter().map(|c| (c.val, c.ty)).collect() - }, - ConstVal::Aggregate(Repeat(v, n)) => { - vec![(v.val, v.ty); n as usize] - }, - _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), - }; - let layout = ecx.layout_of(miri_ty).unwrap(); - for (i, elem) in vec.into_iter().enumerate() { - assert!((i as u64) < n); - let (field_place, _) = - ecx.place_field(miri_place, Field::new(i), layout).unwrap(); - check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0); - } - }, - TyTuple(..) => { - let vec = match ctfe { - ConstVal::Aggregate(Tuple(v)) => v, - _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), - }; - let layout = ecx.layout_of(miri_ty).unwrap(); - for (i, elem) in vec.into_iter().enumerate() { - let (field_place, _) = - ecx.place_field(miri_place, Field::new(i), layout).unwrap(); - check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); - } - }, - TyAdt(def, _) => { - let mut miri_place = miri_place; - let struct_variant = if def.is_enum() { - let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap(); - let variant = def.discriminants(ecx.tcx).position(|variant_discr| { - variant_discr.to_u128_unchecked() == discr - }).expect("miri produced invalid enum discriminant"); - miri_place = ecx.place_downcast(miri_place, variant).unwrap(); - &def.variants[variant] - } else { - def.non_enum_variant() - }; - let vec = match ctfe { - ConstVal::Aggregate(Struct(v)) => v, - ConstVal::Variant(did) => { - assert_eq!(struct_variant.fields.len(), 0); - assert_eq!(did, struct_variant.did); - return; - }, - ctfe => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), - }; - let layout = ecx.layout_of(miri_ty).unwrap(); - for &(name, elem) in vec.into_iter() { - let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap(); - let (field_place, _) = - ecx.place_field(miri_place, Field::new(field), layout).unwrap(); - check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); - } - }, - TySlice(_) => bug!("miri produced a slice?"), - // not supported by ctfe - TyRawPtr(_) | - TyRef(..) => {} - TyDynamic(..) => bug!("miri produced a trait object"), - TyClosure(..) => bug!("miri produced a closure"), - TyGenerator(..) => bug!("miri produced a generator"), - TyGeneratorWitness(..) => bug!("miri produced a generator witness"), - TyNever => bug!("miri produced a value of the never type"), - TyProjection(_) => bug!("miri produced a projection"), - TyAnon(..) => bug!("miri produced an impl Trait type"), - TyParam(_) => bug!("miri produced an unmonomorphized type"), - TyInfer(_) => bug!("miri produced an uninferred type"), - TyError => bug!("miri produced a type error"), - TyForeign(_) => bug!("miri produced an extern type"), - // should be fine - TyFnDef(..) => {} - TyFnPtr(_) => { - let value = ecx.value_to_primval(miri_val); - let ptr = match value { - Ok(PrimVal::Ptr(ptr)) => ptr, - value => bug!("expected fn ptr, got {:?}", value), - }; - let inst = ecx.memory.get_fn(ptr).unwrap(); - match ctfe { - ConstVal::Function(did, substs) => { - let ctfe = ty::Instance::resolve( - ecx.tcx, - ecx.param_env, - did, - substs, - ).unwrap(); - assert_eq!(inst, ctfe, "expected fn ptr {:?}, but got {:?}", ctfe, inst); - }, - _ => bug!("ctfe produced {:?}, but miri produced function {:?}", ctfe, inst), - } - }, - } -} - -fn get_prim<'a, 'tcx>( - ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, - val: ValTy<'tcx>, -) -> u128 { - let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes()); - unwrap_miri(ecx, res) -} - -fn unwrap_miri<'a, 'tcx, T>( - ecx: &EvalContext<'a, 'tcx, CompileTimeEvaluator>, - res: Result>, -) -> T { - match res { - Ok(val) => val, - Err(mut err) => { - ecx.report(&mut err); - ecx.tcx.sess.abort_if_errors(); - bug!("{:#?}", err); + Err(err) => { + Err(ConstEvalErr { span: body.value.span, kind: err.into() }) } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index a8b3864ea87c2..9ac802b720083 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -241,39 +241,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { - use rustc::middle::const_val::ConstVal; - - let primval = match *const_val { - ConstVal::Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()), - - ConstVal::Float(val) => PrimVal::Bytes(val.bits), - - ConstVal::Bool(b) => PrimVal::from_bool(b), - ConstVal::Char(c) => PrimVal::from_char(c), - - ConstVal::Str(ref s) => return self.str_to_value(s), - - ConstVal::ByteStr(ref bs) => { - let ptr = self.memory.allocate_cached(bs.data); - PrimVal::Ptr(ptr) - } - + match *const_val { ConstVal::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - return Ok(self.read_global_as_value(GlobalId { + Ok(self.read_global_as_value(GlobalId { instance, promoted: None, - }, self.layout_of(ty)?)); + }, self.layout_of(ty)?)) } - - ConstVal::Aggregate(..) | - ConstVal::Variant(_) => bug!("should not have aggregate or variant constants in MIR"), - // function items are zero sized and thus have no readable value - ConstVal::Function(..) => PrimVal::Undef, - ConstVal::Value(val) => return Ok(val), - }; - - Ok(Value::ByVal(primval)) + ConstVal::Value(val) => Ok(val), + } } pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> { diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index a6ebdd45968fc..ba894a1728a9b 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr}; +pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr, check_body}; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c5e4eeab86709..4a2b4547cb051 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -118,10 +118,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn read_field( &self, base: Value, + variant: Option, field: mir::Field, base_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> { - let base_layout = self.layout_of(base_ty)?; + let mut base_layout = self.layout_of(base_ty)?; + if let Some(variant_index) = variant { + base_layout = base_layout.for_variant(self, variant_index); + } let field_index = field.index(); let field = base_layout.field(self, field_index)?; let offset = base_layout.fields.offset(field_index); @@ -149,7 +153,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let base_ty = self.place_ty(&proj.base); match proj.elem { - Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)), + Field(field, _) => Ok(self.read_field(base, None, field, base_ty)?.map(|(f, _)| f)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 48cbf54a56920..141f3e3fddd8f 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -16,7 +16,7 @@ use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; -use rustc_const_math::{ConstInt, ConstUsize}; +use rustc_const_math::ConstUsize; use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -444,12 +444,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: func_ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: if tcx.sess.opts.debugging_opts.miri { - // ZST function type - ConstVal::Value(Value::ByVal(PrimVal::Undef)) - } else { - ConstVal::Function(self.def_id, substs) - }, + // ZST function type + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty: func_ty }), }, @@ -512,14 +508,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) - } else { + val: { let value = ConstUsize::new( value, self.tcx.sess.target.usize_ty, - ).unwrap(); - ConstVal::Integral(ConstInt::Usize(value)) + ).unwrap().as_u64(); + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) }, ty: self.tcx.types.usize, }) @@ -749,12 +743,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: if tcx.sess.opts.debugging_opts.miri { - // ZST function type - ConstVal::Value(Value::ByVal(PrimVal::Undef)) - } else { - ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id)) - }, + // ZST function type + val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), ty }), }, diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 9eca343cb5edc..2e8dd623d744d 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -19,6 +19,7 @@ use rustc::hir; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::middle::const_val::ConstVal; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; @@ -541,7 +542,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty: self.tcx.types.bool, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(val), + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))), ty: self.tcx.types.bool }) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 8b05ea4969503..8fd8cb1fcc136 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -68,7 +68,6 @@ use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior}; use rustc::ty::subst::{Kind, Substs}; use util::dump_mir; use util::liveness::{self, LivenessMode}; -use rustc_const_math::ConstInt; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_set::IdxSetBuf; use std::collections::HashMap; @@ -182,11 +181,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty: self.tcx.types.u32, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: if self.tcx.sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))) - } else { - ConstVal::Integral(ConstInt::U32(state_disc)) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))), ty: self.tcx.types.u32 }), }, @@ -703,7 +698,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: tcx.types.bool, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Bool(false), + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), ty: tcx.types.bool }), }, diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 1e1004c4569a8..a91f40491e92a 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -13,6 +13,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use transform::{MirPass, MirSource}; use std::borrow::Cow; @@ -56,9 +57,12 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(box Constant { literal: Literal::Value { - value: &ty::Const { val: ConstVal::Bool(cond), .. } + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))), + .. } }, .. - }), expected, .. } if cond == expected => { + }), expected, .. } if (cond == 1) == expected => { + assert!(cond <= 1); TerminatorKind::Goto { target: target } }, TerminatorKind::FalseEdges { real_target, .. } => { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 666cf30136514..54e60ee8b7f9c 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -946,11 +946,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty: self.tcx().types.usize, literal: Literal::Value { value: self.tcx().mk_const(ty::Const { - val: if self.tcx().sess.opts.debugging_opts.miri { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))) - } else { - ConstVal::Integral(self.tcx().const_usize(val)) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))), ty: self.tcx().types.usize }) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f3462f60b3967..0c47a00a07281 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -25,12 +25,6 @@ // by borrowck::gather_loans use rustc::ty::cast::CastKind; -use rustc_mir::const_eval::ConstContext; -use rustc::middle::const_val::ConstEvalErr; -use rustc::middle::const_val::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll}; -use rustc::middle::const_val::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; -use rustc::middle::const_val::ErrKind::{TypeckError, Math, LayoutError}; -use rustc_const_math::{ConstMathErr, Op}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::map::blocks::FnLikeNode; @@ -41,17 +35,13 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::{queries, Providers}; use rustc::ty::subst::Substs; use rustc::traits::Reveal; -use rustc::util::common::ErrorReported; use rustc::util::nodemap::{ItemLocalSet, NodeSet}; -use rustc::lint::builtin::CONST_ERR; -use rustc::hir::{self, PatKind, RangeEnd}; +use rustc::hir; use std::rc::Rc; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use std::cmp::Ordering; - pub fn provide(providers: &mut Providers) { *providers = Providers { rvalue_promotable_map, @@ -124,32 +114,6 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> { } impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { - fn const_cx(&self) -> ConstContext<'a, 'gcx> { - ConstContext::new(self.tcx, self.param_env.and(self.identity_substs), self.tables) - } - - fn check_const_eval(&self, expr: &'gcx hir::Expr) { - if self.tcx.sess.opts.debugging_opts.miri { - return; - } - if let Err(err) = self.const_cx().eval(expr) { - match err.kind { - UnimplementedConstVal(_) => {} - IndexOpFeatureGated => {} - ErroneousReferencedConstant(_) => {} - TypeckError => {} - MiscCatchAll => {} - _ => { - self.tcx.lint_node(CONST_ERR, - expr.id, - expr.span, - &format!("constant evaluation error: {}", - err.description().into_oneline())); - } - } - } - } - // Returns true iff all the values of the type are promotable. fn type_has_only_promotable_values(&mut self, ty: Ty<'gcx>) -> bool { ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) && @@ -199,9 +163,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.identity_substs = Substs::identity_for_item(self.tcx, item_def_id); let body = self.tcx.hir.body(body_id); - if !self.in_fn { - self.check_const_eval(&body.value); - } let tcx = self.tcx; let param_env = self.param_env; @@ -217,44 +178,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.identity_substs = outer_identity_substs; } - fn visit_pat(&mut self, p: &'tcx hir::Pat) { - match p.node { - PatKind::Lit(ref lit) => { - self.check_const_eval(lit); - } - PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - match self.const_cx().compare_lit_exprs(start, end) { - Ok(Some(Ordering::Less)) => {} - Ok(Some(Ordering::Equal)) | - Ok(Some(Ordering::Greater)) => { - span_err!(self.tcx.sess, - start.span, - E0579, - "lower range bound must be less than upper"); - } - Ok(None) => bug!("ranges must be char or int"), - Err(ErrorReported) => {} - } - } - PatKind::Range(ref start, ref end, RangeEnd::Included) => { - match self.const_cx().compare_lit_exprs(start, end) { - Ok(Some(Ordering::Less)) | - Ok(Some(Ordering::Equal)) => {} - Ok(Some(Ordering::Greater)) => { - struct_span_err!(self.tcx.sess, start.span, E0030, - "lower range bound must be less than or equal to upper") - .span_label(start.span, "lower bound larger than upper bound") - .emit(); - } - Ok(None) => bug!("ranges must be char or int"), - Err(ErrorReported) => {} - } - } - _ => {} - } - intravisit::walk_pat(self, p); - } - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) { match stmt.node { hir::StmtDecl(ref decl, _) => { @@ -303,30 +226,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.promotable = false; } - if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri { - match self.const_cx().eval(ex) { - Ok(_) => {} - Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | - Err(ConstEvalErr { kind: MiscCatchAll, .. }) | - Err(ConstEvalErr { kind: MiscBinaryOp, .. }) | - Err(ConstEvalErr { kind: NonConstPath, .. }) | - Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) | - Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) | - Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) | - Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {} - Err(ConstEvalErr { kind: TypeckError, .. }) => {} - Err(ConstEvalErr { - kind: LayoutError(ty::layout::LayoutError::Unknown(_)), .. - }) => {} - Err(msg) => { - self.tcx.lint_node(CONST_ERR, - ex.id, - msg.span, - &msg.description().into_oneline().into_owned()); - } - } - } - if self.promotable { self.result.insert(ex.hir_id.local_id); } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..fba7a89511d9f 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -31,23 +31,6 @@ const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, */ -E0030: r##" -When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to -requiring the start of the range to be less than or equal to the end of the -range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 ... 1 => {} - // This range is empty, and the compiler can tell. - 1000 ... 5 => {} -} -``` -"##, E0130: r##" You declared a pattern as an argument in a foreign function declaration. @@ -244,24 +227,6 @@ impl Foo for Bar { "##, -E0579: r##" -When matching against an exclusive range, the compiler verifies that the range -is non-empty. Exclusive range patterns include the start point but not the end -point, so this is equivalent to requiring the start of the range to be less -than the end of the range. - -For example: - -```compile_fail -match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} -} -``` -"##, - E0590: r##" `break` or `continue` must include a label when used in the condition of a `while` loop. diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 3514cf5056dee..c585c9044db7c 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -119,7 +119,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { }), ref args, .. } => match val { - ConstVal::Function(def_id, _) => Some((def_id, args)), ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { ty::TyFnDef(did, _) => Some((did, args)), _ => None, diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 9f8d1ddeb4164..62aea8852504e 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -10,7 +10,6 @@ use llvm::{self, ValueRef}; use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; -use rustc_const_math::ConstInt::*; use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; @@ -64,25 +63,6 @@ impl<'a, 'tcx> Const<'tcx> { } } - pub fn from_constint(cx: &CodegenCx<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> { - let tcx = cx.tcx; - let (llval, ty) = match *ci { - I8(v) => (C_int(Type::i8(cx), v as i64), tcx.types.i8), - I16(v) => (C_int(Type::i16(cx), v as i64), tcx.types.i16), - I32(v) => (C_int(Type::i32(cx), v as i64), tcx.types.i32), - I64(v) => (C_int(Type::i64(cx), v as i64), tcx.types.i64), - I128(v) => (C_uint_big(Type::i128(cx), v as u128), tcx.types.i128), - Isize(v) => (C_int(Type::isize(cx), v.as_i64()), tcx.types.isize), - U8(v) => (C_uint(Type::i8(cx), v as u64), tcx.types.u8), - U16(v) => (C_uint(Type::i16(cx), v as u64), tcx.types.u16), - U32(v) => (C_uint(Type::i32(cx), v as u64), tcx.types.u32), - U64(v) => (C_uint(Type::i64(cx), v), tcx.types.u64), - U128(v) => (C_uint_big(Type::i128(cx), v), tcx.types.u128), - Usize(v) => (C_uint(Type::isize(cx), v.as_u64()), tcx.types.usize), - }; - Const { llval: llval, ty: ty } - } - pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { let llval = match ty.sty { ty::TyInt(ast::IntTy::I128) | @@ -124,26 +104,7 @@ impl<'a, 'tcx> Const<'tcx> { let llty = cx.layout_of(ty).llvm_type(cx); trace!("from_constval: {:#?}: {}", cv, ty); let val = match *cv { - ConstVal::Float(v) => { - let bits = match v.ty { - ast::FloatTy::F32 => C_u32(cx, v.bits as u32), - ast::FloatTy::F64 => C_u64(cx, v.bits as u64) - }; - consts::bitcast(bits, llty) - } - ConstVal::Bool(v) => C_bool(cx, v), - ConstVal::Integral(ref i) => return Const::from_constint(cx, i), - ConstVal::Str(ref v) => C_str_slice(cx, v.clone()), - ConstVal::ByteStr(v) => { - consts::addr_of(cx, C_bytes(cx, v.data), cx.align_of(ty), "byte_str") - } - ConstVal::Char(c) => C_uint(Type::char(cx), c as u64), - ConstVal::Function(..) => C_undef(llty), - ConstVal::Variant(_) | - ConstVal::Aggregate(..) | - ConstVal::Unevaluated(..) => { - bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) - } + ConstVal::Unevaluated(..) => unimplemented!("const val `{:?}`", cv), ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { match ty.sty { @@ -157,7 +118,7 @@ impl<'a, 'tcx> Const<'tcx> { .tcx() .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .expect("miri alloc not found"); assert_eq!(len as usize as u128, len); let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; @@ -174,7 +135,7 @@ impl<'a, 'tcx> Const<'tcx> { .tcx() .interpret_interner .borrow() - .get_alloc(ptr.alloc_id.0) + .get_alloc(ptr.alloc_id) .expect("miri alloc not found"); let data = &alloc.bytes[(ptr.offset as usize)..]; consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6aa65231aaba9..ab8e0300188c3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -535,7 +535,6 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } match result { - Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. diff --git a/src/test/compile-fail/issue-31109.rs b/src/test/compile-fail/issue-31109.rs index e3548d740717f..74121e3a420f9 100644 --- a/src/test/compile-fail/issue-31109.rs +++ b/src/test/compile-fail/issue-31109.rs @@ -12,6 +12,5 @@ fn main() { // FIXME(#31407) this error should go away, but in the meantime we test that it // is accompanied by a somewhat useful error message. let _: f64 = 1234567890123456789012345678901234567890e-340; - //~^ ERROR constant evaluation error - //~| unimplemented constant expression: could not evaluate float literal + //~^ ERROR could not evaluate float literal (see issue #31407) } diff --git a/src/test/compile-fail/issue-39559-2.rs b/src/test/compile-fail/issue-39559-2.rs index aa0750230649d..f01fd1fd8f144 100644 --- a/src/test/compile-fail/issue-39559-2.rs +++ b/src/test/compile-fail/issue-39559-2.rs @@ -22,7 +22,9 @@ impl Dim for Dim3 { fn main() { let array: [usize; Dim3::dim()] - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR E0015 + //~| ERROR E0080 = [0; Dim3::dim()]; - //~^ ERROR calls in constants are limited to constant functions + //~^ ERROR E0015 + //~| ERROR E0080 } diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index 191b867e7a8b5..823ece2bdca01 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -18,33 +18,33 @@ fn main() { let x = 42.0; match x { - 5.0 => {}, //~ ERROR floating-point literals cannot be used + 5.0 => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error - 5.0f32 => {}, //~ ERROR floating-point literals cannot be used + 5.0f32 => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error - -5.0 => {}, //~ ERROR floating-point literals cannot be used + -5.0 => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error - 1.0 .. 33.0 => {}, //~ ERROR floating-point literals cannot be used + 1.0 .. 33.0 => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error - //~| ERROR floating-point literals cannot be used + //~| ERROR floating-point cannot be used //~| WARNING hard error - 39.0 ... 70.0 => {}, //~ ERROR floating-point literals cannot be used + 39.0 ... 70.0 => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error - //~| ERROR floating-point literals cannot be used + //~| ERROR floating-point cannot be used //~| WARNING hard error _ => {}, }; let y = 5.0; // Same for tuples match (x, 5) { - (3.14, 1) => {}, //~ ERROR floating-point literals cannot be used + (3.14, 1) => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error _ => {}, } // Or structs struct Foo { x: f32 }; match (Foo { x }) { - Foo { x: 2.0 } => {}, //~ ERROR floating-point literals cannot be used + Foo { x: 2.0 } => {}, //~ ERROR floating-point cannot be used //~| WARNING hard error _ => {}, } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 3e51550d1fa07..e94d1ff779367 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -53,7 +53,7 @@ fn main() { let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits - //~^ WARN: attempt to shift by a negative amount + let n = 1u8 << (4+3); let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index 5593499758346..f7cf8a68d5684 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -17,7 +17,6 @@ #[rustc_error] fn main() { //~ ERROR: compilation successful let x2: i8 = --128; //~ warn: literal out of range for i8 - //~^ warn: attempt to negate with overflow let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 diff --git a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs index 679be9ce219fe..fd888b659f142 100644 --- a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs @@ -28,7 +28,8 @@ fn main() { let x = 0.0; match x { f32::INFINITY => { } - //~^ ERROR floating point constants cannot be used in patterns + //~^ WARNING floating-point cannot be used in patterns + //~| WARNING will become a hard error in a future release _ => { } } } diff --git a/src/test/compile-fail/thread-local-in-ctfe.rs b/src/test/compile-fail/thread-local-in-ctfe.rs index 720e15991c059..dc220bd1cc94f 100644 --- a/src/test/compile-fail/thread-local-in-ctfe.rs +++ b/src/test/compile-fail/thread-local-in-ctfe.rs @@ -16,7 +16,6 @@ static A: u32 = 1; static B: u32 = A; //~^ ERROR thread-local statics cannot be accessed at compile-time //~| ERROR cannot refer to other statics by value -//~| WARN non-constant path in constant expression static C: &u32 = &A; //~^ ERROR thread-local statics cannot be accessed at compile-time @@ -24,7 +23,6 @@ static C: &u32 = &A; const D: u32 = A; //~^ ERROR thread-local statics cannot be accessed at compile-time //~| ERROR cannot refer to statics by value -//~| WARN non-constant path in constant expression const E: &u32 = &A; //~^ ERROR thread-local statics cannot be accessed at compile-time diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr index eed00244041db..f0d466acc9df3 100644 --- a/src/test/ui/const-eval-overflow-2.stderr +++ b/src/test/ui/const-eval-overflow-2.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-2.rs:21:25 | 21 | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ miri failed: attempted to do overflowing math + | ^^^^^^^^ miri failed: Overflow(Neg) at $DIR/const-eval-overflow-2.rs:21:25: 21:33 | note: for pattern here --> $DIR/const-eval-overflow-2.rs:26:9 From dfb11263e81b1a5f5576644add6abae10741d650 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 6 Jan 2018 03:36:39 +0000 Subject: [PATCH 007/115] Initial changes to librustc to support const trait fns. --- src/librustc/hir/def_id.rs | 1 - src/librustc_metadata/decoder.rs | 9 ++++++++- src/librustc_metadata/encoder.rs | 9 ++++++++- src/librustdoc/clean/mod.rs | 9 ++------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 637b156ceef5d..34b3aa53d6bcf 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -220,7 +220,6 @@ impl serialize::UseSpecializedDecodable for DefId {} pub struct LocalDefId(DefIndex); impl LocalDefId { - #[inline] pub fn from_def_id(def_id: DefId) -> LocalDefId { assert!(def_id.is_local()); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 427cd4a0ce976..a9d2164c5723a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -19,7 +19,7 @@ use rustc::middle::cstore::{LinkagePreference, ExternConstBody, ExternBodyNestedBodies}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, - CRATE_DEF_INDEX, LOCAL_CRATE}; + CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId}; use rustc::ich::Fingerprint; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; @@ -273,6 +273,13 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { + #[inline] + fn specialized_decode(&mut self) -> Result { + self.specialized_decode().map(|i| LocalDefId::from_def_id(i)) + } +} + impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ccdf1f3ca5cd8..7fd307949319a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -16,7 +16,7 @@ use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, EncodedMetadata}; use rustc::hir::def::CtorKind; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; use rustc::ich::Fingerprint; use rustc::middle::dependency_format::Linkage; @@ -180,6 +180,13 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { + #[inline] + fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> { + self.specialized_encode(&def_id.to_def_id()) + } +} + impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7c9a49c82a939..bf31cd90a5b85 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -42,7 +42,6 @@ use rustc_typeck::hir_ty_to_ty; use rustc::hir; -use rustc_const_math::ConstInt; use std::default::Default; use std::{mem, slice, vec}; use std::iter::FromIterator; @@ -2453,9 +2452,7 @@ impl Clean for hir::Ty { ty: cx.tcx.types.usize }) }); - let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - n.to_string() - } else if let ConstVal::Unevaluated(def_id, _) = n.val { + let n = if let ConstVal::Unevaluated(def_id, _) = n.val { if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) } else { @@ -2586,9 +2583,7 @@ impl<'tcx> Clean for Ty<'tcx> { n = new_n; } }; - let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - n.to_string() - } else if let ConstVal::Unevaluated(def_id, _) = n.val { + let n = if let ConstVal::Unevaluated(def_id, _) = n.val { if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) } else { From f7f6fe384d5d8851d9850d5374e0a542890fd0ca Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 2 Jan 2018 23:22:09 +0000 Subject: [PATCH 008/115] Prepare for using miri in trans --- src/librustc/dep_graph/dep_node.rs | 8 +- src/librustc/ich/impls_mir.rs | 2 + src/librustc/ich/impls_ty.rs | 8 +- src/librustc/traits/fulfill.rs | 34 +++++-- src/librustc/traits/project.rs | 40 +++++---- src/librustc/traits/select.rs | 24 ++++- src/librustc/ty/maps/config.rs | 7 +- src/librustc/ty/maps/keys.rs | 10 +++ src/librustc/ty/maps/mod.rs | 5 +- src/librustc/ty/mod.rs | 16 +++- src/librustc/ty/relate.rs | 32 ++++--- src/librustc/ty/structural_impls.rs | 52 ++++++++++- src/librustc_mir/const_eval/check.rs | 14 ++- src/librustc_mir/const_eval/pattern.rs | 20 +++-- src/librustc_mir/hair/cx/expr.rs | 14 ++- src/librustc_mir/interpret/const_eval.rs | 109 ++++++++++------------- src/librustc_typeck/check/mod.rs | 13 ++- src/librustc_typeck/collect.rs | 9 +- 18 files changed, 286 insertions(+), 131 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..be6db74804b38 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,15 +60,15 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. +use mir::interpret::{GlobalId}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; -use ich::Fingerprint; +use ich::{Fingerprint, StableHashingContext}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; use ty::subst::Substs; -use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; -use ich::StableHashingContext; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; @@ -515,7 +515,7 @@ define_dep_nodes!( <'tcx> [] TypeckTables(DefId), [] UsedTraitImports(DefId), [] HasTypeckTables(DefId), - [] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> }, + [] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> }, [] CheckMatch(DefId), [] SymbolName(DefId), [] InstanceSymbolName { instance: Instance<'tcx> }, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index f46b590d2dc59..7e36ea276c1bf 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -563,3 +563,5 @@ impl<'gcx> HashStable> for mir::ClosureOutlivesSubjec } } } + +impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted }); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e1434e9da7276..b04495f95cfe1 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -905,13 +905,13 @@ impl<'gcx> HashStable> for ty::InstanceDef<'gcx> { ty::InstanceDef::ClosureOnceShim { call_once } => { call_once.hash_stable(hcx, hasher); } - ty::InstanceDef::DropGlue(def_id, t) => { + ty::InstanceDef::DropGlue(def_id, ty) => { def_id.hash_stable(hcx, hasher); - t.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); } - ty::InstanceDef::CloneShim(def_id, t) => { + ty::InstanceDef::CloneShim(def_id, ty) => { def_id.hash_stable(hcx, hasher); - t.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); } } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 93e33836818ce..21d0113cf4a5e 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -9,6 +9,9 @@ // except according to those terms. use infer::{RegionObligation, InferCtxt, InferOk}; +use middle::const_val::ConstEvalErr; +use middle::const_val::ErrKind::TypeckError; +use mir::interpret::{GlobalId}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; @@ -525,17 +528,34 @@ fn process_predicate<'a, 'gcx, 'tcx>( } Some(param_env) => { match selcx.tcx().lift_to_global(&substs) { + Some(substs) => { + let instance = ty::Instance::resolve( + selcx.tcx().global_tcx(), + param_env, + def_id, + substs, + ); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None, + }; + match selcx.tcx().at(obligation.cause.span) + .const_eval(param_env.and(cid)) { + Ok(_) => Ok(Some(vec![])), + Err(e) => Err(CodeSelectionError(ConstEvalFailure(e))) + } + } else { + Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { + span: selcx.tcx().def_span(def_id), + kind: TypeckError, + }))) + } + }, None => { pending_obligation.stalled_on = substs.types().collect(); Ok(None) } - Some(substs) => { - match selcx.tcx().at(obligation.cause.span) - .const_eval(param_env.and((def_id, substs))) { - Ok(_) => Ok(Some(vec![])), - Err(e) => Err(CodeSelectionError(ConstEvalFailure(e))) - } - } } } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ae539f07336d5..7141c6d0520a7 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -28,6 +28,7 @@ use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use infer::type_variable::TypeVariableOrigin; use middle::const_val::ConstVal; +use mir::interpret::{GlobalId}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::symbol::Symbol; use ty::subst::{Subst, Substs}; @@ -349,12 +350,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { if let ConstVal::Unevaluated(def_id, substs) = constant.val { - if substs.needs_infer() { - let identity_substs = Substs::identity_for_item(self.tcx(), def_id); - let data = self.param_env.and((def_id, identity_substs)); - match self.tcx().lift_to_global(&data) { - Some(data) => { - match self.tcx().const_eval(data) { + let tcx = self.selcx.tcx().global_tcx(); + if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { + if substs.needs_infer() { + let identity_substs = Substs::identity_for_item(tcx, def_id); + let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None + }; + match tcx.const_eval(param_env.and(cid)) { Ok(evaluated) => { let evaluated = evaluated.subst(self.tcx(), substs); return self.fold_const(evaluated); @@ -362,18 +368,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, Err(_) => {} } } - None => {} - } - } else { - let data = self.param_env.and((def_id, substs)); - match self.tcx().lift_to_global(&data) { - Some(data) => { - match self.tcx().const_eval(data) { - Ok(evaluated) => return self.fold_const(evaluated), - Err(_) => {} + } else { + if let Some(substs) = self.tcx().lift_to_global(&substs) { + let instance = ty::Instance::resolve(tcx, param_env, def_id, substs); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(evaluated) => return self.fold_const(evaluated), + Err(_) => {} + } } } - None => {} } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d436d..e777e395d2978 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -40,6 +40,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::relate::TypeRelation; use middle::lang_items; +use mir::interpret::{GlobalId}; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec}; @@ -756,11 +757,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Predicate::ConstEvaluatable(def_id, substs) => { - match self.tcx().lift_to_global(&(obligation.param_env, substs)) { + let tcx = self.tcx(); + match tcx.lift_to_global(&(obligation.param_env, substs)) { Some((param_env, substs)) => { - match self.tcx().const_eval(param_env.and((def_id, substs))) { - Ok(_) => EvaluatedToOk, - Err(_) => EvaluatedToErr + let instance = ty::Instance::resolve( + tcx.global_tcx(), + param_env, + def_id, + substs, + ); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None + }; + match self.tcx().const_eval(param_env.and(cid)) { + Ok(_) => EvaluatedToOk, + Err(_) => EvaluatedToErr + } + } else { + EvaluatedToErr } } None => { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..018d23a33b846 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -10,9 +10,10 @@ use dep_graph::SerializedDepNodeIndex; use hir::def_id::{CrateNum, DefId, DefIndex}; +use mir::interpret::{GlobalId}; use ty::{self, Ty, TyCtxt}; -use ty::maps::queries; use ty::subst::Substs; +use ty::maps::queries; use std::hash::Hash; use syntax_pos::symbol::InternedString; @@ -152,8 +153,8 @@ impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> { } impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { - fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String { - format!("const-evaluating `{}`", tcx.item_path_str(key.value.0)) + fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String { + format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())) } } diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index 3dd482ad16401..8fb1ad0da823b 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -53,6 +53,16 @@ impl<'tcx> Key for ty::Instance<'tcx> { } } +impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { + fn map_crate(&self) -> CrateNum { + self.instance.map_crate() + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + self.instance.default_span(tcx) + } +} + impl Key for CrateNum { fn map_crate(&self) -> CrateNum { *self diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 85fca68187fe6..c5c91eb36bc3a 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -29,6 +29,7 @@ use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::SymbolExportLevel; use mir::mono::{CodegenUnit, Stats}; use mir; +use mir::interpret::{GlobalId}; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::Vtable; @@ -204,7 +205,7 @@ define_maps! { <'tcx> /// Results of evaluating const items or constants embedded in /// other items (such as enum variant explicit discriminants). - [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) + [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> const_val::EvalResult<'tcx>, [] fn check_match: CheckMatch(DefId) @@ -420,7 +421,7 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::TypeckBodiesKrate } -fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) +fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> DepConstructor<'tcx> { DepConstructor::ConstEval { param_env } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 38f17cc8623ef..82182171c994d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,7 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::{GlobalId, Value, PrimVal}; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits; @@ -1790,7 +1790,12 @@ impl<'a, 'gcx, 'tcx> AdtDef { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); - match tcx.const_eval(param_env.and((expr_did, substs))) { + let instance = ty::Instance::new(expr_did, substs); + let cid = GlobalId { + instance, + promoted: None + }; + match tcx.const_eval(param_env.and(cid)) { Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. @@ -1840,7 +1845,12 @@ impl<'a, 'gcx, 'tcx> AdtDef { } ty::VariantDiscr::Explicit(expr_did) => { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); - match tcx.const_eval(param_env.and((expr_did, substs))) { + let instance = ty::Instance::new(expr_did, substs); + let cid = GlobalId { + instance, + promoted: None + }; + match tcx.const_eval(param_env.and(cid)) { Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 38af96e49246a..cb0852cfd25c0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -20,7 +20,7 @@ use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::{GlobalId, Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -487,17 +487,29 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let param_env = ty::ParamEnv::empty(Reveal::UserFacing); match tcx.lift_to_global(&substs) { Some(substs) => { - match tcx.const_eval(param_env.and((def_id, substs))) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - .. - }) => { - assert_eq!(b as u64 as u128, b); - return Ok(b as u64); + let instance = ty::Instance::resolve( + tcx.global_tcx(), + param_env, + def_id, + substs, + ); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + assert_eq!(b as u64 as u128, b); + return Ok(b as u64); + } + _ => {} } - _ => {} } - } + }, None => {} } tcx.sess.delay_span_bug(tcx.def_span(def_id), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ce56eda0c4d40..33964b1092520 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -58,6 +58,7 @@ CopyImpls! { ::syntax::abi::Abi, ::hir::def_id::DefId, ::mir::Local, + ::mir::Promoted, ::traits::Reveal, ::syntax_pos::Span, } @@ -610,7 +611,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { type Lifted = interpret::EvalError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - use mir::interpret::EvalErrorKind::*; + use ::mir::interpret::EvalErrorKind::*; let kind = match self.kind { MachineError(ref err) => MachineError(err.clone()), FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( @@ -765,6 +766,42 @@ impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { + type Lifted = ty::InstanceDef<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ty::InstanceDef::Item(def_id) => + Some(ty::InstanceDef::Item(def_id)), + ty::InstanceDef::Intrinsic(def_id) => + Some(ty::InstanceDef::Intrinsic(def_id)), + ty::InstanceDef::FnPtrShim(def_id, ref ty) => + Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)), + ty::InstanceDef::Virtual(def_id, n) => + Some(ty::InstanceDef::Virtual(def_id, n)), + ty::InstanceDef::ClosureOnceShim { call_once } => + Some(ty::InstanceDef::ClosureOnceShim { call_once }), + ty::InstanceDef::DropGlue(def_id, ref ty) => + Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)), + ty::InstanceDef::CloneShim(def_id, ref ty) => + Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?)), + } + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for ty::Instance<'a> { + type Lifted = ty::Instance<'tcx>; + def, substs + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for interpret::GlobalId<'a> { + type Lifted = interpret::GlobalId<'tcx>; + instance, promoted + } +} + /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // @@ -945,6 +982,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Self { + instance: self.instance.fold_with(folder), + promoted: self.promoted + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.instance.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { diff --git a/src/librustc_mir/const_eval/check.rs b/src/librustc_mir/const_eval/check.rs index 70435c16ff72e..a9508defdcd81 100644 --- a/src/librustc_mir/const_eval/check.rs +++ b/src/librustc_mir/const_eval/check.rs @@ -12,7 +12,7 @@ use rustc::mir::*; use rustc::mir::visit::Visitor; -use rustc::mir::interpret::{Value, PrimVal}; +use rustc::mir::interpret::{Value, PrimVal, GlobalId}; use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind}; use rustc::traits; use interpret::{eval_body_as_integer, check_body}; @@ -41,7 +41,11 @@ pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { let instance = Instance::mono(tcx, def_id); for i in 0.. mir.promoted.len() { use rustc_data_structures::indexed_vec::Idx; - check_body(tcx, instance, Some(Promoted::new(i)), param_env); + let cid = GlobalId { + instance, + promoted: Some(Promoted::new(i)), + }; + check_body(tcx, cid, param_env); } } @@ -65,7 +69,11 @@ impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> { }, Literal::Promoted { index } => { let instance = Instance::mono(self.tcx, self.def_id); - eval_body_as_integer(self.tcx, param_env, instance, Some(index)).unwrap() + let cid = GlobalId { + instance, + promoted: Some(index), + }; + eval_body_as_integer(self.tcx, cid, param_env).unwrap() } }; Some(val) diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index e657a280e7f5c..7cc8a3f271c9f 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -12,7 +12,7 @@ use interpret::{const_val_field, const_discr}; use rustc::middle::const_val::{ConstEvalErr, ErrKind, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; -use rustc::mir::interpret::{Value, PrimVal}; +use rustc::mir::interpret::{GlobalId, Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -673,14 +673,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { + let instance = ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ).unwrap(); + let cid = GlobalId { + instance, + promoted: None, + }; + match self.tcx.at(span).const_eval(self.param_env.and(cid)) { Ok(value) => { - let instance = ty::Instance::resolve( - self.tcx, - self.param_env, - def_id, - substs, - ).unwrap(); return self.const_to_pat(instance, value, id, span) }, Err(e) => { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 47ed60b011367..9dce10793068a 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -15,7 +15,7 @@ use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{Value, PrimVal}; +use rustc::mir::interpret::{GlobalId, Value, PrimVal}; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::cast::CastKind as TyCastKind; @@ -510,7 +510,17 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); - let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { + let instance = ty::Instance::resolve( + cx.tcx.global_tcx(), + cx.param_env, + def_id, + substs, + ).unwrap(); + let global_id = GlobalId { + instance, + promoted: None + }; + let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) { Ok(cv) => cv.val.unwrap_usize(cx.tcx), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index b53069791d510..9cd02e53bf706 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,11 +1,10 @@ -use rustc::ty::{self, TyCtxt, Ty, Instance}; -use rustc::ty::layout::{self, LayoutOf}; -use rustc::ty::subst::Substs; -use rustc::hir::def_id::DefId; -use rustc::mir; +use rustc::hir; use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError}; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use const_eval::lookup_const_by_id; +use rustc::mir; +use rustc::ty::{self, TyCtxt, Ty, Instance}; +use rustc::ty::layout::{self, LayoutOf}; +use rustc::ty::subst::Subst; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -38,20 +37,18 @@ pub fn mk_eval_cx<'a, 'tcx>( pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - promoted: Option, + cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { - eval_body_and_ecx(tcx, instance, promoted, param_env).0 + eval_body_and_ecx(tcx, cid, param_env).0 } pub fn check_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - promoted: Option, + cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) { - let (res, ecx) = eval_body_and_ecx(tcx, instance, promoted, param_env); + let (res, ecx) = eval_body_and_ecx(tcx, cid, param_env); if let Err(mut err) = res { ecx.report(&mut err); } @@ -59,26 +56,22 @@ pub fn check_body<'a, 'tcx>( fn eval_body_and_ecx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - promoted: Option, + cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'tcx, CompileTimeEvaluator>) { - debug!("eval_body: {:?}, {:?}", instance, param_env); + debug!("eval_body: {:?}, {:?}", cid, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); - let cid = GlobalId { - instance, - promoted, - }; - let res = (|| { - if ecx.tcx.has_attr(instance.def_id(), "linkage") { + let mut mir = ecx.load_mir(cid.instance.def)?; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + if ecx.tcx.has_attr(cid.instance.def_id(), "linkage") { return Err(ConstEvalError::NotConst("extern global".to_string()).into()); } - let instance_ty = instance.ty(tcx); if tcx.interpret_interner.borrow().get_cached(cid).is_none() { - let mir = ecx.load_mir(instance.def)?; - let layout = ecx.layout_of(instance_ty)?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( layout.size.bytes(), @@ -87,10 +80,10 @@ fn eval_body_and_ecx<'a, 'tcx>( )?; tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); - let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); trace!("const_eval: pushing stack frame for global: {}", name); ecx.push_stack_frame( - instance, + cid.instance, mir.span, mir, Place::from_ptr(ptr, layout.align), @@ -100,24 +93,22 @@ fn eval_body_and_ecx<'a, 'tcx>( while ecx.step()? {} } let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - let align = ecx.layout_of(instance_ty)?.align; let ptr = MemoryPointer::new(alloc, 0).into(); - let value = match ecx.try_read_value(ptr, align, instance_ty)? { + let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { Some(val) => val, - _ => Value::ByRef(ptr, align), + _ => Value::ByRef(ptr, layout.align), }; - Ok((value, ptr, instance_ty)) + Ok((value, ptr, layout.ty)) })(); (res, ecx) } pub fn eval_body_as_integer<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, + cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, - instance: Instance<'tcx>, - promoted: Option, ) -> EvalResult<'tcx, u128> { - let (value, _, ty) = eval_body(tcx, instance, promoted, param_env)?; + let (value, _, ty) = eval_body(tcx, cid, param_env)?; match value { Value::ByVal(prim) => prim.to_bytes(), _ => err!(TypeNotPrimitive(ty)), @@ -325,7 +316,7 @@ fn const_val_field_inner<'a, 'tcx>( field: mir::Field, value: Value, ty: Ty<'tcx>, -) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Ty<'tcx>)> { trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let (mut field, ty) = match value { @@ -376,51 +367,47 @@ pub fn const_discr<'a, 'tcx>( pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, + key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { trace!("const eval: {:?}", key); - let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) { - resolved - } else { - return Err(ConstEvalErr { - span: tcx.def_span(key.value.0), - kind: TypeckError - }); - }; + let cid = key.value; + let def_id = cid.instance.def.def_id(); + let span = tcx.def_span(def_id); - let tables = tcx.typeck_tables_of(def_id); - let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { - let body_id = tcx.hir.body_owned_by(id); + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + let tables = tcx.typeck_tables_of(def_id); // Do match-check before building MIR if tcx.check_match(def_id).is_err() { return Err(ConstEvalErr { - span: tcx.def_span(key.value.0), + span, kind: CheckMatchError, }); } - tcx.mir_const_qualif(def_id); - tcx.hir.body(body_id) - } else { - tcx.extern_const_body(def_id).body - }; - - // do not continue into miri if typeck errors occurred - // it will fail horribly - if tables.tainted_by_errors { - return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) - } + if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) { + tcx.mir_const_qualif(def_id); + } + // Do not continue into miri if typeck errors occurred; it will fail horribly + if tables.tainted_by_errors { + return Err(ConstEvalErr { + span, + kind: TypeckError + }); + } + }; - let instance = ty::Instance::new(def_id, substs); - match ::interpret::eval_body(tcx, instance, None, key.param_env) { + match ::interpret::eval_body(tcx, cid, key.param_env) { Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), ty: miri_ty, })), Err(err) => { - Err(ConstEvalErr { span: body.value.span, kind: err.into() }) + Err(ConstEvalErr { + span, + kind: err.into() + }) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3ee48c8997a27..90a493064fd4e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,6 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::anon_types::AnonTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; +use rustc::mir::interpret::{GlobalId}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; @@ -4001,7 +4002,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let count_def_id = tcx.hir.body_owner_def_id(count); let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing); let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); - let count = tcx.const_eval(param_env.and((count_def_id, substs))); + let instance = ty::Instance::resolve( + tcx.global_tcx(), + param_env, + count_def_id, + substs, + ).unwrap(); + let global_id = GlobalId { + instance, + promoted: None + }; + let count = tcx.const_eval(param_env.and(global_id)); if let Err(ref err) = count { err.report(tcx, tcx.def_span(count_def_id), "constant expression"); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ab8e0300188c3..cd1ed9dcae130 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -36,7 +36,7 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; -use rustc::mir::interpret::{Value, PrimVal}; +use rustc::mir::interpret::{GlobalId, Value, PrimVal}; use util::nodemap::FxHashMap; use rustc_const_math::ConstInt; @@ -526,7 +526,12 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let substs = Substs::identity_for_item(tcx, expr_did); - let result = tcx.at(variant.span).const_eval(param_env.and((expr_did, substs))); + let instance = ty::Instance::new(expr_did, substs); + let global_id = GlobalId { + instance, + promoted: None + }; + let result = tcx.at(variant.span).const_eval(param_env.and(global_id)); // enum variant evaluation happens before the global constant check // so we need to report the real error From b9345b97efb69bdb52d1a10bd67c8420978bb00d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:31:48 +0100 Subject: [PATCH 009/115] Fully use miri in trans --- src/librustc/middle/const_val.rs | 13 +- src/librustc/mir/interpret/error.rs | 4 +- src/librustc/mir/interpret/mod.rs | 3 + src/librustc/mir/mod.rs | 17 +- src/librustc/traits/error_reporting.rs | 3 +- src/librustc/traits/fulfill.rs | 9 +- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/context.rs | 32 +- src/librustc/ty/maps/mod.rs | 4 +- src/librustc/ty/mod.rs | 8 +- src/librustc/ty/util.rs | 28 +- src/librustc_llvm/ffi.rs | 10 + src/librustc_metadata/decoder.rs | 4 +- src/librustc_metadata/encoder.rs | 8 +- src/librustc_mir/borrow_check/mod.rs | 13 +- src/librustc_mir/const_eval/check.rs | 92 +- src/librustc_mir/const_eval/check_match.rs | 14 +- src/librustc_mir/const_eval/eval.rs | 12 +- src/librustc_mir/const_eval/pattern.rs | 75 +- src/librustc_mir/dataflow/impls/borrows.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 5 +- src/librustc_mir/hair/cx/mod.rs | 13 +- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/interpret/const_eval.rs | 204 ++- src/librustc_mir/interpret/eval_context.rs | 125 +- src/librustc_mir/interpret/machine.rs | 28 +- src/librustc_mir/interpret/memory.rs | 144 +- src/librustc_mir/interpret/mod.rs | 13 +- src/librustc_mir/interpret/operator.rs | 22 +- src/librustc_mir/interpret/place.rs | 55 +- src/librustc_mir/interpret/step.rs | 241 +-- src/librustc_mir/interpret/terminator/drop.rs | 2 +- src/librustc_mir/interpret/terminator/mod.rs | 2 +- src/librustc_mir/interpret/traits.rs | 4 +- src/librustc_mir/monomorphize/collector.rs | 51 +- src/librustc_mir/transform/check_unsafety.rs | 2 +- src/librustc_mir/transform/instcombine.rs | 487 +++++- src/librustc_trans/consts.rs | 12 +- src/librustc_trans/mir/block.rs | 35 +- src/librustc_trans/mir/constant.rs | 1420 +++-------------- src/librustc_trans/mir/mod.rs | 3 + src/librustc_trans/mir/operand.rs | 92 +- src/librustc_trans/trans_item.rs | 7 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 12 +- src/test/compile-fail/E0030.rs | 2 +- src/test/compile-fail/E0080.rs | 5 +- src/test/compile-fail/const-call.rs | 1 + src/test/compile-fail/const-err-early.rs | 13 +- src/test/compile-fail/const-err-multi.rs | 5 + src/test/compile-fail/const-err.rs | 21 - src/test/compile-fail/const-err2.rs | 6 +- src/test/compile-fail/const-err3.rs | 28 + src/test/compile-fail/const-eval-overflow.rs | 154 -- src/test/compile-fail/const-eval-overflow2.rs | 91 ++ .../compile-fail/const-eval-overflow2b.rs | 91 ++ .../compile-fail/const-eval-overflow2c.rs | 91 ++ .../compile-fail/const-integer-bool-ops.rs | 10 + .../const-len-underflow-subspans.rs | 2 +- src/test/compile-fail/const-size_of-cycle.rs | 2 +- src/test/compile-fail/const-slice-oob.rs | 2 + src/test/compile-fail/const-tup-index-span.rs | 1 + src/test/compile-fail/eval-enum.rs | 15 +- .../float-int-invalid-const-cast.rs | 61 - src/test/compile-fail/issue-27895.rs | 3 +- src/test/compile-fail/issue-41255.rs | 18 +- src/test/compile-fail/issue-44578.rs | 4 +- src/test/compile-fail/issue-6804.rs | 7 +- src/test/compile-fail/issue-8460-const.rs | 20 + .../compile-fail/lint-exceeding-bitshifts.rs | 18 +- .../compile-fail/lint-exceeding-bitshifts2.rs | 27 + src/test/compile-fail/lint-type-overflow2.rs | 1 + .../non-constant-in-const-path.rs | 3 +- .../rfc1445/match-forbidden-without-eq.rs | 2 +- .../const-index-feature-gate.rs | 3 +- .../run-pass/float-int-invalid-const-cast.rs | 61 + src/test/ui/const-eval-overflow-2.stderr | 4 +- src/test/ui/const-eval-overflow-4.stderr | 2 +- src/test/ui/const-eval/issue-43197.rs | 2 + src/test/ui/const-eval/issue-43197.stderr | 44 +- src/test/ui/const-expr-addr-operator.stderr | 23 + .../ui/const-len-underflow-separate-spans.rs | 1 + .../const-len-underflow-separate-spans.stderr | 20 +- 84 files changed, 2010 insertions(+), 2192 deletions(-) create mode 100644 src/test/compile-fail/const-err3.rs delete mode 100644 src/test/compile-fail/const-eval-overflow.rs create mode 100644 src/test/compile-fail/const-eval-overflow2.rs create mode 100644 src/test/compile-fail/const-eval-overflow2b.rs create mode 100644 src/test/compile-fail/const-eval-overflow2c.rs delete mode 100644 src/test/compile-fail/float-int-invalid-const-cast.rs create mode 100644 src/test/compile-fail/lint-exceeding-bitshifts2.rs rename src/test/{compile-fail => run-pass}/const-index-feature-gate.rs (83%) create mode 100644 src/test/run-pass/float-int-invalid-const-cast.rs diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index dd99305809c28..35c51c0c206b0 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -15,9 +15,9 @@ use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; use mir::interpret::{Value, PrimVal}; +use errors::DiagnosticBuilder; use graphviz::IntoCow; -use errors::DiagnosticBuilder; use serialize; use syntax_pos::Span; @@ -169,6 +169,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { TypeckError => simple!("type-checking failed"), CheckMatchError => simple!("match-checking failed"), + // FIXME: report a full backtrace Miri(ref err) => simple!("miri failed: {}", err), } } @@ -186,7 +187,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { err = i_err; } - let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + let mut diag = struct_error(tcx, err.span, "constant evaluation error"); err.note(tcx, primary_span, primary_kind, &mut diag); diag } @@ -221,3 +222,11 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_error(tcx, primary_span, primary_kind).emit(); } } + +pub fn struct_error<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + span: Span, + msg: &str, +) -> DiagnosticBuilder<'gcx> { + struct_span_err!(tcx.sess, span, E0080, "{}", msg) +} diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 6386de5952f99..977e617968aa4 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -286,8 +286,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { write!(f, "tried to reallocate memory from {} to {}", old, new), DeallocatedWrongMemoryKind(ref old, ref new) => write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), - Math(span, ref err) => - write!(f, "{:?} at {:?}", err, span), + Math(_, ref err) => + write!(f, "{}", err.description()), Intrinsic(ref err) => write!(f, "{}", err), InvalidChar(c) => diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index b10f3ae9291d3..a55dae33964ab 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -169,6 +169,8 @@ pub struct Allocation { pub undef_mask: UndefMask, /// The alignment of the allocation to detect unaligned reads. pub align: Align, + /// Whether the allocation should be put into mutable memory when translating via llvm + pub mutable: bool, } impl Allocation { @@ -180,6 +182,7 @@ impl Allocation { relocations: BTreeMap::new(), undef_mask, align: Align::from_bytes(1, 1).unwrap(), + mutable: false, } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 2c95aebe0735b..e254beebdd560 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1799,13 +1799,16 @@ fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { let alloc = tcx .interpret_interner .borrow() - .get_alloc(ptr.alloc_id) - .expect("miri alloc not found"); - assert_eq!(len as usize as u128, len); - let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - write!(f, "{:?}", s) + .get_alloc(ptr.alloc_id); + if let Some(alloc) = alloc { + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + write!(f, "{:?}", s) + } else { + write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) + } }) }, _ => write!(f, "{:?}:{}", value, ty), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7b86791026b41..31442256401c5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -32,7 +32,6 @@ use hir; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; -use middle::const_val; use std::fmt; use syntax::ast; use session::DiagnosticMessageId; @@ -762,7 +761,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ConstEvalFailure(ref err) => { - if let const_val::ErrKind::TypeckError = err.kind { + if let ::middle::const_val::ErrKind::TypeckError = err.kind { return; } err.struct_error(self.tcx, span, "constant expression") diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 21d0113cf4a5e..680c6f4d55d77 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -9,8 +9,6 @@ // except according to those terms. use infer::{RegionObligation, InferCtxt, InferOk}; -use middle::const_val::ConstEvalErr; -use middle::const_val::ErrKind::TypeckError; use mir::interpret::{GlobalId}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; use ty::error::ExpectedFound; @@ -18,6 +16,7 @@ use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; use hir::def_id::DefId; +use middle::const_val::{ConstEvalErr, ErrKind}; use super::CodeAmbiguity; use super::CodeProjectionError; @@ -543,12 +542,12 @@ fn process_predicate<'a, 'gcx, 'tcx>( match selcx.tcx().at(obligation.cause.span) .const_eval(param_env.and(cid)) { Ok(_) => Ok(Some(vec![])), - Err(e) => Err(CodeSelectionError(ConstEvalFailure(e))) + Err(err) => Err(CodeSelectionError(ConstEvalFailure(err))) } } else { Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { - span: selcx.tcx().def_span(def_id), - kind: TypeckError, + span: obligation.cause.span, + kind: ErrKind::UnimplementedConstVal("could not resolve"), }))) } }, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 80819a86b7c46..5ffdcb8aef779 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -18,8 +18,8 @@ pub use self::ObligationCauseCode::*; use hir; use hir::def_id::DefId; use infer::outlives::env::OutlivesEnvironment; -use middle::const_val::ConstEvalErr; use middle::region; +use middle::const_val::ConstEvalErr; use ty::subst::Substs; use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate}; use ty::error::{ExpectedFound, TypeError}; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 7cd776c7ba584..a7e5771934723 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -906,16 +906,17 @@ pub struct InterpretInterner<'tcx> { alloc_by_id: FxHashMap, /// Reverse map of `alloc_cache` - /// - /// Multiple globals may share the same memory - global_cache: FxHashMap>>, + global_cache: FxHashMap, /// The AllocId to assign to the next new regular allocation. /// Always incremented, never gets smaller. next_id: interpret::AllocId, - /// Allows checking whether a constant already has an allocation - alloc_cache: FxHashMap, interpret::AllocId>, + /// Allows checking whether a static already has an allocation + /// + /// This is only important for detecting statics referring to themselves + // FIXME(oli-obk) move it to the EvalContext? + alloc_cache: FxHashMap, /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate /// allocations for string and bytestring literals. @@ -950,30 +951,27 @@ impl<'tcx> InterpretInterner<'tcx> { pub fn get_cached( &self, - global_id: interpret::GlobalId<'tcx>, + static_id: DefId, ) -> Option { - self.alloc_cache.get(&global_id).cloned() + self.alloc_cache.get(&static_id).cloned() } pub fn cache( &mut self, - global_id: interpret::GlobalId<'tcx>, + static_id: DefId, alloc_id: interpret::AllocId, ) { - self.global_cache.entry(alloc_id).or_default().push(global_id); - if let Some(old) = self.alloc_cache.insert(global_id, alloc_id) { - bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old); + self.global_cache.insert(alloc_id, static_id); + if let Some(old) = self.alloc_cache.insert(static_id, alloc_id) { + bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old); } } - pub fn get_globals( + pub fn get_corresponding_static_def_id( &self, ptr: interpret::AllocId, - ) -> &[interpret::GlobalId<'tcx>] { - match self.global_cache.get(&ptr) { - Some(v) => v, - None => &[], - } + ) -> Option { + self.global_cache.get(&ptr).cloned() } pub fn intern_at_reserved( diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index c5c91eb36bc3a..c299164543d1a 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -16,7 +16,6 @@ use hir::{self, TraitCandidate, ItemLocalId}; use hir::svh::Svh; use lint; use middle::borrowck::BorrowCheckResult; -use middle::const_val; use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ExternBodyNestedBodies}; use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody}; @@ -27,6 +26,7 @@ use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::SymbolExportLevel; +use middle::const_val::EvalResult; use mir::mono::{CodegenUnit, Stats}; use mir; use mir::interpret::{GlobalId}; @@ -206,7 +206,7 @@ define_maps! { <'tcx> /// Results of evaluating const items or constants embedded in /// other items (such as enum variant explicit discriminants). [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> const_val::EvalResult<'tcx>, + -> EvalResult<'tcx>, [] fn check_match: CheckMatch(DefId) -> Result<(), ErrorReported>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 82182171c994d..332fef5bbb0e6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1809,11 +1809,11 @@ impl<'a, 'gcx, 'tcx> AdtDef { b, uint_type, tcx.sess.target.usize_ty).unwrap(), }; } - err => { + _ => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), "variant discriminant evaluation succeeded \ - in its crate but failed locally: {:?}", err); + in its crate but failed locally"); } } } @@ -1865,11 +1865,11 @@ impl<'a, 'gcx, 'tcx> AdtDef { }; break; } - err => { + _ => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), "variant discriminant evaluation succeeded \ - in its crate but failed locally: {:?}", err); + in its crate but failed locally"); } if explicit_index == 0 { break; diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4348324b2b989..29569423947e4 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -686,22 +686,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Check if the node pointed to by def_id is a mutable static item - pub fn is_static_mut(&self, def_id: DefId) -> bool { + /// Return whether the node pointed to by def_id is a static item, and its mutability + pub fn is_static(&self, def_id: DefId) -> Option { if let Some(node) = self.hir.get_if_local(def_id) { match node { Node::NodeItem(&hir::Item { - node: hir::ItemStatic(_, hir::MutMutable, _), .. - }) => true, + node: hir::ItemStatic(_, mutbl, _), .. + }) => Some(mutbl), Node::NodeForeignItem(&hir::ForeignItem { - node: hir::ForeignItemStatic(_, mutbl), .. - }) => mutbl, - _ => false + node: hir::ForeignItemStatic(_, is_mutbl), .. + }) => + Some(if is_mutbl { + hir::Mutability::MutMutable + } else { + hir::Mutability::MutImmutable + }), + _ => None } } else { match self.describe_def(def_id) { - Some(Def::Static(_, mutbl)) => mutbl, - _ => false + Some(Def::Static(_, is_mutbl)) => + Some(if is_mutbl { + hir::Mutability::MutMutable + } else { + hir::Mutability::MutImmutable + }), + _ => None } } } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 99e43a2ddf98d..67cacee77b092 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -661,6 +661,16 @@ extern "C" { pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstGEP( + ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint, + ) -> ValueRef; + pub fn LLVMConstInBoundsGEP( + ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint, + ) -> ValueRef; pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a9d2164c5723a..f9045a0ffb5eb 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -298,9 +298,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx let allocation = self.tcx.unwrap().intern_const_alloc(allocation); interpret_interner().intern_at_reserved(alloc_id, allocation); - let num = usize::decode(self)?; - for _ in 0..num { - let glob = interpret::GlobalId::decode(self)?; + if let Some(glob) = Option::::decode(self)? { interpret_interner().cache(glob, alloc_id); } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7fd307949319a..953e2e41b417f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -209,11 +209,9 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - let globals = interpret_interner.get_globals(*alloc_id); - globals.len().encode(self)?; - for glob in globals { - glob.encode(self)?; - } + interpret_interner + .get_corresponding_static_def_id(*alloc_id) + .encode(self)?; } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 9a6d83b8eb759..9c16a94013e7c 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1549,11 +1549,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Mutability::Mut => Ok(()), } } - Place::Static(ref static_) => if !self.tcx.is_static_mut(static_.def_id) { - Err(place) - } else { - Ok(()) - }, + Place::Static(ref static_) => + if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) { + Err(place) + } else { + Ok(()) + }, Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { @@ -1706,7 +1707,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if static1.def_id != static2.def_id { debug!("place_element_conflict: DISJOINT-STATIC"); Overlap::Disjoint - } else if self.tcx.is_static_mut(static1.def_id) { + } else if self.tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) { // We ignore mutable statics - they can only be unsafe code. debug!("place_element_conflict: IGNORE-STATIC-MUT"); Overlap::Disjoint diff --git a/src/librustc_mir/const_eval/check.rs b/src/librustc_mir/const_eval/check.rs index a9508defdcd81..9827dd58cd640 100644 --- a/src/librustc_mir/const_eval/check.rs +++ b/src/librustc_mir/const_eval/check.rs @@ -11,47 +11,77 @@ //! Lints statically known runtime failures use rustc::mir::*; +use rustc::hir; +use rustc::hir::map::Node; use rustc::mir::visit::Visitor; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind}; +use rustc::hir::def::Def; use rustc::traits; -use interpret::{eval_body_as_integer, check_body}; -use rustc::ty::{TyCtxt, ParamEnv, self}; +use interpret::eval_body_with_mir; +use rustc::ty::{TyCtxt, ParamEnv}; use rustc::ty::Instance; use rustc::ty::layout::LayoutOf; use rustc::hir::def_id::DefId; +use rustc::ty::subst::Substs; + +fn is_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + if let Some(node) = tcx.hir.get_if_local(def_id) { + match node { + Node::NodeItem(&hir::Item { + node: hir::ItemConst(..), .. + }) => true, + _ => false + } + } else { + match tcx.describe_def(def_id) { + Some(Def::Const(_)) => true, + _ => false + } + } +} pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - if tcx.is_closure(def_id) { - return; + let mir = &tcx.optimized_mir(def_id); + let substs = Substs::identity_for_item(tcx, def_id); + let instance = Instance::new(def_id, substs); + let param_env = tcx.param_env(def_id); + + if is_const(tcx, def_id) { + let cid = GlobalId { + instance, + promoted: None, + }; + eval_body_with_mir(tcx, cid, mir, param_env); } - let generics = tcx.generics_of(def_id); + + ConstErrVisitor { + tcx, + mir, + }.visit_mir(mir); + let outer_def_id = if tcx.is_closure(def_id) { + tcx.closure_base_def_id(def_id) + } else { + def_id + }; + let generics = tcx.generics_of(outer_def_id); // FIXME: miri should be able to eval stuff that doesn't need info // from the generics if generics.parent_types as usize + generics.types.len() > 0 { return; } - let mir = &tcx.optimized_mir(def_id); - ConstErrVisitor { - tcx, - def_id, - mir, - }.visit_mir(mir); - let param_env = ParamEnv::empty(traits::Reveal::All); - let instance = Instance::mono(tcx, def_id); for i in 0.. mir.promoted.len() { use rustc_data_structures::indexed_vec::Idx; let cid = GlobalId { instance, promoted: Some(Promoted::new(i)), }; - check_body(tcx, cid, param_env); + eval_body_with_mir(tcx, cid, mir, param_env); } } struct ConstErrVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, mir: &'a Mir<'tcx>, } @@ -61,22 +91,13 @@ impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> { Operand::Constant(ref c) => c, _ => return None, }; - let param_env = ParamEnv::empty(traits::Reveal::All); - let val = match op.literal { + match op.literal { Literal::Value { value } => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => b, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => Some(b), _ => return None, }, - Literal::Promoted { index } => { - let instance = Instance::mono(self.tcx, self.def_id); - let cid = GlobalId { - instance, - promoted: Some(index), - }; - eval_body_as_integer(self.tcx, cid, param_env).unwrap() - } - }; - Some(val) + _ => None, + } } } @@ -87,13 +108,14 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstErrVisitor<'a, 'tcx> { location: Location) { self.super_terminator(block, terminator, location); match terminator.kind { - TerminatorKind::Assert { cond: Operand::Constant(box Constant { - literal: Literal::Value { - value: &ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))), - .. } - }, .. - }), expected, ref msg, .. } if (cond == 1) != expected => { + TerminatorKind::Assert { ref cond, expected, ref msg, .. } => { + let cond = match self.eval_op(cond) { + Some(val) => val, + None => return, + }; + if (cond == 1) == expected { + return; + } assert!(cond <= 1); // If we know we always panic, and the error message // is also constant, then we can produce a warning. diff --git a/src/librustc_mir/const_eval/check_match.rs b/src/librustc_mir/const_eval/check_match.rs index ba8865f50fa6a..6524ad6945c30 100644 --- a/src/librustc_mir/const_eval/check_match.rs +++ b/src/librustc_mir/const_eval/check_match.rs @@ -138,8 +138,18 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternError::AssociatedConstInPattern(span) => { self.span_e0158(span, "associated consts cannot be referenced in patterns") } - PatternError::ConstEval(ref err) => { - err.report(self.tcx, pat_span, "pattern"); + PatternError::FloatBug => { + // FIXME(#31407) this is only necessary because float parsing is buggy + ::rustc::middle::const_val::struct_error( + self.tcx, pat_span, + "could not evaluate float literal (see issue #31407)", + ).emit(); + } + PatternError::NonConstPath(span) => { + ::rustc::middle::const_val::struct_error( + self.tcx, span, + "runtime values cannot be referenced in patterns", + ).emit(); } } } diff --git a/src/librustc_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs index 370b8681ba648..25a9e52236773 100644 --- a/src/librustc_mir/const_eval/eval.rs +++ b/src/librustc_mir/const_eval/eval.rs @@ -9,8 +9,7 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; -use rustc::middle::const_val::ErrKind::*; -use rustc::middle::const_val::{ConstVal, ErrKind}; +use rustc::middle::const_val::ConstVal; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; @@ -39,7 +38,7 @@ pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, neg: bool) - -> Result, ErrKind<'tcx>> { + -> Result, ()> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -126,11 +125,8 @@ pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, } fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) - -> Result> { - ConstFloat::from_str(num, fty).map_err(|_| { - // FIXME(#31407) this is only necessary because float parsing is buggy - UnimplementedConstVal("could not evaluate float literal (see issue #31407)") - }) + -> Result { + ConstFloat::from_str(num, fty).map_err(|_| ()) } pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 7cc8a3f271c9f..23c4d19ccacfb 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -10,7 +10,7 @@ use interpret::{const_val_field, const_discr}; -use rustc::middle::const_val::{ConstEvalErr, ErrKind, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::interpret::{GlobalId, Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; @@ -28,10 +28,11 @@ use syntax::ptr::P; use syntax_pos::Span; #[derive(Clone, Debug)] -pub enum PatternError<'tcx> { +pub enum PatternError { AssociatedConstInPattern(Span), StaticInPattern(Span), - ConstEval(ConstEvalErr<'tcx>), + FloatBug, + NonConstPath(Span), } #[derive(Copy, Clone, Debug)] @@ -279,7 +280,7 @@ pub struct PatternContext<'a, 'tcx: 'a> { pub param_env: ty::ParamEnv<'tcx>, pub tables: &'a ty::TypeckTables<'tcx>, pub substs: &'tcx Substs<'tcx>, - pub errors: Vec>, + pub errors: Vec, } impl<'a, 'tcx> Pattern<'tcx> { @@ -650,10 +651,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } _ => { - self.errors.push(PatternError::ConstEval(ConstEvalErr { - span, - kind: ErrKind::NonConstPath, - })); + self.errors.push(PatternError::NonConstPath(span)); PatternKind::Wild } } @@ -673,24 +671,35 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - let instance = ty::Instance::resolve( + match ty::Instance::resolve( self.tcx, self.param_env, def_id, substs, - ).unwrap(); - let cid = GlobalId { - instance, - promoted: None, - }; - match self.tcx.at(span).const_eval(self.param_env.and(cid)) { - Ok(value) => { - return self.const_to_pat(instance, value, id, span) + ) { + Some(instance) => { + let cid = GlobalId { + instance, + promoted: None, + }; + match self.tcx.at(span).const_eval(self.param_env.and(cid)) { + Ok(value) => { + return self.const_to_pat(instance, value, id, span) + }, + Err(err) => { + err.report(self.tcx, span, "pattern"); + PatternKind::Wild + }, + } }, - Err(e) => { - self.errors.push(PatternError::ConstEval(e)); + None => { + self.errors.push(if is_associated_const { + PatternError::AssociatedConstInPattern(span) + } else { + PatternError::StaticInPattern(span) + }); PatternKind::Wild - } + }, } } _ => self.lower_variant_or_leaf(def, span, ty, vec![]), @@ -716,11 +725,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let cv = self.tcx.mk_const(ty::Const { val, ty }); *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind }, - Err(e) => { - self.errors.push(PatternError::ConstEval(ConstEvalErr { - span: lit.span, - kind: e, - })); + Err(()) => { + self.errors.push(PatternError::FloatBug); PatternKind::Wild }, } @@ -733,17 +739,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) { - Ok(value) => PatternKind::Constant { - value: self.tcx.mk_const(ty::Const { - ty, - val: value, - }), + Ok(val) => { + let instance = ty::Instance::new( + self.tables.local_id_root.expect("literal outside any scope"), + self.substs, + ); + let cv = self.tcx.mk_const(ty::Const { val, ty }); + *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind }, - Err(e) => { - self.errors.push(PatternError::ConstEval(ConstEvalErr { - span: lit.span, - kind: e, - })); + Err(()) => { + self.errors.push(PatternError::FloatBug); PatternKind::Wild }, } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 80990bcc08089..9313ca87657d7 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -781,7 +781,7 @@ fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>( match *place { Local(_) => false, - Static(ref static_) => tcx.is_static_mut(static_.def_id), + Static(ref static_) => tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable), Projection(ref proj) => { match proj.elem { ProjectionElem::Field(..) | diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 9dce10793068a..0ab3be019781d 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -522,7 +522,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) { Ok(cv) => cv.val.unwrap_usize(cx.tcx), - Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") + Err(e) => { + e.report(cx.tcx, cx.tcx.def_span(def_id), "array length"); + ConstUsize::new(0, cx.tcx.sess.target.usize_ty).unwrap() + }, }; ExprKind::Repeat { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 1cba20db63aa4..f65029fed0a9a 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,7 @@ use hair::*; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -238,17 +238,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { p) } - pub fn fatal_const_eval_err(&mut self, - err: &ConstEvalErr<'tcx>, - primary_span: Span, - primary_kind: &str) - -> ! - { - err.report(self.tcx, primary_span, primary_kind); - self.tcx.sess.abort_if_errors(); - unreachable!() - } - pub fn trait_method(&mut self, trait_def_id: DefId, method_name: &str, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index b476ea5685229..7d7e6ec9451ed 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -7,7 +7,7 @@ use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmeti use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::Float; -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub(super) fn cast_primval( &self, val: PrimVal, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 9cd02e53bf706..4170656d64c90 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,6 +1,6 @@ use rustc::hir; -use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError}; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError}; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; use rustc::ty::layout::{self, LayoutOf}; @@ -9,17 +9,37 @@ use rustc::ty::subst::Subst; use syntax::ast::Mutability; use syntax::codemap::Span; -use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra}; +use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; use std::fmt; use std::error::Error; +pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>, + mir: &'mir mir::Mir<'tcx>, +) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { + debug!("mk_borrowck_eval_cx: {:?}", instance); + let param_env = tcx.param_env(instance.def_id()); + let limits = super::ResourceLimits::default(); + let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); + // insert a stack frame so any queries have the correct substs + ecx.push_stack_frame( + instance, + mir.span, + mir, + Place::undef(), + StackPopCleanup::None, + )?; + Ok(ecx) +} + pub fn mk_eval_cx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, EvalContext<'a, 'tcx, CompileTimeEvaluator>> { +) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> { debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); @@ -35,64 +55,95 @@ pub fn mk_eval_cx<'a, 'tcx>( Ok(ecx) } -pub fn eval_body<'a, 'tcx>( +pub fn eval_body_with_mir<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, + mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { - eval_body_and_ecx(tcx, cid, param_env).0 +) -> Option<(Value, Pointer, Ty<'tcx>)> { + let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); + match res { + Ok(val) => Some(val), + Err(mut err) => { + ecx.report(&mut err, true); + None + } + } } -pub fn check_body<'a, 'tcx>( +pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, -) { - let (res, ecx) = eval_body_and_ecx(tcx, cid, param_env); - if let Err(mut err) = res { - ecx.report(&mut err); +) -> Option<(Value, Pointer, Ty<'tcx>)> { + let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env); + match res { + Ok(val) => Some(val), + Err(mut err) => { + ecx.report(&mut err, true); + None + } } } -fn eval_body_and_ecx<'a, 'tcx>( +fn eval_body_and_ecx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, + mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'tcx, CompileTimeEvaluator>) { +) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { debug!("eval_body: {:?}, {:?}", cid, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); let res = (|| { - let mut mir = ecx.load_mir(cid.instance.def)?; + let mut mir = match mir { + Some(mir) => mir, + None => ecx.load_mir(cid.instance.def)?, + }; if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - if ecx.tcx.has_attr(cid.instance.def_id(), "linkage") { - return Err(ConstEvalError::NotConst("extern global".to_string()).into()); - } - if tcx.interpret_interner.borrow().get_cached(cid).is_none() { - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); - let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - trace!("const_eval: pushing stack frame for global: {}", name); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup.clone(), - )?; - - while ecx.step()? {} - } - let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); + let alloc = tcx.interpret_interner.borrow().get_cached(cid.instance.def_id()); + let alloc = match alloc { + Some(alloc) => { + assert!(cid.promoted.is_none()); + assert!(param_env.caller_bounds.is_empty()); + alloc + }, + None => { + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + if tcx.is_static(cid.instance.def_id()).is_some() { + tcx.interpret_interner.borrow_mut().cache(cid.instance.def_id(), ptr.alloc_id); + } + let span = tcx.def_span(cid.instance.def_id()); + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, span); + let mutability = tcx.is_static(cid.instance.def_id()); + let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + trace!("const_eval: pushing stack frame for global: {}", name); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? {} + ptr.alloc_id + } + }; let ptr = MemoryPointer::new(alloc, 0).into(); let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { Some(val) => val, @@ -103,18 +154,6 @@ fn eval_body_and_ecx<'a, 'tcx>( (res, ecx) } -pub fn eval_body_as_integer<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, u128> { - let (value, _, ty) = eval_body(tcx, cid, param_env)?; - match value { - Value::ByVal(prim) => prim.to_bytes(), - _ => err!(TypeNotPrimitive(ty)), - } -} - pub struct CompileTimeEvaluator; impl<'tcx> Into> for ConstEvalError { @@ -159,11 +198,11 @@ impl Error for ConstEvalError { } } -impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { +impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { type MemoryData = (); type MemoryKinds = !; fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, destination: Option<(Place, mir::BasicBlock)>, _args: &[ValTy<'tcx>], @@ -204,7 +243,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { fn call_intrinsic<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, _args: &[ValTy<'tcx>], dest: Place, @@ -246,7 +285,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } fn try_ptr_op<'a>( - _ecx: &EvalContext<'a, 'tcx, Self>, + _ecx: &EvalContext<'a, 'mir, 'tcx, Self>, _bin_op: mir::BinOp, left: PrimVal, _left_ty: Ty<'tcx>, @@ -262,12 +301,16 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } } - fn mark_static_initialized(m: !) -> EvalResult<'tcx> { - m + fn mark_static_initialized<'a>( + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _mutability: Mutability, + ) -> EvalResult<'tcx, bool> { + Ok(false) } fn box_alloc<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _ty: Ty<'tcx>, _dest: Place, ) -> EvalResult<'tcx> { @@ -277,7 +320,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } fn global_item_with_linkage<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _instance: ty::Instance<'tcx>, _mutability: Mutability, ) -> EvalResult<'tcx> { @@ -374,14 +417,34 @@ pub fn const_eval_provider<'a, 'tcx>( let def_id = cid.instance.def.def_id(); let span = tcx.def_span(def_id); + if tcx.is_foreign_item(def_id) { + let id = tcx.interpret_interner.borrow().get_cached(def_id); + let id = match id { + // FIXME: due to caches this shouldn't happen, add some assertions + Some(id) => id, + None => { + let id = tcx.interpret_interner.borrow_mut().reserve(); + tcx.interpret_interner.borrow_mut().cache(def_id, id); + id + }, + }; + let ty = tcx.type_of(def_id); + let layout = (tcx, key.param_env).layout_of(ty).unwrap(); + let ptr = MemoryPointer::new(id, 0); + return Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)), + ty, + })) + } + if let Some(id) = tcx.hir.as_local_node_id(def_id) { let tables = tcx.typeck_tables_of(def_id); // Do match-check before building MIR if tcx.check_match(def_id).is_err() { return Err(ConstEvalErr { - span, kind: CheckMatchError, + span, }); } @@ -392,22 +455,19 @@ pub fn const_eval_provider<'a, 'tcx>( // Do not continue into miri if typeck errors occurred; it will fail horribly if tables.tainted_by_errors { return Err(ConstEvalErr { + kind: TypeckError, span, - kind: TypeckError }); } }; - match ::interpret::eval_body(tcx, cid, key.param_env) { - Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + eval_body_and_ecx(tcx, cid, None, key.param_env).0.map(|(miri_value, _, miri_ty)| { + tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), ty: miri_ty, - })), - Err(err) => { - Err(ConstEvalErr { - span, - kind: err.into() - }) - } - } + }) + }).map_err(|err| ConstEvalErr { + kind: err.into(), + span, + }) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 9ac802b720083..ad91c58da9fb9 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; -use rustc::middle::const_val::ConstVal; +use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc::mir; use rustc::traits::Reveal; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; @@ -21,7 +21,7 @@ use super::{Place, PlaceExtra, Memory, HasMemory, MemoryKind, operator, Machine}; -pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { +pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. pub machine: M, @@ -32,10 +32,10 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { pub param_env: ty::ParamEnv<'tcx>, /// The virtual memory system. - pub memory: Memory<'a, 'tcx, M>, + pub memory: Memory<'a, 'mir, 'tcx, M>, /// The virtual call stack. - pub(crate) stack: Vec>, + pub(crate) stack: Vec>, /// The maximum number of stack frames allowed pub(crate) stack_limit: usize, @@ -47,12 +47,12 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { } /// A stack frame. -pub struct Frame<'tcx> { +pub struct Frame<'mir, 'tcx: 'mir> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// /// The MIR for the function called on this frame. - pub mir: &'tcx mir::Mir<'tcx>, + pub mir: &'mir mir::Mir<'tcx>, /// The def_id and substs of the current function pub instance: ty::Instance<'tcx>, @@ -131,6 +131,15 @@ pub struct ValTy<'tcx> { pub ty: Ty<'tcx>, } +impl<'tcx> ValTy<'tcx> { + pub fn from(val: &ty::Const<'tcx>) -> Option { + match val.val { + ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }), + ConstVal::Unevaluated { .. } => None, + } + } +} + impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { type Target = Value; fn deref(&self) -> &Value { @@ -138,37 +147,37 @@ impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { } } -impl<'a, 'tcx, M: Machine<'tcx>> HasDataLayout for &'a EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { &self.tcx.data_layout } } -impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> HasDataLayout - for &'c &'b mut EvalContext<'a, 'tcx, M> { +impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout + for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { &self.tcx.data_layout } } -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } } -impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasTyCtxt<'tcx> - for &'c &'b mut EvalContext<'a, 'tcx, M> { +impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> + for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> { self.tcx } } -impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf> for &'a EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf> for &'a EvalContext<'a, 'mir, 'tcx, M> { type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { @@ -177,8 +186,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf> for &'a EvalContext<'a, 'tcx } } -impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf> - for &'c &'b mut EvalContext<'a, 'tcx, M> { +impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf> + for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; #[inline] @@ -187,7 +196,7 @@ impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> LayoutOf> } } -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn new( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -214,15 +223,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.memory.allocate(size, layout.align, Some(MemoryKind::Stack)) } - pub fn memory(&self) -> &Memory<'a, 'tcx, M> { + pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { &self.memory } - pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { + pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> { &mut self.memory } - pub fn stack(&self) -> &[Frame<'tcx>] { + pub fn stack(&self) -> &[Frame<'mir, 'tcx>] { &self.stack } @@ -240,14 +249,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { )) } - pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { match *const_val { ConstVal::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - Ok(self.read_global_as_value(GlobalId { + self.read_global_as_value(GlobalId { instance, promoted: None, - }, self.layout_of(ty)?)) + }, ty) } ConstVal::Value(val) => Ok(val), } @@ -380,14 +389,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { &mut self, instance: ty::Instance<'tcx>, span: codemap::Span, - mir: &'tcx mir::Mir<'tcx>, + mir: &'mir mir::Mir<'tcx>, return_place: Place, return_to_block: StackPopCleanup, ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; /// Return the set of locals that have a storage annotation anywhere - fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet { + fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet { use rustc::mir::StatementKind::*; let mut set = HashSet::new(); @@ -815,7 +824,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.read_global_as_value(GlobalId { instance: self.frame().instance, promoted: Some(index), - }, self.layout_of(ty)?) + }, ty)? } }; @@ -927,9 +936,28 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(()) } - pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value { - let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"); - Value::ByRef(MemoryPointer::new(alloc, 0).into(), layout.align) + pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + if gid.promoted.is_none() { + let cached = self + .tcx + .interpret_interner + .borrow() + .get_cached(gid.instance.def_id()); + if let Some(alloc_id) = cached { + let layout = self.layout_of(ty)?; + let ptr = MemoryPointer::new(alloc_id, 0); + return Ok(Value::ByRef(ptr.into(), layout.align)) + } + } + let cv = match self.tcx.const_eval(self.param_env.and(gid)) { + Ok(val) => val, + Err(err) => match err.kind { + ErrKind::Miri(miri) => return Err(miri), + ErrKind::TypeckError => return err!(TypeckError), + other => bug!("const eval returned {:?}", other), + }, + }; + self.const_to_value(&cv.val, ty) } pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> { @@ -1322,15 +1350,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(Some(Value::ByVal(val))) } - pub fn frame(&self) -> &Frame<'tcx> { + pub fn frame(&self) -> &Frame<'mir, 'tcx> { self.stack.last().expect("no call frames exist") } - pub fn frame_mut(&mut self) -> &mut Frame<'tcx> { + pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> { self.stack.last_mut().expect("no call frames exist") } - pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> { + pub(super) fn mir(&self) -> &'mir mir::Mir<'tcx> { self.frame().mir } @@ -1540,7 +1568,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(()) } - pub fn report(&self, e: &mut EvalError) { + pub fn report(&self, e: &mut EvalError, as_err: bool) { + if let EvalErrorKind::TypeckError = e.kind { + return; + } if let Some(ref mut backtrace) = e.backtrace { let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); backtrace.resolve(); @@ -1578,8 +1609,34 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } else { block.terminator().source_info.span }; - let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); + let node_id = self + .stack() + .iter() + .rev() + .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id())) + .next() + .expect("some part of a failing const eval must be local"); + let mut err = if as_err { + ::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error") + } else { + self.tcx.struct_span_lint_node( + ::rustc::lint::builtin::CONST_ERR, + node_id, + span, + "constant evaluation error", + ) + }; + err.span_label(span, e.to_string()); + let mut last_span = None; for &Frame { instance, span, .. } in self.stack().iter().rev() { + // make sure we don't emit frames that are duplicates of the previous + if let Some(last) = last_span { + if last == span { + continue; + } + } else { + last_span = Some(span); + } if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr { @@ -1595,7 +1652,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } -impl<'tcx> Frame<'tcx> { +impl<'mir, 'tcx> Frame<'mir, 'tcx> { pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into()) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index c2989dbaaf11f..d5e57d3317c55 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -12,7 +12,7 @@ use syntax::ast::Mutability; /// Methods of this trait signifies a point where CTFE evaluation would fail /// and some use case dependent behaviour can instead be applied -pub trait Machine<'tcx>: Sized { +pub trait Machine<'mir, 'tcx>: Sized { /// Additional data that can be accessed via the Memory type MemoryData; @@ -26,7 +26,7 @@ pub trait Machine<'tcx>: Sized { /// /// Returns Ok(false) if a new stack frame was pushed fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], @@ -36,7 +36,7 @@ pub trait Machine<'tcx>: Sized { /// directly process an intrinsic without pushing a stack frame. fn call_intrinsic<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Place, @@ -51,7 +51,7 @@ pub trait Machine<'tcx>: Sized { /// /// Returns a (value, overflowed) pair if the operation succeeded fn try_ptr_op<'a>( - ecx: &EvalContext<'a, 'tcx, Self>, + ecx: &EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: Ty<'tcx>, @@ -60,26 +60,30 @@ pub trait Machine<'tcx>: Sized { ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; /// Called when trying to mark machine defined `MemoryKinds` as static - fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>; + fn mark_static_initialized<'a>( + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _mutability: Mutability, + ) -> EvalResult<'tcx, bool>; /// Heap allocations via the `box` keyword /// /// Returns a pointer to the allocated memory fn box_alloc<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ty: Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx>; /// Called when trying to access a global declared with a `linkage` attribute fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, mutability: Mutability, ) -> EvalResult<'tcx>; fn check_locks<'a>( - _mem: &Memory<'a, 'tcx, Self>, + _mem: &Memory<'a, 'mir, 'tcx, Self>, _ptr: MemoryPointer, _size: u64, _access: AccessKind, @@ -88,12 +92,12 @@ pub trait Machine<'tcx>: Sized { } fn add_lock<'a>( - _mem: &mut Memory<'a, 'tcx, Self>, + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, _id: AllocId, ) {} fn free_lock<'a>( - _mem: &mut Memory<'a, 'tcx, Self>, + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, _id: AllocId, _len: u64, ) -> EvalResult<'tcx> { @@ -101,14 +105,14 @@ pub trait Machine<'tcx>: Sized { } fn end_region<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _reg: Option<::rustc::middle::region::Scope>, ) -> EvalResult<'tcx> { Ok(()) } fn validation_op<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _op: ::rustc::mir::ValidationOp, _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c49..63c0c950dd49b 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,6 +1,6 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; -use std::{ptr, mem, io}; +use std::{ptr, io}; use rustc::ty::{Instance, TyCtxt}; use rustc::ty::layout::{self, Align, TargetDataLayout}; @@ -19,8 +19,6 @@ use super::{EvalContext, Machine}; pub enum MemoryKind { /// Error if deallocated except during a stack pop Stack, - /// A mutable Static. All the others are interned in the tcx - MutableStatic, // FIXME: move me into the machine, rustc const eval doesn't need them /// Additional memory kinds a machine wishes to distinguish from the builtin ones Machine(T), } @@ -29,7 +27,7 @@ pub enum MemoryKind { // Top-level interpreter memory //////////////////////////////////////////////////////////////////////////////// -pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> { +pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// Additional data required by the Machine pub data: M::MemoryData, @@ -56,7 +54,7 @@ pub struct Memory<'a, 'tcx: 'a, M: Machine<'tcx>> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self { Memory { data, @@ -107,6 +105,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { relocations: BTreeMap::new(), undef_mask: UndefMask::new(size), align, + mutable: false, }; let id = self.tcx.interpret_interner.borrow_mut().reserve(); M::add_lock(self, id); @@ -119,7 +118,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { None => { self.uninitialized_statics.insert(id, alloc); }, - Some(MemoryKind::MutableStatic) => bug!("don't allocate mutable statics directly") } Ok(MemoryPointer::new(id, 0)) } @@ -164,10 +162,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn deallocate_local(&mut self, ptr: MemoryPointer) -> EvalResult<'tcx> { match self.alloc_kind.get(&ptr.alloc_id).cloned() { - // for a constant like `const FOO: &i32 = &1;` the local containing - // the `1` is referred to by the global. We transitively marked everything - // the global refers to as static itself, so we don't free it here - Some(MemoryKind::MutableStatic) => Ok(()), Some(MemoryKind::Stack) => self.deallocate(ptr, None, MemoryKind::Stack), // Happens if the memory was interned into immutable memory None => Ok(()), @@ -292,7 +286,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Allocation accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { // normal alloc? match self.alloc_map.get(&id) { @@ -376,7 +370,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { Some(a) => (a, match self.alloc_kind[&id] { MemoryKind::Stack => " (stack)".to_owned(), MemoryKind::Machine(m) => format!(" ({:?})", m), - MemoryKind::MutableStatic => " (static mut)".to_owned(), }), // uninitialized static alloc? None => match self.uninitialized_statics.get(&id) { @@ -388,15 +381,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { Some(a) => (a, "(immutable)".to_owned()), None => if let Some(func) = int.get_fn(id) { trace!("{} {}", msg, func); - continue; + continue; } else { - trace!("{} (deallocated)", msg); - continue; + trace!("{} (deallocated)", msg); + continue; }, - } + } }, }, - }; + }; for i in 0..(alloc.bytes.len() as u64) { if let Some(&target_id) = alloc.relocations.get(&i) { @@ -441,14 +434,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn leak_report(&self) -> usize { trace!("### LEAK REPORT ###"); - let kinds = &self.alloc_kind; let leaks: Vec<_> = self.alloc_map .keys() - .filter_map(|key| if kinds[key] != MemoryKind::MutableStatic { - Some(*key) - } else { - None - }) + .cloned() .collect(); let n = leaks.len(); self.dump_allocs(leaks); @@ -457,7 +445,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Byte accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { fn get_bytes_unchecked( &self, ptr: MemoryPointer, @@ -521,7 +509,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Reading and writing -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// mark an allocation pointed to by a static as static and initialized fn mark_inner_allocation_initialized( &mut self, @@ -529,10 +517,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { mutability: Mutability, ) -> EvalResult<'tcx> { match self.alloc_kind.get(&alloc) { - // do not go into immutable statics - None | - // or mutable statics - Some(&MemoryKind::MutableStatic) => Ok(()), + // do not go into statics + None => Ok(()), // just locals and machine allocs Some(_) => self.mark_static_initalized(alloc, mutability), } @@ -549,60 +535,27 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { alloc_id, mutability ); - if mutability == Mutability::Immutable { - let alloc = self.alloc_map.remove(&alloc_id); - let kind = self.alloc_kind.remove(&alloc_id); - assert_ne!(kind, Some(MemoryKind::MutableStatic)); - let uninit = self.uninitialized_statics.remove(&alloc_id); - if let Some(alloc) = alloc.or(uninit) { - let alloc = self.tcx.intern_const_alloc(alloc); - self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc); - // recurse into inner allocations - for &alloc in alloc.relocations.values() { - self.mark_inner_allocation_initialized(alloc, mutability)?; - } - } - return Ok(()); + // The machine handled it + if M::mark_static_initialized(self, alloc_id, mutability)? { + return Ok(()) } - // We are marking the static as initialized, so move it out of the uninit map - if let Some(uninit) = self.uninitialized_statics.remove(&alloc_id) { - self.alloc_map.insert(alloc_id, uninit); + let alloc = self.alloc_map.remove(&alloc_id); + match self.alloc_kind.remove(&alloc_id) { + None => {}, + Some(MemoryKind::Machine(_)) => bug!("machine didn't handle machine alloc"), + Some(MemoryKind::Stack) => {}, } - // do not use `self.get_mut(alloc_id)` here, because we might have already marked a - // sub-element or have circular pointers (e.g. `Rc`-cycles) - let relocations = match self.alloc_map.get_mut(&alloc_id) { - Some(&mut Allocation { - ref mut relocations, - .. - }) => { - match self.alloc_kind.get(&alloc_id) { - // const eval results can refer to "locals". - // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1` - None | - Some(&MemoryKind::Stack) => {}, - Some(&MemoryKind::Machine(m)) => M::mark_static_initialized(m)?, - Some(&MemoryKind::MutableStatic) => { - trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized"); - return Ok(()); - }, - } - // overwrite or insert - self.alloc_kind.insert(alloc_id, MemoryKind::MutableStatic); - // take out the relocations vector to free the borrow on self, so we can call - // mark recursively - mem::replace(relocations, Default::default()) + let uninit = self.uninitialized_statics.remove(&alloc_id); + if let Some(mut alloc) = alloc.or(uninit) { + // ensure llvm knows not to put this into immutable memroy + alloc.mutable = mutability == Mutability::Mutable; + let alloc = self.tcx.intern_const_alloc(alloc); + self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc); + // recurse into inner allocations + for &alloc in alloc.relocations.values() { + self.mark_inner_allocation_initialized(alloc, mutability)?; } - None => return err!(DanglingPointerDeref), - }; - // recurse into inner allocations - for &alloc in relocations.values() { - self.mark_inner_allocation_initialized(alloc, mutability)?; } - // put back the relocations - self.alloc_map - .get_mut(&alloc_id) - .expect("checked above") - .relocations = relocations; Ok(()) } @@ -829,7 +782,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Relocations -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { fn relocations( &self, ptr: MemoryPointer, @@ -883,7 +836,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Undefined bytes -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // FIXME(solson): This is a very naive, slow version. fn copy_undef_mask( &mut self, @@ -944,7 +897,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { // Methods to access integers in the target endianess //////////////////////////////////////////////////////////////////////////////// -fn write_target_uint( +pub fn write_target_uint( endianess: layout::Endian, mut target: &mut [u8], data: u128, @@ -955,7 +908,8 @@ fn write_target_uint( layout::Endian::Big => target.write_uint128::(data, len), } } -fn write_target_int( + +pub fn write_target_int( endianess: layout::Endian, mut target: &mut [u8], data: i128, @@ -967,14 +921,14 @@ fn write_target_int( } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { +pub fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { match endianess { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { +pub fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { match endianess { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), @@ -985,9 +939,9 @@ fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result> { - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>; - fn memory(&self) -> &Memory<'a, 'tcx, M>; +pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { + fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M>; + fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M>; /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, /// this may have to perform a load. @@ -1051,31 +1005,31 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> { } } -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for Memory<'a, 'mir, 'tcx, M> { #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { + fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> { self } #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { + fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { self } } -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasMemory<'a, 'mir, 'tcx, M> for EvalContext<'a, 'mir, 'tcx, M> { #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { + fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> { &mut self.memory } #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { + fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { &self.memory } } -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a Memory<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasDataLayout for &'a Memory<'a, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index ba894a1728a9b..f23ba90fd4c3f 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,17 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr, check_body}; +pub use self::const_eval::{ + eval_body_with_mir, + mk_borrowck_eval_cx, + eval_body, + CompileTimeEvaluator, + const_eval_provider, + const_val_field, + const_discr, +}; pub use self::machine::Machine; + +pub use self::operator::unary_op; +pub use self::memory::{write_target_uint, write_target_int, read_target_uint, read_target_int}; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index b20540b00ceae..bad744194d5e3 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -8,7 +8,7 @@ use super::{EvalContext, Place, Machine, ValTy}; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, bytes_to_f32, bytes_to_f64}; -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { fn binop_with_overflow( &mut self, op: mir::BinOp, @@ -56,6 +56,24 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } macro_rules! overflow { + (overflowing_div, $l:expr, $r:expr) => ({ + let (val, overflowed) = if $r == 0 { + ($l, true) + } else { + $l.overflowing_div($r) + }; + let primval = PrimVal::Bytes(val as u128); + Ok((primval, overflowed)) + }); + (overflowing_rem, $l:expr, $r:expr) => ({ + let (val, overflowed) = if $r == 0 { + ($l, true) + } else { + $l.overflowing_rem($r) + }; + let primval = PrimVal::Bytes(val as u128); + Ok((primval, overflowed)) + }); ($op:ident, $l:expr, $r:expr) => ({ let (val, overflowed) = $l.$op($r); let primval = PrimVal::Bytes(val as u128); @@ -105,7 +123,7 @@ macro_rules! int_shift { }) } -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Returns the result of the specified operation and whether it overflowed. pub fn binary_op( &self, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4a2b4547cb051..349ac63055992 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1,11 +1,13 @@ use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::traits; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer}; use super::{EvalContext, Machine, ValTy}; use interpret::memory::HasMemory; +use rustc::middle::const_val::ErrKind; #[derive(Copy, Clone, Debug)] pub enum Place { @@ -90,7 +92,7 @@ impl<'tcx> Place { } } -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Reads a value from the place without going through the intermediate step of obtaining /// a `miri::Place` pub fn try_read_place( @@ -106,10 +108,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Directly reading a static will always succeed Static(ref static_) => { let instance = ty::Instance::mono(self.tcx, static_.def_id); - Ok(Some(self.read_global_as_value(GlobalId { + self.read_global_as_value(GlobalId { instance, promoted: None, - }, self.layout_of(self.place_ty(place))?))) + }, self.place_ty(place)).map(Some) } Projection(ref proj) => self.try_read_place_projection(proj), } @@ -199,17 +201,44 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }, Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - let gid = GlobalId { - instance, - promoted: None, - }; + let alloc = self + .tcx + .interpret_interner + .borrow() + .get_cached(static_.def_id); let layout = self.layout_of(self.place_ty(mir_place))?; - let alloc = self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"); - Place::Ptr { - ptr: MemoryPointer::new(alloc, 0).into(), - align: layout.align, - extra: PlaceExtra::None, + if let Some(alloc) = alloc { + Place::Ptr { + ptr: MemoryPointer::new(alloc, 0).into(), + align: layout.align, + extra: PlaceExtra::None, + } + } else { + let instance = ty::Instance::mono(self.tcx, static_.def_id); + let cid = GlobalId { + instance, + promoted: None + }; + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + // ensure the static is computed + if let Err(err) = self.tcx.const_eval(param_env.and(cid)) { + match err.kind { + ErrKind::Miri(miri) => return Err(miri), + ErrKind::TypeckError => return err!(TypeckError), + other => bug!("const eval returned {:?}", other), + } + }; + let alloc = self + .tcx + .interpret_interner + .borrow() + .get_cached(static_.def_id) + .expect("uncached static"); + Place::Ptr { + ptr: MemoryPointer::new(alloc, 0).into(), + align: layout.align, + extra: PlaceExtra::None, + } } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 2b0f9041d5115..21e81ff668ea5 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -2,21 +2,12 @@ //! //! The main entry point is the `step` method. -use rustc::hir; -use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir; -use rustc::ty::{self, Instance}; -use rustc::ty::layout::LayoutOf; -use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::GlobalId; -use rustc::mir::interpret::{EvalResult, EvalErrorKind}; -use super::{EvalContext, StackPopCleanup, Place, Machine}; +use rustc::mir::interpret::EvalResult; +use super::{EvalContext, Machine}; -use syntax::codemap::Span; -use syntax::ast::Mutability; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { self.steps_remaining = self.steps_remaining.saturating_sub(n); if self.steps_remaining > 0 { @@ -41,52 +32,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let old_frames = self.cur_frame(); if let Some(stmt) = basic_block.statements.get(stmt_id) { - let mut new = Ok(false); - ConstantExtractor { - span: stmt.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constant: &mut new, - }.visit_statement( - block, - stmt, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added a new frame, we don't execute anything here - // but await the next call to step - if !new? { - assert_eq!(old_frames, self.cur_frame()); - self.statement(stmt)?; - } + assert_eq!(old_frames, self.cur_frame()); + self.statement(stmt)?; return Ok(true); } let terminator = basic_block.terminator(); - let mut new = Ok(false); - ConstantExtractor { - span: terminator.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constant: &mut new, - }.visit_terminator( - block, - terminator, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added a new frame, we don't execute anything here - // but await the next call to step - if !new? { - assert_eq!(old_frames, self.cur_frame()); - self.terminator(terminator)?; - } + assert_eq!(old_frames, self.cur_frame()); + self.terminator(terminator)?; Ok(true) } @@ -152,184 +105,4 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } Ok(()) } - - /// returns `true` if a stackframe was pushed - fn global_item( - &mut self, - instance: Instance<'tcx>, - span: Span, - mutability: Mutability, - ) -> EvalResult<'tcx, bool> { - debug!("global_item: {:?}", instance); - let cid = GlobalId { - instance, - promoted: None, - }; - if self.tcx.interpret_interner.borrow().get_cached(cid).is_some() { - return Ok(false); - } - if self.tcx.has_attr(instance.def_id(), "linkage") { - M::global_item_with_linkage(self, cid.instance, mutability)?; - return Ok(false); - } - let instance_ty = instance.ty(self.tcx); - let layout = self.layout_of(instance_ty)?; - assert!(!layout.is_unsized()); - let ptr = self.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); - let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span); - let mutability = if mutability == Mutability::Mutable || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); - trace!("pushing stack frame for global: {}", name); - let mir = self.load_mir(instance.def)?; - self.push_stack_frame( - instance, - span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - Ok(true) - } -} - -struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> { - span: Span, - ecx: &'a mut EvalContext<'b, 'tcx, M>, - mir: &'tcx mir::Mir<'tcx>, - instance: ty::Instance<'tcx>, - // Whether a stackframe for a new constant has been pushed - new_constant: &'a mut EvalResult<'tcx, bool>, -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> { - fn try EvalResult<'tcx, bool>>(&mut self, f: F) { - match *self.new_constant { - // already computed a constant, don't do more than one per iteration - Ok(true) => {}, - // no constants computed yet - Ok(false) => *self.new_constant = f(self), - // error happened, abort the visitor traversing - Err(_) => {}, - } - } -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> { - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) { - self.super_constant(constant, location); - self.try(|this| { - match constant.literal { - // already computed by rustc - mir::Literal::Value { value: &ty::Const { val: ConstVal::Unevaluated(def_id, substs), .. } } => { - debug!("global_item: {:?}, {:#?}", def_id, substs); - let substs = this.ecx.tcx.trans_apply_param_substs(this.instance.substs, &substs); - debug!("global_item_new_substs: {:#?}", substs); - debug!("global_item_param_env: {:#?}", this.ecx.param_env); - let instance = Instance::resolve( - this.ecx.tcx, - this.ecx.param_env, - def_id, - substs, - ).ok_or(EvalErrorKind::TypeckError)?; // turn error prop into a panic to expose associated type in const issue - this.ecx.global_item( - instance, - constant.span, - Mutability::Immutable, - ) - } - mir::Literal::Value { .. } => Ok(false), - mir::Literal::Promoted { index } => { - let cid = GlobalId { - instance: this.instance, - promoted: Some(index), - }; - if this.ecx.tcx.interpret_interner.borrow().get_cached(cid).is_some() { - return Ok(false); - } - let mir = &this.mir.promoted[index]; - let ty = this.ecx.monomorphize(mir.return_ty(), this.instance.substs); - let layout = this.ecx.layout_of(ty)?; - assert!(!layout.is_unsized()); - let ptr = this.ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); - trace!("pushing stack frame for {:?}", index); - this.ecx.push_stack_frame( - this.instance, - constant.span, - mir, - Place::from_ptr(ptr, layout.align), - StackPopCleanup::MarkStatic(Mutability::Immutable), - )?; - Ok(true) - } - } - }); - } - - fn visit_place( - &mut self, - place: &mir::Place<'tcx>, - context: PlaceContext<'tcx>, - location: mir::Location, - ) { - self.super_place(place, context, location); - self.try(|this| { - if let mir::Place::Static(ref static_) = *place { - let def_id = static_.def_id; - let span = this.span; - if let Some(node_item) = this.ecx.tcx.hir.get_if_local(def_id) { - if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item { - if let hir::ItemStatic(_, m, _) = *node { - let instance = Instance::mono(this.ecx.tcx, def_id); - this.ecx.global_item( - instance, - span, - if m == hir::MutMutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - } else { - bug!("static def id doesn't point to static"); - } - } else { - bug!("static def id doesn't point to item"); - } - } else { - let def = this.ecx.tcx.describe_def(def_id).expect("static not found"); - if let hir::def::Def::Static(_, mutable) = def { - let instance = Instance::mono(this.ecx.tcx, def_id); - this.ecx.global_item( - instance, - span, - if mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - } else { - bug!("static found but isn't a static: {:?}", def); - } - } - } else { - Ok(false) - } - }); - } } diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs index c5942712b87dd..fbc0c499e59de 100644 --- a/src/librustc_mir/interpret/terminator/drop.rs +++ b/src/librustc_mir/interpret/terminator/drop.rs @@ -5,7 +5,7 @@ use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, PrimVal, Value}; use interpret::{Machine, ValTy, EvalContext, Place, PlaceExtra}; -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub(crate) fn drop_place( &mut self, place: Place, diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index b083a81022487..783755ea553ce 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -13,7 +13,7 @@ use interpret::memory::HasMemory; mod drop; -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn goto_block(&mut self, target: mir::BasicBlock) { self.frame_mut().block = target; self.frame_mut().stmt = 0; diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 22417201f0dc5..4dc0879c85d52 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{PrimVal, Value, MemoryPointer, EvalResult}; use super::{EvalContext, eval_context, Machine}; -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// objects. /// @@ -54,7 +54,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.memory.mark_static_initalized( vtable.alloc_id, - Mutability::Mutable, + Mutability::Immutable, )?; Ok(vtable) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f16187797d4e5..3a665ba4f6c07 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -194,6 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; +use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::traits; use rustc::ty::subst::{Substs, Kind}; @@ -571,14 +572,26 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - if let ConstVal::Unevaluated(def_id, substs) = constant.val { - let substs = self.tcx.trans_apply_param_substs(self.param_substs, - &substs); - let instance = ty::Instance::resolve(self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap(); - collect_neighbours(self.tcx, instance, true, self.output); + match constant.val { + ConstVal::Unevaluated(def_id, substs) => { + let substs = self.tcx.trans_apply_param_substs(self.param_substs, + &substs); + let instance = ty::Instance::resolve(self.tcx, + ty::ParamEnv::empty(traits::Reveal::All), + def_id, + substs).unwrap(); + collect_neighbours(self.tcx, instance, true, self.output); + }, + ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { + collect_miri(self.tcx, a.alloc_id, self.output); + collect_miri(self.tcx, b.alloc_id, self.output); + } + ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) | + ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) | + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) | + ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => + collect_miri(self.tcx, ptr.alloc_id, self.output), + _ => {}, } self.super_const(constant); @@ -1101,6 +1114,28 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +/// Scan the miri alloc in order to find function calls, closures, and drop-glue +fn collect_miri<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + alloc_id: AllocId, + output: &mut Vec>, +) { + let interpret_interner = tcx.interpret_interner.borrow(); + if let Some(alloc) = interpret_interner.get_alloc(alloc_id) { + trace!("collecting {:?} with {:#?}", alloc_id, alloc); + for &inner in alloc.relocations.values() { + collect_miri(tcx, inner, output); + } + } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id) { + if should_monomorphize_locally(tcx, &fn_instance) { + trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); + output.push(create_fn_mono_item(fn_instance)); + } + } else { + bug!("alloc id without corresponding allocation: {}", alloc_id); + } +} + /// Scan the MIR in order to find function calls, closures, and drop-glue fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index ae27f54e618a1..543eb562f88f5 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // locals are safe } &Place::Static(box Static { def_id, ty: _ }) => { - if self.tcx.is_static_mut(def_id) { + if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) { self.require_unsafe("use of mutable static"); } else if self.tcx.is_foreign_item(def_id) { let source_info = self.source_info; diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 8856d263864cd..e27e7c72473be 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,44 +11,52 @@ //! Performs various peephole optimizations. use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}; -use rustc::mir::visit::{MutVisitor, Visitor}; -use rustc::ty::{TyCtxt, TypeVariants}; +use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock}; +use rustc::mir::{SourceInfo, ARGUMENT_VISIBILITY_SCOPE, TerminatorKind}; +use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; +use rustc::middle::const_val::ConstVal; +use rustc::ty::{TyCtxt, TypeVariants, self, Instance}; +use rustc::mir::interpret::{Value, PrimVal, GlobalId}; +use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::Idx; use std::mem; +use std::collections::VecDeque; use transform::{MirPass, MirSource}; +use syntax::codemap::{Span, DUMMY_SP}; +use rustc_data_structures::control_flow_graph::ControlFlowGraph; +use rustc::ty::subst::Substs; pub struct InstCombine; impl MirPass for InstCombine { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, + source: MirSource, mir: &mut Mir<'tcx>) { - // We only run when optimizing MIR (at any level). - if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { - return - } // First, find optimization opportunities. This is done in a pre-pass to keep the MIR // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). let optimizations = { - let mut optimization_finder = OptimizationFinder::new(mir, tcx); + let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); optimization_finder.visit_mir(mir); optimization_finder.optimizations }; // Then carry out those optimizations. - MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir); + MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations, tcx }, mir); } } -pub struct InstCombineVisitor<'tcx> { +type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); + +pub struct InstCombineVisitor<'a, 'tcx: 'a> { optimizations: OptimizationList<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { +impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { if self.optimizations.and_stars.remove(&location) { debug!("Replacing `&*`: {:?}", rvalue); @@ -67,28 +75,460 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { *rvalue = Rvalue::Use(Operand::Constant(box constant)); } + if let Some((value, ty, span)) = self.optimizations.const_prop.remove(&location) { + let value = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + }); + debug!("Replacing `{:?}` with {:?}", rvalue, value); + let constant = Constant { + ty, + literal: Literal::Value { value }, + span, + }; + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } + self.super_rvalue(rvalue, location) } + + fn visit_constant( + &mut self, + constant: &mut Constant<'tcx>, + location: Location, + ) { + self.super_constant(constant, location); + if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) { + constant.literal = Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Value(val), + ty, + }), + }; + } + } + + fn visit_operand( + &mut self, + operand: &mut Operand<'tcx>, + location: Location, + ) { + self.super_operand(operand, location); + let new = match operand { + Operand::Move(Place::Local(local)) | + Operand::Copy(Place::Local(local)) => { + trace!("trying to read {:?}", local); + self.optimizations.places.get(&local).cloned() + }, + _ => return, + }; + if let Some((value, ty, span)) = new { + let value = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + }); + debug!("Replacing `{:?}` with {:?}", operand, value); + let constant = Constant { + ty, + literal: Literal::Value { value }, + span, + }; + *operand = Operand::Constant(box constant); + } + } + + fn visit_terminator_kind( + &mut self, + block: BasicBlock, + kind: &mut TerminatorKind<'tcx>, + location: Location, + ) { + match kind { + TerminatorKind::SwitchInt { discr: value, .. } | + TerminatorKind::Yield { value, .. } | + TerminatorKind::Assert { cond: value, .. } => { + if let Some((new, ty, span)) = self.optimizations.const_prop.remove(&location) { + let new = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(new), + ty, + }); + debug!("Replacing `{:?}` with {:?}", value, new); + let constant = Constant { + ty, + literal: Literal::Value { value: new }, + span, + }; + *value = Operand::Constant(box constant); + } + } + // FIXME: do this optimization for function calls + _ => {}, + } + self.super_terminator_kind(block, kind, location) + } } /// Finds optimization opportunities on the MIR. struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, optimizations: OptimizationList<'tcx>, } impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { - fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { + fn new( + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + ) -> OptimizationFinder<'b, 'a, 'tcx> { OptimizationFinder { mir, tcx, + source, optimizations: OptimizationList::default(), } } + + fn eval_constant(&mut self, c: &Constant<'tcx>, span: Span) -> Option> { + if let Some(&val) = self.optimizations.constants.get(c) { + return Some(val); + } + match c.literal { + Literal::Value { value } => match value.val { + ConstVal::Value(v) => Some((v, value.ty, span)), + ConstVal::Unevaluated(did, substs) => { + let param_env = self.tcx.param_env(self.source.def_id); + let span = self.tcx.def_span(did); + let instance = Instance::resolve( + self.tcx, + param_env, + did, + substs, + )?; + let cid = GlobalId { + instance, + promoted: None, + }; + let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; + let val = (value, ty, span); + trace!("evaluated {:?} to {:?}", c, val); + self.optimizations.constants.insert(c.clone(), val); + Some(val) + }, + }, + // evaluate the promoted and replace the constant with the evaluated result + Literal::Promoted { index } => { + let generics = self.tcx.generics_of(self.source.def_id); + if generics.parent_types as usize + generics.types.len() > 0 { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let cid = GlobalId { + instance, + promoted: Some(index), + }; + let span = self.tcx.def_span(self.source.def_id); + let param_env = self.tcx.param_env(self.source.def_id); + let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; + let val = (value, ty, span); + trace!("evaluated {:?} to {:?}", c, val); + self.optimizations.constants.insert(c.clone(), val); + Some(val) + } + } + } + + fn eval_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option> { + match *op { + Operand::Constant(ref c) => self.eval_constant(c, span), + Operand::Move(ref place) | Operand::Copy(ref place) => match *place { + Place::Local(loc) => self.optimizations.places.get(&loc).cloned(), + // FIXME(oli-obk): field and index projections + Place::Projection(_) => None, + _ => None, + }, + } + } + + fn simplify_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option> { + match *op { + Operand::Constant(ref c) => match c.literal { + Literal::Value { .. } => None, + _ => self.eval_operand(op, span), + }, + _ => self.eval_operand(op, span), + } + } + + fn const_prop( + &mut self, + rvalue: &Rvalue<'tcx>, + place_ty: ty::Ty<'tcx>, + span: Span, + ) -> Option> { + match *rvalue { + Rvalue::Use(ref op) => self.simplify_operand(op, span), + Rvalue::Repeat(..) | + Rvalue::Ref(..) | + Rvalue::Cast(..) | + Rvalue::Aggregate(..) | + Rvalue::NullaryOp(NullOp::Box, _) | + Rvalue::Discriminant(..) => None, + // FIXME(oli-obk): evaluate static/constant slice lengths + Rvalue::Len(_) => None, + Rvalue::NullaryOp(NullOp::SizeOf, ty) => { + let param_env = self.tcx.param_env(self.source.def_id); + type_size_of(self.tcx, param_env, ty).map(|n| ( + Value::ByVal(PrimVal::Bytes(n as u128)), + self.tcx.types.usize, + span, + )) + } + Rvalue::UnaryOp(op, ref arg) => { + let def_id = if self.tcx.is_closure(self.source.def_id) { + self.tcx.closure_base_def_id(self.source.def_id) + } else { + self.source.def_id + }; + let generics = self.tcx.generics_of(def_id); + if generics.parent_types as usize + generics.types.len() > 0 { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir).unwrap(); + + let val = self.eval_operand(arg, span)?; + let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; + let kind = ecx.ty_to_primval_kind(val.1).ok()?; + match unary_op(op, prim, kind) { + Ok(val) => Some((Value::ByVal(val), place_ty, span)), + Err(mut err) => { + ecx.report(&mut err, false); + None + }, + } + } + Rvalue::CheckedBinaryOp(op, ref left, ref right) | + Rvalue::BinaryOp(op, ref left, ref right) => { + trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); + let left = self.eval_operand(left, span)?; + let right = self.eval_operand(right, span)?; + let def_id = if self.tcx.is_closure(self.source.def_id) { + self.tcx.closure_base_def_id(self.source.def_id) + } else { + self.source.def_id + }; + let generics = self.tcx.generics_of(def_id); + let has_generics = generics.parent_types as usize + generics.types.len() > 0; + if has_generics { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir).unwrap(); + + let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; + let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); + match ecx.binary_op(op, l, left.1, r, right.1) { + Ok((val, overflow)) => { + let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { + Value::ByValPair( + val, + PrimVal::from_bool(overflow), + ) + } else { + if overflow { + use rustc::mir::interpret::EvalError; + use rustc::mir::interpret::EvalErrorKind; + let mut err = EvalError { + kind: EvalErrorKind::OverflowingMath, + backtrace: None, + }; + ecx.report(&mut err, false); + return None; + } + Value::ByVal(val) + }; + Some((val, place_ty, span)) + }, + Err(mut err) => { + ecx.report(&mut err, false); + None + }, + } + }, + } + } +} + +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Ty<'tcx>) -> Option { + use rustc::ty::layout::LayoutOf; + (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) +} + +struct ConstPropVisitor { + local: Local, + can_const_prop: bool, + // false at the beginning, once set, there are not allowed to be any more assignments + found_assignment: bool, +} + +impl ConstPropVisitor { + /// returns true if `local` can be propagated + fn check<'tcx>(local: Local, mir: &Mir<'tcx>) -> bool { + let mut cpv = ConstPropVisitor { + local, + can_const_prop: true, + found_assignment: false, + }; + cpv.visit_mir(mir); + cpv.can_const_prop + } +} + +impl<'tcx> Visitor<'tcx> for ConstPropVisitor { + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + self.super_statement(block, statement, location); + match statement.kind { + StatementKind::SetDiscriminant { place: Place::Local(local), .. } | + StatementKind::Assign(Place::Local(local), _) => { + if local == self.local { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true + } + } + }, + StatementKind::InlineAsm { ref outputs, .. } => { + for place in outputs { + if let Place::Local(local) = *place { + if local == self.local { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true + } + return; + } + } + } + } + _ => {} + } + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + if let Rvalue::Ref(_, _, Place::Local(local)) = *rvalue { + if local == self.local { + self.can_const_prop = false; + } + } + } } impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { + // override to visit basic blocks in execution order + fn super_mir(&mut self, mir: &Mir<'tcx>) { + let mut seen = FxHashSet::default(); + seen.insert(mir.start_node()); + let mut sorted = Vec::new(); + let mut next = VecDeque::new(); + sorted.push(mir.start_node()); + next.push_back(mir.start_node()); + while let Some(current) = next.pop_front() { + for successor in mir.successors(current) { + trace!("checking successor of {:?}: {:?}", current, successor); + trace!("{:?}, {:?}", sorted, next); + if seen.contains(&successor) { + for &pending in &next { + // not a back-edge, just a branch merging back into a single execution + if pending == successor { + // move to the back of the queue + let i = sorted.iter().position(|&b| b == successor).unwrap(); + sorted.remove(i); + sorted.push(successor); + break; + } + } + } else { + seen.insert(successor); + sorted.push(successor); + next.push_back(successor); + } + } + } + trace!("checking basic blocks: {:?}", sorted); + for bb in sorted { + self.visit_basic_block_data(bb, &mir[bb]); + } + + for scope in &mir.visibility_scopes { + self.visit_visibility_scope_data(scope); + } + + self.visit_ty(&mir.return_ty(), TyContext::ReturnTy(SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + })); + + for local in mir.local_decls.indices() { + self.visit_local_decl(local, &mir.local_decls[local]); + } + + self.visit_span(&mir.span); + } + + fn visit_constant( + &mut self, + constant: &Constant<'tcx>, + location: Location, + ) { + trace!("visit_constant: {:?}", constant); + self.super_constant(constant, location); + self.eval_constant(constant, DUMMY_SP); + } + + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + trace!("visit_statement: {:?}", statement); + if let StatementKind::Assign(ref place, ref rval) = statement.kind { + let place_ty = place + .ty(&self.mir.local_decls, self.tcx) + .to_ty(self.tcx); + let span = self.mir.source_info(location).span; + if let Some(value) = self.const_prop(rval, place_ty, span) { + self.optimizations.const_prop.insert(location, value); + if let Place::Local(local) = *place { + if !self.mir.local_decls[local].is_user_variable + && ConstPropVisitor::check(local, self.mir) { + trace!("storing {:?} to {:?}", value, local); + assert!(self.optimizations.places.insert(local, value).is_none()); + } + } + } + } + self.super_statement(block, statement, location); + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { @@ -111,10 +551,33 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { self.super_rvalue(rvalue, location) } + + fn visit_terminator_kind( + &mut self, + _block: BasicBlock, + kind: &TerminatorKind<'tcx>, + location: Location, + ) { + let span = self.mir.source_info(location).span; + match kind { + TerminatorKind::SwitchInt { discr: value, .. } | + TerminatorKind::Yield { value, .. } | + TerminatorKind::Assert { cond: value, .. } => { + if let Some(value) = self.simplify_operand(value, span) { + self.optimizations.const_prop.insert(location, value); + } + } + // FIXME: do this optimization for function calls + _ => {}, + } + } } #[derive(Default)] struct OptimizationList<'tcx> { and_stars: FxHashSet, arrays_lengths: FxHashMap>, + const_prop: FxHashMap>, + places: FxHashMap>, + constants: FxHashMap, Const<'tcx>>, } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index d5b33d837c5bd..95dfa6fe05d10 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -13,7 +13,6 @@ use llvm::{SetUnnamedAddr}; use llvm::{ValueRef, True}; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use rustc::middle::const_val::ConstEvalErr; use debuginfo; use base; use monomorphize::{MonoItem, MonoItemExt}; @@ -247,13 +246,16 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, m: hir::Mutability, id: ast::NodeId, - attrs: &[ast::Attribute]) - -> Result> { + attrs: &[ast::Attribute]) { unsafe { let def_id = cx.tcx.hir.local_def_id(id); let g = get_static(cx, def_id); - let v = ::mir::trans_static_initializer(cx, def_id)?; + let v = match ::mir::trans_static_initializer(cx, def_id) { + Ok(v) => v, + // FIXME: report this? + Err(_) => return, + }; // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected @@ -317,7 +319,5 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); cx.used_statics.borrow_mut().push(cast); } - - Ok(g) } } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index fe16b3bca64f6..040cef6200f45 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,7 +10,6 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::traits; @@ -19,7 +18,7 @@ use abi::{Abi, FnType, ArgType, PassMode}; use base; use callee; use builder::Builder; -use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_undef}; +use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; use consts; use meth; use monomorphize; @@ -30,7 +29,6 @@ use syntax::symbol::Symbol; use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; -use super::constant::Const; use super::place::PlaceRef; use super::operand::OperandRef; use super::operand::OperandValue::{Pair, Ref, Immediate}; @@ -206,10 +204,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); + let switch_llty = bcx.ccx.layout_of(switch_ty).immediate_llvm_type(bcx.ccx); for (&value, target) in values.iter().zip(targets) { - let val = Const::from_bytes(bx.cx, value, switch_ty); + let llval = C_uint_big(switch_llty, value); let llbb = llblock(self, *target); - bx.add_case(switch, val.llval, llbb) + bx.add_case(switch, llval, llbb) } } } @@ -359,10 +358,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let const_err = common::const_to_opt_u128(len, false) .and_then(|len| common::const_to_opt_u128(index, false) - .map(|index| ErrKind::IndexOutOfBounds { - len: len as u64, - index: index as u64 - })); + .map(|index| format!( + "index out of bounds: the len is {} but the index is {}", + len, index, + ))); let file_line_col = C_struct(bx.cx, &[filename, line, col], false); let file_line_col = consts::addr_of(bx.cx, @@ -385,7 +384,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { "panic_loc"); (lang_items::PanicFnLangItem, vec![msg_file_line_col], - Some(ErrKind::Math(err.clone()))) + Some(err.description().to_owned())) } mir::AssertMessage::GeneratorResumedAfterReturn | mir::AssertMessage::GeneratorResumedAfterPanic => { @@ -413,10 +412,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // is also constant, then we can produce a warning. if const_cond == Some(!expected) { if let Some(err) = const_err { - let err = ConstEvalErr{ span: span, kind: err }; let mut diag = bx.tcx().sess.struct_span_warn( - span, "this expression will panic at run-time"); - err.note(bx.tcx(), span, "expression", &mut diag); + span, &format!( + "this expression will panic at run-time with {:?}", + err, + )); diag.emit(); } } @@ -530,10 +530,13 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { span_bug!(span, "shuffle indices must be constant"); } mir::Operand::Constant(ref constant) => { - let val = self.trans_constant(&bx, constant); + let (llval, ty) = self.remove_me_shuffle_indices( + &bx, + constant, + ); return OperandRef { - val: Immediate(val.llval), - layout: bx.cx.layout_of(val.ty) + val: Immediate(llval), + layout: bx.cx.layout_of(ty) }; } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 62aea8852504e..5050628b024db 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -9,962 +9,27 @@ // except according to those terms. use llvm::{self, ValueRef}; -use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; -use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP}; +use rustc_const_math::{ConstInt, ConstMathErr}; +use rustc::middle::const_val::{ConstVal, ConstEvalErr}; +use rustc_mir::interpret::{read_target_uint, const_val_field}; use rustc::hir::def_id::DefId; -use rustc::infer::TransNormalize; use rustc::traits; use rustc::mir; -use rustc::mir::interpret::{Value as MiriValue, PrimVal}; -use rustc::mir::tcx::PlaceTy; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf, Size}; -use rustc::ty::cast::{CastTy, IntTy}; -use rustc::ty::subst::{Kind, Substs}; -use rustc_apfloat::{ieee, Float, Status}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::indexed_vec::Idx; +use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; use base; -use abi::{self, Abi}; -use callee; use builder::Builder; -use common::{self, CodegenCx, const_get_elt, val_ty}; -use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_uint_big, C_u32, C_u64}; -use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, C_fat_ptr}; +use common::{CodegenCx}; +use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; use common::const_to_opt_u128; use consts; use type_of::LayoutLlvmExt; use type_::Type; -use value::Value; -use syntax_pos::Span; -use syntax::ast; -use syntax::symbol::Symbol; - -use std::fmt; -use std::ptr; - -use super::operand::{OperandRef, OperandValue}; -use super::FunctionCx; - -/// A sized constant rvalue. -/// The LLVM type might not be the same for a single Rust type, -/// e.g. each enum variant would have its own LLVM struct type. -#[derive(Copy, Clone)] -pub struct Const<'tcx> { - pub llval: ValueRef, - pub ty: Ty<'tcx> -} - -impl<'a, 'tcx> Const<'tcx> { - pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> { - Const { - llval, - ty, - } - } - - pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { - let llval = match ty.sty { - ty::TyInt(ast::IntTy::I128) | - ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b), - ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64), - ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64), - ty::TyBool => { - assert!(b <= 1); - C_bool(ccx, b == 1) - }, - ty::TyChar => { - assert_eq!(b as u32 as u128, b); - let c = b as u32; - assert!(::std::char::from_u32(c).is_some()); - C_uint(Type::char(ccx), c as u64) - }, - ty::TyFloat(fty) => { - let llty = ccx.layout_of(ty).llvm_type(ccx); - let bits = match fty { - ast::FloatTy::F32 => C_u32(ccx, b as u32), - ast::FloatTy::F64 => C_u64(ccx, b as u64), - }; - consts::bitcast(bits, llty) - }, - ty::TyAdt(adt, _) if adt.is_enum() => { - use rustc::ty::util::IntTypeExt; - Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval - }, - _ => bug!("from_bytes({}, {})", b, ty), - }; - Const { llval, ty } - } - - /// Translate ConstVal into a LLVM constant value. - pub fn from_constval(cx: &CodegenCx<'a, 'tcx>, - cv: &ConstVal, - ty: Ty<'tcx>) - -> Const<'tcx> { - let llty = cx.layout_of(ty).llvm_type(cx); - trace!("from_constval: {:#?}: {}", cv, ty); - let val = match *cv { - ConstVal::Unevaluated(..) => unimplemented!("const val `{:?}`", cv), - ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), - ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { - match ty.sty { - ty::TyRef(_, ref tam) => match tam.ty.sty { - ty::TyStr => {}, - _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), - }, - _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), - } - let alloc = ccx - .tcx() - .interpret_interner - .borrow() - .get_alloc(ptr.alloc_id) - .expect("miri alloc not found"); - assert_eq!(len as usize as u128, len); - let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - C_str_slice(ccx, Symbol::intern(s).as_str()) - }, - ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(), - ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) => - return Const::from_bytes(ccx, b, ty), - ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty), - ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => { - let alloc = ccx - .tcx() - .interpret_interner - .borrow() - .get_alloc(ptr.alloc_id) - .expect("miri alloc not found"); - let data = &alloc.bytes[(ptr.offset as usize)..]; - consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") - } - }; - - assert!(!ty.has_erasable_regions()); - - Const::new(val, ty) - } - - fn get_field(&self, cx: &CodegenCx<'a, 'tcx>, i: usize) -> ValueRef { - let layout = cx.layout_of(self.ty); - let field = layout.field(cx, i); - if field.is_zst() { - return C_undef(field.immediate_llvm_type(cx)); - } - let offset = layout.fields.offset(i); - match layout.abi { - layout::Abi::Scalar(_) | - layout::Abi::ScalarPair(..) | - layout::Abi::Vector { .. } - if offset.bytes() == 0 && field.size == layout.size => self.llval, - - layout::Abi::ScalarPair(ref a, ref b) => { - if offset.bytes() == 0 { - assert_eq!(field.size, a.value.size(cx)); - const_get_elt(self.llval, 0) - } else { - assert_eq!(offset, a.value.size(cx) - .abi_align(b.value.align(cx))); - assert_eq!(field.size, b.value.size(cx)); - const_get_elt(self.llval, 1) - } - } - _ => { - match layout.fields { - layout::FieldPlacement::Union(_) => self.llval, - _ => const_get_elt(self.llval, layout.llvm_field_index(i)), - } - } - } - } - - fn get_pair(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) { - (self.get_field(cx, 0), self.get_field(cx, 1)) - } - - fn get_fat_ptr(&self, cx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) { - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - self.get_pair(cx) - } - - fn as_place(&self) -> ConstPlace<'tcx> { - ConstPlace { - base: Base::Value(self.llval), - llextra: ptr::null_mut(), - ty: self.ty - } - } - - pub fn to_operand(&self, cx: &CodegenCx<'a, 'tcx>) -> OperandRef<'tcx> { - let layout = cx.layout_of(self.ty); - let llty = layout.immediate_llvm_type(cx); - let llvalty = val_ty(self.llval); - - let val = if llty == llvalty && layout.is_llvm_scalar_pair() { - OperandValue::Pair( - const_get_elt(self.llval, 0), - const_get_elt(self.llval, 1)) - } else if llty == llvalty && layout.is_llvm_immediate() { - // If the types match, we can use the value directly. - OperandValue::Immediate(self.llval) - } else { - // Otherwise, or if the value is not immediate, we create - // a constant LLVM global and cast its address if necessary. - let align = cx.align_of(self.ty); - let ptr = consts::addr_of(cx, self.llval, align, "const"); - OperandValue::Ref(consts::ptrcast(ptr, layout.llvm_type(cx).ptr_to()), - layout.align) - }; - - OperandRef { - val, - layout - } - } -} - -impl<'tcx> fmt::Debug for Const<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty) - } -} - -#[derive(Copy, Clone)] -enum Base { - /// A constant value without an unique address. - Value(ValueRef), - - /// String literal base pointer (cast from array). - Str(ValueRef), - - /// The address of a static. - Static(ValueRef) -} - -/// A place as seen from a constant. -#[derive(Copy, Clone)] -struct ConstPlace<'tcx> { - base: Base, - llextra: ValueRef, - ty: Ty<'tcx> -} - -impl<'tcx> ConstPlace<'tcx> { - fn to_const(&self, span: Span) -> Const<'tcx> { - match self.base { - Base::Value(val) => Const::new(val, self.ty), - Base::Str(ptr) => { - span_bug!(span, "loading from `str` ({:?}) in constant", - Value(ptr)) - } - Base::Static(val) => { - span_bug!(span, "loading from `static` ({:?}) in constant", - Value(val)) - } - } - } - - pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { - match self.ty.sty { - ty::TyArray(_, n) => { - C_usize(cx, n.val.unwrap_u64()) - } - ty::TySlice(_) | ty::TyStr => { - assert!(self.llextra != ptr::null_mut()); - self.llextra - } - _ => bug!("unexpected type `{}` in ConstPlace::len", self.ty) - } - } -} - -/// Machinery for translating a constant's MIR to LLVM values. -/// FIXME(eddyb) use miri and lower its allocations to LLVM. -struct MirConstContext<'a, 'tcx: 'a> { - cx: &'a CodegenCx<'a, 'tcx>, - mir: &'a mir::Mir<'tcx>, - - /// Type parameters for const fn and associated constants. - substs: &'tcx Substs<'tcx>, - - /// Values of locals in a constant or const fn. - locals: IndexVec, ConstEvalErr<'tcx>>>> -} - -fn add_err<'tcx, U, V>(failure: &mut Result>, - value: &Result>) -{ - if let &Err(ref err) = value { - if failure.is_ok() { - *failure = Err(err.clone()); - } - } -} - -impl<'a, 'tcx> MirConstContext<'a, 'tcx> { - fn new(cx: &'a CodegenCx<'a, 'tcx>, - mir: &'a mir::Mir<'tcx>, - substs: &'tcx Substs<'tcx>, - args: IndexVec, ConstEvalErr<'tcx>>>) - -> MirConstContext<'a, 'tcx> { - let mut context = MirConstContext { - cx, - mir, - substs, - locals: (0..mir.local_decls.len()).map(|_| None).collect(), - }; - for (i, arg) in args.into_iter().enumerate() { - // Locals after local 0 are the function arguments - let index = mir::Local::new(i + 1); - context.locals[index] = Some(arg); - } - context - } - - fn trans_def(cx: &'a CodegenCx<'a, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - args: IndexVec, ConstEvalErr<'tcx>>>) - -> Result, ConstEvalErr<'tcx>> { - let instance = ty::Instance::resolve(cx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap(); - let mir = cx.tcx.instance_mir(instance.def); - MirConstContext::new(cx, &mir, instance.substs, args).trans() - } - - fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> - { - self.cx.tcx.trans_apply_param_substs(self.substs, value) - } - - fn trans(&mut self) -> Result, ConstEvalErr<'tcx>> { - let tcx = self.cx.tcx; - let mut bb = mir::START_BLOCK; - - // Make sure to evaluate all statements to - // report as many errors as we possibly can. - let mut failure = Ok(()); - - loop { - let data = &self.mir[bb]; - for statement in &data.statements { - let span = statement.source_info.span; - match statement.kind { - mir::StatementKind::Assign(ref dest, ref rvalue) => { - let ty = dest.ty(self.mir, tcx); - let ty = self.monomorphize(&ty).to_ty(tcx); - let value = self.const_rvalue(rvalue, ty, span); - add_err(&mut failure, &value); - self.store(dest, value, span); - } - mir::StatementKind::StorageLive(_) | - mir::StatementKind::StorageDead(_) | - mir::StatementKind::Validate(..) | - mir::StatementKind::EndRegion(_) | - mir::StatementKind::Nop => {} - mir::StatementKind::InlineAsm { .. } | - mir::StatementKind::SetDiscriminant{ .. } => { - span_bug!(span, "{:?} should not appear in constants?", statement.kind); - } - } - } - - let terminator = data.terminator(); - let span = terminator.source_info.span; - bb = match terminator.kind { - mir::TerminatorKind::Drop { target, .. } | // No dropping. - mir::TerminatorKind::Goto { target } => target, - mir::TerminatorKind::Return => { - failure?; - return self.locals[mir::RETURN_PLACE].clone().unwrap_or_else(|| { - span_bug!(span, "no returned value in constant"); - }); - } - - mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => { - let cond = self.const_operand(cond, span)?; - let cond_bool = common::const_to_uint(cond.llval) != 0; - if cond_bool != expected { - let err = match *msg { - mir::AssertMessage::BoundsCheck { ref len, ref index } => { - let len = self.const_operand(len, span)?; - let index = self.const_operand(index, span)?; - ErrKind::IndexOutOfBounds { - len: common::const_to_uint(len.llval), - index: common::const_to_uint(index.llval) - } - } - mir::AssertMessage::Math(ref err) => { - ErrKind::Math(err.clone()) - } - mir::AssertMessage::GeneratorResumedAfterReturn | - mir::AssertMessage::GeneratorResumedAfterPanic => - span_bug!(span, "{:?} should not appear in constants?", msg), - }; - - let err = ConstEvalErr { span: span, kind: err }; - err.report(tcx, span, "expression"); - failure = Err(err); - } - target - } - - mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => { - let fn_ty = func.ty(self.mir, tcx); - let fn_ty = self.monomorphize(&fn_ty); - let (def_id, substs) = match fn_ty.sty { - ty::TyFnDef(def_id, substs) => (def_id, substs), - _ => span_bug!(span, "calling {:?} (of type {}) in constant", - func, fn_ty) - }; - trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args); - - let mut arg_vals = IndexVec::with_capacity(args.len()); - for arg in args { - let arg_val = self.const_operand(arg, span); - add_err(&mut failure, &arg_val); - arg_vals.push(arg_val); - } - if let Some((ref dest, target)) = *destination { - let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic { - match &tcx.item_name(def_id)[..] { - "size_of" => { - let llval = C_usize(self.cx, - self.cx.size_of(substs.type_at(0)).bytes()); - Ok(Const::new(llval, tcx.types.usize)) - } - "min_align_of" => { - let llval = C_usize(self.cx, - self.cx.align_of(substs.type_at(0)).abi()); - Ok(Const::new(llval, tcx.types.usize)) - } - "type_id" => { - let llval = C_u64(self.cx, - self.cx.tcx.type_id_hash(substs.type_at(0))); - Ok(Const::new(llval, tcx.types.u64)) - } - _ => span_bug!(span, "{:?} in constant", terminator.kind) - } - } else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) { - (||{ - assert_eq!(arg_vals.len(), 2); - let rhs = arg_vals.pop().unwrap()?; - let lhs = arg_vals.pop().unwrap()?; - if !is_checked { - let binop_ty = op.ty(tcx, lhs.ty, rhs.ty); - let (lhs, rhs) = (lhs.llval, rhs.llval); - Ok(Const::new(const_scalar_binop(op, lhs, rhs, binop_ty), - binop_ty)) - } else { - let ty = lhs.ty; - let val_ty = op.ty(tcx, lhs.ty, rhs.ty); - let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false); - let (lhs, rhs) = (lhs.llval, rhs.llval); - assert!(!ty.is_fp()); - - match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) { - Some((llval, of)) => { - Ok(trans_const_adt( - self.cx, - binop_ty, - &mir::AggregateKind::Tuple, - &[ - Const::new(llval, val_ty), - Const::new(C_bool(self.cx, of), tcx.types.bool) - ])) - } - None => { - span_bug!(span, - "{:?} got non-integer operands: {:?} and {:?}", - op, Value(lhs), Value(rhs)); - } - } - } - })() - } else { - MirConstContext::trans_def(self.cx, def_id, substs, arg_vals) - }; - add_err(&mut failure, &result); - self.store(dest, result, span); - target - } else { - span_bug!(span, "diverging {:?} in constant", terminator.kind); - } - } - _ => span_bug!(span, "{:?} in constant", terminator.kind) - }; - } - } - - fn store(&mut self, - dest: &mir::Place<'tcx>, - value: Result, ConstEvalErr<'tcx>>, - span: Span) { - if let mir::Place::Local(index) = *dest { - self.locals[index] = Some(value); - } else { - span_bug!(span, "assignment to {:?} in constant", dest); - } - } - - fn const_place(&self, place: &mir::Place<'tcx>, span: Span) - -> Result, ConstEvalErr<'tcx>> { - let tcx = self.cx.tcx; - - if let mir::Place::Local(index) = *place { - return self.locals[index].clone().unwrap_or_else(|| { - span_bug!(span, "{:?} not initialized", place) - }).map(|v| v.as_place()); - } - - let place = match *place { - mir::Place::Local(_) => bug!(), // handled above - mir::Place::Static(box mir::Static { def_id, ty }) => { - ConstPlace { - base: Base::Static(consts::get_static(self.cx, def_id)), - llextra: ptr::null_mut(), - ty: self.monomorphize(&ty), - } - } - mir::Place::Projection(ref projection) => { - let tr_base = self.const_place(&projection.base, span)?; - let projected_ty = PlaceTy::Ty { ty: tr_base.ty } - .projection_ty(tcx, &projection.elem); - let base = tr_base.to_const(span); - let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx); - let has_metadata = self.cx.type_has_metadata(projected_ty); - - let (projected, llextra) = match projection.elem { - mir::ProjectionElem::Deref => { - let (base, extra) = if !has_metadata { - (base.llval, ptr::null_mut()) - } else { - base.get_fat_ptr(self.cx) - }; - if self.cx.statics.borrow().contains_key(&base) { - (Base::Static(base), extra) - } else if let ty::TyStr = projected_ty.sty { - (Base::Str(base), extra) - } else { - let v = base; - let v = self.cx.const_unsized.borrow().get(&v).map_or(v, |&v| v); - let mut val = unsafe { llvm::LLVMGetInitializer(v) }; - if val.is_null() { - span_bug!(span, "dereference of non-constant pointer `{:?}`", - Value(base)); - } - let layout = self.cx.layout_of(projected_ty); - if let layout::Abi::Scalar(ref scalar) = layout.abi { - let i1_type = Type::i1(self.cx); - if scalar.is_bool() && val_ty(val) != i1_type { - unsafe { - val = llvm::LLVMConstTrunc(val, i1_type.to_ref()); - } - } - } - (Base::Value(val), extra) - } - } - mir::ProjectionElem::Field(ref field, _) => { - let llprojected = base.get_field(self.cx, field.index()); - let llextra = if !has_metadata { - ptr::null_mut() - } else { - tr_base.llextra - }; - (Base::Value(llprojected), llextra) - } - mir::ProjectionElem::Index(index) => { - let index = &mir::Operand::Copy(mir::Place::Local(index)); - let llindex = self.const_operand(index, span)?.llval; - - let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) { - iv - } else { - span_bug!(span, "index is not an integer-constant expression") - }; - - // Produce an undef instead of a LLVM assertion on OOB. - let len = common::const_to_uint(tr_base.len(self.cx)); - let llelem = if iv < len as u128 { - const_get_elt(base.llval, iv as u64) - } else { - C_undef(self.cx.layout_of(projected_ty).llvm_type(self.cx)) - }; - - (Base::Value(llelem), ptr::null_mut()) - } - _ => span_bug!(span, "{:?} in constant", projection.elem) - }; - ConstPlace { - base: projected, - llextra, - ty: projected_ty - } - } - }; - Ok(place) - } - - fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) - -> Result, ConstEvalErr<'tcx>> { - debug!("const_operand({:?} @ {:?})", operand, span); - let result = match *operand { - mir::Operand::Copy(ref place) | - mir::Operand::Move(ref place) => { - Ok(self.const_place(place, span)?.to_const(span)) - } - - mir::Operand::Constant(ref constant) => { - let ty = self.monomorphize(&constant.ty); - match constant.literal.clone() { - mir::Literal::Promoted { index } => { - let mir = &self.mir.promoted[index]; - MirConstContext::new(self.cx, mir, self.substs, IndexVec::new()).trans() - } - mir::Literal::Value { value } => { - if let ConstVal::Unevaluated(def_id, substs) = value.val { - let substs = self.monomorphize(&substs); - MirConstContext::trans_def(self.cx, def_id, substs, IndexVec::new()) - } else { - Ok(Const::from_constval(self.cx, &value.val, ty)) - } - } - } - } - }; - debug!("const_operand({:?} @ {:?}) = {:?}", operand, span, - result.as_ref().ok()); - result - } - - fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef]) - -> Const<'tcx> - { - let elem_ty = array_ty.builtin_index().unwrap_or_else(|| { - bug!("bad array type {:?}", array_ty) - }); - let llunitty = self.cx.layout_of(elem_ty).llvm_type(self.cx); - // If the array contains enums, an LLVM array won't work. - let val = if fields.iter().all(|&f| val_ty(f) == llunitty) { - C_array(llunitty, fields) - } else { - C_struct(self.cx, fields, false) - }; - Const::new(val, array_ty) - } - - fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, - dest_ty: Ty<'tcx>, span: Span) - -> Result, ConstEvalErr<'tcx>> { - let tcx = self.cx.tcx; - debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span); - let val = match *rvalue { - mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, - - mir::Rvalue::Repeat(ref elem, count) => { - let elem = self.const_operand(elem, span)?; - let size = count.as_u64(); - assert_eq!(size as usize as u64, size); - let fields = vec![elem.llval; size as usize]; - self.const_array(dest_ty, &fields) - } - - mir::Rvalue::Aggregate(box mir::AggregateKind::Array(_), ref operands) => { - // Make sure to evaluate all operands to - // report as many errors as we possibly can. - let mut fields = Vec::with_capacity(operands.len()); - let mut failure = Ok(()); - for operand in operands { - match self.const_operand(operand, span) { - Ok(val) => fields.push(val.llval), - Err(err) => if failure.is_ok() { failure = Err(err); } - } - } - failure?; - - self.const_array(dest_ty, &fields) - } - - mir::Rvalue::Aggregate(ref kind, ref operands) => { - // Make sure to evaluate all operands to - // report as many errors as we possibly can. - let mut fields = Vec::with_capacity(operands.len()); - let mut failure = Ok(()); - for operand in operands { - match self.const_operand(operand, span) { - Ok(val) => fields.push(val), - Err(err) => if failure.is_ok() { failure = Err(err); } - } - } - failure?; - - trans_const_adt(self.cx, dest_ty, kind, &fields) - } - - mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { - let operand = self.const_operand(source, span)?; - let cast_ty = self.monomorphize(&cast_ty); - - let val = match *kind { - mir::CastKind::ReifyFnPointer => { - match operand.ty.sty { - ty::TyFnDef(def_id, substs) => { - callee::resolve_and_get_fn(self.cx, def_id, substs) - } - _ => { - span_bug!(span, "{} cannot be reified to a fn ptr", - operand.ty) - } - } - } - mir::CastKind::ClosureFnPointer => { - match operand.ty.sty { - ty::TyClosure(def_id, substs) => { - // Get the def_id for FnOnce::call_once - let fn_once = tcx.lang_items().fn_once_trait().unwrap(); - let call_once = tcx - .global_tcx().associated_items(fn_once) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap().def_id; - // Now create its substs [Closure, Tuple] - let input = substs.closure_sig(def_id, tcx).input(0); - let input = tcx.erase_late_bound_regions_and_normalize(&input); - let substs = tcx.mk_substs([operand.ty, input] - .iter().cloned().map(Kind::from)); - callee::resolve_and_get_fn(self.cx, call_once, substs) - } - _ => { - bug!("{} cannot be cast to a fn ptr", operand.ty) - } - } - } - mir::CastKind::UnsafeFnPointer => { - // this is a no-op at the LLVM level - operand.llval - } - mir::CastKind::Unsize => { - let pointee_ty = operand.ty.builtin_deref(true) - .expect("consts: unsizing got non-pointer type").ty; - let (base, old_info) = if !self.cx.type_is_sized(pointee_ty) { - // Normally, the source is a thin pointer and we are - // adding extra info to make a fat pointer. The exception - // is when we are upcasting an existing object fat pointer - // to use a different vtable. In that case, we want to - // load out the original data pointer so we can repackage - // it. - let (base, extra) = operand.get_fat_ptr(self.cx); - (base, Some(extra)) - } else { - (operand.llval, None) - }; - - let unsized_ty = cast_ty.builtin_deref(true) - .expect("consts: unsizing got non-pointer target type").ty; - let ptr_ty = self.cx.layout_of(unsized_ty).llvm_type(self.cx).ptr_to(); - let base = consts::ptrcast(base, ptr_ty); - let info = base::unsized_info(self.cx, pointee_ty, - unsized_ty, old_info); - - if old_info.is_none() { - let prev_const = self.cx.const_unsized.borrow_mut() - .insert(base, operand.llval); - assert!(prev_const.is_none() || prev_const == Some(operand.llval)); - } - C_fat_ptr(self.cx, base, info) - } - mir::CastKind::Misc if self.cx.layout_of(operand.ty).is_llvm_immediate() => { - let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - let cast_layout = self.cx.layout_of(cast_ty); - assert!(cast_layout.is_llvm_immediate()); - let ll_t_out = cast_layout.immediate_llvm_type(self.cx); - let llval = operand.llval; - - let mut signed = false; - let l = self.cx.layout_of(operand.ty); - if let layout::Abi::Scalar(ref scalar) = l.abi { - if let layout::Int(_, true) = scalar.value { - signed = true; - } - } - - unsafe { - match (r_t_in, r_t_out) { - (CastTy::Int(_), CastTy::Int(_)) => { - let s = signed as llvm::Bool; - llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s) - } - (CastTy::Int(_), CastTy::Float) => { - cast_const_int_to_float(self.cx, llval, signed, ll_t_out) - } - (CastTy::Float, CastTy::Float) => { - llvm::LLVMConstFPCast(llval, ll_t_out.to_ref()) - } - (CastTy::Float, CastTy::Int(IntTy::I)) => { - cast_const_float_to_int(self.cx, &operand, - true, ll_t_out, span) - } - (CastTy::Float, CastTy::Int(_)) => { - cast_const_float_to_int(self.cx, &operand, - false, ll_t_out, span) - } - (CastTy::Ptr(_), CastTy::Ptr(_)) | - (CastTy::FnPtr, CastTy::Ptr(_)) | - (CastTy::RPtr(_), CastTy::Ptr(_)) => { - consts::ptrcast(llval, ll_t_out) - } - (CastTy::Int(_), CastTy::Ptr(_)) => { - let s = signed as llvm::Bool; - let usize_llval = llvm::LLVMConstIntCast(llval, - self.cx.isize_ty.to_ref(), s); - llvm::LLVMConstIntToPtr(usize_llval, ll_t_out.to_ref()) - } - (CastTy::Ptr(_), CastTy::Int(_)) | - (CastTy::FnPtr, CastTy::Int(_)) => { - llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref()) - } - _ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) - } - } - } - mir::CastKind::Misc => { // Casts from a fat-ptr. - let l = self.cx.layout_of(operand.ty); - let cast = self.cx.layout_of(cast_ty); - if l.is_llvm_scalar_pair() { - let (data_ptr, meta) = operand.get_fat_ptr(self.cx); - if cast.is_llvm_scalar_pair() { - let data_cast = consts::ptrcast(data_ptr, - cast.scalar_pair_element_llvm_type(self.cx, 0)); - C_fat_ptr(self.cx, data_cast, meta) - } else { // cast to thin-ptr - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and - // pointer-cast of that pointer to desired pointer type. - let llcast_ty = cast.immediate_llvm_type(self.cx); - consts::ptrcast(data_ptr, llcast_ty) - } - } else { - bug!("Unexpected non-fat-pointer operand") - } - } - }; - Const::new(val, cast_ty) - } - - mir::Rvalue::Ref(_, bk, ref place) => { - let tr_place = self.const_place(place, span)?; - - let ty = tr_place.ty; - let ref_ty = tcx.mk_ref(tcx.types.re_erased, - ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }); - - let base = match tr_place.base { - Base::Value(llval) => { - // FIXME: may be wrong for &*(&simd_vec as &fmt::Debug) - let align = if self.cx.type_is_sized(ty) { - self.cx.align_of(ty) - } else { - self.cx.tcx.data_layout.pointer_align - }; - if bk == mir::BorrowKind::Mut { - consts::addr_of_mut(self.cx, llval, align, "ref_mut") - } else { - consts::addr_of(self.cx, llval, align, "ref") - } - } - Base::Str(llval) | - Base::Static(llval) => llval - }; - - let ptr = if self.cx.type_is_sized(ty) { - base - } else { - C_fat_ptr(self.cx, base, tr_place.llextra) - }; - Const::new(ptr, ref_ty) - } - - mir::Rvalue::Len(ref place) => { - let tr_place = self.const_place(place, span)?; - Const::new(tr_place.len(self.cx), tcx.types.usize) - } - - mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.const_operand(lhs, span)?; - let rhs = self.const_operand(rhs, span)?; - let ty = lhs.ty; - let binop_ty = op.ty(tcx, lhs.ty, rhs.ty); - let (lhs, rhs) = (lhs.llval, rhs.llval); - Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty) - } - - mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.const_operand(lhs, span)?; - let rhs = self.const_operand(rhs, span)?; - let ty = lhs.ty; - let val_ty = op.ty(tcx, lhs.ty, rhs.ty); - let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false); - let (lhs, rhs) = (lhs.llval, rhs.llval); - assert!(!ty.is_fp()); - - match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) { - Some((llval, of)) => { - trans_const_adt(self.cx, binop_ty, &mir::AggregateKind::Tuple, &[ - Const::new(llval, val_ty), - Const::new(C_bool(self.cx, of), tcx.types.bool) - ]) - } - None => { - span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}", - rvalue, Value(lhs), Value(rhs)); - } - } - } - - mir::Rvalue::UnaryOp(op, ref operand) => { - let operand = self.const_operand(operand, span)?; - let lloperand = operand.llval; - let llval = match op { - mir::UnOp::Not => { - unsafe { - llvm::LLVMConstNot(lloperand) - } - } - mir::UnOp::Neg => { - let is_float = operand.ty.is_fp(); - unsafe { - if is_float { - llvm::LLVMConstFNeg(lloperand) - } else { - llvm::LLVMConstNeg(lloperand) - } - } - } - }; - Const::new(llval, operand.ty) - } - - mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { - assert!(self.cx.type_is_sized(ty)); - let llval = C_usize(self.cx, self.cx.size_of(ty).bytes()); - Const::new(llval, tcx.types.usize) - } - - _ => span_bug!(span, "{:?} in constant", rvalue) - }; - - debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val); - - Ok(val) - } - -} +use super::super::callee; +use super::MirContext; fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { match t.sty { @@ -1070,278 +135,239 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -unsafe fn cast_const_float_to_int(cx: &CodegenCx, - operand: &Const, - signed: bool, - int_ty: Type, - span: Span) -> ValueRef { - let llval = operand.llval; - let float_bits = match operand.ty.sty { - ty::TyFloat(fty) => fty.bit_width(), - _ => bug!("cast_const_float_to_int: operand not a float"), - }; - // Note: this breaks if llval is a complex constant expression rather than a simple constant. - // One way that might happen would be if addresses could be turned into integers in constant - // expressions, but that doesn't appear to be possible? - // In any case, an ICE is better than producing undef. - let llval_bits = consts::bitcast(llval, Type::ix(cx, float_bits as u64)); - let bits = const_to_opt_u128(llval_bits, false).unwrap_or_else(|| { - panic!("could not get bits of constant float {:?}", - Value(llval)); - }); - let int_width = int_ty.int_width() as usize; - // Try to convert, but report an error for overflow and NaN. This matches HIR const eval. - let cast_result = match float_bits { - 32 if signed => ieee::Single::from_bits(bits).to_i128(int_width).map(|v| v as u128), - 64 if signed => ieee::Double::from_bits(bits).to_i128(int_width).map(|v| v as u128), - 32 => ieee::Single::from_bits(bits).to_u128(int_width), - 64 => ieee::Double::from_bits(bits).to_u128(int_width), - n => bug!("unsupported float width {}", n), - }; - if cast_result.status.contains(Status::INVALID_OP) { - let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast }; - err.report(cx.tcx, span, "expression"); - } - C_uint_big(int_ty, cast_result.value) -} - -unsafe fn cast_const_int_to_float(cx: &CodegenCx, - llval: ValueRef, - signed: bool, - float_ty: Type) -> ValueRef { - // Note: this breaks if llval is a complex constant expression rather than a simple constant. - // One way that might happen would be if addresses could be turned into integers in constant - // expressions, but that doesn't appear to be possible? - // In any case, an ICE is better than producing undef. - let value = const_to_opt_u128(llval, signed).unwrap_or_else(|| { - panic!("could not get z128 value of constant integer {:?}", - Value(llval)); - }); - if signed { - llvm::LLVMConstSIToFP(llval, float_ty.to_ref()) - } else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP { - // We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity. - let infinity_bits = C_u32(cx, ieee::Single::INFINITY.to_bits() as u32); - consts::bitcast(infinity_bits, float_ty) - } else { - llvm::LLVMConstUIToFP(llval, float_ty.to_ref()) - } -} - -impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_constant(&mut self, - bx: &Builder<'a, 'tcx>, - constant: &mir::Constant<'tcx>) - -> Const<'tcx> - { - debug!("trans_constant({:?})", constant); - let ty = self.monomorphize(&constant.ty); - let result = match constant.literal.clone() { - mir::Literal::Promoted { index } => { - let mir = &self.mir.promoted[index]; - MirConstContext::new(bx.cx, mir, self.param_substs, IndexVec::new()).trans() +pub fn primval_to_llvm(ccx: &CrateContext, + cv: PrimVal, + scalar: &Scalar, + llty: Type) -> ValueRef { + let bits = if scalar.is_bool() { 1 } else { scalar.value.size(ccx).bits() }; + match cv { + PrimVal::Undef => C_undef(Type::ix(ccx, bits)), + PrimVal::Bytes(b) => { + let llval = C_uint_big(Type::ix(ccx, bits), b); + if scalar.value == layout::Pointer { + unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) } - mir::Literal::Value { value } => { - if let ConstVal::Unevaluated(def_id, substs) = value.val { - let substs = self.monomorphize(&substs); - MirConstContext::trans_def(bx.cx, def_id, substs, IndexVec::new()) + }, + PrimVal::Ptr(ptr) => { + let interpret_interner = ccx.tcx().interpret_interner.borrow(); + if let Some(fn_instance) = interpret_interner.get_fn(ptr.alloc_id) { + callee::get_fn(ccx, fn_instance) + } else { + let static_ = interpret_interner.get_corresponding_static_def_id(ptr.alloc_id); + let base_addr = if let Some(def_id) = static_ { + assert!(ccx.tcx().is_static(def_id).is_some()); + consts::get_static(ccx, def_id) + } else if let Some(alloc) = interpret_interner.get_alloc(ptr.alloc_id) { + let init = global_initializer(ccx, alloc); + if alloc.mutable { + consts::addr_of_mut(ccx, init, alloc.align, "byte_str") + } else { + consts::addr_of(ccx, init, alloc.align, "byte_str") + } } else { - Ok(Const::from_constval(bx.cx, &value.val, ty)) + bug!("missing allocation {:?}", ptr.alloc_id); + }; + + let llval = unsafe { llvm::LLVMConstInBoundsGEP( + consts::bitcast(base_addr, Type::i8p(ccx)), + &C_usize(ccx, ptr.offset), + 1, + ) }; + if scalar.value != layout::Pointer { + unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) } } - }; - - let result = result.unwrap_or_else(|_| { - // We've errored, so we don't have to produce working code. - let llty = bx.cx.layout_of(ty).llvm_type(bx.cx); - Const::new(C_undef(llty), ty) - }); - - debug!("trans_constant({:?}) = {:?}", constant, result); - result + } } } +pub fn global_initializer(ccx: &CrateContext, alloc: &Allocation) -> ValueRef { + let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); + let layout = ccx.data_layout(); + let pointer_size = layout.pointer_size.bytes() as usize; + + let mut next_offset = 0; + for (&offset, &alloc_id) in &alloc.relocations { + assert_eq!(offset as usize as u64, offset); + let offset = offset as usize; + if offset > next_offset { + llvals.push(C_bytes(ccx, &alloc.bytes[next_offset..offset])); + } + let ptr_offset = read_target_uint( + layout.endian, + &alloc.bytes[offset..(offset + pointer_size)], + ).expect("global_initializer: could not read relocation pointer") as u64; + llvals.push(primval_to_llvm( + ccx, + PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), + &Scalar { + value: layout::Primitive::Pointer, + valid_range: 0..=!0 + }, + Type::i8p(ccx) + )); + next_offset = offset + pointer_size; + } + if alloc.bytes.len() >= next_offset { + llvals.push(C_bytes(ccx, &alloc.bytes[next_offset ..])); + } + + C_struct(ccx, &llvals, true) +} pub fn trans_static_initializer<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, def_id: DefId) -> Result> { - MirConstContext::trans_def(cx, def_id, Substs::empty(), IndexVec::new()) - .map(|c| c.llval) -} - -/// Construct a constant value, suitable for initializing a -/// GlobalVariable, given a case and constant values for its fields. -/// Note that this may have a different LLVM type (and different -/// alignment!) from the representation's `type_of`, so it needs a -/// pointer cast before use. -/// -/// The LLVM type system does not directly support unions, and only -/// pointers can be bitcast, so a constant (and, by extension, the -/// GlobalVariable initialized by it) will have a type that can vary -/// depending on which case of an enum it is. -/// -/// To understand the alignment situation, consider `enum E { V64(u64), -/// V32(u32, u32) }` on Windows. The type has 8-byte alignment to -/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32, -/// i32, i32}`, which is 4-byte aligned. -/// -/// Currently the returned value has the same size as the type, but -/// this could be changed in the future to avoid allocating unnecessary -/// space after values of shorter-than-maximum cases. -fn trans_const_adt<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - t: Ty<'tcx>, - kind: &mir::AggregateKind, - vals: &[Const<'tcx>] -) -> Const<'tcx> { - let l = cx.layout_of(t); - let variant_index = match *kind { - mir::AggregateKind::Adt(_, index, _, _) => index, - _ => 0, + let instance = ty::Instance::mono(ccx.tcx(), def_id); + let cid = GlobalId { + instance, + promoted: None }; + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + ccx.tcx().const_eval(param_env.and(cid))?; + + let alloc_id = ccx + .tcx() + .interpret_interner + .borrow() + .get_cached(def_id) + .expect("global not cached"); + + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(alloc_id) + .expect("miri allocation never successfully created"); + Ok(global_initializer(ccx, alloc)) +} - if let layout::Abi::Uninhabited = l.abi { - return Const::new(C_undef(l.llvm_type(cx)), t); - } - - match l.variants { - layout::Variants::Single { index } => { - assert_eq!(variant_index, index); - if let layout::FieldPlacement::Union(_) = l.fields { - assert_eq!(variant_index, 0); - assert_eq!(vals.len(), 1); - let (field_size, field_align) = cx.size_and_align_of(vals[0].ty); - let contents = [ - vals[0].llval, - padding(cx, l.size - field_size) - ]; - - let packed = l.align.abi() < field_align.abi(); - Const::new(C_struct(cx, &contents, packed), t) - } else { - if let layout::Abi::Vector { .. } = l.abi { - if let layout::FieldPlacement::Array { .. } = l.fields { - return Const::new(C_vector(&vals.iter().map(|x| x.llval) - .collect::>()), t); - } - } - build_const_struct(cx, l, vals, None) - } - } - layout::Variants::Tagged { .. } => { - let discr = match *kind { - mir::AggregateKind::Adt(adt_def, _, _, _) => { - adt_def.discriminant_for_variant(cx.tcx, variant_index) - .to_u128_unchecked() as u64 - }, - _ => 0, - }; - let discr_field = l.field(cx, 0); - let discr = C_int(discr_field.llvm_type(cx), discr as i64); - if let layout::Abi::Scalar(_) = l.abi { - Const::new(discr, t) - } else { - let discr = Const::new(discr, discr_field.ty); - build_const_struct(cx, l.for_variant(cx, variant_index), vals, Some(discr)) - } - } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, - .. - } => { - if variant_index == dataful_variant { - build_const_struct(cx, l.for_variant(cx, dataful_variant), vals, None) - } else { - let niche = l.field(cx, 0); - let niche_llty = niche.llvm_type(cx); - let niche_value = ((variant_index - niche_variants.start) as u128) - .wrapping_add(niche_start); - // FIXME(eddyb) Check the actual primitive type here. - let niche_llval = if niche_value == 0 { - // HACK(eddyb) Using `C_null` as it works on all types. - C_null(niche_llty) - } else { - C_uint_big(niche_llty, niche_value) +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + fn const_to_miri_value( + &mut self, + bcx: &Builder<'a, 'tcx>, + constant: &'tcx ty::Const<'tcx>, + ) -> Result> { + match constant.val { + ConstVal::Unevaluated(def_id, ref substs) => { + let tcx = bcx.tcx(); + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); + let cid = GlobalId { + instance, + promoted: None, }; - build_const_struct(cx, l, &[Const::new(niche_llval, niche.ty)], None) - } + let c = tcx.const_eval(param_env.and(cid))?; + self.const_to_miri_value(bcx, c) + }, + ConstVal::Value(miri_val) => Ok(miri_val), } } -} - -/// Building structs is a little complicated, because we might need to -/// insert padding if a field's value is less aligned than its type. -/// -/// Continuing the example from `trans_const_adt`, a value of type `(u32, -/// E)` should have the `E` at offset 8, but if that field's -/// initializer is 4-byte aligned then simply translating the tuple as -/// a two-element struct will locate it at offset 4, and accesses to it -/// will read the wrong memory. -fn build_const_struct<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: layout::TyLayout<'tcx>, - vals: &[Const<'tcx>], - discr: Option>) - -> Const<'tcx> { - assert_eq!(vals.len(), layout.fields.count()); - match layout.abi { - layout::Abi::Scalar(_) | - layout::Abi::ScalarPair(..) | - layout::Abi::Vector { .. } if discr.is_none() => { - let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| { - (f, layout.fields.offset(i)) - }).filter(|&(f, _)| !cx.layout_of(f.ty).is_zst()); - match (non_zst_fields.next(), non_zst_fields.next()) { - (Some((x, offset)), None) if offset.bytes() == 0 => { - return Const::new(x.llval, layout.ty); - } - (Some((a, a_offset)), Some((b, _))) if a_offset.bytes() == 0 => { - return Const::new(C_struct(cx, &[a.llval, b.llval], false), layout.ty); - } - (Some((a, _)), Some((b, b_offset))) if b_offset.bytes() == 0 => { - return Const::new(C_struct(cx, &[b.llval, a.llval], false), layout.ty); - } - _ => {} + pub fn mir_constant_to_miri_value( + &mut self, + bcx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>, + ) -> Result> { + match constant.literal { + mir::Literal::Promoted { index } => { + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(index), + }; + bcx.tcx().const_eval(param_env.and(cid)) } - } - _ => {} - } - - // offset of current value - let mut packed = false; - let mut offset = Size::from_bytes(0); - let mut cfields = Vec::new(); - cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2); - - if let Some(discr) = discr { - let (field_size, field_align) = cx.size_and_align_of(discr.ty); - packed |= layout.align.abi() < field_align.abi(); - cfields.push(discr.llval); - offset = field_size; + mir::Literal::Value { value } => { + Ok(self.monomorphize(&value)) + } + }.and_then(|c| self.const_to_miri_value(bcx, c)) } - let parts = layout.fields.index_by_increasing_offset().map(|i| { - (vals[i], layout.fields.offset(i)) - }); - for (val, target_offset) in parts { - let (field_size, field_align) = cx.size_and_align_of(val.ty); - packed |= layout.align.abi() < field_align.abi(); - cfields.push(padding(cx, target_offset - offset)); - cfields.push(val.llval); - offset = target_offset + field_size; + // Old version of trans_constant now used just for SIMD shuffle + pub fn remove_me_shuffle_indices(&mut self, + bcx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>) + -> (ValueRef, Ty<'tcx>) + { + let layout = bcx.ccx.layout_of(constant.ty); + self.mir_constant_to_miri_value(bcx, constant) + .and_then(|c| { + let llval = match c { + MiriValue::ByVal(val) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + primval_to_llvm(bcx.ccx, val, scalar, layout.immediate_llvm_type(bcx.ccx)) + }, + MiriValue::ByValPair(a_val, b_val) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + bcx.ccx, + a_val, + a_scalar, + layout.scalar_pair_element_llvm_type(bcx.ccx, 0), + ); + let b_llval = primval_to_llvm( + bcx.ccx, + b_val, + b_scalar, + layout.scalar_pair_element_llvm_type(bcx.ccx, 1), + ); + C_struct(bcx.ccx, &[a_llval, b_llval], false) + }, + MiriValue::ByRef(..) => { + let field_ty = constant.ty.builtin_index().unwrap(); + let fields = match constant.ty.sty { + ty::TyArray(_, n) => n.val.unwrap_u64(), + ref other => bug!("invalid simd shuffle type: {}", other), + }; + let values: Result, _> = (0..fields).map(|field| { + let field = const_val_field( + bcx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + self.instance, + None, + mir::Field::new(field as usize), + c, + constant.ty, + )?; + match field.val { + ConstVal::Value(MiriValue::ByVal(prim)) => { + let layout = bcx.ccx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(primval_to_llvm( + bcx.ccx, prim, scalar, + layout.immediate_llvm_type(bcx.ccx), + )) + }, + other => bug!("simd shuffle field {:?}, {}", other, constant.ty), + } + }).collect(); + C_struct(bcx.ccx, &values?, false) + }, + }; + Ok((llval, constant.ty)) + }) + .unwrap_or_else(|e| { + e.report(bcx.tcx(), constant.span, "shuffle_indices"); + // We've errored, so we don't have to produce working code. + let ty = self.monomorphize(&constant.ty); + let llty = bcx.ccx.layout_of(ty).llvm_type(bcx.ccx); + (C_undef(llty), ty) + }) } - - // Pad to the size of the whole type, not e.g. the variant. - cfields.push(padding(cx, cx.size_of(layout.ty) - offset)); - - Const::new(C_struct(cx, &cfields, packed), layout.ty) -} - -fn padding(cx: &CodegenCx, size: Size) -> ValueRef { - C_undef(Type::array(&Type::i8(cx), size.bytes())) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index da01592d9118a..63a0e1032fe29 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -42,6 +42,8 @@ use self::operand::{OperandRef, OperandValue}; /// Master context for translating MIR. pub struct FunctionCx<'a, 'tcx:'a> { + instance: Instance<'tcx>, + mir: &'a mir::Mir<'tcx>, debug_context: debuginfo::FunctionDebugContext, @@ -225,6 +227,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( let (landing_pads, funclets) = create_funclets(&bx, &cleanup_kinds, &block_bxs); let mut fx = FunctionCx { + instance, mir, llfn, fn_ty, diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index e1b906646aa43..01cf324124c4f 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -9,12 +9,14 @@ // except according to those terms. use llvm::ValueRef; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::middle::const_val::ConstEvalErr; use rustc::mir; +use rustc::mir::interpret::Value as MiriValue; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; use base; -use common::{self, CodegenCx, C_undef, C_usize}; +use common::{self, CodegenCx, C_null, C_undef, C_usize}; use builder::Builder; use value::Value; use type_of::LayoutLlvmExt; @@ -24,6 +26,7 @@ use std::fmt; use std::ptr; use super::{FunctionCx, LocalRef}; +use super::constant::{primval_to_llvm}; use super::place::PlaceRef; /// The representation of a Rust value. The enum variant is in fact @@ -89,6 +92,70 @@ impl<'a, 'tcx> OperandRef<'tcx> { } } + pub fn from_const(bcx: &Builder<'a, 'tcx>, + miri_val: MiriValue, + ty: ty::Ty<'tcx>) + -> Result, ConstEvalErr<'tcx>> { + let layout = bcx.ccx.layout_of(ty); + + if layout.is_zst() { + return Ok(OperandRef::new_zst(bcx.ccx, layout)); + } + + let val = match miri_val { + MiriValue::ByVal(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + let llval = primval_to_llvm( + bcx.ccx, + x, + scalar, + layout.immediate_llvm_type(bcx.ccx), + ); + OperandValue::Immediate(llval) + }, + MiriValue::ByValPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + bcx.ccx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(bcx.ccx, 0), + ); + let b_llval = primval_to_llvm( + bcx.ccx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(bcx.ccx, 1), + ); + OperandValue::Pair(a_llval, b_llval) + }, + MiriValue::ByRef(ptr, align) => { + let scalar = layout::Scalar { + value: layout::Primitive::Pointer, + valid_range: 0..=!0 + }; + let ptr = primval_to_llvm( + bcx.ccx, + ptr.into_inner_primval(), + &scalar, + layout.llvm_type(bcx.ccx).ptr_to(), + ); + return Ok(PlaceRef::new_sized(ptr, layout, align).load(bcx)); + }, + }; + + Ok(OperandRef { + val, + layout + }) + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { @@ -327,14 +394,19 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::Operand::Constant(ref constant) => { - let val = self.trans_constant(&bx, constant); - let operand = val.to_operand(bx.cx); - if let OperandValue::Ref(ptr, align) = operand.val { - // If this is a OperandValue::Ref to an immediate constant, load it. - PlaceRef::new_sized(ptr, operand.layout, align).load(bx) - } else { - operand - } + let ty = self.monomorphize(&constant.ty); + self.mir_constant_to_miri_value(bx, constant) + .and_then(|c| OperandRef::from_const(bx, c, ty)) + .unwrap_or_else(|err| { + err.report(bx.tcx(), constant.span, "const operand"); + // We've errored, so we don't have to produce working code. + let layout = bx.cx.layout_of(ty); + PlaceRef::new_sized( + C_null(layout.llvm_type(bx.cx).ptr_to()), + layout, + layout.align, + ).load(bx) + }) } } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5eb6679fe252c..d2eed2f4e1909 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -48,12 +48,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { let tcx = cx.tcx; let item = tcx.hir.expect_item(node_id); if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&cx, m, item.id, &item.attrs) { - Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => { - err.report(tcx, item.span, "static"); - } - }; + consts::trans_static(&cx, m, item.id, &item.attrs); } else { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 90a493064fd4e..0db3d63a4c7e4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4015,7 +4015,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let count = tcx.const_eval(param_env.and(global_id)); if let Err(ref err) = count { - err.report(tcx, tcx.def_span(count_def_id), "constant expression"); + err.report(tcx, tcx.def_span(count_def_id), "constant expression"); } let uty = match expected { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index cd1ed9dcae130..1cab5b7f6350a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -537,7 +537,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // so we need to report the real error if let Err(ref err) = result { err.report(tcx, variant.span, "enum discriminant"); - } +} match result { Ok(&ty::Const { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bf31cd90a5b85..b2d41a374fd87 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2446,7 +2446,11 @@ impl Clean for hir::Ty { let def_id = cx.tcx.hir.body_owner_def_id(n); let param_env = cx.tcx.param_env(def_id); let substs = Substs::identity_for_item(cx.tcx, def_id); - let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| { + let cid = GlobalId { + instance: ty::Instance::new(def_id, substs), + promoted: None + }; + let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| { cx.tcx.mk_const(ty::Const { val: ConstVal::Unevaluated(def_id, substs), ty: cx.tcx.types.usize @@ -2579,7 +2583,11 @@ impl<'tcx> Clean for Ty<'tcx> { let mut n = cx.tcx.lift(&n).unwrap(); if let ConstVal::Unevaluated(def_id, substs) = n.val { let param_env = cx.tcx.param_env(def_id); - if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) { + let cid = GlobalId { + instance: ty::Instance::new(def_id, substs), + promoted: None + }; + if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) { n = new_n; } }; diff --git a/src/test/compile-fail/E0030.rs b/src/test/compile-fail/E0030.rs index ef3bded4beffb..896dd2599bf53 100644 --- a/src/test/compile-fail/E0030.rs +++ b/src/test/compile-fail/E0030.rs @@ -10,7 +10,7 @@ fn main() { - match 5u32 { + match 5u32 { //~ ERROR non-exhaustive patterns 1000 ... 5 => {} //~^ ERROR lower range bound must be less than or equal to upper } diff --git a/src/test/compile-fail/E0080.rs b/src/test/compile-fail/E0080.rs index 2f199c48e46e7..6e525d4ea9ec7 100644 --- a/src/test/compile-fail/E0080.rs +++ b/src/test/compile-fail/E0080.rs @@ -10,9 +10,10 @@ enum Enum { X = (1 << 500), //~ ERROR E0080 - //~| WARNING shift left with overflow + //~| shift left with overflow Y = (1 / 0) //~ ERROR E0080 - //~| WARNING divide by zero + //~| const_err + //~| divide by zero } fn main() { diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index 18476494300b2..02264228a6bf6 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -15,4 +15,5 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions + //~| E0080 } diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 42fb40394fb29..8c2e6233abfe2 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -11,14 +11,15 @@ #![feature(const_indexing)] #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow -pub const B: u8 = 200u8 + 200u8; //~ ERROR attempt to add with overflow -pub const C: u8 = 200u8 * 4; //~ ERROR attempt to multiply with overflow -pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempt to subtract with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 +//~^ ERROR attempt to negate with overflow +//~| ERROR const_err +pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 +pub const C: u8 = 200u8 * 4; //~ ERROR E0080 +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080 pub const E: u8 = [5u8][1]; -//~^ ERROR index out of bounds: the len is 1 but the index is 1 +//~^ ERROR E0080 fn main() { let _e = [6u8][1]; - //~^ ERROR index out of bounds: the len is 1 but the index is 1 } diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index d4f9c0fe56dae..668f95f2c8d73 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -11,9 +11,14 @@ #![deny(const_err)] pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow +//~^ ERROR E0080 +//~| ERROR const_err pub const B: i8 = A; +//~^ ERROR E0080 pub const C: u8 = A as u8; +//~^ ERROR E0080 pub const D: i8 = 50 - A; +//~^ ERROR E0080 fn main() { } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index e65194ab56f98..8bd759b6d3735 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -26,26 +26,5 @@ const FOO: u8 = [5u8][1]; //~| index out of bounds: the len is 1 but the index is 1 fn main() { - let a = -std::i8::MIN; - //~^ WARN this expression will panic at run-time - //~| attempt to negate with overflow - let b = 200u8 + 200u8 + 200u8; - //~^ WARN this expression will panic at run-time - //~^^ WARN this expression will panic at run-time - //~| attempt to add with overflow - let c = 200u8 * 4; - //~^ WARN this expression will panic at run-time - //~| attempt to multiply with overflow - let d = 42u8 - (42u8 + 1); - //~^ WARN this expression will panic at run-time - //~| attempt to subtract with overflow - let _e = [5u8][1]; - //~^ WARN this expression will panic at run-time - //~| index out of bounds: the len is 1 but the index is 1 - black_box(a); - black_box(b); - black_box(c); - black_box(d); - black_box((FOO, FOO)); } diff --git a/src/test/compile-fail/const-err2.rs b/src/test/compile-fail/const-err2.rs index 9889ca1392ac1..a0648993aac74 100644 --- a/src/test/compile-fail/const-err2.rs +++ b/src/test/compile-fail/const-err2.rs @@ -18,13 +18,11 @@ fn black_box(_: T) { fn main() { let a = -std::i8::MIN; - //~^ ERROR attempt to negate with overflow + //~^ ERROR const_err + //~| ERROR const_err let b = 200u8 + 200u8 + 200u8; - //~^ ERROR attempt to add with overflow let c = 200u8 * 4; - //~^ ERROR attempt to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ ERROR attempt to subtract with overflow let _e = [5u8][1]; black_box(a); black_box(b); diff --git a/src/test/compile-fail/const-err3.rs b/src/test/compile-fail/const-err3.rs new file mode 100644 index 0000000000000..636537d1df250 --- /dev/null +++ b/src/test/compile-fail/const-err3.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![deny(const_err)] + +fn black_box(_: T) { + unimplemented!() +} + +fn main() { + let b = 200u8 + 200u8 + 200u8; + //~^ ERROR const_err + //~| ERROR const_err + let c = 200u8 * 4; + let d = 42u8 - (42u8 + 1); + let _e = [5u8][1]; + black_box(b); + black_box(c); + black_box(d); +} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs deleted file mode 100644 index 058a8d0a1bd4f..0000000000000 --- a/src/test/compile-fail/const-eval-overflow.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(unused_imports)] - -// Note: the relevant lint pass here runs before some of the constant -// evaluation below (e.g. that performed by trans and llvm), so if you -// change this warn to a deny, then the compiler will exit before -// those errors are detected. - -#![warn(const_err)] - -use std::fmt; -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; - -const VALS_I8: (i8, i8, i8, i8) = - (-i8::MIN, - //~^ ERROR constant evaluation error - //~| attempt to negate with overflow - i8::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - i8::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - i8::MIN * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_I16: (i16, i16, i16, i16) = - (-i16::MIN, - //~^ ERROR constant evaluation error - //~| attempt to negate with overflow - i16::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - i16::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - i16::MIN * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_I32: (i32, i32, i32, i32) = - (-i32::MIN, - //~^ ERROR constant evaluation error - //~| attempt to negate with overflow - i32::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - i32::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - i32::MIN * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_I64: (i64, i64, i64, i64) = - (-i64::MIN, - //~^ ERROR constant evaluation error - //~| attempt to negate with overflow - i64::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - i64::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - i64::MAX * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_U8: (u8, u8, u8, u8) = - ( //~ WARN constant evaluation error: attempt to subtract with overflow - -(u8::MIN as i8) as u8, - u8::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - u8::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - u8::MAX * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_U16: (u16, u16, u16, u16) = - ( //~ WARN constant evaluation error: attempt to subtract with overflow - -(u16::MIN as i16) as u16, - u16::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - u16::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - u16::MAX * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_U32: (u32, u32, u32, u32) = - ( //~ WARN constant evaluation error: attempt to subtract with overflow - -(u32::MIN as i32) as u32, - u32::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - u32::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - u32::MAX * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -const VALS_U64: (u64, u64, u64, u64) = - ( //~ WARN constant evaluation error: attempt to subtract with overflow - -(u64::MIN as i64) as u64, - u64::MIN - 1, - //~^ ERROR constant evaluation error - //~| attempt to subtract with overflow - u64::MAX + 1, - //~^ ERROR constant evaluation error - //~| attempt to add with overflow - u64::MAX * 2, - //~^ ERROR constant evaluation error - //~| attempt to multiply with overflow - ); - -fn main() { - foo(VALS_I8); - foo(VALS_I16); - foo(VALS_I32); - foo(VALS_I64); - - foo(VALS_U8); - foo(VALS_U16); - foo(VALS_U32); - foo(VALS_U64); -} - -fn foo(x: T) { - println!("{:?}", x); -} diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs new file mode 100644 index 0000000000000..61a653589fff9 --- /dev/null +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -0,0 +1,91 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g. that performed by trans and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +#![deny(const_err)] + +use std::fmt; +use std::{i8, i16, i32, i64, isize}; +use std::{u8, u16, u32, u64, usize}; + +const VALS_I8: (i8,) = + ( + i8::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_I16: (i16,) = + ( + i16::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_I32: (i32,) = + ( + i32::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_I64: (i64,) = + ( + i64::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_U8: (u8,) = + ( + u8::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_U16: (u16,) = ( + u16::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_U32: (u32,) = ( + u32::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +const VALS_U64: (u64,) = + ( + u64::MIN - 1, + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow + ); + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo(_: T) { +} diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs new file mode 100644 index 0000000000000..b2e84486101bc --- /dev/null +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -0,0 +1,91 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g. that performed by trans and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +#![deny(const_err)] + +use std::fmt; +use std::{i8, i16, i32, i64, isize}; +use std::{u8, u16, u32, u64, usize}; + +const VALS_I8: (i8,) = + ( + i8::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_I16: (i16,) = + ( + i16::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_I32: (i32,) = + ( + i32::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_I64: (i64,) = + ( + i64::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_U8: (u8,) = + ( + u8::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_U16: (u16,) = ( + u16::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_U32: (u32,) = ( + u32::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +const VALS_U64: (u64,) = + ( + u64::MAX + 1, + //~^ ERROR constant evaluation error + //~| attempt to add with overflow + ); + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo(_: T) { +} diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs new file mode 100644 index 0000000000000..c4a8beaf0f057 --- /dev/null +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -0,0 +1,91 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused_imports)] + +// Note: the relevant lint pass here runs before some of the constant +// evaluation below (e.g. that performed by trans and llvm), so if you +// change this warn to a deny, then the compiler will exit before +// those errors are detected. + +#![deny(const_err)] + +use std::fmt; +use std::{i8, i16, i32, i64, isize}; +use std::{u8, u16, u32, u64, usize}; + +const VALS_I8: (i8,) = + ( + i8::MIN * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_I16: (i16,) = + ( + i16::MIN * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_I32: (i32,) = + ( + i32::MIN * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_I64: (i64,) = + ( + i64::MIN * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_U8: (u8,) = + ( + u8::MAX * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_U16: (u16,) = ( + u16::MAX * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_U32: (u32,) = ( + u32::MAX * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +const VALS_U64: (u64,) = + ( + u64::MAX * 2, + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow + ); + +fn main() { + foo(VALS_I8); + foo(VALS_I16); + foo(VALS_I32); + foo(VALS_I64); + + foo(VALS_U8); + foo(VALS_U16); + foo(VALS_U32); + foo(VALS_U64); +} + +fn foo(_: T) { +} diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 29bc665a22e7b..3065122af6a94 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -16,6 +16,7 @@ const X: usize = 42 && 39; //~| ERROR mismatched types //~| expected usize, found bool const ARR: [i32; X] = [99; 34]; +//~^ ERROR constant evaluation error const X1: usize = 42 || 39; //~^ ERROR mismatched types @@ -25,6 +26,7 @@ const X1: usize = 42 || 39; //~| ERROR mismatched types //~| expected usize, found bool const ARR1: [i32; X1] = [99; 47]; +//~^ ERROR constant evaluation error const X2: usize = -42 || -39; //~^ ERROR mismatched types @@ -34,6 +36,7 @@ const X2: usize = -42 || -39; //~| ERROR mismatched types //~| expected usize, found bool const ARR2: [i32; X2] = [99; 18446744073709551607]; +//~^ ERROR constant evaluation error const X3: usize = -42 && -39; //~^ ERROR mismatched types @@ -43,36 +46,43 @@ const X3: usize = -42 && -39; //~| ERROR mismatched types //~| expected usize, found bool const ARR3: [i32; X3] = [99; 6]; +//~^ ERROR constant evaluation error const Y: usize = 42.0 == 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR: [i32; Y] = [99; 1]; +//~^ ERROR constant evaluation error const Y1: usize = 42.0 >= 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR1: [i32; Y1] = [99; 1]; +//~^ ERROR constant evaluation error const Y2: usize = 42.0 <= 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR2: [i32; Y2] = [99; 1]; +//~^ ERROR constant evaluation error const Y3: usize = 42.0 > 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR3: [i32; Y3] = [99; 0]; +//~^ ERROR constant evaluation error const Y4: usize = 42.0 < 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR4: [i32; Y4] = [99; 0]; +//~^ ERROR constant evaluation error const Y5: usize = 42.0 != 42.0; //~^ ERROR mismatched types //~| expected usize, found bool const ARRR5: [i32; Y5] = [99; 0]; +//~^ ERROR constant evaluation error fn main() { let _ = ARR; diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index 7f2229b5a6534..85cc893aa133c 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -16,6 +16,6 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); - //~^ ERROR constant evaluation error [E0080] + //~^ ERROR constant evaluation error //~| attempt to subtract with overflow } diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs index cbeafdfe6acc9..9720d3809120c 100644 --- a/src/test/compile-fail/const-size_of-cycle.rs +++ b/src/test/compile-fail/const-size_of-cycle.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unsupported cyclic reference between types/traits detected +//error-pattern: cyclic reference #![feature(const_fn)] diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index b1b4bfe2d1c39..179ea9e853f3a 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(const_err)] + const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; //~^ ERROR constant evaluation error [E0080] diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index b42c440f87d74..7596881ef9b9a 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -14,6 +14,7 @@ const TUP: (usize,) = 5usize << 64; //~^ ERROR mismatched types //~| expected tuple, found usize const ARR: [i32; TUP.0] = []; +//~^ ERROR constant evaluation error fn main() { } diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 86cc2c144ac07..49f76c532df54 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum test { - div_zero = 1/0, //~ ERROR E0080 - //~| attempt to divide by zero - rem_zero = 1%0, - //~^ ERROR E0080 - //~| attempt to calculate the remainder with a divisor of zero +enum Test { + DivZero = 1/0, + //~^ attempt to divide by zero + //~| ERROR constant evaluation error + //~| WARN constant evaluation error + RemZero = 1%0, + //~^ attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error + //~| WARN constant evaluation error } fn main() {} diff --git a/src/test/compile-fail/float-int-invalid-const-cast.rs b/src/test/compile-fail/float-int-invalid-const-cast.rs deleted file mode 100644 index 1f07422e21be4..0000000000000 --- a/src/test/compile-fail/float-int-invalid-const-cast.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2017 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(i128_type)] -#![allow(const_err)] // this test is only about hard errors - -use std::{f32, f64}; - -// Forces evaluation of constants, triggering hard error -fn force(_: T) {} - -fn main() { - { const X: u16 = -1. as u16; force(X); } //~ ERROR constant evaluation error - { const X: u128 = -100. as u128; force(X); } //~ ERROR constant evaluation error - - { const X: i8 = f32::NAN as i8; force(X); } //~ ERROR constant evaluation error - { const X: i32 = f32::NAN as i32; force(X); } //~ ERROR constant evaluation error - { const X: u64 = f32::NAN as u64; force(X); } //~ ERROR constant evaluation error - { const X: u128 = f32::NAN as u128; force(X); } //~ ERROR constant evaluation error - - { const X: i8 = f32::INFINITY as i8; force(X); } //~ ERROR constant evaluation error - { const X: u32 = f32::INFINITY as u32; force(X); } //~ ERROR constant evaluation error - { const X: i128 = f32::INFINITY as i128; force(X); } //~ ERROR constant evaluation error - { const X: u128 = f32::INFINITY as u128; force(X); } //~ ERROR constant evaluation error - - { const X: u8 = f32::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error - { const X: u16 = f32::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error - { const X: i64 = f32::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error - { const X: i128 = f32::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error - - { const X: i8 = f64::NAN as i8; force(X); } //~ ERROR constant evaluation error - { const X: i32 = f64::NAN as i32; force(X); } //~ ERROR constant evaluation error - { const X: u64 = f64::NAN as u64; force(X); } //~ ERROR constant evaluation error - { const X: u128 = f64::NAN as u128; force(X); } //~ ERROR constant evaluation error - - { const X: i8 = f64::INFINITY as i8; force(X); } //~ ERROR constant evaluation error - { const X: u32 = f64::INFINITY as u32; force(X); } //~ ERROR constant evaluation error - { const X: i128 = f64::INFINITY as i128; force(X); } //~ ERROR constant evaluation error - { const X: u128 = f64::INFINITY as u128; force(X); } //~ ERROR constant evaluation error - - { const X: u8 = f64::NEG_INFINITY as u8; force(X); } //~ ERROR constant evaluation error - { const X: u16 = f64::NEG_INFINITY as u16; force(X); } //~ ERROR constant evaluation error - { const X: i64 = f64::NEG_INFINITY as i64; force(X); } //~ ERROR constant evaluation error - { const X: i128 = f64::NEG_INFINITY as i128; force(X); } //~ ERROR constant evaluation error - - { const X: u8 = 256. as u8; force(X); } //~ ERROR constant evaluation error - { const X: i8 = -129. as i8; force(X); } //~ ERROR constant evaluation error - { const X: i8 = 128. as i8; force(X); } //~ ERROR constant evaluation error - { const X: i32 = 2147483648. as i32; force(X); } //~ ERROR constant evaluation error - { const X: i32 = -2147483904. as i32; force(X); } //~ ERROR constant evaluation error - { const X: u32 = 4294967296. as u32; force(X); } //~ ERROR constant evaluation error - { const X: u128 = 1e40 as u128; force(X); } //~ ERROR constant evaluation error - { const X: i128 = 1e40 as i128; force(X); } //~ ERROR constant evaluation error -} diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index ca8d5a1f70473..be76796c5c465 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -14,8 +14,7 @@ fn main() { match i { 0...index => println!("winner"), - //~^ ERROR constant evaluation error - //~| non-constant path in constant expression + //~^ ERROR runtime values cannot be referenced in patterns _ => println!("hello"), } } diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index 823ece2bdca01..ac85e43cf4f05 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -18,33 +18,33 @@ fn main() { let x = 42.0; match x { - 5.0 => {}, //~ ERROR floating-point cannot be used + 5.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error - 5.0f32 => {}, //~ ERROR floating-point cannot be used + 5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error - -5.0 => {}, //~ ERROR floating-point cannot be used + -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error - 1.0 .. 33.0 => {}, //~ ERROR floating-point cannot be used + 1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error - //~| ERROR floating-point cannot be used + //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error - 39.0 ... 70.0 => {}, //~ ERROR floating-point cannot be used + 39.0 ... 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error - //~| ERROR floating-point cannot be used + //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error _ => {}, }; let y = 5.0; // Same for tuples match (x, 5) { - (3.14, 1) => {}, //~ ERROR floating-point cannot be used + (3.14, 1) => {}, //~ ERROR floating-point types cannot be used //~| WARNING hard error _ => {}, } // Or structs struct Foo { x: f32 }; match (Foo { x }) { - Foo { x: 2.0 } => {}, //~ ERROR floating-point cannot be used + Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used //~| WARNING hard error _ => {}, } diff --git a/src/test/compile-fail/issue-44578.rs b/src/test/compile-fail/issue-44578.rs index a6ae21c3b5497..9efe3d90a93c5 100644 --- a/src/test/compile-fail/issue-44578.rs +++ b/src/test/compile-fail/issue-44578.rs @@ -18,7 +18,7 @@ enum Bar { } impl Foo for Bar { - const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ ERROR constant evaluation + const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ E0080 } impl Foo for u8 { @@ -30,5 +30,5 @@ impl Foo for u16 { } fn main() { - println!("{}", as Foo>::AMT); + println!("{}", as Foo>::AMT); //~ E0080 } diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index 2a97945f26648..9191dfa155c65 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -12,18 +12,21 @@ #![feature(slice_patterns)] #![allow(unused)] +#![deny(illegal_floating_point_literal_pattern)] use std::f64::NAN; fn main() { let x = NAN; match x { - NAN => {}, //~ ERROR floating point constants cannot be used + NAN => {}, //~ ERROR floating-point types cannot be used + //~^ WARN this was previously accepted by the compiler but is being phased out _ => {}, }; match [x, 1.0] { - [NAN, _] => {}, //~ ERROR floating point constants cannot be used + [NAN, _] => {}, //~ ERROR floating-point types cannot be used + //~^ WARN this was previously accepted by the compiler but is being phased out _ => {}, }; } diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index d8ab48d1ec3e6..1d59e75a0f0f0 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -16,42 +16,62 @@ use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~| ERROR constant evaluation error } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index e94d1ff779367..2634157c80671 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -10,7 +10,7 @@ #![deny(exceeding_bitshifts)] #![allow(unused_variables)] -#![allow(dead_code)] +#![allow(dead_code, const_err)] #![feature(const_indexing)] fn main() { @@ -54,21 +54,5 @@ fn main() { let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits - - let n = 1u8 << (4+3); - let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits - - #[cfg(target_pointer_width = "32")] - const BITS: usize = 32; - #[cfg(target_pointer_width = "64")] - const BITS: usize = 64; - - let n = 1_isize << BITS; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1_usize << BITS; //~ ERROR: bitshift exceeds the type's number of bits - - let n = 1i8<<(1isize+-1); - - let n = 1i64 >> [63][0]; - let n = 1i64 >> [64][0]; //~ ERROR: bitshift exceeds the type's number of bits } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts2.rs b/src/test/compile-fail/lint-exceeding-bitshifts2.rs new file mode 100644 index 0000000000000..d95e1b370aafd --- /dev/null +++ b/src/test/compile-fail/lint-exceeding-bitshifts2.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(exceeding_bitshifts)] +#![allow(unused_variables, const_err)] +#![allow(dead_code)] + +fn main() { + let n = 1u8 << (4+3); + let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i64 >> [63][0]; + let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation + + #[cfg(target_pointer_width = "32")] + const BITS: usize = 32; + #[cfg(target_pointer_width = "64")] + const BITS: usize = 64; + let n = 1_isize << BITS; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1_usize << BITS; //~ ERROR: bitshift exceeds the type's number of bits +} diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index f7cf8a68d5684..9178d8d2f6ed2 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -17,6 +17,7 @@ #[rustc_error] fn main() { //~ ERROR: compilation successful let x2: i8 = --128; //~ warn: literal out of range for i8 + //~^ WARN constant evaluation error let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index 737f80372debf..fe88ab4e11798 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -12,7 +12,6 @@ fn main() { let x = 0; match 1 { 0 ... x => {} - //~^ ERROR constant evaluation error - //~| non-constant path in constant expression + //~^ ERROR runtime values cannot be referenced in patterns }; } diff --git a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs index fd888b659f142..ca9af78dd9936 100644 --- a/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/compile-fail/rfc1445/match-forbidden-without-eq.rs @@ -28,7 +28,7 @@ fn main() { let x = 0.0; match x { f32::INFINITY => { } - //~^ WARNING floating-point cannot be used in patterns + //~^ WARNING floating-point types cannot be used in patterns //~| WARNING will become a hard error in a future release _ => { } } diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/run-pass/const-index-feature-gate.rs similarity index 83% rename from src/test/compile-fail/const-index-feature-gate.rs rename to src/test/run-pass/const-index-feature-gate.rs index 4f92770df289c..2e60634d15eed 100644 --- a/src/test/compile-fail/const-index-feature-gate.rs +++ b/src/test/run-pass/const-index-feature-gate.rs @@ -9,8 +9,7 @@ // except according to those terms. const ARR: [usize; 1] = [2]; -const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080 - //~| unstable +const ARR2: [i32; ARR[0]] = [5, 6]; fn main() { } diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs new file mode 100644 index 0000000000000..80ab12482cbb7 --- /dev/null +++ b/src/test/run-pass/float-int-invalid-const-cast.rs @@ -0,0 +1,61 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(i128_type)] +#![deny(const_err)] + +use std::{f32, f64}; + +// Forces evaluation of constants, triggering hard error +fn force(_: T) {} + +fn main() { + { const X: u16 = -1. as u16; force(X); } + { const X: u128 = -100. as u128; force(X); } + + { const X: i8 = f32::NAN as i8; force(X); } + { const X: i32 = f32::NAN as i32; force(X); } + { const X: u64 = f32::NAN as u64; force(X); } + { const X: u128 = f32::NAN as u128; force(X); } + + { const X: i8 = f32::INFINITY as i8; force(X); } + { const X: u32 = f32::INFINITY as u32; force(X); } + { const X: i128 = f32::INFINITY as i128; force(X); } + { const X: u128 = f32::INFINITY as u128; force(X); } + + { const X: u8 = f32::NEG_INFINITY as u8; force(X); } + { const X: u16 = f32::NEG_INFINITY as u16; force(X); } + { const X: i64 = f32::NEG_INFINITY as i64; force(X); } + { const X: i128 = f32::NEG_INFINITY as i128; force(X); } + + { const X: i8 = f64::NAN as i8; force(X); } + { const X: i32 = f64::NAN as i32; force(X); } + { const X: u64 = f64::NAN as u64; force(X); } + { const X: u128 = f64::NAN as u128; force(X); } + + { const X: i8 = f64::INFINITY as i8; force(X); } + { const X: u32 = f64::INFINITY as u32; force(X); } + { const X: i128 = f64::INFINITY as i128; force(X); } + { const X: u128 = f64::INFINITY as u128; force(X); } + + { const X: u8 = f64::NEG_INFINITY as u8; force(X); } + { const X: u16 = f64::NEG_INFINITY as u16; force(X); } + { const X: i64 = f64::NEG_INFINITY as i64; force(X); } + { const X: i128 = f64::NEG_INFINITY as i128; force(X); } + + { const X: u8 = 256. as u8; force(X); } + { const X: i8 = -129. as i8; force(X); } + { const X: i8 = 128. as i8; force(X); } + { const X: i32 = 2147483648. as i32; force(X); } + { const X: i32 = -2147483904. as i32; force(X); } + { const X: u32 = 4294967296. as u32; force(X); } + { const X: u128 = 1e40 as u128; force(X); } + { const X: i128 = 1e40 as i128; force(X); } +} diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr index f0d466acc9df3..e92754fc13582 100644 --- a/src/test/ui/const-eval-overflow-2.stderr +++ b/src/test/ui/const-eval-overflow-2.stderr @@ -1,8 +1,8 @@ error[E0080]: constant evaluation error - --> $DIR/const-eval-overflow-2.rs:21:25 + --> $DIR/const-eval-overflow-2.rs:21:1 | 21 | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^ miri failed: Overflow(Neg) at $DIR/const-eval-overflow-2.rs:21:25: 21:33 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: attempt to negate with overflow | note: for pattern here --> $DIR/const-eval-overflow-2.rs:26:9 diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr index 6cd2dd52edeae..2f8bf78758a0f 100644 --- a/src/test/ui/const-eval-overflow-4.stderr +++ b/src/test/ui/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-4.rs:23:13 | 23 | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: Overflow(Add) at $DIR/const-eval-overflow-4.rs:23:13: 23:34 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: attempt to add with overflow error: aborting due to previous error diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index 86c5e873df866..e87b2caa49f90 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -18,4 +18,6 @@ fn main() { const X: u32 = 0-1; //~ ERROR constant evaluation error const Y: u32 = foo(0-1); //~ ERROR constant evaluation error println!("{} {}", X, Y); + //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error } diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index f624fc03cd871..9ba9c43462c53 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -1,14 +1,50 @@ error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:18:20 + --> $DIR/issue-43197.rs:20:23 | -18 | const X: u32 = 0-1; //~ ERROR constant evaluation error - | ^^^ attempt to subtract with overflow +20 | println!("{} {}", X, Y); + | ^ attempt to subtract with overflow + | +note: inside call to main + --> $DIR/issue-43197.rs:20:23 + | +20 | println!("{} {}", X, Y); + | ^ + +error[E0080]: constant evaluation error + --> $DIR/issue-43197.rs:20:26 + | +20 | println!("{} {}", X, Y); + | ^ attempt to subtract with overflow + | +note: inside call to main + --> $DIR/issue-43197.rs:20:26 + | +20 | println!("{} {}", X, Y); + | ^ error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:19:24 | 19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error | ^^^ attempt to subtract with overflow + | +note: inside call to main::Y + --> $DIR/issue-43197.rs:19:5 + | +19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: constant evaluation error + --> $DIR/issue-43197.rs:18:20 + | +18 | const X: u32 = 0-1; //~ ERROR constant evaluation error + | ^^^ attempt to subtract with overflow + | +note: inside call to main::X + --> $DIR/issue-43197.rs:18:5 + | +18 | const X: u32 = 0-1; //~ ERROR constant evaluation error + | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/const-expr-addr-operator.stderr b/src/test/ui/const-expr-addr-operator.stderr index e69de29bb2d1d..b40ce13f58f31 100644 --- a/src/test/ui/const-expr-addr-operator.stderr +++ b/src/test/ui/const-expr-addr-operator.stderr @@ -0,0 +1,23 @@ +warning: constant evaluation error + --> $DIR/const-expr-addr-operator.rs:17:5 + | +17 | / assert_eq!(0, match &22 { +18 | | X => 0, +19 | | _ => 1, +20 | | }); + | |_______^ machine error: "Pointer arithmetic or comparison" needs an rfc before being allowed inside constants + | + = note: #[warn(const_err)] on by default +note: inside call to main + --> $DIR/const-expr-addr-operator.rs:14:1 + | +14 | / pub fn main() { +15 | | // Constant of generic type (int) +16 | | const X: &'static u32 = &22; +17 | | assert_eq!(0, match &22 { +... | +20 | | }); +21 | | } + | |_^ + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs index 7582d0efa812e..35e3ba9ce0945 100644 --- a/src/test/ui/const-len-underflow-separate-spans.rs +++ b/src/test/ui/const-len-underflow-separate-spans.rs @@ -15,6 +15,7 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; +//~^ ERROR E0080 fn main() { let a: [i8; LEN] = unimplemented!(); diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 77a41258b3435..6b2789c145444 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -1,8 +1,20 @@ error[E0080]: constant evaluation error - --> $DIR/const-len-underflow-separate-spans.rs:20:17 + --> $DIR/const-len-underflow-separate-spans.rs:17:20 | -20 | let a: [i8; LEN] = unimplemented!(); - | ^^^ miri failed: Overflow(Sub) at $DIR/const-len-underflow-separate-spans.rs:17:20: 17:29 +17 | const LEN: usize = ONE - TWO; + | ^^^^^^^^^ attempt to subtract with overflow + | +note: inside call to LEN + --> $DIR/const-len-underflow-separate-spans.rs:17:1 + | +17 | const LEN: usize = ONE - TWO; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: constant evaluation error + --> $DIR/const-len-underflow-separate-spans.rs:21:17 + | +21 | let a: [i8; LEN] = unimplemented!(); + | ^^^ miri failed: attempt to subtract with overflow -error: aborting due to previous error +error: aborting due to 2 previous errors From d407761c207ae85ece50d13e940f2237001ace33 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 14 Jan 2018 13:03:49 +0100 Subject: [PATCH 010/115] Always report errors for statics --- src/librustc_mir/interpret/const_eval.rs | 10 ++++++++-- src/librustc_trans/consts.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 4170656d64c90..5521191f792e7 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -461,13 +461,19 @@ pub fn const_eval_provider<'a, 'tcx>( } }; - eval_body_and_ecx(tcx, cid, None, key.param_env).0.map(|(miri_value, _, miri_ty)| { + let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); + res.map(|(miri_value, _, miri_ty)| { tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), ty: miri_ty, }) - }).map_err(|err| ConstEvalErr { + }).map_err(|mut err| { + if tcx.is_static(def_id).is_some() { + ecx.report(&mut err, true); + } + ConstEvalErr { kind: err.into(), span, + } }) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 95dfa6fe05d10..7cab7a5482225 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -253,7 +253,7 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let v = match ::mir::trans_static_initializer(cx, def_id) { Ok(v) => v, - // FIXME: report this? + // Error has already been reported Err(_) => return, }; From 06cc93da521554f6b7aa718c43a699106c7f461c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 14 Jan 2018 13:04:02 +0100 Subject: [PATCH 011/115] Evaluate 128 lowering lang items manually --- src/librustc_mir/interpret/const_eval.rs | 28 ++++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 5521191f792e7..5b7d6fff3f930 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -205,15 +205,29 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, destination: Option<(Place, mir::BasicBlock)>, - _args: &[ValTy<'tcx>], + args: &[ValTy<'tcx>], span: Span, - _sig: ty::FnSig<'tcx>, + sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool> { debug!("eval_fn_call: {:?}", instance); if !ecx.tcx.is_const_fn(instance.def_id()) { - return Err( - ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), - ); + let def_id = instance.def_id(); + let (op, oflo) = if let Some(op) = ecx.tcx.is_binop_lang_item(def_id) { + op + } else { + return Err( + ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), + ); + }; + let (dest, bb) = destination.expect("128 lowerings can't diverge"); + let dest_ty = sig.output(); + if oflo { + ecx.intrinsic_with_overflow(op, args[0], args[1], dest, dest_ty)?; + } else { + ecx.intrinsic_overflowing(op, args[0], args[1], dest, dest_ty)?; + } + ecx.goto_block(bb); + return Ok(true); } let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, @@ -472,8 +486,8 @@ pub fn const_eval_provider<'a, 'tcx>( ecx.report(&mut err, true); } ConstEvalErr { - kind: err.into(), - span, + kind: err.into(), + span, } }) } From 8f9356e1d7df4e8335dfbeb7869aa30b6f0338f9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 14 Jan 2018 13:25:38 +0100 Subject: [PATCH 012/115] Update to latests rustc --- src/librustc_mir/const_eval/pattern.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 23c4d19ccacfb..7ac96a634cf98 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -836,7 +836,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } }, ty::TyAdt(adt_def, _) => { - let struct_var = adt_def.struct_variant(); + let struct_var = adt_def.non_enum_variant(); PatternKind::Leaf { subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| { let field = Field::new(i); From 5420c4bf68142c63c653b1bb1b23b7027270e9f8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 14 Jan 2018 20:29:57 +0100 Subject: [PATCH 013/115] Implement on disk cache for AllocId --- src/librustc/ty/maps/on_disk_cache.rs | 80 ++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 24256934099c6..2522b70a5ba1f 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -187,6 +187,7 @@ impl<'sess> OnDiskCache<'sess> { type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), expn_info_shorthands: FxHashMap(), + interpret_alloc_shorthands: FxHashMap(), codemap: CachingCodemapView::new(tcx.sess.codemap()), file_to_file_index, }; @@ -363,6 +364,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_file: &mut file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, synthetic_expansion_infos: &mut synthetic_expansion_infos, + interpret_alloc_cache: FxHashMap::default(), }; match decode_tagged(&mut decoder, dep_node_index) { @@ -424,6 +426,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { synthetic_expansion_infos: &'x mut FxHashMap, file_index_to_file: &'x mut FxHashMap>, file_index_to_stable_id: &'x FxHashMap, + interpret_alloc_cache: FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -543,13 +546,51 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); - impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { - unimplemented!() + const MAX1: usize = usize::max_value() - 1; + let tcx = self.tcx; + let interpret_interner = || tcx.interpret_interner.borrow_mut(); + let pos = TyDecoder::position(self); + match usize::decode(self)? { + ::std::usize::MAX => { + let alloc_id = interpret_interner().reserve(); + trace!("creating alloc id {:?} at {}", alloc_id, pos); + // insert early to allow recursive allocs + self.interpret_alloc_cache.insert(pos, alloc_id); + + let allocation = interpret::Allocation::decode(self)?; + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); + let allocation = self.tcx.intern_const_alloc(allocation); + interpret_interner().intern_at_reserved(alloc_id, allocation); + + if let Some(glob) = Option::::decode(self)? { + interpret_interner().cache(glob, alloc_id); + } + + Ok(alloc_id) + }, + MAX1 => { + trace!("creating fn alloc id at {}", pos); + let instance = ty::Instance::decode(self)?; + trace!("decoded fn alloc instance: {:?}", instance); + let id = interpret_interner().create_fn_alloc(instance); + trace!("created fn alloc id: {:?}", id); + self.interpret_alloc_cache.insert(pos, id); + Ok(id) + }, + shorthand => { + trace!("loading shorthand {}", shorthand); + if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) { + return Ok(alloc_id); + } + trace!("shorthand {} not cached, loading entire allocation", shorthand); + // need to load allocation + self.with_position(shorthand, |this| interpret::AllocId::decode(this)) + }, + } } } - impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; @@ -706,6 +747,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, expn_info_shorthands: FxHashMap, + interpret_alloc_shorthands: FxHashMap, codemap: CachingCodemapView<'tcx>, file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, } @@ -738,6 +780,38 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> } } +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + trace!("encoding {:?} at {}", alloc_id, self.position()); + if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { + trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand); + return shorthand.encode(self); + } + let start = self.position(); + // cache the allocation shorthand now, because the allocation itself might recursively + // point to itself. + self.interpret_alloc_shorthands.insert(*alloc_id, start); + let interpret_interner = self.tcx.interpret_interner.borrow(); + if let Some(alloc) = interpret_interner.get_alloc(*alloc_id) { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); + usize::max_value().encode(self)?; + alloc.encode(self)?; + interpret_interner + .get_corresponding_static_def_id(*alloc_id) + .encode(self)?; + } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); + (usize::max_value() - 1).encode(self)?; + fn_instance.encode(self)?; + } else { + bug!("alloc id without corresponding allocation: {}", alloc_id); + } + Ok(()) + } +} + impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> where E: 'enc + ty_codec::TyEncoder { From 80be23bbbfe6e0ed145613037cdf966dcb88c0bf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 15 Jan 2018 10:31:28 +0100 Subject: [PATCH 014/115] Codegen tests --- src/test/codegen/consts.rs | 10 +++++----- src/test/codegen/link_section.rs | 2 +- src/test/codegen/remap_path_prefix/main.rs | 2 +- src/test/compile-fail/issue-43105.rs | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index a75b8f3992d07..13c037e96cbe3 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: -C no-prepopulate-passes +// ignore-tidy-linelength #![crate_type = "lib"] @@ -19,12 +20,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @ref.{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @byte_str.{{[0-9]+}} = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@ref.[0-9]+]] = {{.*}}, align 4 -// CHECK: [[LOW_HIGH_REF:@const.[0-9]+]] = {{.*}} [[LOW_HIGH]] +// CHECK: [[LOW_HIGH:@byte_str.[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] @@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 2, i1 false) *&E::A(0) } @@ -62,6 +62,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant -// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i64 8, i32 4, i1 false) *&E::A(0) } diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 1879002e7f3d7..9c56a316b341c 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,7 +12,7 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant i32 1, section ".test_one" +// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] pub static VAR1: u32 = 1; diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index ea0c9ad2b8324..c5aa00e7b8673 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -22,7 +22,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: internal constant [34 x i8] c"/the/src/remap_path_prefix/main.rs" +// CHECK: @byte_str.1 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/src/test/compile-fail/issue-43105.rs b/src/test/compile-fail/issue-43105.rs index fb419d751b4e8..c0af3b4b9e695 100644 --- a/src/test/compile-fail/issue-43105.rs +++ b/src/test/compile-fail/issue-43105.rs @@ -12,6 +12,7 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); //~^ ERROR calls in constants are limited to constant functions, struct and enum constructors +//~| ERROR constant evaluation error fn main() { match 1 { From bfb588ba630529a1556690d213fe24248ee8f6e9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 10:15:41 +0100 Subject: [PATCH 015/115] Add tests for fixed issues --- .../ctfe/chained-constants-stackoverflow.rs | 364 ++++++++++++++++++ src/test/run-pass/ctfe/deref_in_pattern.rs | 20 + src/test/run-pass/ctfe/issue-broken-mir.rs | 18 + .../run-pass/ctfe/match-const-fn-structs.rs | 31 ++ src/test/run-pass/ctfe/non-scalar-cast.rs | 17 + src/test/run-pass/ctfe/return-in-const-fn.rs | 19 + .../ctfe/tuple-struct-constructors.rs | 20 + src/test/ui/infinite-recursion-const-fn.rs | 18 + .../ui/infinite-recursion-const-fn.stderr | 8 + 9 files changed, 515 insertions(+) create mode 100644 src/test/run-pass/ctfe/chained-constants-stackoverflow.rs create mode 100644 src/test/run-pass/ctfe/deref_in_pattern.rs create mode 100644 src/test/run-pass/ctfe/issue-broken-mir.rs create mode 100644 src/test/run-pass/ctfe/match-const-fn-structs.rs create mode 100644 src/test/run-pass/ctfe/non-scalar-cast.rs create mode 100644 src/test/run-pass/ctfe/return-in-const-fn.rs create mode 100644 src/test/run-pass/ctfe/tuple-struct-constructors.rs create mode 100644 src/test/ui/infinite-recursion-const-fn.rs create mode 100644 src/test/ui/infinite-recursion-const-fn.stderr diff --git a/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs b/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs new file mode 100644 index 0000000000000..813dd5fbb9941 --- /dev/null +++ b/src/test/run-pass/ctfe/chained-constants-stackoverflow.rs @@ -0,0 +1,364 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/34997 + +pub const CST_1: u32 = 0; +pub const CST_2: u32 = CST_1+1; +pub const CST_3: u32 = CST_2+1; +pub const CST_4: u32 = CST_3+1; +pub const CST_5: u32 = CST_4+1; +pub const CST_6: u32 = CST_5+1; +pub const CST_7: u32 = CST_6+1; +pub const CST_8: u32 = CST_7+1; +pub const CST_9: u32 = CST_8+1; +pub const CST_10: u32 = CST_9+1; +pub const CST_11: u32 = CST_10+1; +pub const CST_12: u32 = CST_11+1; +pub const CST_13: u32 = CST_12+1; +pub const CST_14: u32 = CST_13+1; +pub const CST_15: u32 = CST_14+1; +pub const CST_16: u32 = CST_15+1; +pub const CST_17: u32 = CST_16+1; +pub const CST_18: u32 = CST_17+1; +pub const CST_19: u32 = CST_18+1; +pub const CST_20: u32 = CST_19+1; +pub const CST_21: u32 = CST_20+1; +pub const CST_22: u32 = CST_21+1; +pub const CST_23: u32 = CST_22+1; +pub const CST_24: u32 = CST_23+1; +pub const CST_25: u32 = CST_24+1; +pub const CST_26: u32 = CST_25+1; +pub const CST_27: u32 = CST_26+1; +pub const CST_28: u32 = CST_27+1; +pub const CST_29: u32 = CST_28+1; +pub const CST_30: u32 = CST_29+1; +pub const CST_31: u32 = CST_30+1; +pub const CST_32: u32 = CST_31+1; +pub const CST_33: u32 = CST_32+1; +pub const CST_34: u32 = CST_33+1; +pub const CST_35: u32 = CST_34+1; +pub const CST_36: u32 = CST_35+1; +pub const CST_37: u32 = CST_36+1; +pub const CST_38: u32 = CST_37+1; +pub const CST_39: u32 = CST_38+1; +pub const CST_40: u32 = CST_39+1; +pub const CST_41: u32 = CST_40+1; +pub const CST_42: u32 = CST_41+1; +pub const CST_43: u32 = CST_42+1; +pub const CST_44: u32 = CST_43+1; +pub const CST_45: u32 = CST_44+1; +pub const CST_46: u32 = CST_45+1; +pub const CST_47: u32 = CST_46+1; +pub const CST_48: u32 = CST_47+1; +pub const CST_49: u32 = CST_48+1; +pub const CST_50: u32 = CST_49+1; +pub const CST_51: u32 = CST_50+1; +pub const CST_52: u32 = CST_51+1; +pub const CST_53: u32 = CST_52+1; +pub const CST_54: u32 = CST_53+1; +pub const CST_55: u32 = CST_54+1; +pub const CST_56: u32 = CST_55+1; +pub const CST_57: u32 = CST_56+1; +pub const CST_58: u32 = CST_57+1; +pub const CST_59: u32 = CST_58+1; +pub const CST_60: u32 = CST_59+1; +pub const CST_61: u32 = CST_60+1; +pub const CST_62: u32 = CST_61+1; +pub const CST_63: u32 = CST_62+1; +pub const CST_64: u32 = CST_63+1; +pub const CST_65: u32 = CST_64+1; +pub const CST_66: u32 = CST_65+1; +pub const CST_67: u32 = CST_66+1; +pub const CST_68: u32 = CST_67+1; +pub const CST_69: u32 = CST_68+1; +pub const CST_70: u32 = CST_69+1; +pub const CST_71: u32 = CST_70+1; +pub const CST_72: u32 = CST_71+1; +pub const CST_73: u32 = CST_72+1; +pub const CST_74: u32 = CST_73+1; +pub const CST_75: u32 = CST_74+1; +pub const CST_76: u32 = CST_75+1; +pub const CST_77: u32 = CST_76+1; +pub const CST_78: u32 = CST_77+1; +pub const CST_79: u32 = CST_78+1; +pub const CST_80: u32 = CST_79+1; +pub const CST_81: u32 = CST_80+1; +pub const CST_82: u32 = CST_81+1; +pub const CST_83: u32 = CST_82+1; +pub const CST_84: u32 = CST_83+1; +pub const CST_85: u32 = CST_84+1; +pub const CST_86: u32 = CST_85+1; +pub const CST_87: u32 = CST_86+1; +pub const CST_88: u32 = CST_87+1; +pub const CST_89: u32 = CST_88+1; +pub const CST_90: u32 = CST_89+1; +pub const CST_91: u32 = CST_90+1; +pub const CST_92: u32 = CST_91+1; +pub const CST_93: u32 = CST_92+1; +pub const CST_94: u32 = CST_93+1; +pub const CST_95: u32 = CST_94+1; +pub const CST_96: u32 = CST_95+1; +pub const CST_97: u32 = CST_96+1; +pub const CST_98: u32 = CST_97+1; +pub const CST_99: u32 = CST_98+1; +pub const CST_100: u32 = CST_99+1; +pub const CST_101: u32 = CST_100+1; +pub const CST_102: u32 = CST_101+1; +pub const CST_103: u32 = CST_102+1; +pub const CST_104: u32 = CST_103+1; +pub const CST_105: u32 = CST_104+1; +pub const CST_106: u32 = CST_105+1; +pub const CST_107: u32 = CST_106+1; +pub const CST_108: u32 = CST_107+1; +pub const CST_109: u32 = CST_108+1; +pub const CST_110: u32 = CST_109+1; +pub const CST_111: u32 = CST_110+1; +pub const CST_112: u32 = CST_111+1; +pub const CST_113: u32 = CST_112+1; +pub const CST_114: u32 = CST_113+1; +pub const CST_115: u32 = CST_114+1; +pub const CST_116: u32 = CST_115+1; +pub const CST_117: u32 = CST_116+1; +pub const CST_118: u32 = CST_117+1; +pub const CST_119: u32 = CST_118+1; +pub const CST_120: u32 = CST_119+1; +pub const CST_121: u32 = CST_120+1; +pub const CST_122: u32 = CST_121+1; +pub const CST_123: u32 = CST_122+1; +pub const CST_124: u32 = CST_123+1; +pub const CST_125: u32 = CST_124+1; +pub const CST_126: u32 = CST_125+1; +pub const CST_127: u32 = CST_126+1; +pub const CST_128: u32 = CST_127+1; +pub const CST_129: u32 = CST_128+1; +pub const CST_130: u32 = CST_129+1; +pub const CST_131: u32 = CST_130+1; +pub const CST_132: u32 = CST_131+1; +pub const CST_133: u32 = CST_132+1; +pub const CST_134: u32 = CST_133+1; +pub const CST_135: u32 = CST_134+1; +pub const CST_136: u32 = CST_135+1; +pub const CST_137: u32 = CST_136+1; +pub const CST_138: u32 = CST_137+1; +pub const CST_139: u32 = CST_138+1; +pub const CST_140: u32 = CST_139+1; +pub const CST_141: u32 = CST_140+1; +pub const CST_142: u32 = CST_141+1; +pub const CST_143: u32 = CST_142+1; +pub const CST_144: u32 = CST_143+1; +pub const CST_145: u32 = CST_144+1; +pub const CST_146: u32 = CST_145+1; +pub const CST_147: u32 = CST_146+1; +pub const CST_148: u32 = CST_147+1; +pub const CST_149: u32 = CST_148+1; +pub const CST_150: u32 = CST_149+1; +pub const CST_151: u32 = CST_150+1; +pub const CST_152: u32 = CST_151+1; +pub const CST_153: u32 = CST_152+1; +pub const CST_154: u32 = CST_153+1; +pub const CST_155: u32 = CST_154+1; +pub const CST_156: u32 = CST_155+1; +pub const CST_157: u32 = CST_156+1; +pub const CST_158: u32 = CST_157+1; +pub const CST_159: u32 = CST_158+1; +pub const CST_160: u32 = CST_159+1; +pub const CST_161: u32 = CST_160+1; +pub const CST_162: u32 = CST_161+1; +pub const CST_163: u32 = CST_162+1; +pub const CST_164: u32 = CST_163+1; +pub const CST_165: u32 = CST_164+1; +pub const CST_166: u32 = CST_165+1; +pub const CST_167: u32 = CST_166+1; +pub const CST_168: u32 = CST_167+1; +pub const CST_169: u32 = CST_168+1; +pub const CST_170: u32 = CST_169+1; +pub const CST_171: u32 = CST_170+1; +pub const CST_172: u32 = CST_171+1; +pub const CST_173: u32 = CST_172+1; +pub const CST_174: u32 = CST_173+1; +pub const CST_175: u32 = CST_174+1; +pub const CST_176: u32 = CST_175+1; +pub const CST_177: u32 = CST_176+1; +pub const CST_178: u32 = CST_177+1; +pub const CST_179: u32 = CST_178+1; +pub const CST_180: u32 = CST_179+1; +pub const CST_181: u32 = CST_180+1; +pub const CST_182: u32 = CST_181+1; +pub const CST_183: u32 = CST_182+1; +pub const CST_184: u32 = CST_183+1; +pub const CST_185: u32 = CST_184+1; +pub const CST_186: u32 = CST_185+1; +pub const CST_187: u32 = CST_186+1; +pub const CST_188: u32 = CST_187+1; +pub const CST_189: u32 = CST_188+1; +pub const CST_190: u32 = CST_189+1; +pub const CST_191: u32 = CST_190+1; +pub const CST_192: u32 = CST_191+1; +pub const CST_193: u32 = CST_192+1; +pub const CST_194: u32 = CST_193+1; +pub const CST_195: u32 = CST_194+1; +pub const CST_196: u32 = CST_195+1; +pub const CST_197: u32 = CST_196+1; +pub const CST_198: u32 = CST_197+1; +pub const CST_199: u32 = CST_198+1; +pub const CST_200: u32 = CST_199+1; +pub const CST_201: u32 = CST_200+1; +pub const CST_202: u32 = CST_201+1; +pub const CST_203: u32 = CST_202+1; +pub const CST_204: u32 = CST_203+1; +pub const CST_205: u32 = CST_204+1; +pub const CST_206: u32 = CST_205+1; +pub const CST_207: u32 = CST_206+1; +pub const CST_208: u32 = CST_207+1; +pub const CST_209: u32 = CST_208+1; +pub const CST_210: u32 = CST_209+1; +pub const CST_211: u32 = CST_210+1; +pub const CST_212: u32 = CST_211+1; +pub const CST_213: u32 = CST_212+1; +pub const CST_214: u32 = CST_213+1; +pub const CST_215: u32 = CST_214+1; +pub const CST_216: u32 = CST_215+1; +pub const CST_217: u32 = CST_216+1; +pub const CST_218: u32 = CST_217+1; +pub const CST_219: u32 = CST_218+1; +pub const CST_220: u32 = CST_219+1; +pub const CST_221: u32 = CST_220+1; +pub const CST_222: u32 = CST_221+1; +pub const CST_223: u32 = CST_222+1; +pub const CST_224: u32 = CST_223+1; +pub const CST_225: u32 = CST_224+1; +pub const CST_226: u32 = CST_225+1; +pub const CST_227: u32 = CST_226+1; +pub const CST_228: u32 = CST_227+1; +pub const CST_229: u32 = CST_228+1; +pub const CST_230: u32 = CST_229+1; +pub const CST_231: u32 = CST_230+1; +pub const CST_232: u32 = CST_231+1; +pub const CST_233: u32 = CST_232+1; +pub const CST_234: u32 = CST_233+1; +pub const CST_235: u32 = CST_234+1; +pub const CST_236: u32 = CST_235+1; +pub const CST_237: u32 = CST_236+1; +pub const CST_238: u32 = CST_237+1; +pub const CST_239: u32 = CST_238+1; +pub const CST_240: u32 = CST_239+1; +pub const CST_241: u32 = CST_240+1; +pub const CST_242: u32 = CST_241+1; +pub const CST_243: u32 = CST_242+1; +pub const CST_244: u32 = CST_243+1; +pub const CST_245: u32 = CST_244+1; +pub const CST_246: u32 = CST_245+1; +pub const CST_247: u32 = CST_246+1; +pub const CST_248: u32 = CST_247+1; +pub const CST_249: u32 = CST_248+1; +pub const CST_250: u32 = CST_249+1; +pub const CST_251: u32 = CST_250+1; +pub const CST_252: u32 = CST_251+1; +pub const CST_253: u32 = CST_252+1; +pub const CST_254: u32 = CST_253+1; +pub const CST_255: u32 = CST_254+1; +pub const CST_256: u32 = CST_255+1; +pub const CST_257: u32 = CST_256+1; +pub const CST_258: u32 = CST_257+1; +pub const CST_259: u32 = CST_258+1; +pub const CST_260: u32 = CST_259+1; +pub const CST_261: u32 = CST_260+1; +pub const CST_262: u32 = CST_261+1; +pub const CST_263: u32 = CST_262+1; +pub const CST_264: u32 = CST_263+1; +pub const CST_265: u32 = CST_264+1; +pub const CST_266: u32 = CST_265+1; +pub const CST_267: u32 = CST_266+1; +pub const CST_268: u32 = CST_267+1; +pub const CST_269: u32 = CST_268+1; +pub const CST_270: u32 = CST_269+1; +pub const CST_271: u32 = CST_270+1; +pub const CST_272: u32 = CST_271+1; +pub const CST_273: u32 = CST_272+1; +pub const CST_274: u32 = CST_273+1; +pub const CST_275: u32 = CST_274+1; +pub const CST_276: u32 = CST_275+1; +pub const CST_277: u32 = CST_276+1; +pub const CST_278: u32 = CST_277+1; +pub const CST_279: u32 = CST_278+1; +pub const CST_280: u32 = CST_279+1; +pub const CST_281: u32 = CST_280+1; +pub const CST_282: u32 = CST_281+1; +pub const CST_283: u32 = CST_282+1; +pub const CST_284: u32 = CST_283+1; +pub const CST_285: u32 = CST_284+1; +pub const CST_286: u32 = CST_285+1; +pub const CST_287: u32 = CST_286+1; +pub const CST_288: u32 = CST_287+1; +pub const CST_289: u32 = CST_288+1; +pub const CST_290: u32 = CST_289+1; +pub const CST_291: u32 = CST_290+1; +pub const CST_292: u32 = CST_291+1; +pub const CST_293: u32 = CST_292+1; +pub const CST_294: u32 = CST_293+1; +pub const CST_295: u32 = CST_294+1; +pub const CST_296: u32 = CST_295+1; +pub const CST_297: u32 = CST_296+1; +pub const CST_298: u32 = CST_297+1; +pub const CST_299: u32 = CST_298+1; +pub const CST_300: u32 = CST_299+1; +pub const CST_301: u32 = CST_300+1; +pub const CST_302: u32 = CST_301+1; +pub const CST_303: u32 = CST_302+1; +pub const CST_304: u32 = CST_303+1; +pub const CST_305: u32 = CST_304+1; +pub const CST_306: u32 = CST_305+1; +pub const CST_307: u32 = CST_306+1; +pub const CST_308: u32 = CST_307+1; +pub const CST_309: u32 = CST_308+1; +pub const CST_310: u32 = CST_309+1; +pub const CST_311: u32 = CST_310+1; +pub const CST_312: u32 = CST_311+1; +pub const CST_313: u32 = CST_312+1; +pub const CST_314: u32 = CST_313+1; +pub const CST_315: u32 = CST_314+1; +pub const CST_316: u32 = CST_315+1; +pub const CST_317: u32 = CST_316+1; +pub const CST_318: u32 = CST_317+1; +pub const CST_319: u32 = CST_318+1; +pub const CST_320: u32 = CST_319+1; +pub const CST_321: u32 = CST_320+1; +pub const CST_322: u32 = CST_321+1; +pub const CST_323: u32 = CST_322+1; +pub const CST_324: u32 = CST_323+1; +pub const CST_325: u32 = CST_324+1; +pub const CST_326: u32 = CST_325+1; +pub const CST_327: u32 = CST_326+1; +pub const CST_328: u32 = CST_327+1; +pub const CST_329: u32 = CST_328+1; +pub const CST_330: u32 = CST_329+1; +pub const CST_331: u32 = CST_330+1; +pub const CST_332: u32 = CST_331+1; +pub const CST_333: u32 = CST_332+1; +pub const CST_334: u32 = CST_333+1; +pub const CST_335: u32 = CST_334+1; +pub const CST_336: u32 = CST_335+1; +pub const CST_337: u32 = CST_336+1; +pub const CST_338: u32 = CST_337+1; +pub const CST_339: u32 = CST_338+1; +pub const CST_340: u32 = CST_339+1; +pub const CST_341: u32 = CST_340+1; +pub const CST_342: u32 = CST_341+1; +pub const CST_343: u32 = CST_342+1; +pub const CST_344: u32 = CST_343+1; +pub const CST_345: u32 = CST_344+1; +pub const CST_346: u32 = CST_345+1; +pub const CST_347: u32 = CST_346+1; +pub const CST_348: u32 = CST_347+1; +pub const CST_349: u32 = CST_348+1; +pub const CST_350: u32 = CST_349+1; + +fn main() {} diff --git a/src/test/run-pass/ctfe/deref_in_pattern.rs b/src/test/run-pass/ctfe/deref_in_pattern.rs new file mode 100644 index 0000000000000..4ccfa0338f393 --- /dev/null +++ b/src/test/run-pass/ctfe/deref_in_pattern.rs @@ -0,0 +1,20 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/25574 + +const A: [u8; 4] = *b"fooo"; + +fn main() { + match *b"xxxx" { + A => {}, + _ => {} + } +} diff --git a/src/test/run-pass/ctfe/issue-broken-mir.rs b/src/test/run-pass/ctfe/issue-broken-mir.rs new file mode 100644 index 0000000000000..6ed0c7c0d5dc4 --- /dev/null +++ b/src/test/run-pass/ctfe/issue-broken-mir.rs @@ -0,0 +1,18 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/27918 + +fn main() { + match b" " { + b"1234" => {}, + _ => {}, + } +} diff --git a/src/test/run-pass/ctfe/match-const-fn-structs.rs b/src/test/run-pass/ctfe/match-const-fn-structs.rs new file mode 100644 index 0000000000000..0bb253d1a6455 --- /dev/null +++ b/src/test/run-pass/ctfe/match-const-fn-structs.rs @@ -0,0 +1,31 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/46114 + +#![feature(const_fn)] + +#[derive(Eq, PartialEq)] +struct A { value: u32 } + +const fn new(value: u32) -> A { + A { value } +} + +const A_1: A = new(1); +const A_2: A = new(2); + +fn main() { + let a_str = match new(42) { + A_1 => "A 1", + A_2 => "A 2", + _ => "Unknown A", + }; +} diff --git a/src/test/run-pass/ctfe/non-scalar-cast.rs b/src/test/run-pass/ctfe/non-scalar-cast.rs new file mode 100644 index 0000000000000..ff4474f47c9f3 --- /dev/null +++ b/src/test/run-pass/ctfe/non-scalar-cast.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/37448 + +fn main() { + struct A; + const FOO: &A = &(A as A); + let _x = FOO; +} diff --git a/src/test/run-pass/ctfe/return-in-const-fn.rs b/src/test/run-pass/ctfe/return-in-const-fn.rs new file mode 100644 index 0000000000000..d57d3bcb49aa8 --- /dev/null +++ b/src/test/run-pass/ctfe/return-in-const-fn.rs @@ -0,0 +1,19 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/43754 + +#![feature(const_fn)] +const fn foo(x: usize) -> usize { + return x; +} +fn main() { + [0; foo(2)]; +} diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs new file mode 100644 index 0000000000000..ecc5d37663679 --- /dev/null +++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs @@ -0,0 +1,20 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/41898 + +#![feature(nonzero, const_fn)] +extern crate core; +use core::nonzero::NonZero; + +fn main() { + const FOO: NonZero = unsafe { NonZero::new_unchecked(2) }; + if let FOO = FOO {} +} diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs new file mode 100644 index 0000000000000..05e40abdc0f2f --- /dev/null +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -0,0 +1,18 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//https://github.com/rust-lang/rust/issues/31364 + +#![feature(const_fn)] +const fn a() -> usize { b() } +const fn b() -> usize { a() } +const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error + +fn main(){} diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr new file mode 100644 index 0000000000000..ce1b35aac7ecc --- /dev/null +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -0,0 +1,8 @@ +error[E0080]: constant evaluation error + --> $DIR/infinite-recursion-const-fn.rs:16:18 + | +16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error + | ^^^ miri failed: reached the configured maximum number of stack frames + +error: aborting due to previous error + From e84ffa43425193b58929878de8872b92bf979c7d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 10:16:38 +0100 Subject: [PATCH 016/115] Add InterpretInterner to StableHashingContext for AllocId serialization --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/hir/map/collector.rs | 12 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ich/hcx.rs | 47 ++-- src/librustc/ich/impls_hir.rs | 132 ++++++------ src/librustc/ich/impls_mir.rs | 94 ++++---- src/librustc/ich/impls_syntax.rs | 48 +++-- src/librustc/ich/impls_ty.rs | 200 +++++++++++------- src/librustc/lint/levels.rs | 4 +- src/librustc/macros.rs | 16 +- src/librustc/middle/borrowck.rs | 4 +- src/librustc/middle/region.rs | 4 +- src/librustc/mir/cache.rs | 4 +- src/librustc/mir/interpret/mod.rs | 2 + src/librustc/mir/mono.rs | 8 +- src/librustc/session/config.rs | 4 +- .../traits/specialize/specialization_graph.rs | 4 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/fast_reject.rs | 6 +- src/librustc/ty/layout.rs | 20 +- src/librustc/ty/mod.rs | 16 +- src/librustc/ty/trait_def.rs | 4 +- src/librustc_metadata/schema.rs | 8 +- 23 files changed, 348 insertions(+), 302 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index be6db74804b38..b1ae572cbe034 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -661,7 +661,7 @@ trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { } impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T - where T: HashStable> + fmt::Debug + where T: HashStable> + fmt::Debug { default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 0e1c66277163e..9f5e89d43caba 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -41,7 +41,7 @@ pub(super) struct NodeCollector<'a, 'hir> { dep_graph: &'a DepGraph, definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a>, + hcx: StableHashingContext<'a, 'a>, // We are collecting DepNode::HirBody hashes here so we can compute the // crate hash from then later on. @@ -52,7 +52,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn root(krate: &'hir Crate, dep_graph: &'a DepGraph, definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a>) + hcx: StableHashingContext<'a, 'a>) -> NodeCollector<'a, 'hir> { let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX); @@ -235,7 +235,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { self.parent_node = parent_node; } - fn with_dep_node_owner>, + fn with_dep_node_owner>, F: FnOnce(&mut Self)>(&mut self, dep_node_owner: DefIndex, item_like: &T, @@ -513,11 +513,11 @@ struct HirItemLike { hash_bodies: bool, } -impl<'hir, T> HashStable> for HirItemLike - where T: HashStable> +impl<'a, 'hir, T> HashStable> for HirItemLike + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'hir>, + hcx: &mut StableHashingContext<'a, 'hir>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| { self.item_like.hash_stable(hcx, hasher); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5feea602d2814..59e0f20119cee 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1053,7 +1053,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, definitions: &'hir Definitions) -> Map<'hir> { let (map, crate_hash) = { - let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); + let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore, None); let mut collector = NodeCollector::root(&forest.krate, &forest.dep_graph, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 67f6c0c2e49e8..92103a3e1ffd4 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -14,7 +14,7 @@ use hir::map::DefPathHash; use hir::map::definitions::Definitions; use ich::{self, CachingCodemapView, Fingerprint}; use middle::cstore::CrateStore; -use ty::{TyCtxt, fast_reject}; +use ty::{TyCtxt, fast_reject, InterpretInterner}; use session::Session; use std::cmp::Ord; @@ -46,7 +46,7 @@ pub fn compute_ignored_attr_names() -> FxHashSet { /// a reference to the TyCtxt) and it holds a few caches for speeding up various /// things (e.g. each DefId/DefPath is only hashed once). #[derive(Clone)] -pub struct StableHashingContext<'gcx> { +pub struct StableHashingContext<'a, 'gcx: 'a> { sess: &'gcx Session, definitions: &'gcx Definitions, cstore: &'gcx CrateStore, @@ -54,6 +54,7 @@ pub struct StableHashingContext<'gcx> { hash_spans: bool, hash_bodies: bool, node_id_hashing_mode: NodeIdHashingMode, + pub interpret_interner: Option<&'a RefCell>>, // Very often, we are hashing something that does not need the // CachingCodemapView, so we initialize it lazily. @@ -81,14 +82,15 @@ impl<'gcx> BodyResolver<'gcx> { } } -impl<'gcx> StableHashingContext<'gcx> { +impl<'a, 'gcx> StableHashingContext<'a, 'gcx> { // The `krate` here is only used for mapping BodyIds to Bodies. // Don't use it for anything else or you'll run the risk of // leaking data out of the tracking system. pub fn new(sess: &'gcx Session, krate: &'gcx hir::Crate, definitions: &'gcx Definitions, - cstore: &'gcx CrateStore) + cstore: &'gcx CrateStore, + interpret_interner: Option<&'a RefCell>>) -> Self { let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans; @@ -102,6 +104,7 @@ impl<'gcx> StableHashingContext<'gcx> { hash_spans: hash_spans_initial, hash_bodies: true, node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + interpret_interner, } } @@ -193,27 +196,27 @@ impl<'gcx> StableHashingContext<'gcx> { } impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> { - type ContextType = StableHashingContext<'gcx>; + type ContextType = StableHashingContext<'a, 'gcx>; fn create_stable_hashing_context(&self) -> Self::ContextType { (*self).create_stable_hashing_context() } } -impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> { - type ContextType = StableHashingContext<'gcx>; +impl<'a, 'gcx> StableHashingContextProvider for StableHashingContext<'a, 'gcx> { + type ContextType = StableHashingContext<'a, 'gcx>; fn create_stable_hashing_context(&self) -> Self::ContextType { self.clone() } } -impl<'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'gcx> { +impl<'a, 'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'a, 'gcx> { } -impl<'gcx> HashStable> for hir::BodyId { +impl<'a, 'gcx> HashStable> for hir::BodyId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { if hcx.hash_bodies() { hcx.body_resolver.body(*self).hash_stable(hcx, hasher); @@ -221,10 +224,10 @@ impl<'gcx> HashStable> for hir::BodyId { } } -impl<'gcx> HashStable> for hir::HirId { +impl<'a, 'gcx> HashStable> for hir::HirId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { @@ -243,21 +246,21 @@ impl<'gcx> HashStable> for hir::HirId { } } -impl<'gcx> ToStableHashKey> for hir::HirId { +impl<'a, 'gcx> ToStableHashKey> for hir::HirId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'gcx>) + hcx: &StableHashingContext<'a, 'gcx>) -> (DefPathHash, hir::ItemLocalId) { let def_path_hash = hcx.local_def_path_hash(self.owner); (def_path_hash, self.local_id) } } -impl<'gcx> HashStable> for ast::NodeId { +impl<'a, 'gcx> HashStable> for ast::NodeId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { @@ -270,18 +273,18 @@ impl<'gcx> HashStable> for ast::NodeId { } } -impl<'gcx> ToStableHashKey> for ast::NodeId { +impl<'a, 'gcx> ToStableHashKey> for ast::NodeId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'gcx>) + hcx: &StableHashingContext<'a, 'gcx>) -> (DefPathHash, hir::ItemLocalId) { hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx) } } -impl<'gcx> HashStable> for Span { +impl<'a, 'gcx> HashStable> for Span { // Hash a span in a stable way. We can't directly hash the span's BytePos // fields (that would be similar to hashing pointers, since those are just @@ -293,7 +296,7 @@ impl<'gcx> HashStable> for Span { // Also, hashing filenames is expensive so we avoid doing it twice when the // span starts and ends in the same file, which is almost always the case. fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; @@ -373,8 +376,8 @@ impl<'gcx> HashStable> for Span { } } -pub fn hash_stable_trait_impls<'gcx, W, R>( - hcx: &mut StableHashingContext<'gcx>, +pub fn hash_stable_trait_impls<'a, 'gcx, W, R>( + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher, blanket_impls: &Vec, non_blanket_impls: &HashMap, R>) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 7dca96f94e655..0eacb6d7b9920 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -20,46 +20,46 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, use std::mem; use syntax::ast; -impl<'gcx> HashStable> for DefId { +impl<'a, 'gcx> HashStable> for DefId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'gcx> ToStableHashKey> for DefId { +impl<'a, 'gcx> ToStableHashKey> for DefId { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { hcx.def_path_hash(*self) } } -impl<'gcx> HashStable> for LocalDefId { +impl<'a, 'gcx> HashStable> for LocalDefId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); } } -impl<'gcx> ToStableHashKey> for LocalDefId { +impl<'a, 'gcx> ToStableHashKey> for LocalDefId { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { hcx.def_path_hash(self.to_def_id()) } } -impl<'gcx> HashStable> for CrateNum { +impl<'a, 'gcx> HashStable> for CrateNum { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.def_path_hash(DefId { krate: *self, @@ -68,11 +68,11 @@ impl<'gcx> HashStable> for CrateNum { } } -impl<'gcx> ToStableHashKey> for CrateNum { +impl<'a, 'gcx> ToStableHashKey> for CrateNum { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; def_id.to_stable_hash_key(hcx) } @@ -80,13 +80,13 @@ impl<'gcx> ToStableHashKey> for CrateNum { impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); -impl<'gcx> ToStableHashKey> +impl<'a, 'gcx> ToStableHashKey> for hir::ItemLocalId { type KeyType = hir::ItemLocalId; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'gcx>) + _: &StableHashingContext<'a, 'gcx>) -> hir::ItemLocalId { *self } @@ -99,9 +99,9 @@ for hir::ItemLocalId { // want to pick up on a reference changing its target, so we hash the NodeIds // in "DefPath Mode". -impl<'gcx> HashStable> for hir::ItemId { +impl<'a, 'gcx> HashStable> for hir::ItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::ItemId { id @@ -113,9 +113,9 @@ impl<'gcx> HashStable> for hir::ItemId { } } -impl<'gcx> HashStable> for hir::TraitItemId { +impl<'a, 'gcx> HashStable> for hir::TraitItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::TraitItemId { node_id @@ -127,9 +127,9 @@ impl<'gcx> HashStable> for hir::TraitItemId { } } -impl<'gcx> HashStable> for hir::ImplItemId { +impl<'a, 'gcx> HashStable> for hir::ImplItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::ImplItemId { node_id @@ -270,9 +270,9 @@ impl_stable_hash_for!(struct hir::TypeBinding { span }); -impl<'gcx> HashStable> for hir::Ty { +impl<'a, 'gcx> HashStable> for hir::Ty { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Ty { @@ -338,9 +338,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy { Return(t) }); -impl<'gcx> HashStable> for hir::TraitRef { +impl<'a, 'gcx> HashStable> for hir::TraitRef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::TraitRef { ref path, @@ -375,9 +375,9 @@ impl_stable_hash_for!(struct hir::MacroDef { }); -impl<'gcx> HashStable> for hir::Block { +impl<'a, 'gcx> HashStable> for hir::Block { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::Block { ref stmts, @@ -399,9 +399,9 @@ impl<'gcx> HashStable> for hir::Block { } } -impl<'gcx> HashStable> for hir::Pat { +impl<'a, 'gcx> HashStable> for hir::Pat { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::Pat { id: _, @@ -526,9 +526,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource { UserProvided }); -impl<'gcx> HashStable> for hir::Expr { +impl<'a, 'gcx> HashStable> for hir::Expr { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { @@ -590,9 +590,9 @@ impl_stable_hash_for!(enum hir::LoopSource { ForLoop }); -impl<'gcx> HashStable> for hir::MatchSource { +impl<'a, 'gcx> HashStable> for hir::MatchSource { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use hir::MatchSource; @@ -646,9 +646,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget { Loop(loop_id_result) }); -impl<'gcx> HashStable> for ast::Ident { +impl<'a, 'gcx> HashStable> for ast::Ident { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ast::Ident { ref name, @@ -659,9 +659,9 @@ impl<'gcx> HashStable> for ast::Ident { } } -impl<'gcx> HashStable> for hir::TraitItem { +impl<'a, 'gcx> HashStable> for hir::TraitItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::TraitItem { id: _, @@ -694,9 +694,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind { Type(bounds, rhs) }); -impl<'gcx> HashStable> for hir::ImplItem { +impl<'a, 'gcx> HashStable> for hir::ImplItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::ImplItem { id: _, @@ -728,9 +728,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind { Type(t) }); -impl<'gcx> HashStable> for hir::Visibility { +impl<'a, 'gcx> HashStable> for hir::Visibility { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -749,9 +749,9 @@ impl<'gcx> HashStable> for hir::Visibility { } } -impl<'gcx> HashStable> for hir::Defaultness { +impl<'a, 'gcx> HashStable> for hir::Defaultness { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -770,9 +770,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity { Negative }); -impl<'gcx> HashStable> for hir::Mod { +impl<'a, 'gcx> HashStable> for hir::Mod { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::Mod { inner, @@ -825,9 +825,9 @@ impl_stable_hash_for!(enum hir::VariantData { Unit(id) }); -impl<'gcx> HashStable> for hir::Item { +impl<'a, 'gcx> HashStable> for hir::Item { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::Item { name, @@ -884,10 +884,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef { defaultness }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for hir::AssociatedItemKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -929,9 +929,9 @@ impl_stable_hash_for!(struct hir::Arg { hir_id }); -impl<'gcx> HashStable> for hir::Body { +impl<'a, 'gcx> HashStable> for hir::Body { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::Body { ref arguments, @@ -947,12 +947,12 @@ impl<'gcx> HashStable> for hir::Body { } } -impl<'gcx> ToStableHashKey> for hir::BodyId { +impl<'a, 'gcx> ToStableHashKey> for hir::BodyId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'gcx>) + hcx: &StableHashingContext<'a, 'gcx>) -> (DefPathHash, hir::ItemLocalId) { let hir::BodyId { node_id } = *self; node_id.to_stable_hash_key(hcx) @@ -965,9 +965,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); -impl<'gcx> HashStable> for hir::GlobalAsm { +impl<'a, 'gcx> HashStable> for hir::GlobalAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::GlobalAsm { asm, @@ -978,9 +978,9 @@ impl<'gcx> HashStable> for hir::GlobalAsm { } } -impl<'gcx> HashStable> for hir::InlineAsm { +impl<'a, 'gcx> HashStable> for hir::InlineAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let hir::InlineAsm { asm, @@ -1061,22 +1061,22 @@ impl_stable_hash_for!(enum hir::Constness { NotConst }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for hir::def_id::DefIndex { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.local_def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'gcx> ToStableHashKey> +impl<'a, 'gcx> ToStableHashKey> for hir::def_id::DefIndex { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { hcx.local_def_path_hash(*self) } } @@ -1089,10 +1089,10 @@ impl_stable_hash_for!(struct hir::def::Export { is_import }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::lang_items::LangItem { fn hash_stable(&self, - _: &mut StableHashingContext<'gcx>, + _: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } @@ -1103,10 +1103,10 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems { missing }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for hir::TraitCandidate { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let hir::TraitCandidate { @@ -1120,11 +1120,11 @@ for hir::TraitCandidate { } } -impl<'gcx> ToStableHashKey> for hir::TraitCandidate { +impl<'a, 'gcx> ToStableHashKey> for hir::TraitCandidate { type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>); fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'gcx>) + hcx: &StableHashingContext<'a, 'gcx>) -> Self::KeyType { let hir::TraitCandidate { def_id, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 7e36ea276c1bf..7daf82d09ed5a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -36,11 +36,11 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::UnsafetyViolationKind { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -61,12 +61,12 @@ impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info }); -impl<'gcx, T> HashStable> for mir::ClearCrossCrate - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for mir::ClearCrossCrate + where T: HashStable> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -78,61 +78,61 @@ impl<'gcx, T> HashStable> for mir::ClearCrossCrate } } -impl<'gcx> HashStable> for mir::Local { +impl<'a, 'gcx> HashStable> for mir::Local { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> for mir::BasicBlock { +impl<'a, 'gcx> HashStable> for mir::BasicBlock { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> for mir::Field { +impl<'a, 'gcx> HashStable> for mir::Field { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::VisibilityScope { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> for mir::Promoted { +impl<'a, 'gcx> HashStable> for mir::Promoted { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::TerminatorKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -205,10 +205,10 @@ for mir::TerminatorKind<'gcx> { } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::AssertMessage<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -228,10 +228,10 @@ for mir::AssertMessage<'gcx> { impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::StatementKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -265,12 +265,12 @@ for mir::StatementKind<'gcx> { } } -impl<'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for mir::ValidationOperand<'gcx, T> - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { self.place.hash_stable(hcx, hasher); @@ -282,9 +282,9 @@ impl<'gcx, T> HashStable> impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) }); -impl<'gcx> HashStable> for mir::Place<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -301,14 +301,14 @@ impl<'gcx> HashStable> for mir::Place<'gcx> { } } -impl<'gcx, B, V, T> HashStable> +impl<'a, 'gcx, B, V, T> HashStable> for mir::Projection<'gcx, B, V, T> - where B: HashStable>, - V: HashStable>, - T: HashStable> + where B: HashStable>, + V: HashStable>, + T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let mir::Projection { ref base, @@ -320,13 +320,13 @@ for mir::Projection<'gcx, B, V, T> } } -impl<'gcx, V, T> HashStable> +impl<'a, 'gcx, V, T> HashStable> for mir::ProjectionElem<'gcx, V, T> - where V: HashStable>, - T: HashStable> + where V: HashStable>, + T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -360,9 +360,9 @@ impl_stable_hash_for!(struct mir::VisibilityScopeInfo { lint_root, safety }); -impl<'gcx> HashStable> for mir::Safety { +impl<'a, 'gcx> HashStable> for mir::Safety { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -377,9 +377,9 @@ impl<'gcx> HashStable> for mir::Safety { } } -impl<'gcx> HashStable> for mir::Operand<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Operand<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -397,9 +397,9 @@ impl<'gcx> HashStable> for mir::Operand<'gcx> { } } -impl<'gcx> HashStable> for mir::Rvalue<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Rvalue<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -457,10 +457,10 @@ impl_stable_hash_for!(enum mir::CastKind { Unsize }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::AggregateKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -519,9 +519,9 @@ impl_stable_hash_for!(enum mir::NullOp { impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); -impl<'gcx> HashStable> for mir::Literal<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Literal<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -548,9 +548,9 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> { blame_span }); -impl<'gcx> HashStable> for mir::ClosureOutlivesSubject<'gcx> { +impl<'a, 'gcx> HashStable> for mir::ClosureOutlivesSubject<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c31a5c9d86d77..34dbf15b31f98 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -28,42 +28,42 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use rustc_data_structures::accumulate_vec::AccumulateVec; -impl<'gcx> HashStable> for InternedString { +impl<'a, 'gcx> HashStable> for InternedString { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let s: &str = &**self; s.hash_stable(hcx, hasher); } } -impl<'gcx> ToStableHashKey> for InternedString { +impl<'a, 'gcx> ToStableHashKey> for InternedString { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'gcx>) + _: &StableHashingContext<'a, 'gcx>) -> InternedString { self.clone() } } -impl<'gcx> HashStable> for ast::Name { +impl<'a, 'gcx> HashStable> for ast::Name { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } } -impl<'gcx> ToStableHashKey> for ast::Name { +impl<'a, 'gcx> ToStableHashKey> for ast::Name { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'gcx>) + _: &StableHashingContext<'a, 'gcx>) -> InternedString { self.as_str() } @@ -110,10 +110,10 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { rustc_const_unstable }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::syntax::attr::StabilityLevel { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -165,9 +165,9 @@ impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, ident }); impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); -impl<'gcx> HashStable> for [ast::Attribute] { +impl<'a, 'gcx> HashStable> for [ast::Attribute] { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { if self.len() == 0 { self.len().hash_stable(hcx, hasher); @@ -190,9 +190,9 @@ impl<'gcx> HashStable> for [ast::Attribute] { } } -impl<'gcx> HashStable> for ast::Attribute { +impl<'a, 'gcx> HashStable> for ast::Attribute { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); @@ -219,10 +219,10 @@ impl<'gcx> HashStable> for ast::Attribute { } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for tokenstream::TokenTree { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -241,10 +241,10 @@ for tokenstream::TokenTree { } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for tokenstream::TokenStream { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); @@ -252,9 +252,11 @@ for tokenstream::TokenStream { } } -fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token, - hcx: &mut StableHashingContext<'gcx>, - hasher: &mut StableHasher) { +fn hash_token<'a, 'gcx, W: StableHasherResult>( + token: &token::Token, + hcx: &mut StableHashingContext<'a, 'gcx>, + hasher: &mut StableHasher, +) { mem::discriminant(token).hash_stable(hcx, hasher); match *token { token::Token::Eq | @@ -382,9 +384,9 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName { Custom(s) }); -impl<'gcx> HashStable> for FileMap { +impl<'a, 'gcx> HashStable> for FileMap { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let FileMap { name: _, // We hash the smaller name_hash instead of this diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index b04495f95cfe1..d95e0c8b99d61 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -23,11 +23,11 @@ use traits; use ty; use mir; -impl<'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for &'gcx ty::Slice - where T: HashStable> { + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = @@ -52,20 +52,20 @@ for &'gcx ty::Slice } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::subst::Kind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { self.as_type().hash_stable(hcx, hasher); self.as_region().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::RegionKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -109,20 +109,20 @@ for ty::RegionKind { } } -impl<'gcx> HashStable> for ty::RegionVid { +impl<'a, 'gcx> HashStable> for ty::RegionVid { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::adjustment::AutoBorrow<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -137,10 +137,10 @@ for ty::adjustment::AutoBorrow<'gcx> { } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::adjustment::Adjust<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -172,10 +172,10 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::UpvarCapture<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -199,11 +199,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> { abi }); -impl<'gcx, T> HashStable> for ty::Binder - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for ty::Binder + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::Binder(ref inner) = *self; inner.hash_stable(hcx, hasher); @@ -223,13 +223,13 @@ impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); -impl<'gcx, A, B> HashStable> +impl<'a, 'gcx, A, B> HashStable> for ty::OutlivesPredicate - where A: HashStable>, - B: HashStable>, + where A: HashStable>, + B: HashStable>, { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::OutlivesPredicate(ref a, ref b) = *self; a.hash_stable(hcx, hasher); @@ -241,9 +241,9 @@ impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty } impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id }); -impl<'gcx> HashStable> for ty::Predicate<'gcx> { +impl<'a, 'gcx> HashStable> for ty::Predicate<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -284,9 +284,9 @@ impl<'gcx> HashStable> for ty::Predicate<'gcx> { } } -impl<'gcx> HashStable> for ty::AdtFlags { +impl<'a, 'gcx> HashStable> for ty::AdtFlags { fn hash_stable(&self, - _: &mut StableHashingContext<'gcx>, + _: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { std_hash::Hash::hash(self, hasher); } @@ -311,10 +311,10 @@ impl_stable_hash_for!(struct ty::FieldDef { vis }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::const_val::ConstVal<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use middle::const_val::ConstVal::*; @@ -347,7 +347,45 @@ impl_stable_hash_for!(struct mir::interpret::MemoryPointer { offset }); -impl_stable_hash_for!(tuple_struct mir::interpret::AllocId{id}); +impl<'a, 'gcx> HashStable> for mir::interpret::AllocId { + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a, 'gcx>, + hasher: &mut StableHasher, + ) { + let interner = hcx + .interpret_interner + .expect("cannot hash AllocIds during HIR lowering") + .borrow(); + if let Some(alloc) = interner.get_alloc(*self) { + false.hash_stable(hcx, hasher); + // FIXME: recursive allocations + alloc.hash_stable(hcx, hasher); + } else if let Some(inst) = interner.get_fn(*self) { + true.hash_stable(hcx, hasher); + inst.hash_stable(hcx, hasher); + } else { + bug!("no allocation for {}", self); + } + } +} + +impl<'a, 'gcx> HashStable> for mir::interpret::Allocation { + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a, 'gcx>, + hasher: &mut StableHasher, + ) { + self.bytes.hash_stable(hcx, hasher); + for reloc in self.relocations.iter() { + reloc.hash_stable(hcx, hasher); + } + self.undef_mask.hash_stable(hcx, hasher); + self.align.hash_stable(hcx, hasher); + self.mutable.hash_stable(hcx, hasher); + } +} + impl_stable_hash_for!(struct mir::interpret::Pointer{primval}); impl_stable_hash_for!(enum mir::interpret::PrimVal { @@ -366,10 +404,10 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> { kind }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::const_val::ErrKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use middle::const_val::ErrKind::*; @@ -420,10 +458,10 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { predicates }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::mir::interpret::EvalError<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use mir::interpret::EvalErrorKind::*; @@ -600,9 +638,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { Struct(index) }); -impl<'gcx> HashStable> for ty::Generics { +impl<'a, 'gcx> HashStable> for ty::Generics { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::Generics { parent, @@ -628,10 +666,10 @@ impl<'gcx> HashStable> for ty::Generics { } } -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::RegionParameterDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::RegionParameterDef { name, @@ -657,12 +695,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef { synthetic }); -impl<'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for ::middle::resolve_lifetime::Set1 - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use middle::resolve_lifetime::Set1; @@ -713,11 +751,11 @@ impl_stable_hash_for!(enum ty::cast::CastKind { impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx }); impl_stable_hash_for!(struct ::middle::region::Scope { id, code }); -impl<'gcx> ToStableHashKey> for region::Scope { +impl<'a, 'gcx> ToStableHashKey> for region::Scope { type KeyType = region::Scope; #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'gcx>) -> region::Scope { + fn to_stable_hash_key(&self, _: &StableHashingContext<'a, 'gcx>) -> region::Scope { *self } } @@ -743,11 +781,11 @@ impl_stable_hash_for!(enum ty::BoundRegion { BrEnv }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::TypeVariants<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use ty::TypeVariants::*; @@ -844,11 +882,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { mutbl }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::ExistentialPredicate<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -881,9 +919,9 @@ impl_stable_hash_for!(struct ty::Instance<'tcx> { substs }); -impl<'gcx> HashStable> for ty::InstanceDef<'gcx> { +impl<'a, 'gcx> HashStable> for ty::InstanceDef<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -917,9 +955,9 @@ impl<'gcx> HashStable> for ty::InstanceDef<'gcx> { } } -impl<'gcx> HashStable> for ty::TraitDef { +impl<'a, 'gcx> HashStable> for ty::TraitDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::TraitDef { // We already have the def_path_hash below, no need to hash it twice @@ -947,9 +985,9 @@ impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> { }); -impl<'gcx> HashStable> for ty::CrateVariancesMap { +impl<'a, 'gcx> HashStable> for ty::CrateVariancesMap { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::CrateVariancesMap { ref variances, @@ -983,12 +1021,12 @@ impl_stable_hash_for!(enum ty::AssociatedItemContainer { }); -impl<'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for ty::steal::Steal - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { self.borrow().hash_stable(hcx, hasher); } @@ -1010,10 +1048,10 @@ impl_stable_hash_for!(enum ::middle::privacy::AccessLevel { Public }); -impl<'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::privacy::AccessLevels { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let ::middle::privacy::AccessLevels { @@ -1040,10 +1078,10 @@ impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet { reachable_set }); -impl<'gcx, N> HashStable> -for traits::Vtable<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::Vtable<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use traits::Vtable::*; @@ -1062,10 +1100,10 @@ for traits::Vtable<'gcx, N> where N: HashStable> { } } -impl<'gcx, N> HashStable> -for traits::VtableImplData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableImplData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableImplData { impl_def_id, @@ -1078,10 +1116,10 @@ for traits::VtableImplData<'gcx, N> where N: HashStable HashStable> -for traits::VtableAutoImplData where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableAutoImplData where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableAutoImplData { trait_def_id, @@ -1092,10 +1130,10 @@ for traits::VtableAutoImplData where N: HashStable } } -impl<'gcx, N> HashStable> -for traits::VtableObjectData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableObjectData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableObjectData { upcast_trait_ref, @@ -1108,10 +1146,10 @@ for traits::VtableObjectData<'gcx, N> where N: HashStable HashStable> -for traits::VtableBuiltinData where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableBuiltinData where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableBuiltinData { ref nested, @@ -1120,10 +1158,10 @@ for traits::VtableBuiltinData where N: HashStable> } } -impl<'gcx, N> HashStable> -for traits::VtableClosureData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableClosureData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableClosureData { closure_def_id, @@ -1136,10 +1174,10 @@ for traits::VtableClosureData<'gcx, N> where N: HashStable HashStable> -for traits::VtableFnPointerData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableFnPointerData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableFnPointerData { fn_ty, @@ -1150,10 +1188,10 @@ for traits::VtableFnPointerData<'gcx, N> where N: HashStable HashStable> -for traits::VtableGeneratorData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableGeneratorData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let traits::VtableGeneratorData { closure_def_id, diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 4bc37747f2a76..16bfa5dae96c9 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -391,10 +391,10 @@ impl LintLevelMap { } } -impl<'gcx> HashStable> for LintLevelMap { +impl<'a, 'gcx> HashStable> for LintLevelMap { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let LintLevelMap { ref sets, diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index f0285d6a93782..c18e585f79553 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field { #[macro_export] macro_rules! impl_stable_hash_for { (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { - impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $enum_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { use $enum_name::*; ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); @@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for { } }; (struct $struct_name:path { $($field:ident),* }) => { - impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name { $(ref $field),* @@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for { } }; (tuple_struct $struct_name:path { $($field:ident),* }) => { - impl<'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'tcx>> for $struct_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name ( $(ref $field),* @@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for { macro_rules! impl_stable_hash_for_spanned { ($T:path) => ( - impl<'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'tcx>, + hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { self.node.hash_stable(hcx, hasher); self.span.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs index 380f79361e27f..138ef03b5a0db 100644 --- a/src/librustc/middle/borrowck.rs +++ b/src/librustc/middle/borrowck.rs @@ -20,9 +20,9 @@ pub struct BorrowCheckResult { pub used_mut_nodes: FxHashSet, } -impl<'gcx> HashStable> for BorrowCheckResult { +impl<'a, 'gcx> HashStable> for BorrowCheckResult { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let BorrowCheckResult { ref used_mut_nodes, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index e5619f469e774..cf3e5cd7807a3 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1488,9 +1488,9 @@ pub fn provide(providers: &mut Providers) { }; } -impl<'gcx> HashStable> for ScopeTree { +impl<'a, 'gcx> HashStable> for ScopeTree { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ScopeTree { root_body, diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index efc2f647cfdf5..5c25703df8661 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -35,9 +35,9 @@ impl serialize::Decodable for Cache { } } -impl<'gcx> HashStable> for Cache { +impl<'a, 'gcx> HashStable> for Cache { fn hash_stable(&self, - _: &mut StableHashingContext<'gcx>, + _: &mut StableHashingContext<'a, 'gcx>, _: &mut StableHasher) { // do nothing } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index a55dae33964ab..a41ad94f00a0b 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -200,6 +200,8 @@ pub struct UndefMask { len: u64, } +impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len}); + impl UndefMask { pub fn new(size: u64) -> Self { let mut m = UndefMask { diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 49e5c0dc21f9e..07a79417e35bd 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -40,9 +40,9 @@ impl<'tcx> MonoItem<'tcx> { } } -impl<'tcx> HashStable> for MonoItem<'tcx> { +impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'tcx>, + hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { ::std::mem::discriminant(self).hash_stable(hcx, hasher); @@ -168,9 +168,9 @@ impl<'tcx> CodegenUnit<'tcx> { } } -impl<'tcx> HashStable> for CodegenUnit<'tcx> { +impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'tcx>, + hcx: &mut StableHashingContext<'a, 'tcx>, hasher: &mut StableHasher) { let CodegenUnit { ref items, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c56575f432d1e..9ead81821847b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -123,10 +123,10 @@ impl_stable_hash_for!(enum self::OutputType { DepInfo }); -impl<'tcx> ToStableHashKey> for OutputType { +impl<'a, 'tcx> ToStableHashKey> for OutputType { type KeyType = OutputType; #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'tcx>) -> Self::KeyType { + fn to_stable_hash_key(&self, _: &StableHashingContext<'a, 'tcx>) -> Self::KeyType { *self } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index a10169e13e60a..f677f851d1d20 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -391,9 +391,9 @@ pub fn ancestors(tcx: TyCtxt, } } -impl<'gcx> HashStable> for Children { +impl<'a, 'gcx> HashStable> for Children { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let Children { ref nonblanket_impls, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a7e5771934723..bb235f0c800dc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -675,9 +675,9 @@ impl<'tcx> TypeckTables<'tcx> { } } -impl<'gcx> HashStable> for TypeckTables<'gcx> { +impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::TypeckTables { local_id_root, @@ -1361,13 +1361,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.cstore.crate_data_as_rc_any(cnum) } - pub fn create_stable_hashing_context(self) -> StableHashingContext<'gcx> { + pub fn create_stable_hashing_context(self) -> StableHashingContext<'a, 'gcx> { let krate = self.dep_graph.with_ignore(|| self.gcx.hir.krate()); StableHashingContext::new(self.sess, krate, self.hir.definitions(), - self.cstore) + self.cstore, + Some(&self.interpret_interner)) } // This method makes sure that we have a DepNode and a Fingerprint for diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 97c259e6bf383..2a2ee6d0f1c56 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -154,12 +154,12 @@ impl SimplifiedTypeGen { } } -impl<'gcx, D> HashStable> for SimplifiedTypeGen +impl<'a, 'gcx, D> HashStable> for SimplifiedTypeGen where D: Copy + Debug + Ord + Eq + Hash + - HashStable>, + HashStable>, { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 9e110d2c74cc8..262ce9d5afd2f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2369,9 +2369,9 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } -impl<'gcx> HashStable> for Variants { +impl<'a, 'gcx> HashStable> for Variants { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use ty::layout::Variants::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2405,9 +2405,9 @@ impl<'gcx> HashStable> for Variants { } } -impl<'gcx> HashStable> for FieldPlacement { +impl<'a, 'gcx> HashStable> for FieldPlacement { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use ty::layout::FieldPlacement::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2428,9 +2428,9 @@ impl<'gcx> HashStable> for FieldPlacement { } } -impl<'gcx> HashStable> for Abi { +impl<'a, 'gcx> HashStable> for Abi { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use ty::layout::Abi::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2455,9 +2455,9 @@ impl<'gcx> HashStable> for Abi { } } -impl<'gcx> HashStable> for Scalar { +impl<'a, 'gcx> HashStable> for Scalar { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; value.hash_stable(hcx, hasher); @@ -2498,10 +2498,10 @@ impl_stable_hash_for!(struct ::ty::layout::Size { raw }); -impl<'gcx> HashStable> for LayoutError<'gcx> +impl<'a, 'gcx> HashStable> for LayoutError<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { use ty::layout::LayoutError::*; mem::discriminant(self).hash_stable(hcx, hasher); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 332fef5bbb0e6..a95d053ab0735 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -81,7 +81,7 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local}; -pub use self::context::{Lift, TypeckTables}; +pub use self::context::{Lift, TypeckTables, InterpretInterner}; pub use self::instance::{Instance, InstanceDef}; @@ -544,9 +544,9 @@ impl<'tcx> TyS<'tcx> { } } -impl<'gcx> HashStable> for ty::TyS<'gcx> { +impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ty::TyS { ref sty, @@ -1395,11 +1395,11 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { } } -impl<'gcx, T> HashStable> for ParamEnvAnd<'gcx, T> - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for ParamEnvAnd<'gcx, T> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let ParamEnvAnd { ref param_env, @@ -1500,9 +1500,9 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} -impl<'gcx> HashStable> for AdtDef { +impl<'a, 'gcx> HashStable> for AdtDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 0fbf9f1bd587b..a44f7ff4fd98f 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -186,9 +186,9 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -impl<'gcx> HashStable> for TraitImpls { +impl<'a, 'gcx> HashStable> for TraitImpls { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let TraitImpls { ref blanket_impls, diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index c542f65dcecf3..e3e486ffce0f8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -225,9 +225,9 @@ pub struct TraitImpls { pub impls: LazySeq, } -impl<'gcx> HashStable> for TraitImpls { +impl<'a, 'gcx> HashStable> for TraitImpls { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { let TraitImpls { trait_id: (krate, def_index), @@ -308,9 +308,9 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } -impl<'gcx> HashStable> for EntryKind<'gcx> { +impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a, 'gcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { From 5de5a61a43469d620dd0f092ffe91f3a0a9e2f36 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 12:25:08 +0100 Subject: [PATCH 017/115] Update rustdoc --- src/librustdoc/clean/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b2d41a374fd87..8c9de3690f4b0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -32,6 +32,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; +use rustc::mir::interpret::GlobalId; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::ty::subst::Substs; From 1fd56de9c8e50ec6b0e400f45610068e3df7e3fe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 13:25:41 +0100 Subject: [PATCH 018/115] Update to master --- src/librustc/ich/impls_ty.rs | 12 ++-- src/librustc_trans/mir/analyze.rs | 2 +- src/librustc_trans/mir/block.rs | 2 +- src/librustc_trans/mir/constant.rs | 100 ++++++++++++++--------------- src/librustc_trans/mir/operand.rs | 24 +++---- 5 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d95e0c8b99d61..c2bda9f45a0e7 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -357,12 +357,16 @@ impl<'a, 'gcx> HashStable> for mir::interpret::Al .interpret_interner .expect("cannot hash AllocIds during HIR lowering") .borrow(); - if let Some(alloc) = interner.get_alloc(*self) { - false.hash_stable(hcx, hasher); - // FIXME: recursive allocations + if let Some(def_id) = interner.get_corresponding_static_def_id(*self) { + 0.hash_stable(hcx, hasher); + // statics are unique via their DefId + def_id.hash_stable(hcx, hasher); + } else if let Some(alloc) = interner.get_alloc(*self) { + // not a static, can't be recursive, hash the allocation + 1.hash_stable(hcx, hasher); alloc.hash_stable(hcx, hasher); } else if let Some(inst) = interner.get_fn(*self) { - true.hash_stable(hcx, hasher); + 2.hash_stable(hcx, hasher); inst.hash_stable(hcx, hasher); } else { bug!("no allocation for {}", self); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index c585c9044db7c..c7f8d1a69c8f4 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -128,7 +128,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { _ => None, }; if let Some((def_id, args)) = check { - if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() { + if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() { // box_free(x) shares with `drop x` the property that it // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 040cef6200f45..d0121ebe1e011 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); - let switch_llty = bcx.ccx.layout_of(switch_ty).immediate_llvm_type(bcx.ccx); + let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx); for (&value, target) in values.iter().zip(targets) { let llval = C_uint_big(switch_llty, value); let llbb = llblock(self, *target); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 5050628b024db..be5cb311b9cc2 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -29,7 +29,7 @@ use type_of::LayoutLlvmExt; use type_::Type; use super::super::callee; -use super::MirContext; +use super::FunctionCx; fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { match t.sty { @@ -135,15 +135,15 @@ pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn primval_to_llvm(ccx: &CrateContext, +pub fn primval_to_llvm(cx: &CodegenCx, cv: PrimVal, scalar: &Scalar, llty: Type) -> ValueRef { - let bits = if scalar.is_bool() { 1 } else { scalar.value.size(ccx).bits() }; + let bits = if scalar.is_bool() { 1 } else { scalar.value.size(cx).bits() }; match cv { - PrimVal::Undef => C_undef(Type::ix(ccx, bits)), + PrimVal::Undef => C_undef(Type::ix(cx, bits)), PrimVal::Bytes(b) => { - let llval = C_uint_big(Type::ix(ccx, bits), b); + let llval = C_uint_big(Type::ix(cx, bits), b); if scalar.value == layout::Pointer { unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) } } else { @@ -151,28 +151,28 @@ pub fn primval_to_llvm(ccx: &CrateContext, } }, PrimVal::Ptr(ptr) => { - let interpret_interner = ccx.tcx().interpret_interner.borrow(); + let interpret_interner = cx.tcx.interpret_interner.borrow(); if let Some(fn_instance) = interpret_interner.get_fn(ptr.alloc_id) { - callee::get_fn(ccx, fn_instance) + callee::get_fn(cx, fn_instance) } else { let static_ = interpret_interner.get_corresponding_static_def_id(ptr.alloc_id); let base_addr = if let Some(def_id) = static_ { - assert!(ccx.tcx().is_static(def_id).is_some()); - consts::get_static(ccx, def_id) + assert!(cx.tcx.is_static(def_id).is_some()); + consts::get_static(cx, def_id) } else if let Some(alloc) = interpret_interner.get_alloc(ptr.alloc_id) { - let init = global_initializer(ccx, alloc); + let init = global_initializer(cx, alloc); if alloc.mutable { - consts::addr_of_mut(ccx, init, alloc.align, "byte_str") + consts::addr_of_mut(cx, init, alloc.align, "byte_str") } else { - consts::addr_of(ccx, init, alloc.align, "byte_str") + consts::addr_of(cx, init, alloc.align, "byte_str") } } else { bug!("missing allocation {:?}", ptr.alloc_id); }; let llval = unsafe { llvm::LLVMConstInBoundsGEP( - consts::bitcast(base_addr, Type::i8p(ccx)), - &C_usize(ccx, ptr.offset), + consts::bitcast(base_addr, Type::i8p(cx)), + &C_usize(cx, ptr.offset), 1, ) }; if scalar.value != layout::Pointer { @@ -185,9 +185,9 @@ pub fn primval_to_llvm(ccx: &CrateContext, } } -pub fn global_initializer(ccx: &CrateContext, alloc: &Allocation) -> ValueRef { +pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); - let layout = ccx.data_layout(); + let layout = cx.data_layout(); let pointer_size = layout.pointer_size.bytes() as usize; let mut next_offset = 0; @@ -195,28 +195,28 @@ pub fn global_initializer(ccx: &CrateContext, alloc: &Allocation) -> ValueRef { assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - llvals.push(C_bytes(ccx, &alloc.bytes[next_offset..offset])); + llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset])); } let ptr_offset = read_target_uint( layout.endian, &alloc.bytes[offset..(offset + pointer_size)], ).expect("global_initializer: could not read relocation pointer") as u64; llvals.push(primval_to_llvm( - ccx, + cx, PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), &Scalar { value: layout::Primitive::Pointer, valid_range: 0..=!0 }, - Type::i8p(ccx) + Type::i8p(cx) )); next_offset = offset + pointer_size; } if alloc.bytes.len() >= next_offset { - llvals.push(C_bytes(ccx, &alloc.bytes[next_offset ..])); + llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..])); } - C_struct(ccx, &llvals, true) + C_struct(cx, &llvals, true) } pub fn trans_static_initializer<'a, 'tcx>( @@ -224,39 +224,39 @@ pub fn trans_static_initializer<'a, 'tcx>( def_id: DefId) -> Result> { - let instance = ty::Instance::mono(ccx.tcx(), def_id); + let instance = ty::Instance::mono(cx.tcx, def_id); let cid = GlobalId { instance, promoted: None }; let param_env = ty::ParamEnv::empty(traits::Reveal::All); - ccx.tcx().const_eval(param_env.and(cid))?; + cx.tcx.const_eval(param_env.and(cid))?; - let alloc_id = ccx - .tcx() + let alloc_id = cx + .tcx .interpret_interner .borrow() .get_cached(def_id) .expect("global not cached"); - let alloc = ccx - .tcx() + let alloc = cx + .tcx .interpret_interner .borrow() .get_alloc(alloc_id) .expect("miri allocation never successfully created"); - Ok(global_initializer(ccx, alloc)) + Ok(global_initializer(cx, alloc)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { fn const_to_miri_value( &mut self, - bcx: &Builder<'a, 'tcx>, + bx: &Builder<'a, 'tcx>, constant: &'tcx ty::Const<'tcx>, ) -> Result> { match constant.val { ConstVal::Unevaluated(def_id, ref substs) => { - let tcx = bcx.tcx(); + let tcx = bx.tcx(); let param_env = ty::ParamEnv::empty(traits::Reveal::All); let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); let cid = GlobalId { @@ -264,7 +264,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { promoted: None, }; let c = tcx.const_eval(param_env.and(cid))?; - self.const_to_miri_value(bcx, c) + self.const_to_miri_value(bx, c) }, ConstVal::Value(miri_val) => Ok(miri_val), } @@ -272,7 +272,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { pub fn mir_constant_to_miri_value( &mut self, - bcx: &Builder<'a, 'tcx>, + bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, ) -> Result> { match constant.literal { @@ -282,22 +282,22 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { instance: self.instance, promoted: Some(index), }; - bcx.tcx().const_eval(param_env.and(cid)) + bx.tcx().const_eval(param_env.and(cid)) } mir::Literal::Value { value } => { Ok(self.monomorphize(&value)) } - }.and_then(|c| self.const_to_miri_value(bcx, c)) + }.and_then(|c| self.const_to_miri_value(bx, c)) } // Old version of trans_constant now used just for SIMD shuffle pub fn remove_me_shuffle_indices(&mut self, - bcx: &Builder<'a, 'tcx>, + bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>) -> (ValueRef, Ty<'tcx>) { - let layout = bcx.ccx.layout_of(constant.ty); - self.mir_constant_to_miri_value(bcx, constant) + let layout = bx.cx.layout_of(constant.ty); + self.mir_constant_to_miri_value(bx, constant) .and_then(|c| { let llval = match c { MiriValue::ByVal(val) => { @@ -305,7 +305,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) }; - primval_to_llvm(bcx.ccx, val, scalar, layout.immediate_llvm_type(bcx.ccx)) + primval_to_llvm(bx.cx, val, scalar, layout.immediate_llvm_type(bx.cx)) }, MiriValue::ByValPair(a_val, b_val) => { let (a_scalar, b_scalar) = match layout.abi { @@ -313,18 +313,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) }; let a_llval = primval_to_llvm( - bcx.ccx, + bx.cx, a_val, a_scalar, - layout.scalar_pair_element_llvm_type(bcx.ccx, 0), + layout.scalar_pair_element_llvm_type(bx.cx, 0), ); let b_llval = primval_to_llvm( - bcx.ccx, + bx.cx, b_val, b_scalar, - layout.scalar_pair_element_llvm_type(bcx.ccx, 1), + layout.scalar_pair_element_llvm_type(bx.cx, 1), ); - C_struct(bcx.ccx, &[a_llval, b_llval], false) + C_struct(bx.cx, &[a_llval, b_llval], false) }, MiriValue::ByRef(..) => { let field_ty = constant.ty.builtin_index().unwrap(); @@ -334,7 +334,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { }; let values: Result, _> = (0..fields).map(|field| { let field = const_val_field( - bcx.tcx(), + bx.tcx(), ty::ParamEnv::empty(traits::Reveal::All), self.instance, None, @@ -344,29 +344,29 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { )?; match field.val { ConstVal::Value(MiriValue::ByVal(prim)) => { - let layout = bcx.ccx.layout_of(field_ty); + let layout = bx.cx.layout_of(field_ty); let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) }; Ok(primval_to_llvm( - bcx.ccx, prim, scalar, - layout.immediate_llvm_type(bcx.ccx), + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), )) }, other => bug!("simd shuffle field {:?}, {}", other, constant.ty), } }).collect(); - C_struct(bcx.ccx, &values?, false) + C_struct(bx.cx, &values?, false) }, }; Ok((llval, constant.ty)) }) .unwrap_or_else(|e| { - e.report(bcx.tcx(), constant.span, "shuffle_indices"); + e.report(bx.tcx(), constant.span, "shuffle_indices"); // We've errored, so we don't have to produce working code. let ty = self.monomorphize(&constant.ty); - let llty = bcx.ccx.layout_of(ty).llvm_type(bcx.ccx); + let llty = bx.cx.layout_of(ty).llvm_type(bx.cx); (C_undef(llty), ty) }) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 01cf324124c4f..a66528858e14a 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -92,14 +92,14 @@ impl<'a, 'tcx> OperandRef<'tcx> { } } - pub fn from_const(bcx: &Builder<'a, 'tcx>, + pub fn from_const(bx: &Builder<'a, 'tcx>, miri_val: MiriValue, ty: ty::Ty<'tcx>) -> Result, ConstEvalErr<'tcx>> { - let layout = bcx.ccx.layout_of(ty); + let layout = bx.cx.layout_of(ty); if layout.is_zst() { - return Ok(OperandRef::new_zst(bcx.ccx, layout)); + return Ok(OperandRef::new_zst(bx.cx, layout)); } let val = match miri_val { @@ -109,10 +109,10 @@ impl<'a, 'tcx> OperandRef<'tcx> { _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) }; let llval = primval_to_llvm( - bcx.ccx, + bx.cx, x, scalar, - layout.immediate_llvm_type(bcx.ccx), + layout.immediate_llvm_type(bx.cx), ); OperandValue::Immediate(llval) }, @@ -122,16 +122,16 @@ impl<'a, 'tcx> OperandRef<'tcx> { _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) }; let a_llval = primval_to_llvm( - bcx.ccx, + bx.cx, a, a_scalar, - layout.scalar_pair_element_llvm_type(bcx.ccx, 0), + layout.scalar_pair_element_llvm_type(bx.cx, 0), ); let b_llval = primval_to_llvm( - bcx.ccx, + bx.cx, b, b_scalar, - layout.scalar_pair_element_llvm_type(bcx.ccx, 1), + layout.scalar_pair_element_llvm_type(bx.cx, 1), ); OperandValue::Pair(a_llval, b_llval) }, @@ -141,12 +141,12 @@ impl<'a, 'tcx> OperandRef<'tcx> { valid_range: 0..=!0 }; let ptr = primval_to_llvm( - bcx.ccx, + bx.cx, ptr.into_inner_primval(), &scalar, - layout.llvm_type(bcx.ccx).ptr_to(), + layout.llvm_type(bx.cx).ptr_to(), ); - return Ok(PlaceRef::new_sized(ptr, layout, align).load(bcx)); + return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx)); }, }; From 033f3fb65966bd3bb4cceaaa41869fbbf9b1d5de Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 16:09:24 +0100 Subject: [PATCH 019/115] Print rendered miri values in rustdoc --- src/librustc/mir/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 52 +++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index e254beebdd560..97aeba75ec4f3 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1778,7 +1778,7 @@ fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { } } -fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { +pub fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { use ty::TypeVariants::*; use rustc_const_math::ConstFloat; match (value, &ty.sty) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8c9de3690f4b0..8983d3dcfd071 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2457,14 +2457,24 @@ impl Clean for hir::Ty { ty: cx.tcx.types.usize }) }); - let n = if let ConstVal::Unevaluated(def_id, _) = n.val { - if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { - print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) - } else { - inline::print_inlined_const(cx, def_id) - } - } else { - format!("{:?}", n) + let n = match n.val { + ConstVal::Unevaluated(def_id, _) => { + if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { + print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) + } else { + inline::print_inlined_const(cx, def_id) + } + }, + ConstVal::Value(val) => { + let mut s = String::new(); + ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); + // array lengths are obviously usize + if s.ends_with("usize") { + let n = s.len() - "usize".len(); + s.truncate(n); + } + s + }, }; Array(box ty.clean(cx), n) }, @@ -2592,14 +2602,24 @@ impl<'tcx> Clean for Ty<'tcx> { n = new_n; } }; - let n = if let ConstVal::Unevaluated(def_id, _) = n.val { - if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { - print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) - } else { - inline::print_inlined_const(cx, def_id) - } - } else { - format!("{:?}", n) + let n = match n.val { + ConstVal::Unevaluated(def_id, _) => { + if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { + print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) + } else { + inline::print_inlined_const(cx, def_id) + } + }, + ConstVal::Value(val) => { + let mut s = String::new(); + ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); + // array lengths are obviously usize + if s.ends_with("usize") { + let n = s.len() - "usize".len(); + s.truncate(n); + } + s + }, }; Array(box ty.clean(cx), n) } From 2ba0635fb1fa948e577586f04bf68794041b845c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 19:36:30 +0100 Subject: [PATCH 020/115] Remove unused error code --- src/librustc_mir/diagnostics.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 58814cf171010..f53fe35b15d93 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -72,36 +72,6 @@ fn foo(x: Option) { ``` "##, -E0003: r##" -#### Note: this error code is no longer emitted by the compiler. - -Not-a-Number (NaN) values cannot be compared for equality and hence can never -match the input to a match expression. So, the following will not compile: - -```compile_fail -const NAN: f32 = 0.0 / 0.0; - -let number = 0.1f32; - -match number { - NAN => { /* ... */ }, - _ => {} -} -``` - -To match against NaN values, you should instead use the `is_nan()` method in a -guard, like so: - -``` -let number = 0.1f32; - -match number { - x if x.is_nan() => { /* ... */ } - _ => {} -} -``` -"##, - E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for one or more possible inputs to a match expression. Guaranteed matches are From 36a1209348736d78c60f7008aad163c0fbfb9e56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 Jan 2018 08:50:13 +0100 Subject: [PATCH 021/115] Use the TLS tcx instead of passing it into the StableHashContext --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/hir/map/collector.rs | 12 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ich/hcx.rs | 67 +++--- src/librustc/ich/impls_hir.rs | 132 +++++------ src/librustc/ich/impls_mir.rs | 94 ++++---- src/librustc/ich/impls_syntax.rs | 42 ++-- src/librustc/ich/impls_ty.rs | 206 +++++++++--------- src/librustc/lint/levels.rs | 4 +- src/librustc/macros.rs | 16 +- src/librustc/middle/borrowck.rs | 4 +- src/librustc/middle/region.rs | 4 +- src/librustc/mir/cache.rs | 4 +- src/librustc/mir/mono.rs | 8 +- src/librustc/session/config.rs | 4 +- .../traits/specialize/specialization_graph.rs | 4 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/fast_reject.rs | 6 +- src/librustc/ty/layout.rs | 20 +- src/librustc/ty/mod.rs | 14 +- src/librustc/ty/trait_def.rs | 4 +- src/librustc_metadata/schema.rs | 8 +- 22 files changed, 332 insertions(+), 334 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index b1ae572cbe034..74ad67eb804ad 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -661,7 +661,7 @@ trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { } impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T - where T: HashStable> + fmt::Debug + where T: HashStable> + fmt::Debug { default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 9f5e89d43caba..d8619ad9299ac 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -41,7 +41,7 @@ pub(super) struct NodeCollector<'a, 'hir> { dep_graph: &'a DepGraph, definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a, 'a>, + hcx: StableHashingContext<'a>, // We are collecting DepNode::HirBody hashes here so we can compute the // crate hash from then later on. @@ -52,7 +52,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn root(krate: &'hir Crate, dep_graph: &'a DepGraph, definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a, 'a>) + hcx: StableHashingContext<'a>) -> NodeCollector<'a, 'hir> { let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX); @@ -235,7 +235,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { self.parent_node = parent_node; } - fn with_dep_node_owner>, + fn with_dep_node_owner>, F: FnOnce(&mut Self)>(&mut self, dep_node_owner: DefIndex, item_like: &T, @@ -513,11 +513,11 @@ struct HirItemLike { hash_bodies: bool, } -impl<'a, 'hir, T> HashStable> for HirItemLike - where T: HashStable> +impl<'a, 'hir, T> HashStable> for HirItemLike + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'hir>, + hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| { self.item_like.hash_stable(hcx, hasher); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 59e0f20119cee..5feea602d2814 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1053,7 +1053,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, definitions: &'hir Definitions) -> Map<'hir> { let (map, crate_hash) = { - let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore, None); + let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); let mut collector = NodeCollector::root(&forest.krate, &forest.dep_graph, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 92103a3e1ffd4..0206888cd3e0a 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -14,7 +14,7 @@ use hir::map::DefPathHash; use hir::map::definitions::Definitions; use ich::{self, CachingCodemapView, Fingerprint}; use middle::cstore::CrateStore; -use ty::{TyCtxt, fast_reject, InterpretInterner}; +use ty::{TyCtxt, fast_reject}; use session::Session; use std::cmp::Ord; @@ -46,20 +46,19 @@ pub fn compute_ignored_attr_names() -> FxHashSet { /// a reference to the TyCtxt) and it holds a few caches for speeding up various /// things (e.g. each DefId/DefPath is only hashed once). #[derive(Clone)] -pub struct StableHashingContext<'a, 'gcx: 'a> { - sess: &'gcx Session, - definitions: &'gcx Definitions, - cstore: &'gcx CrateStore, - body_resolver: BodyResolver<'gcx>, +pub struct StableHashingContext<'a> { + sess: &'a Session, + definitions: &'a Definitions, + cstore: &'a CrateStore, + body_resolver: BodyResolver<'a>, hash_spans: bool, hash_bodies: bool, node_id_hashing_mode: NodeIdHashingMode, - pub interpret_interner: Option<&'a RefCell>>, // Very often, we are hashing something that does not need the // CachingCodemapView, so we initialize it lazily. - raw_codemap: &'gcx CodeMap, - caching_codemap: Option>, + raw_codemap: &'a CodeMap, + caching_codemap: Option>, } #[derive(PartialEq, Eq, Clone, Copy)] @@ -82,15 +81,14 @@ impl<'gcx> BodyResolver<'gcx> { } } -impl<'a, 'gcx> StableHashingContext<'a, 'gcx> { +impl<'a> StableHashingContext<'a> { // The `krate` here is only used for mapping BodyIds to Bodies. // Don't use it for anything else or you'll run the risk of // leaking data out of the tracking system. - pub fn new(sess: &'gcx Session, - krate: &'gcx hir::Crate, - definitions: &'gcx Definitions, - cstore: &'gcx CrateStore, - interpret_interner: Option<&'a RefCell>>) + pub fn new(sess: &'a Session, + krate: &'a hir::Crate, + definitions: &'a Definitions, + cstore: &'a CrateStore) -> Self { let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans; @@ -104,12 +102,11 @@ impl<'a, 'gcx> StableHashingContext<'a, 'gcx> { hash_spans: hash_spans_initial, hash_bodies: true, node_id_hashing_mode: NodeIdHashingMode::HashDefPath, - interpret_interner, } } #[inline] - pub fn sess(&self) -> &'gcx Session { + pub fn sess(&self) -> &'a Session { self.sess } @@ -168,7 +165,7 @@ impl<'a, 'gcx> StableHashingContext<'a, 'gcx> { } #[inline] - pub fn codemap(&mut self) -> &mut CachingCodemapView<'gcx> { + pub fn codemap(&mut self) -> &mut CachingCodemapView<'a> { match self.caching_codemap { Some(ref mut cm) => { cm @@ -196,27 +193,27 @@ impl<'a, 'gcx> StableHashingContext<'a, 'gcx> { } impl<'a, 'gcx, 'lcx> StableHashingContextProvider for TyCtxt<'a, 'gcx, 'lcx> { - type ContextType = StableHashingContext<'a, 'gcx>; + type ContextType = StableHashingContext<'a>; fn create_stable_hashing_context(&self) -> Self::ContextType { (*self).create_stable_hashing_context() } } -impl<'a, 'gcx> StableHashingContextProvider for StableHashingContext<'a, 'gcx> { - type ContextType = StableHashingContext<'a, 'gcx>; +impl<'a> StableHashingContextProvider for StableHashingContext<'a> { + type ContextType = StableHashingContext<'a>; fn create_stable_hashing_context(&self) -> Self::ContextType { self.clone() } } -impl<'a, 'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'a, 'gcx> { +impl<'a> ::dep_graph::DepGraphSafe for StableHashingContext<'a> { } -impl<'a, 'gcx> HashStable> for hir::BodyId { +impl<'a> HashStable> for hir::BodyId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if hcx.hash_bodies() { hcx.body_resolver.body(*self).hash_stable(hcx, hasher); @@ -224,10 +221,10 @@ impl<'a, 'gcx> HashStable> for hir::BodyId { } } -impl<'a, 'gcx> HashStable> for hir::HirId { +impl<'a> HashStable> for hir::HirId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { @@ -246,21 +243,21 @@ impl<'a, 'gcx> HashStable> for hir::HirId { } } -impl<'a, 'gcx> ToStableHashKey> for hir::HirId { +impl<'a> ToStableHashKey> for hir::HirId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'a, 'gcx>) + hcx: &StableHashingContext<'a>) -> (DefPathHash, hir::ItemLocalId) { let def_path_hash = hcx.local_def_path_hash(self.owner); (def_path_hash, self.local_id) } } -impl<'a, 'gcx> HashStable> for ast::NodeId { +impl<'a> HashStable> for ast::NodeId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { @@ -273,18 +270,18 @@ impl<'a, 'gcx> HashStable> for ast::NodeId { } } -impl<'a, 'gcx> ToStableHashKey> for ast::NodeId { +impl<'a> ToStableHashKey> for ast::NodeId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'a, 'gcx>) + hcx: &StableHashingContext<'a>) -> (DefPathHash, hir::ItemLocalId) { hcx.definitions.node_to_hir_id(*self).to_stable_hash_key(hcx) } } -impl<'a, 'gcx> HashStable> for Span { +impl<'a> HashStable> for Span { // Hash a span in a stable way. We can't directly hash the span's BytePos // fields (that would be similar to hashing pointers, since those are just @@ -296,7 +293,7 @@ impl<'a, 'gcx> HashStable> for Span { // Also, hashing filenames is expensive so we avoid doing it twice when the // span starts and ends in the same file, which is almost always the case. fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; @@ -377,7 +374,7 @@ impl<'a, 'gcx> HashStable> for Span { } pub fn hash_stable_trait_impls<'a, 'gcx, W, R>( - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, blanket_impls: &Vec, non_blanket_impls: &HashMap, R>) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 0eacb6d7b9920..9dce26c7f22ae 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -20,46 +20,46 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, use std::mem; use syntax::ast; -impl<'a, 'gcx> HashStable> for DefId { +impl<'a> HashStable> for DefId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'a, 'gcx> ToStableHashKey> for DefId { +impl<'a> ToStableHashKey> for DefId { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { hcx.def_path_hash(*self) } } -impl<'a, 'gcx> HashStable> for LocalDefId { +impl<'a> HashStable> for LocalDefId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); } } -impl<'a, 'gcx> ToStableHashKey> for LocalDefId { +impl<'a> ToStableHashKey> for LocalDefId { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { hcx.def_path_hash(self.to_def_id()) } } -impl<'a, 'gcx> HashStable> for CrateNum { +impl<'a> HashStable> for CrateNum { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.def_path_hash(DefId { krate: *self, @@ -68,11 +68,11 @@ impl<'a, 'gcx> HashStable> for CrateNum { } } -impl<'a, 'gcx> ToStableHashKey> for CrateNum { +impl<'a> ToStableHashKey> for CrateNum { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; def_id.to_stable_hash_key(hcx) } @@ -80,13 +80,13 @@ impl<'a, 'gcx> ToStableHashKey> for CrateNum { impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); -impl<'a, 'gcx> ToStableHashKey> +impl<'a> ToStableHashKey> for hir::ItemLocalId { type KeyType = hir::ItemLocalId; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'a, 'gcx>) + _: &StableHashingContext<'a>) -> hir::ItemLocalId { *self } @@ -99,9 +99,9 @@ for hir::ItemLocalId { // want to pick up on a reference changing its target, so we hash the NodeIds // in "DefPath Mode". -impl<'a, 'gcx> HashStable> for hir::ItemId { +impl<'a> HashStable> for hir::ItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ItemId { id @@ -113,9 +113,9 @@ impl<'a, 'gcx> HashStable> for hir::ItemId { } } -impl<'a, 'gcx> HashStable> for hir::TraitItemId { +impl<'a> HashStable> for hir::TraitItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::TraitItemId { node_id @@ -127,9 +127,9 @@ impl<'a, 'gcx> HashStable> for hir::TraitItemId { } } -impl<'a, 'gcx> HashStable> for hir::ImplItemId { +impl<'a> HashStable> for hir::ImplItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ImplItemId { node_id @@ -270,9 +270,9 @@ impl_stable_hash_for!(struct hir::TypeBinding { span }); -impl<'a, 'gcx> HashStable> for hir::Ty { +impl<'a> HashStable> for hir::Ty { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Ty { @@ -338,9 +338,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy { Return(t) }); -impl<'a, 'gcx> HashStable> for hir::TraitRef { +impl<'a> HashStable> for hir::TraitRef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::TraitRef { ref path, @@ -375,9 +375,9 @@ impl_stable_hash_for!(struct hir::MacroDef { }); -impl<'a, 'gcx> HashStable> for hir::Block { +impl<'a> HashStable> for hir::Block { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Block { ref stmts, @@ -399,9 +399,9 @@ impl<'a, 'gcx> HashStable> for hir::Block { } } -impl<'a, 'gcx> HashStable> for hir::Pat { +impl<'a> HashStable> for hir::Pat { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Pat { id: _, @@ -526,9 +526,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource { UserProvided }); -impl<'a, 'gcx> HashStable> for hir::Expr { +impl<'a> HashStable> for hir::Expr { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { @@ -590,9 +590,9 @@ impl_stable_hash_for!(enum hir::LoopSource { ForLoop }); -impl<'a, 'gcx> HashStable> for hir::MatchSource { +impl<'a> HashStable> for hir::MatchSource { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use hir::MatchSource; @@ -646,9 +646,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget { Loop(loop_id_result) }); -impl<'a, 'gcx> HashStable> for ast::Ident { +impl<'a> HashStable> for ast::Ident { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ast::Ident { ref name, @@ -659,9 +659,9 @@ impl<'a, 'gcx> HashStable> for ast::Ident { } } -impl<'a, 'gcx> HashStable> for hir::TraitItem { +impl<'a> HashStable> for hir::TraitItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::TraitItem { id: _, @@ -694,9 +694,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind { Type(bounds, rhs) }); -impl<'a, 'gcx> HashStable> for hir::ImplItem { +impl<'a> HashStable> for hir::ImplItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::ImplItem { id: _, @@ -728,9 +728,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind { Type(t) }); -impl<'a, 'gcx> HashStable> for hir::Visibility { +impl<'a> HashStable> for hir::Visibility { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -749,9 +749,9 @@ impl<'a, 'gcx> HashStable> for hir::Visibility { } } -impl<'a, 'gcx> HashStable> for hir::Defaultness { +impl<'a> HashStable> for hir::Defaultness { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -770,9 +770,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity { Negative }); -impl<'a, 'gcx> HashStable> for hir::Mod { +impl<'a> HashStable> for hir::Mod { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Mod { inner, @@ -825,9 +825,9 @@ impl_stable_hash_for!(enum hir::VariantData { Unit(id) }); -impl<'a, 'gcx> HashStable> for hir::Item { +impl<'a> HashStable> for hir::Item { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Item { name, @@ -884,10 +884,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef { defaultness }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for hir::AssociatedItemKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -929,9 +929,9 @@ impl_stable_hash_for!(struct hir::Arg { hir_id }); -impl<'a, 'gcx> HashStable> for hir::Body { +impl<'a> HashStable> for hir::Body { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Body { ref arguments, @@ -947,12 +947,12 @@ impl<'a, 'gcx> HashStable> for hir::Body { } } -impl<'a, 'gcx> ToStableHashKey> for hir::BodyId { +impl<'a> ToStableHashKey> for hir::BodyId { type KeyType = (DefPathHash, hir::ItemLocalId); #[inline] fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'a, 'gcx>) + hcx: &StableHashingContext<'a>) -> (DefPathHash, hir::ItemLocalId) { let hir::BodyId { node_id } = *self; node_id.to_stable_hash_key(hcx) @@ -965,9 +965,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); -impl<'a, 'gcx> HashStable> for hir::GlobalAsm { +impl<'a> HashStable> for hir::GlobalAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::GlobalAsm { asm, @@ -978,9 +978,9 @@ impl<'a, 'gcx> HashStable> for hir::GlobalAsm { } } -impl<'a, 'gcx> HashStable> for hir::InlineAsm { +impl<'a> HashStable> for hir::InlineAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::InlineAsm { asm, @@ -1061,22 +1061,22 @@ impl_stable_hash_for!(enum hir::Constness { NotConst }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for hir::def_id::DefIndex { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.local_def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'a, 'gcx> ToStableHashKey> +impl<'a> ToStableHashKey> for hir::def_id::DefIndex { type KeyType = DefPathHash; #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a, 'gcx>) -> DefPathHash { + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { hcx.local_def_path_hash(*self) } } @@ -1089,10 +1089,10 @@ impl_stable_hash_for!(struct hir::def::Export { is_import }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for ::middle::lang_items::LangItem { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'gcx>, + _: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } @@ -1103,10 +1103,10 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems { missing }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for hir::TraitCandidate { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let hir::TraitCandidate { @@ -1120,11 +1120,11 @@ for hir::TraitCandidate { } } -impl<'a, 'gcx> ToStableHashKey> for hir::TraitCandidate { +impl<'a> ToStableHashKey> for hir::TraitCandidate { type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>); fn to_stable_hash_key(&self, - hcx: &StableHashingContext<'a, 'gcx>) + hcx: &StableHashingContext<'a>) -> Self::KeyType { let hir::TraitCandidate { def_id, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 7daf82d09ed5a..e549d1b7530fe 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -36,11 +36,11 @@ impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for mir::UnsafetyViolationKind { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -61,12 +61,12 @@ impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info }); -impl<'a, 'gcx, T> HashStable> for mir::ClearCrossCrate - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for mir::ClearCrossCrate + where T: HashStable> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -78,61 +78,61 @@ impl<'a, 'gcx, T> HashStable> for mir::ClearCross } } -impl<'a, 'gcx> HashStable> for mir::Local { +impl<'a> HashStable> for mir::Local { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> for mir::BasicBlock { +impl<'a> HashStable> for mir::BasicBlock { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> for mir::Field { +impl<'a> HashStable> for mir::Field { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for mir::VisibilityScope { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> for mir::Promoted { +impl<'a> HashStable> for mir::Promoted { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::TerminatorKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -205,10 +205,10 @@ for mir::TerminatorKind<'gcx> { } } -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::AssertMessage<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -228,10 +228,10 @@ for mir::AssertMessage<'gcx> { impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::StatementKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -265,12 +265,12 @@ for mir::StatementKind<'gcx> { } } -impl<'a, 'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for mir::ValidationOperand<'gcx, T> - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.place.hash_stable(hcx, hasher); @@ -282,9 +282,9 @@ impl<'a, 'gcx, T> HashStable> impl_stable_hash_for!(enum mir::ValidationOp { Acquire, Release, Suspend(region_scope) }); -impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -301,14 +301,14 @@ impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { } } -impl<'a, 'gcx, B, V, T> HashStable> +impl<'a, 'gcx, B, V, T> HashStable> for mir::Projection<'gcx, B, V, T> - where B: HashStable>, - V: HashStable>, - T: HashStable> + where B: HashStable>, + V: HashStable>, + T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let mir::Projection { ref base, @@ -320,13 +320,13 @@ for mir::Projection<'gcx, B, V, T> } } -impl<'a, 'gcx, V, T> HashStable> +impl<'a, 'gcx, V, T> HashStable> for mir::ProjectionElem<'gcx, V, T> - where V: HashStable>, - T: HashStable> + where V: HashStable>, + T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -360,9 +360,9 @@ impl_stable_hash_for!(struct mir::VisibilityScopeInfo { lint_root, safety }); -impl<'a, 'gcx> HashStable> for mir::Safety { +impl<'a> HashStable> for mir::Safety { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -377,9 +377,9 @@ impl<'a, 'gcx> HashStable> for mir::Safety { } } -impl<'a, 'gcx> HashStable> for mir::Operand<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Operand<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -397,9 +397,9 @@ impl<'a, 'gcx> HashStable> for mir::Operand<'gcx> } } -impl<'a, 'gcx> HashStable> for mir::Rvalue<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Rvalue<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -457,10 +457,10 @@ impl_stable_hash_for!(enum mir::CastKind { Unsize }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for mir::AggregateKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -519,9 +519,9 @@ impl_stable_hash_for!(enum mir::NullOp { impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); -impl<'a, 'gcx> HashStable> for mir::Literal<'gcx> { +impl<'a, 'gcx> HashStable> for mir::Literal<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -548,9 +548,9 @@ impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> { blame_span }); -impl<'a, 'gcx> HashStable> for mir::ClosureOutlivesSubject<'gcx> { +impl<'a, 'gcx> HashStable> for mir::ClosureOutlivesSubject<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 34dbf15b31f98..03fcf581950af 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -28,42 +28,42 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use rustc_data_structures::accumulate_vec::AccumulateVec; -impl<'a, 'gcx> HashStable> for InternedString { +impl<'a> HashStable> for InternedString { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let s: &str = &**self; s.hash_stable(hcx, hasher); } } -impl<'a, 'gcx> ToStableHashKey> for InternedString { +impl<'a> ToStableHashKey> for InternedString { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'a, 'gcx>) + _: &StableHashingContext<'a>) -> InternedString { self.clone() } } -impl<'a, 'gcx> HashStable> for ast::Name { +impl<'a> HashStable> for ast::Name { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> ToStableHashKey> for ast::Name { +impl<'a> ToStableHashKey> for ast::Name { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, - _: &StableHashingContext<'a, 'gcx>) + _: &StableHashingContext<'a>) -> InternedString { self.as_str() } @@ -110,10 +110,10 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { rustc_const_unstable }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for ::syntax::attr::StabilityLevel { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -165,9 +165,9 @@ impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, ident }); impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); -impl<'a, 'gcx> HashStable> for [ast::Attribute] { +impl<'a> HashStable> for [ast::Attribute] { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if self.len() == 0 { self.len().hash_stable(hcx, hasher); @@ -190,9 +190,9 @@ impl<'a, 'gcx> HashStable> for [ast::Attribute] { } } -impl<'a, 'gcx> HashStable> for ast::Attribute { +impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); @@ -219,10 +219,10 @@ impl<'a, 'gcx> HashStable> for ast::Attribute { } } -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for tokenstream::TokenTree { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -241,10 +241,10 @@ for tokenstream::TokenTree { } } -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for tokenstream::TokenStream { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); @@ -254,7 +254,7 @@ for tokenstream::TokenStream { fn hash_token<'a, 'gcx, W: StableHasherResult>( token: &token::Token, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { mem::discriminant(token).hash_stable(hcx, hasher); @@ -384,9 +384,9 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName { Custom(s) }); -impl<'a, 'gcx> HashStable> for FileMap { +impl<'a> HashStable> for FileMap { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let FileMap { name: _, // We hash the smaller name_hash instead of this diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index c2bda9f45a0e7..532080710ea24 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -23,11 +23,11 @@ use traits; use ty; use mir; -impl<'a, 'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for &'gcx ty::Slice - where T: HashStable> { + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = @@ -52,20 +52,20 @@ for &'gcx ty::Slice } } -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::subst::Kind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_type().hash_stable(hcx, hasher); self.as_region().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for ty::RegionKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -109,20 +109,20 @@ for ty::RegionKind { } } -impl<'a, 'gcx> HashStable> for ty::RegionVid { +impl<'a> HashStable> for ty::RegionVid { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::adjustment::AutoBorrow<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -137,10 +137,10 @@ for ty::adjustment::AutoBorrow<'gcx> { } } -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::adjustment::Adjust<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -172,10 +172,10 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::UpvarCapture<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -199,11 +199,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> { abi }); -impl<'a, 'gcx, T> HashStable> for ty::Binder - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for ty::Binder + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::Binder(ref inner) = *self; inner.hash_stable(hcx, hasher); @@ -223,13 +223,13 @@ impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); -impl<'a, 'gcx, A, B> HashStable> +impl<'a, 'gcx, A, B> HashStable> for ty::OutlivesPredicate - where A: HashStable>, - B: HashStable>, + where A: HashStable>, + B: HashStable>, { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::OutlivesPredicate(ref a, ref b) = *self; a.hash_stable(hcx, hasher); @@ -241,9 +241,9 @@ impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty } impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id }); -impl<'a, 'gcx> HashStable> for ty::Predicate<'gcx> { +impl<'a, 'gcx> HashStable> for ty::Predicate<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -284,9 +284,9 @@ impl<'a, 'gcx> HashStable> for ty::Predicate<'gcx } } -impl<'a, 'gcx> HashStable> for ty::AdtFlags { +impl<'a> HashStable> for ty::AdtFlags { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'gcx>, + _: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { std_hash::Hash::hash(self, hasher); } @@ -311,10 +311,10 @@ impl_stable_hash_for!(struct ty::FieldDef { vis }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::const_val::ConstVal<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use middle::const_val::ConstVal::*; @@ -347,37 +347,39 @@ impl_stable_hash_for!(struct mir::interpret::MemoryPointer { offset }); -impl<'a, 'gcx> HashStable> for mir::interpret::AllocId { +impl<'a> HashStable> for mir::interpret::AllocId { fn hash_stable( &self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { - let interner = hcx - .interpret_interner - .expect("cannot hash AllocIds during HIR lowering") - .borrow(); - if let Some(def_id) = interner.get_corresponding_static_def_id(*self) { - 0.hash_stable(hcx, hasher); - // statics are unique via their DefId - def_id.hash_stable(hcx, hasher); - } else if let Some(alloc) = interner.get_alloc(*self) { - // not a static, can't be recursive, hash the allocation - 1.hash_stable(hcx, hasher); - alloc.hash_stable(hcx, hasher); - } else if let Some(inst) = interner.get_fn(*self) { - 2.hash_stable(hcx, hasher); - inst.hash_stable(hcx, hasher); - } else { - bug!("no allocation for {}", self); - } + ty::tls::with_opt(|tcx| { + let tcx = tcx.expect("can't hash AllocIds during hir lowering"); + let interner = tcx + .interpret_interner + .borrow(); + if let Some(def_id) = interner.get_corresponding_static_def_id(*self) { + 0.hash_stable(hcx, hasher); + // statics are unique via their DefId + def_id.hash_stable(hcx, hasher); + } else if let Some(alloc) = interner.get_alloc(*self) { + // not a static, can't be recursive, hash the allocation + 1.hash_stable(hcx, hasher); + alloc.hash_stable(hcx, hasher); + } else if let Some(inst) = interner.get_fn(*self) { + 2.hash_stable(hcx, hasher); + inst.hash_stable(hcx, hasher); + } else { + bug!("no allocation for {}", self); + } + }); } } -impl<'a, 'gcx> HashStable> for mir::interpret::Allocation { +impl<'a> HashStable> for mir::interpret::Allocation { fn hash_stable( &self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { self.bytes.hash_stable(hcx, hasher); @@ -408,10 +410,10 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> { kind }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::middle::const_val::ErrKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use middle::const_val::ErrKind::*; @@ -462,10 +464,10 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { predicates }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ::mir::interpret::EvalError<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use mir::interpret::EvalErrorKind::*; @@ -642,9 +644,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { Struct(index) }); -impl<'a, 'gcx> HashStable> for ty::Generics { +impl<'a> HashStable> for ty::Generics { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::Generics { parent, @@ -670,10 +672,10 @@ impl<'a, 'gcx> HashStable> for ty::Generics { } } -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for ty::RegionParameterDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::RegionParameterDef { name, @@ -699,12 +701,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef { synthetic }); -impl<'a, 'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for ::middle::resolve_lifetime::Set1 - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use middle::resolve_lifetime::Set1; @@ -755,11 +757,11 @@ impl_stable_hash_for!(enum ty::cast::CastKind { impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx }); impl_stable_hash_for!(struct ::middle::region::Scope { id, code }); -impl<'a, 'gcx> ToStableHashKey> for region::Scope { +impl<'a> ToStableHashKey> for region::Scope { type KeyType = region::Scope; #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a, 'gcx>) -> region::Scope { + fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> region::Scope { *self } } @@ -785,11 +787,11 @@ impl_stable_hash_for!(enum ty::BoundRegion { BrEnv }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::TypeVariants<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use ty::TypeVariants::*; @@ -886,11 +888,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { mutbl }); -impl<'a, 'gcx> HashStable> +impl<'a, 'gcx> HashStable> for ty::ExistentialPredicate<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -923,9 +925,9 @@ impl_stable_hash_for!(struct ty::Instance<'tcx> { substs }); -impl<'a, 'gcx> HashStable> for ty::InstanceDef<'gcx> { +impl<'a, 'gcx> HashStable> for ty::InstanceDef<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -959,9 +961,9 @@ impl<'a, 'gcx> HashStable> for ty::InstanceDef<'g } } -impl<'a, 'gcx> HashStable> for ty::TraitDef { +impl<'a> HashStable> for ty::TraitDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TraitDef { // We already have the def_path_hash below, no need to hash it twice @@ -989,9 +991,9 @@ impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> { }); -impl<'a, 'gcx> HashStable> for ty::CrateVariancesMap { +impl<'a> HashStable> for ty::CrateVariancesMap { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::CrateVariancesMap { ref variances, @@ -1025,12 +1027,12 @@ impl_stable_hash_for!(enum ty::AssociatedItemContainer { }); -impl<'a, 'gcx, T> HashStable> +impl<'a, 'gcx, T> HashStable> for ty::steal::Steal - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.borrow().hash_stable(hcx, hasher); } @@ -1052,10 +1054,10 @@ impl_stable_hash_for!(enum ::middle::privacy::AccessLevel { Public }); -impl<'a, 'gcx> HashStable> +impl<'a> HashStable> for ::middle::privacy::AccessLevels { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let ::middle::privacy::AccessLevels { @@ -1082,10 +1084,10 @@ impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet { reachable_set }); -impl<'a, 'gcx, N> HashStable> -for traits::Vtable<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::Vtable<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use traits::Vtable::*; @@ -1104,10 +1106,10 @@ for traits::Vtable<'gcx, N> where N: HashStable> } } -impl<'a, 'gcx, N> HashStable> -for traits::VtableImplData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableImplData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableImplData { impl_def_id, @@ -1120,10 +1122,10 @@ for traits::VtableImplData<'gcx, N> where N: HashStable HashStable> -for traits::VtableAutoImplData where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableAutoImplData where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableAutoImplData { trait_def_id, @@ -1134,10 +1136,10 @@ for traits::VtableAutoImplData where N: HashStable HashStable> -for traits::VtableObjectData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableObjectData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableObjectData { upcast_trait_ref, @@ -1150,10 +1152,10 @@ for traits::VtableObjectData<'gcx, N> where N: HashStable HashStable> -for traits::VtableBuiltinData where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableBuiltinData where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableBuiltinData { ref nested, @@ -1162,10 +1164,10 @@ for traits::VtableBuiltinData where N: HashStable HashStable> -for traits::VtableClosureData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableClosureData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableClosureData { closure_def_id, @@ -1178,10 +1180,10 @@ for traits::VtableClosureData<'gcx, N> where N: HashStable HashStable> -for traits::VtableFnPointerData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableFnPointerData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableFnPointerData { fn_ty, @@ -1192,10 +1194,10 @@ for traits::VtableFnPointerData<'gcx, N> where N: HashStable HashStable> -for traits::VtableGeneratorData<'gcx, N> where N: HashStable> { +impl<'a, 'gcx, N> HashStable> +for traits::VtableGeneratorData<'gcx, N> where N: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let traits::VtableGeneratorData { closure_def_id, diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 16bfa5dae96c9..0a9e71b5655aa 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -391,10 +391,10 @@ impl LintLevelMap { } } -impl<'a, 'gcx> HashStable> for LintLevelMap { +impl<'a> HashStable> for LintLevelMap { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let LintLevelMap { ref sets, diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index c18e585f79553..9a394e524817b 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field { #[macro_export] macro_rules! impl_stable_hash_for { (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { - impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { use $enum_name::*; ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); @@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for { } }; (struct $struct_name:path { $($field:ident),* }) => { - impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name { $(ref $field),* @@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for { } }; (tuple_struct $struct_name:path { $($field:ident),* }) => { - impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name ( $(ref $field),* @@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for { macro_rules! impl_stable_hash_for_spanned { ($T:path) => ( - impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.node.hash_stable(hcx, hasher); self.span.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs index 138ef03b5a0db..6f5791ed5d71b 100644 --- a/src/librustc/middle/borrowck.rs +++ b/src/librustc/middle/borrowck.rs @@ -20,9 +20,9 @@ pub struct BorrowCheckResult { pub used_mut_nodes: FxHashSet, } -impl<'a, 'gcx> HashStable> for BorrowCheckResult { +impl<'a> HashStable> for BorrowCheckResult { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let BorrowCheckResult { ref used_mut_nodes, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index cf3e5cd7807a3..2229684b06d85 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1488,9 +1488,9 @@ pub fn provide(providers: &mut Providers) { }; } -impl<'a, 'gcx> HashStable> for ScopeTree { +impl<'a> HashStable> for ScopeTree { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ScopeTree { root_body, diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 5c25703df8661..45cb70d007068 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -35,9 +35,9 @@ impl serialize::Decodable for Cache { } } -impl<'a, 'gcx> HashStable> for Cache { +impl<'a> HashStable> for Cache { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'gcx>, + _: &mut StableHashingContext<'a>, _: &mut StableHasher) { // do nothing } diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 07a79417e35bd..d792ca5c81121 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -40,9 +40,9 @@ impl<'tcx> MonoItem<'tcx> { } } -impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { +impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { ::std::mem::discriminant(self).hash_stable(hcx, hasher); @@ -168,9 +168,9 @@ impl<'tcx> CodegenUnit<'tcx> { } } -impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { +impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let CodegenUnit { ref items, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 9ead81821847b..287a61272ee84 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -123,10 +123,10 @@ impl_stable_hash_for!(enum self::OutputType { DepInfo }); -impl<'a, 'tcx> ToStableHashKey> for OutputType { +impl<'a, 'tcx> ToStableHashKey> for OutputType { type KeyType = OutputType; #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a, 'tcx>) -> Self::KeyType { + fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> Self::KeyType { *self } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index f677f851d1d20..6e5942b90fbb6 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -391,9 +391,9 @@ pub fn ancestors(tcx: TyCtxt, } } -impl<'a, 'gcx> HashStable> for Children { +impl<'a> HashStable> for Children { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let Children { ref nonblanket_impls, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bb235f0c800dc..87c446e780e3a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -675,9 +675,9 @@ impl<'tcx> TypeckTables<'tcx> { } } -impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { +impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TypeckTables { local_id_root, @@ -1361,14 +1361,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.cstore.crate_data_as_rc_any(cnum) } - pub fn create_stable_hashing_context(self) -> StableHashingContext<'a, 'gcx> { + pub fn create_stable_hashing_context(self) -> StableHashingContext<'a> { let krate = self.dep_graph.with_ignore(|| self.gcx.hir.krate()); StableHashingContext::new(self.sess, krate, self.hir.definitions(), - self.cstore, - Some(&self.interpret_interner)) + self.cstore) } // This method makes sure that we have a DepNode and a Fingerprint for diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 2a2ee6d0f1c56..93d8a4d979de6 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -154,12 +154,12 @@ impl SimplifiedTypeGen { } } -impl<'a, 'gcx, D> HashStable> for SimplifiedTypeGen +impl<'a, 'gcx, D> HashStable> for SimplifiedTypeGen where D: Copy + Debug + Ord + Eq + Hash + - HashStable>, + HashStable>, { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 262ce9d5afd2f..a74029aa0a2e6 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2369,9 +2369,9 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } -impl<'a, 'gcx> HashStable> for Variants { +impl<'a> HashStable> for Variants { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use ty::layout::Variants::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2405,9 +2405,9 @@ impl<'a, 'gcx> HashStable> for Variants { } } -impl<'a, 'gcx> HashStable> for FieldPlacement { +impl<'a> HashStable> for FieldPlacement { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use ty::layout::FieldPlacement::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2428,9 +2428,9 @@ impl<'a, 'gcx> HashStable> for FieldPlacement { } } -impl<'a, 'gcx> HashStable> for Abi { +impl<'a> HashStable> for Abi { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use ty::layout::Abi::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -2455,9 +2455,9 @@ impl<'a, 'gcx> HashStable> for Abi { } } -impl<'a, 'gcx> HashStable> for Scalar { +impl<'a> HashStable> for Scalar { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let Scalar { value, valid_range: RangeInclusive { start, end } } = *self; value.hash_stable(hcx, hasher); @@ -2498,10 +2498,10 @@ impl_stable_hash_for!(struct ::ty::layout::Size { raw }); -impl<'a, 'gcx> HashStable> for LayoutError<'gcx> +impl<'a, 'gcx> HashStable> for LayoutError<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use ty::layout::LayoutError::*; mem::discriminant(self).hash_stable(hcx, hasher); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a95d053ab0735..19109504ebb62 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -544,9 +544,9 @@ impl<'tcx> TyS<'tcx> { } } -impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { +impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TyS { ref sty, @@ -1395,11 +1395,11 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> { } } -impl<'a, 'gcx, T> HashStable> for ParamEnvAnd<'gcx, T> - where T: HashStable> +impl<'a, 'gcx, T> HashStable> for ParamEnvAnd<'gcx, T> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ParamEnvAnd { ref param_env, @@ -1500,9 +1500,9 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} -impl<'a, 'gcx> HashStable> for AdtDef { +impl<'a> HashStable> for AdtDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { static CACHE: RefCell> = diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index a44f7ff4fd98f..9c9ce17d8ad0e 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -186,9 +186,9 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -impl<'a, 'gcx> HashStable> for TraitImpls { +impl<'a> HashStable> for TraitImpls { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let TraitImpls { ref blanket_impls, diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index e3e486ffce0f8..6b020903d0055 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -225,9 +225,9 @@ pub struct TraitImpls { pub impls: LazySeq, } -impl<'a, 'gcx> HashStable> for TraitImpls { +impl<'a, 'gcx> HashStable> for TraitImpls { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let TraitImpls { trait_id: (krate, def_index), @@ -308,9 +308,9 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } -impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { +impl<'a, 'gcx> HashStable> for EntryKind<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { From 6aa6189704b88c1c5ec77e3e34616f08a5914e0a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 Jan 2018 11:33:51 +0100 Subject: [PATCH 022/115] Use the correct span for error reporting in MIR --- src/librustc_mir/transform/instcombine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index e27e7c72473be..b66375bb662d6 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -514,7 +514,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { let place_ty = place .ty(&self.mir.local_decls, self.tcx) .to_ty(self.tcx); - let span = self.mir.source_info(location).span; + let span = statement.source_info.span; if let Some(value) = self.const_prop(rval, place_ty, span) { self.optimizations.const_prop.insert(location, value); if let Place::Local(local) = *place { From 1374efd1c872977f7aa6469ef6f4dca3fe520f5c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 Jan 2018 13:44:06 +0100 Subject: [PATCH 023/115] Reference patterns should use PartialEq for figuring out the matching logic --- src/librustc_mir/build/matches/test.rs | 8 ++----- src/test/ui/const-expr-addr-operator.stderr | 23 --------------------- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 30c70ac30a70b..d4974f14d0a35 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -354,15 +354,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }), val) }; - // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. + // Use PartialEq::eq for references, instead of BinOp::Eq. let fail = self.cfg.start_new_block(); let str_or_bytestr = ty .builtin_deref(true, ty::NoPreference) - .and_then(|tam| match tam.ty.sty { - ty::TyStr => Some(tam.ty), - ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty), - _ => None, - }); + .map(|tam| tam.ty); if let Some(ty) = str_or_bytestr { let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); diff --git a/src/test/ui/const-expr-addr-operator.stderr b/src/test/ui/const-expr-addr-operator.stderr index b40ce13f58f31..e69de29bb2d1d 100644 --- a/src/test/ui/const-expr-addr-operator.stderr +++ b/src/test/ui/const-expr-addr-operator.stderr @@ -1,23 +0,0 @@ -warning: constant evaluation error - --> $DIR/const-expr-addr-operator.rs:17:5 - | -17 | / assert_eq!(0, match &22 { -18 | | X => 0, -19 | | _ => 1, -20 | | }); - | |_______^ machine error: "Pointer arithmetic or comparison" needs an rfc before being allowed inside constants - | - = note: #[warn(const_err)] on by default -note: inside call to main - --> $DIR/const-expr-addr-operator.rs:14:1 - | -14 | / pub fn main() { -15 | | // Constant of generic type (int) -16 | | const X: &'static u32 = &22; -17 | | assert_eq!(0, match &22 { -... | -20 | | }); -21 | | } - | |_^ - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - From 8f690c4dad20ab26e903a3228da5771d52f9979e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 Jan 2018 13:45:11 +0100 Subject: [PATCH 024/115] Const propagation often marks terminator operands as constant --- src/librustc_mir/transform/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 563405fccc970..ff3b5888e340c 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -256,6 +256,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx // Optimizations begin. inline::Inline, instcombine::InstCombine, + simplify_branches::SimplifyBranches::new("after-const-prop"), deaggregator::Deaggregator, copy_prop::CopyPropagation, remove_noop_landing_pads::RemoveNoopLandingPads, From e3f6e150c21e854917f9008c2c380497fa4ca9f7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 17 Jan 2018 13:51:11 +0100 Subject: [PATCH 025/115] Use the correct spans for const error reporting --- src/librustc_mir/interpret/const_eval.rs | 9 ++-- src/librustc_mir/interpret/eval_context.rs | 12 +++-- src/librustc_mir/transform/instcombine.rs | 52 +++++++++++----------- src/test/compile-fail/const-err2.rs | 4 +- src/test/compile-fail/const-err3.rs | 3 +- 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 5b7d6fff3f930..d7abb58d2aa70 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -19,6 +19,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, mir: &'mir mir::Mir<'tcx>, + span: Span, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { debug!("mk_borrowck_eval_cx: {:?}", instance); let param_env = tcx.param_env(instance.def_id()); @@ -27,7 +28,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( instance, - mir.span, + span, mir, Place::undef(), StackPopCleanup::None, @@ -65,7 +66,7 @@ pub fn eval_body_with_mir<'a, 'mir, 'tcx>( match res { Ok(val) => Some(val), Err(mut err) => { - ecx.report(&mut err, true); + ecx.report(&mut err, true, None); None } } @@ -80,7 +81,7 @@ pub fn eval_body<'a, 'tcx>( match res { Ok(val) => Some(val), Err(mut err) => { - ecx.report(&mut err, true); + ecx.report(&mut err, true, None); None } } @@ -483,7 +484,7 @@ pub fn const_eval_provider<'a, 'tcx>( }) }).map_err(|mut err| { if tcx.is_static(def_id).is_some() { - ecx.report(&mut err, true); + ecx.report(&mut err, true, None); } ConstEvalErr { kind: err.into(), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ad91c58da9fb9..27bf856b7c752 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -10,7 +10,7 @@ use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs, Kind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; -use syntax::codemap::{self, DUMMY_SP}; +use syntax::codemap::{self, DUMMY_SP, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, @@ -1568,7 +1568,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } - pub fn report(&self, e: &mut EvalError, as_err: bool) { + pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { if let EvalErrorKind::TypeckError = e.kind { return; } @@ -1604,11 +1604,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } if let Some(frame) = self.stack().last() { let block = &frame.mir.basic_blocks()[frame.block]; - let span = if frame.stmt < block.statements.len() { + let span = explicit_span.unwrap_or_else(|| if frame.stmt < block.statements.len() { block.statements[frame.stmt].source_info.span } else { block.terminator().source_info.span - }; + }); + trace!("reporting const eval failure at {:?}", span); let node_id = self .stack() .iter() @@ -1630,6 +1631,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let mut last_span = None; for &Frame { instance, span, .. } in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous + if explicit_span == Some(span) { + continue; + } if let Some(last) = last_span { if last == span { continue; diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index b66375bb662d6..6079e1929b578 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -23,7 +23,7 @@ use rustc_data_structures::indexed_vec::Idx; use std::mem; use std::collections::VecDeque; use transform::{MirPass, MirSource}; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::Span; use rustc_data_structures::control_flow_graph::ControlFlowGraph; use rustc::ty::subst::Substs; @@ -147,7 +147,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { TerminatorKind::SwitchInt { discr: value, .. } | TerminatorKind::Yield { value, .. } | TerminatorKind::Assert { cond: value, .. } => { - if let Some((new, ty, span)) = self.optimizations.const_prop.remove(&location) { + if let Some((new, ty, span)) = self.optimizations.terminators.remove(&block) { let new = self.tcx.mk_const(ty::Const { val: ConstVal::Value(new), ty, @@ -190,13 +190,13 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } } - fn eval_constant(&mut self, c: &Constant<'tcx>, span: Span) -> Option> { + fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { if let Some(&val) = self.optimizations.constants.get(c) { return Some(val); } match c.literal { Literal::Value { value } => match value.val { - ConstVal::Value(v) => Some((v, value.ty, span)), + ConstVal::Value(v) => Some((v, value.ty, c.span)), ConstVal::Unevaluated(did, substs) => { let param_env = self.tcx.param_env(self.source.def_id); let span = self.tcx.def_span(did); @@ -230,10 +230,9 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { instance, promoted: Some(index), }; - let span = self.tcx.def_span(self.source.def_id); let param_env = self.tcx.param_env(self.source.def_id); let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; - let val = (value, ty, span); + let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); self.optimizations.constants.insert(c.clone(), val); Some(val) @@ -241,9 +240,9 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } } - fn eval_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option> { + fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, span), + Operand::Constant(ref c) => self.eval_constant(c), Operand::Move(ref place) | Operand::Copy(ref place) => match *place { Place::Local(loc) => self.optimizations.places.get(&loc).cloned(), // FIXME(oli-obk): field and index projections @@ -253,13 +252,13 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } } - fn simplify_operand(&mut self, op: &Operand<'tcx>, span: Span) -> Option> { + fn simplify_operand(&mut self, op: &Operand<'tcx>) -> Option> { match *op { Operand::Constant(ref c) => match c.literal { Literal::Value { .. } => None, - _ => self.eval_operand(op, span), + _ => self.eval_operand(op), }, - _ => self.eval_operand(op, span), + _ => self.eval_operand(op), } } @@ -270,7 +269,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { span: Span, ) -> Option> { match *rvalue { - Rvalue::Use(ref op) => self.simplify_operand(op, span), + Rvalue::Use(ref op) => self.simplify_operand(op), Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::Cast(..) | @@ -300,15 +299,15 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } let substs = Substs::identity_for_item(self.tcx, self.source.def_id); let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir).unwrap(); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - let val = self.eval_operand(arg, span)?; + let val = self.eval_operand(arg)?; let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; let kind = ecx.ty_to_primval_kind(val.1).ok()?; match unary_op(op, prim, kind) { Ok(val) => Some((Value::ByVal(val), place_ty, span)), Err(mut err) => { - ecx.report(&mut err, false); + ecx.report(&mut err, false, Some(span)); None }, } @@ -316,8 +315,8 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); - let left = self.eval_operand(left, span)?; - let right = self.eval_operand(right, span)?; + let left = self.eval_operand(left)?; + let right = self.eval_operand(right)?; let def_id = if self.tcx.is_closure(self.source.def_id) { self.tcx.closure_base_def_id(self.source.def_id) } else { @@ -331,7 +330,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } let substs = Substs::identity_for_item(self.tcx, self.source.def_id); let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir).unwrap(); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; @@ -351,7 +350,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { kind: EvalErrorKind::OverflowingMath, backtrace: None, }; - ecx.report(&mut err, false); + ecx.report(&mut err, false, Some(span)); return None; } Value::ByVal(val) @@ -359,7 +358,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { Some((val, place_ty, span)) }, Err(mut err) => { - ecx.report(&mut err, false); + ecx.report(&mut err, false, Some(span)); None }, } @@ -500,7 +499,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { ) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - self.eval_constant(constant, DUMMY_SP); + self.eval_constant(constant); } fn visit_statement( @@ -554,17 +553,16 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { fn visit_terminator_kind( &mut self, - _block: BasicBlock, + block: BasicBlock, kind: &TerminatorKind<'tcx>, - location: Location, + _location: Location, ) { - let span = self.mir.source_info(location).span; match kind { TerminatorKind::SwitchInt { discr: value, .. } | TerminatorKind::Yield { value, .. } | TerminatorKind::Assert { cond: value, .. } => { - if let Some(value) = self.simplify_operand(value, span) { - self.optimizations.const_prop.insert(location, value); + if let Some(value) = self.simplify_operand(value) { + self.optimizations.terminators.insert(block, value); } } // FIXME: do this optimization for function calls @@ -578,6 +576,8 @@ struct OptimizationList<'tcx> { and_stars: FxHashSet, arrays_lengths: FxHashMap>, const_prop: FxHashMap>, + /// Terminators that get their Operand(s) turned into constants. + terminators: FxHashMap>, places: FxHashMap>, constants: FxHashMap, Const<'tcx>>, } diff --git a/src/test/compile-fail/const-err2.rs b/src/test/compile-fail/const-err2.rs index a0648993aac74..09983f179266d 100644 --- a/src/test/compile-fail/const-err2.rs +++ b/src/test/compile-fail/const-err2.rs @@ -19,10 +19,12 @@ fn black_box(_: T) { fn main() { let a = -std::i8::MIN; //~^ ERROR const_err - //~| ERROR const_err let b = 200u8 + 200u8 + 200u8; + //~^ ERROR const_err let c = 200u8 * 4; + //~^ ERROR const_err let d = 42u8 - (42u8 + 1); + //~^ ERROR const_err let _e = [5u8][1]; black_box(a); black_box(b); diff --git a/src/test/compile-fail/const-err3.rs b/src/test/compile-fail/const-err3.rs index 636537d1df250..9656af6002442 100644 --- a/src/test/compile-fail/const-err3.rs +++ b/src/test/compile-fail/const-err3.rs @@ -18,9 +18,10 @@ fn black_box(_: T) { fn main() { let b = 200u8 + 200u8 + 200u8; //~^ ERROR const_err - //~| ERROR const_err let c = 200u8 * 4; + //~^ ERROR const_err let d = 42u8 - (42u8 + 1); + //~^ ERROR const_err let _e = [5u8][1]; black_box(b); black_box(c); From 61524349d579f3b24bf6489e46d4cef0290f876e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 18 Jan 2018 14:07:03 +0100 Subject: [PATCH 026/115] Don't treat references special --- src/librustc_mir/build/matches/test.rs | 138 +++++++++++++------------ 1 file changed, 73 insertions(+), 65 deletions(-) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index d4974f14d0a35..fb8a488796765 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -20,12 +20,10 @@ 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; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal}; -use rustc::hir::RangeEnd; +use rustc::hir::{RangeEnd, Mutability}; use syntax_pos::Span; use std::cmp::Ordering; @@ -297,72 +295,82 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::Eq { value, ty } => { let tcx = self.hir.tcx(); let mut val = Operand::Copy(place.clone()); - - let bytes = match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { - let is_array_ptr = ty - .builtin_deref(true, ty::NoPreference) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == self.hir.tcx().types.u8); - if is_array_ptr { - self.hir - .tcx() - .interpret_interner - .borrow() - .get_alloc(p.alloc_id) - .map(|alloc| &alloc.bytes[..]) - } else { - None - } - }, - _ => None, - }; - // If we're using b"..." as a pattern, we need to insert an - // unsizing coercion, as the byte string has the type &[u8; N]. - // - // We want to do this even when the scrutinee is a reference to an - // array, so we can call `<[u8]>::eq` rather than having to find an - // `<[u8; N]>::eq`. - let expect = if let Some(bytes) = bytes { - let tcx = self.hir.tcx(); - - // Unsize the place to &[u8], too, if necessary. - if let ty::TyRef(region, mt) = ty.sty { - if let ty::TyArray(_, _) = mt.ty.sty { - ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); - let val_slice = self.temp(ty, test.span); - self.cfg.push_assign(block, source_info, &val_slice, - Rvalue::Cast(CastKind::Unsize, val, ty)); - val = Operand::Move(val_slice); - } - } - - assert!(ty.is_slice()); - - let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64); - let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); - let array = self.literal_operand(test.span, array_ref, Literal::Value { - value - }); - - let val = self.to_slice_operand(block, source_info, val); - let slice = self.to_slice_operand(block, source_info, array); - (slice, val) - } else { - (self.literal_operand(test.span, ty, Literal::Value { - value - }), val) - }; - - // Use PartialEq::eq for references, instead of BinOp::Eq. + let mut expect = self.literal_operand(test.span, ty, Literal::Value { + value + }); + // Use PartialEq::eq instead of BinOp::Eq + // (the binop can only handle primitives) let fail = self.cfg.start_new_block(); - let str_or_bytestr = ty - .builtin_deref(true, ty::NoPreference) - .map(|tam| tam.ty); - if let Some(ty) = str_or_bytestr { + if !ty.is_scalar() { + // If we're using b"..." as a pattern, we need to insert an + // unsizing coercion, as the byte string has the type &[u8; N]. + // + // We want to do this even when the scrutinee is a reference to an + // array, so we can call `<[u8]>::eq` rather than having to find an + // `<[u8; N]>::eq`. + let unsize = |ty: Ty<'tcx>| match ty.sty { + ty::TyRef(region, tam) => match tam.ty.sty { + ty::TyArray(inner_ty, n) => Some((region, inner_ty, n)), + _ => None, + }, + _ => None, + }; + let opt_ref_ty = unsize(ty); + let opt_ref_test_ty = unsize(value.ty); + let mut place = place.clone(); + match (opt_ref_ty, opt_ref_test_ty) { + // nothing to do, neither is an array + (None, None) => {}, + (Some((region, elem_ty, _)), _) | + (None, Some((region, elem_ty, _))) => { + let tcx = self.hir.tcx(); + // make both a slice + ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); + if opt_ref_ty.is_some() { + place = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &place, + Rvalue::Cast(CastKind::Unsize, val, ty)); + } + if opt_ref_test_ty.is_some() { + let array = self.literal_operand(test.span, value.ty, Literal::Value { + value + }); + + let slice = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &slice, + Rvalue::Cast(CastKind::Unsize, array, ty)); + expect = Operand::Move(slice); + } + }, + } let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); + // take the argument by reference + let region_scope = self.topmost_scope(); + let region = self.hir.tcx().mk_region(ty::ReScope(region_scope)); + let tam = ty::TypeAndMut { + ty, + mutbl: Mutability::MutImmutable, + }; + let ref_ty = self.hir.tcx().mk_ref(region, tam); + + // let lhs_ref_place = &lhs; + let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, place.clone()); + let lhs_ref_place = self.temp(ref_ty, test.span); + self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue); + let val = Operand::Move(lhs_ref_place); + + // let rhs_place = rhs; + let rhs_place = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect)); + + // let rhs_ref_place = &rhs_place; + let ref_rvalue = Rvalue::Ref(region, BorrowKind::Shared, rhs_place); + let rhs_ref_place = self.temp(ref_ty, test.span); + self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue); + let expect = Operand::Move(rhs_ref_place); + let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty, test.span); let eq_block = self.cfg.start_new_block(); From 9a9a8e7edc92005a7cba3f788085ed0156eff0b4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 18 Jan 2018 14:14:55 +0100 Subject: [PATCH 027/115] Add test for matching on constants with reference type --- src/librustc_mir/build/matches/test.rs | 10 +++++--- src/test/run-pass/ctfe/references.rs | 34 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/ctfe/references.rs diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index fb8a488796765..067041b14f583 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -332,9 +332,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Rvalue::Cast(CastKind::Unsize, val, ty)); } if opt_ref_test_ty.is_some() { - let array = self.literal_operand(test.span, value.ty, Literal::Value { - value - }); + let array = self.literal_operand( + test.span, + value.ty, + Literal::Value { + value + }, + ); let slice = self.temp(ty, test.span); self.cfg.push_assign(block, source_info, &slice, diff --git a/src/test/run-pass/ctfe/references.rs b/src/test/run-pass/ctfe/references.rs new file mode 100644 index 0000000000000..ad7dbeb79c721 --- /dev/null +++ b/src/test/run-pass/ctfe/references.rs @@ -0,0 +1,34 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: &[u8] = b"foo"; +const BAR: &[u8] = &[1, 2, 3]; + +const BOO: &i32 = &42; + +fn main() { + match &[1u8, 2, 3] as &[u8] { + FOO => panic!("a"), + BAR => println!("b"), + _ => panic!("c"), + } + + match b"foo" as &[u8] { + FOO => println!("a"), + BAR => panic!("b"), + _ => panic!("c"), + } + + match &43 { + &42 => panic!(), + BOO => panic!(), + _ => println!("d"), + } +} From 29daa4fc4393a0086c66f6e0132661f9ebd5b50d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 19 Jan 2018 12:01:14 +0100 Subject: [PATCH 028/115] Fix typo --- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/interpret/memory.rs | 6 +++--- src/librustc_mir/interpret/traits.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 27bf856b7c752..5509c6161e485 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -464,7 +464,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M StackPopCleanup::MarkStatic(mutable) => { if let Place::Ptr { ptr, .. } = frame.return_place { // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions - self.memory.mark_static_initalized( + self.memory.mark_static_initialized( ptr.to_ptr()?.alloc_id, mutable, )? diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 63c0c950dd49b..85d76b34942f2 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -520,18 +520,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // do not go into statics None => Ok(()), // just locals and machine allocs - Some(_) => self.mark_static_initalized(alloc, mutability), + Some(_) => self.mark_static_initialized(alloc, mutability), } } /// mark an allocation as static and initialized, either mutable or not - pub fn mark_static_initalized( + pub fn mark_static_initialized( &mut self, alloc_id: AllocId, mutability: Mutability, ) -> EvalResult<'tcx> { trace!( - "mark_static_initalized {:?}, mutability: {:?}", + "mark_static_initialized {:?}, mutability: {:?}", alloc_id, mutability ); diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 4dc0879c85d52..03b215fa0b8ea 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -52,7 +52,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } } - self.memory.mark_static_initalized( + self.memory.mark_static_initialized( vtable.alloc_id, Mutability::Immutable, )?; From 27044e83db4f19b62163d32df7d918f9c6981bad Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 22 Jan 2018 10:21:22 +0100 Subject: [PATCH 029/115] Print whether the stackframe is for a promoted --- src/librustc_mir/interpret/const_eval.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index d7abb58d2aa70..d3d7f34e62c08 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -132,7 +132,9 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( }; let cleanup = StackPopCleanup::MarkStatic(mutability); let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - trace!("const_eval: pushing stack frame for global: {}", name); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); ecx.push_stack_frame( cid.instance, mir.span, From e5ea3c55e51c4a388d0462eb77d4c023d171e1af Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 22 Jan 2018 10:21:49 +0100 Subject: [PATCH 030/115] Additional sanity assertion --- src/librustc_mir/interpret/memory.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 85d76b34942f2..fecf8c58c089a 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -518,7 +518,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> EvalResult<'tcx> { match self.alloc_kind.get(&alloc) { // do not go into statics - None => Ok(()), + None => Ok(()), // just locals and machine allocs Some(_) => self.mark_static_initialized(alloc, mutability), } @@ -555,6 +555,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { for &alloc in alloc.relocations.values() { self.mark_inner_allocation_initialized(alloc, mutability)?; } + } else { + bug!("no allocation found for {:?}", alloc_id); } Ok(()) } From d0716f0b69ecef7b12e7bda1a995b12e95632d2a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 23 Jan 2018 16:36:55 +0100 Subject: [PATCH 031/115] Enable const prop to also evaluate constants, not just literals --- src/librustc_mir/transform/instcombine.rs | 64 ++++++++++++++++------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 6079e1929b578..25787608e39ca 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,7 +11,7 @@ //! Performs various peephole optimizations. use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}; -use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock}; +use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::{SourceInfo, ARGUMENT_VISIBILITY_SCOPE, TerminatorKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::middle::const_val::ConstVal; @@ -34,6 +34,7 @@ impl MirPass for InstCombine { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, mir: &mut Mir<'tcx>) { + trace!("InstCombine starting for {:?}", source.def_id); // First, find optimization opportunities. This is done in a pre-pass to keep the MIR // read-only so that we can do global analyses on the MIR in the process (e.g. @@ -46,6 +47,7 @@ impl MirPass for InstCombine { // Then carry out those optimizations. MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations, tcx }, mir); + trace!("InstCombine done for {:?}", source.def_id); } } @@ -199,7 +201,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { ConstVal::Value(v) => Some((v, value.ty, c.span)), ConstVal::Unevaluated(did, substs) => { let param_env = self.tcx.param_env(self.source.def_id); - let span = self.tcx.def_span(did); let instance = Instance::resolve( self.tcx, param_env, @@ -211,7 +212,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { promoted: None, }; let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; - let val = (value, ty, span); + let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); self.optimizations.constants.insert(c.clone(), val); Some(val) @@ -269,7 +270,24 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { span: Span, ) -> Option> { match *rvalue { - Rvalue::Use(ref op) => self.simplify_operand(op), + // No need to overwrite an already evaluated constant + Rvalue::Use(Operand::Constant(box Constant { + literal: Literal::Value { + value: &ty::Const { + val: ConstVal::Value(_), + .. + }, + }, + .. + })) => None, + // This branch exists for the sanity type check + Rvalue::Use(Operand::Constant(ref c)) => { + assert_eq!(c.ty, place_ty); + self.eval_constant(c) + }, + Rvalue::Use(ref op) => { + self.eval_operand(op) + }, Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::Cast(..) | @@ -392,6 +410,17 @@ impl ConstPropVisitor { cpv.visit_mir(mir); cpv.can_const_prop } + + fn is_our_local(&mut self, mut place: &Place) -> bool { + while let Place::Projection(ref proj) = place { + place = &proj.base; + } + if let Place::Local(local) = *place { + local == self.local + } else { + false + } + } } impl<'tcx> Visitor<'tcx> for ConstPropVisitor { @@ -403,9 +432,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { ) { self.super_statement(block, statement, location); match statement.kind { - StatementKind::SetDiscriminant { place: Place::Local(local), .. } | - StatementKind::Assign(Place::Local(local), _) => { - if local == self.local { + StatementKind::SetDiscriminant { ref place, .. } | + StatementKind::Assign(ref place, _) => { + if self.is_our_local(place) { if self.found_assignment { self.can_const_prop = false; } else { @@ -415,15 +444,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { }, StatementKind::InlineAsm { ref outputs, .. } => { for place in outputs { - if let Place::Local(local) = *place { - if local == self.local { - if self.found_assignment { - self.can_const_prop = false; - } else { - self.found_assignment = true - } - return; + if self.is_our_local(place) { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true } + return; } } } @@ -432,8 +459,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - if let Rvalue::Ref(_, _, Place::Local(local)) = *rvalue { - if local == self.local { + if let Rvalue::Ref(_, _, ref place) = *rvalue { + if self.is_our_local(place) { self.can_const_prop = false; } } @@ -517,12 +544,13 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { if let Some(value) = self.const_prop(rval, place_ty, span) { self.optimizations.const_prop.insert(location, value); if let Place::Local(local) = *place { - if !self.mir.local_decls[local].is_user_variable + if self.mir.local_kind(local) == LocalKind::Temp && ConstPropVisitor::check(local, self.mir) { trace!("storing {:?} to {:?}", value, local); assert!(self.optimizations.places.insert(local, value).is_none()); } } + return; } } self.super_statement(block, statement, location); From 19cdcfe6c8f9dad2cee91ced97d2276904bd495c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 23 Jan 2018 16:37:39 +0100 Subject: [PATCH 032/115] More const eval sanity checks (invalid slice fat pointers) --- src/librustc_mir/interpret/eval_context.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 5509c6161e485..7a24d84a44ce8 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1259,9 +1259,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ty::TyDynamic(..) => Ok(p.to_value_with_vtable( self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?, )), - ty::TySlice(..) | ty::TyStr => Ok( - p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64), - ), + ty::TySlice(..) | ty::TyStr => { + match p.primval { + PrimVal::Bytes(b) => bug!("slice ptr: {:x}", b), + PrimVal::Undef => bug!("undef slice ptr"), + _ => {}, + } + Ok( + p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64), + ) + }, _ => bug!("unsized primval ptr read from {:?}", pointee_ty), } } From d1ed0c8ab3312a29a02be8964d4232e3e002ec8a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 23 Jan 2018 18:25:44 +0100 Subject: [PATCH 033/115] Rebase fallout --- src/librustc_mir/build/matches/test.rs | 36 +------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 067041b14f583..3b9fbc5c867a1 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -173,39 +173,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - /// Convert a byte array or byte slice to a byte slice. - fn to_slice_operand(&mut self, - block: BasicBlock, - source_info: SourceInfo, - operand: Operand<'tcx>) - -> Operand<'tcx> - { - let tcx = self.hir.tcx(); - let ty = operand.ty(&self.local_decls, tcx); - debug!("to_slice_operand({:?}, {:?}: {:?})", block, operand, ty); - match ty.sty { - ty::TyRef(region, mt) => match mt.ty.sty { - ty::TyArray(ety, _) => { - let ty = tcx.mk_imm_ref(region, tcx.mk_slice(ety)); - let temp = self.temp(ty, source_info.span); - self.cfg.push_assign(block, source_info, &temp, - Rvalue::Cast(CastKind::Unsize, operand, ty)); - Operand::Move(temp) - } - ty::TySlice(_) => operand, - _ => { - span_bug!(source_info.span, - "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty) - } - } - _ => { - span_bug!(source_info.span, - "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty) - } - } - - } - /// Generates the code to perform a test. pub fn perform_test(&mut self, block: BasicBlock, @@ -292,8 +259,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ret } - TestKind::Eq { value, ty } => { - let tcx = self.hir.tcx(); + TestKind::Eq { value, mut ty } => { let mut val = Operand::Copy(place.clone()); let mut expect = self.literal_operand(test.span, ty, Literal::Value { value From 55d46ec15e8d84213c2e146779a6a437ca067e3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 08:06:53 +0100 Subject: [PATCH 034/115] Allow writing mutable statics in miri by adding them to the Machine --- src/librustc_mir/interpret/const_eval.rs | 24 +++++++++++++++++- src/librustc_mir/interpret/eval_context.rs | 27 +++++++++----------- src/librustc_mir/interpret/machine.rs | 9 ++++++- src/librustc_mir/interpret/place.rs | 29 +++------------------- 4 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index d3d7f34e62c08..c7669c298ff5c 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,6 +1,7 @@ use rustc::hir; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError}; +use rustc::traits; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; use rustc::ty::layout::{self, LayoutOf}; @@ -326,6 +327,27 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { Ok(false) } + fn init_static<'a>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + cid: GlobalId<'tcx>, + ) -> EvalResult<'tcx, AllocId> { + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + // ensure the static is computed + if let Err(err) = ecx.tcx.const_eval(param_env.and(cid)) { + match err.kind { + ErrKind::Miri(miri) => return Err(miri), + ErrKind::TypeckError => return err!(TypeckError), + other => bug!("const eval returned {:?}", other), + } + }; + Ok(ecx + .tcx + .interpret_interner + .borrow() + .get_cached(cid.instance.def_id()) + .expect("uncached static")) + } + fn box_alloc<'a>( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _ty: Ty<'tcx>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 7a24d84a44ce8..aea6ebf01bdd6 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1260,14 +1260,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_ptr()?, )), ty::TySlice(..) | ty::TyStr => { - match p.primval { - PrimVal::Bytes(b) => bug!("slice ptr: {:x}", b), - PrimVal::Undef => bug!("undef slice ptr"), - _ => {}, - } - Ok( - p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra, ptr_align)?.to_bytes()? as u64), - ) + let len = self + .memory + .read_ptr_sized_unsigned(extra, ptr_align)? + .to_bytes()?; + Ok(p.to_value_with_len(len as u64)) }, _ => bug!("unsized primval ptr read from {:?}", pointee_ty), } @@ -1617,16 +1614,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M block.terminator().source_info.span }); trace!("reporting const eval failure at {:?}", span); - let node_id = self - .stack() - .iter() - .rev() - .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id())) - .next() - .expect("some part of a failing const eval must be local"); let mut err = if as_err { ::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error") } else { + let node_id = self + .stack() + .iter() + .rev() + .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id())) + .next() + .expect("some part of a failing const eval must be local"); self.tcx.struct_span_lint_node( ::rustc::lint::builtin::CONST_ERR, node_id, diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index d5e57d3317c55..5af0a053e9239 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -2,7 +2,7 @@ //! This separation exists to ensure that no fancy miri features like //! interpreting common C functions leak into CTFE. -use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind}; +use rustc::mir::interpret::{AllocId, EvalResult, PrimVal, MemoryPointer, AccessKind, GlobalId}; use super::{EvalContext, Place, ValTy, Memory}; use rustc::mir; @@ -66,6 +66,13 @@ pub trait Machine<'mir, 'tcx>: Sized { _mutability: Mutability, ) -> EvalResult<'tcx, bool>; + /// Called when requiring a pointer to a static. Non const eval can + /// create a mutable memory location for `static mut` + fn init_static<'a>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + cid: GlobalId<'tcx>, + ) -> EvalResult<'tcx, AllocId>; + /// Heap allocations via the `box` keyword /// /// Returns a pointer to the allocated memory diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 349ac63055992..12725fb6dff75 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1,13 +1,11 @@ use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; -use rustc::traits; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer}; use super::{EvalContext, Machine, ValTy}; use interpret::memory::HasMemory; -use rustc::middle::const_val::ErrKind; #[derive(Copy, Clone, Debug)] pub enum Place { @@ -105,14 +103,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Local(mir::RETURN_PLACE) => err!(ReadFromReturnPointer), // Directly reading a local will always succeed Local(local) => self.frame().get_local(local).map(Some), - // Directly reading a static will always succeed - Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - self.read_global_as_value(GlobalId { - instance, - promoted: None, - }, self.place_ty(place)).map(Some) - } + // No fast path for statics. Reading from statics is rare and would require another + // Machine function to handle differently in miri. + Static(_) => Ok(None), Projection(ref proj) => self.try_read_place_projection(proj), } } @@ -219,21 +212,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { instance, promoted: None }; - let param_env = ty::ParamEnv::empty(traits::Reveal::All); - // ensure the static is computed - if let Err(err) = self.tcx.const_eval(param_env.and(cid)) { - match err.kind { - ErrKind::Miri(miri) => return Err(miri), - ErrKind::TypeckError => return err!(TypeckError), - other => bug!("const eval returned {:?}", other), - } - }; - let alloc = self - .tcx - .interpret_interner - .borrow() - .get_cached(static_.def_id) - .expect("uncached static"); + let alloc = Machine::init_static(self, cid)?; Place::Ptr { ptr: MemoryPointer::new(alloc, 0).into(), align: layout.align, From bae7b9081a5b3086c2efc995da7aca4342effecf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 09:04:00 +0100 Subject: [PATCH 035/115] Allow tools (e.g. miri) to enable rust logging --- src/librustc_driver/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9522edd044da8..541b432eb8892 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1505,8 +1505,14 @@ pub fn diagnostics_registry() -> errors::registry::Registry { Registry::new(&all_errors) } -pub fn main() { +/// This allows tools to enable rust logging without having to magically match rustc's +/// log crate version +pub fn init_rustc_env_logger() { env_logger::init().unwrap(); +} + +pub fn main() { + init_rustc_env_logger(); let result = run(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { From caaf6cddf9af933acf7885de930e2aa20992c910 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 12:12:07 +0100 Subject: [PATCH 036/115] Don't borrow the interpret_interner for anything but a direct function call --- src/librustc/ty/maps/on_disk_cache.rs | 7 +++---- src/librustc_metadata/encoder.rs | 9 ++++----- src/librustc_mir/interpret/memory.rs | 5 ++--- src/librustc_mir/monomorphize/collector.rs | 5 ++--- src/librustc_trans/mir/constant.rs | 12 ++++++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 2522b70a5ba1f..dcc2e4280f5bd 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -793,15 +793,14 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder< // cache the allocation shorthand now, because the allocation itself might recursively // point to itself. self.interpret_alloc_shorthands.insert(*alloc_id, start); - let interpret_interner = self.tcx.interpret_interner.borrow(); - if let Some(alloc) = interpret_interner.get_alloc(*alloc_id) { + if let Some(alloc) = self.tcx.interpret_interner.borrow().get_alloc(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - interpret_interner + self.tcx.interpret_interner.borrow() .get_corresponding_static_def_id(*alloc_id) .encode(self)?; - } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) { + } else if let Some(fn_instance) = self.tcx.interpret_interner.borrow().get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 953e2e41b417f..5a72af1255829 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -204,15 +204,14 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx // cache the allocation shorthand now, because the allocation itself might recursively // point to itself. self.interpret_alloc_shorthands.insert(*alloc_id, start); - let interpret_interner = self.tcx.interpret_interner.borrow(); - if let Some(alloc) = interpret_interner.get_alloc(*alloc_id) { + if let Some(alloc) = self.tcx.interpret_interner.borrow().get_alloc(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - interpret_interner + self.tcx.interpret_interner.borrow() .get_corresponding_static_def_id(*alloc_id) .encode(self)?; - } else if let Some(fn_instance) = interpret_interner.get_fn(*alloc_id) { + } else if let Some(fn_instance) = self.tcx.interpret_interner.borrow().get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; @@ -1153,7 +1152,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => None, }, mir: match item.node { - hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => { + hir::ItemStatic(..) => { self.encode_optimized_mir(def_id) } hir::ItemConst(..) => self.encode_optimized_mir(def_id), diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index fecf8c58c089a..f204ddc46a5cc 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -375,11 +375,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { None => match self.uninitialized_statics.get(&id) { Some(a) => (a, " (static in the process of initialization)".to_owned()), None => { - let int = self.tcx.interpret_interner.borrow(); // static alloc? - match int.get_alloc(id) { + match self.tcx.interpret_interner.borrow().get_alloc(id) { Some(a) => (a, "(immutable)".to_owned()), - None => if let Some(func) = int.get_fn(id) { + None => if let Some(func) = self.tcx.interpret_interner.borrow().get_fn(id) { trace!("{} {}", msg, func); continue; } else { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 3a665ba4f6c07..809dc077204ab 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1120,13 +1120,12 @@ fn collect_miri<'a, 'tcx>( alloc_id: AllocId, output: &mut Vec>, ) { - let interpret_interner = tcx.interpret_interner.borrow(); - if let Some(alloc) = interpret_interner.get_alloc(alloc_id) { + if let Some(alloc) = tcx.interpret_interner.borrow().get_alloc(alloc_id) { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &inner in alloc.relocations.values() { collect_miri(tcx, inner, output); } - } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id) { + } else if let Some(fn_instance) = tcx.interpret_interner.borrow().get_fn(alloc_id) { if should_monomorphize_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(fn_instance)); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index be5cb311b9cc2..1ca9bd81893aa 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -151,15 +151,19 @@ pub fn primval_to_llvm(cx: &CodegenCx, } }, PrimVal::Ptr(ptr) => { - let interpret_interner = cx.tcx.interpret_interner.borrow(); - if let Some(fn_instance) = interpret_interner.get_fn(ptr.alloc_id) { + if let Some(fn_instance) = cx.tcx.interpret_interner.borrow().get_fn(ptr.alloc_id) { callee::get_fn(cx, fn_instance) } else { - let static_ = interpret_interner.get_corresponding_static_def_id(ptr.alloc_id); + let static_ = cx + .tcx + .interpret_interner + .borrow() + .get_corresponding_static_def_id(ptr.alloc_id); let base_addr = if let Some(def_id) = static_ { assert!(cx.tcx.is_static(def_id).is_some()); consts::get_static(cx, def_id) - } else if let Some(alloc) = interpret_interner.get_alloc(ptr.alloc_id) { + } else if let Some(alloc) = cx.tcx.interpret_interner.borrow() + .get_alloc(ptr.alloc_id) { let init = global_initializer(cx, alloc); if alloc.mutable { consts::addr_of_mut(cx, init, alloc.align, "byte_str") From bfd5a2867c7d1310c7be6efad61d533f1a4c5421 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 12:12:19 +0100 Subject: [PATCH 037/115] Don't read from zero sized fields --- src/librustc_mir/interpret/place.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 12725fb6dff75..dd8dfbfe92690 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -123,6 +123,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } let field_index = field.index(); let field = base_layout.field(self, field_index)?; + if field.size.bytes() == 0 { + return Ok(Some((Value::ByVal(PrimVal::Undef), field.ty))) + } let offset = base_layout.fields.offset(field_index); match base { // the field covers the entire type From 74ec6fda43a6a00b199cc7338051856ae0bf2e8f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 12:59:24 +0100 Subject: [PATCH 038/115] Hide the RefCell inside InterpretInterner It was too easy to get this wrong --- src/librustc/ich/impls_ty.rs | 9 +-- src/librustc/mir/mod.rs | 1 - src/librustc/ty/context.rs | 57 +++++++++++-------- src/librustc/ty/maps/on_disk_cache.rs | 15 +++-- src/librustc_metadata/decoder.rs | 11 ++-- src/librustc_metadata/encoder.rs | 6 +- .../borrow_check/nll/type_check/mod.rs | 3 +- src/librustc_mir/const_eval/_match.rs | 4 -- src/librustc_mir/interpret/const_eval.rs | 11 ++-- src/librustc_mir/interpret/eval_context.rs | 1 - src/librustc_mir/interpret/memory.rs | 25 ++++---- src/librustc_mir/interpret/place.rs | 1 - src/librustc_mir/monomorphize/collector.rs | 4 +- src/librustc_trans/mir/constant.rs | 7 +-- 14 files changed, 71 insertions(+), 84 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 532080710ea24..b9d896166fde2 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -355,18 +355,15 @@ impl<'a> HashStable> for mir::interpret::AllocId { ) { ty::tls::with_opt(|tcx| { let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - let interner = tcx - .interpret_interner - .borrow(); - if let Some(def_id) = interner.get_corresponding_static_def_id(*self) { + if let Some(def_id) = tcx.interpret_interner.get_corresponding_static_def_id(*self) { 0.hash_stable(hcx, hasher); // statics are unique via their DefId def_id.hash_stable(hcx, hasher); - } else if let Some(alloc) = interner.get_alloc(*self) { + } else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) { // not a static, can't be recursive, hash the allocation 1.hash_stable(hcx, hasher); alloc.hash_stable(hcx, hasher); - } else if let Some(inst) = interner.get_fn(*self) { + } else if let Some(inst) = tcx.interpret_interner.get_fn(*self) { 2.hash_stable(hcx, hasher); inst.hash_stable(hcx, hasher); } else { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 97aeba75ec4f3..37d1239110012 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1798,7 +1798,6 @@ pub fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Resul ty::tls::with(|tcx| { let alloc = tcx .interpret_interner - .borrow() .get_alloc(ptr.alloc_id); if let Some(alloc) = alloc { assert_eq!(len as usize as u128, len); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 87c446e780e3a..80708808f5633 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -868,7 +868,7 @@ pub struct GlobalCtxt<'tcx> { stability_interner: RefCell>, - pub interpret_interner: RefCell>, + pub interpret_interner: InterpretInterner<'tcx>, layout_interner: RefCell>, @@ -892,6 +892,11 @@ pub struct GlobalCtxt<'tcx> { /// Everything needed to efficiently work with interned allocations #[derive(Debug, Default)] pub struct InterpretInterner<'tcx> { + inner: RefCell>, +} + +#[derive(Debug, Default)] +struct InterpretInternerInner<'tcx> { /// Stores the value of constants (and deduplicates the actual memory) allocs: FxHashSet<&'tcx interpret::Allocation>, @@ -924,14 +929,15 @@ pub struct InterpretInterner<'tcx> { } impl<'tcx> InterpretInterner<'tcx> { - pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> interpret::AllocId { - if let Some(&alloc_id) = self.function_cache.get(&instance) { + pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> interpret::AllocId { + if let Some(&alloc_id) = self.inner.borrow().function_cache.get(&instance) { return alloc_id; } let id = self.reserve(); debug!("creating fn ptr: {}", id); - self.functions.insert(id, instance); - self.function_cache.insert(instance, id); + let mut inner = self.inner.borrow_mut(); + inner.functions.insert(id, instance); + inner.function_cache.insert(instance, id); id } @@ -939,30 +945,31 @@ impl<'tcx> InterpretInterner<'tcx> { &self, id: interpret::AllocId, ) -> Option> { - self.functions.get(&id).cloned() + self.inner.borrow().functions.get(&id).cloned() } pub fn get_alloc( &self, id: interpret::AllocId, ) -> Option<&'tcx interpret::Allocation> { - self.alloc_by_id.get(&id).cloned() + self.inner.borrow().alloc_by_id.get(&id).cloned() } pub fn get_cached( &self, static_id: DefId, ) -> Option { - self.alloc_cache.get(&static_id).cloned() + self.inner.borrow().alloc_cache.get(&static_id).cloned() } pub fn cache( - &mut self, + &self, static_id: DefId, alloc_id: interpret::AllocId, ) { - self.global_cache.insert(alloc_id, static_id); - if let Some(old) = self.alloc_cache.insert(static_id, alloc_id) { + let mut inner = self.inner.borrow_mut(); + inner.global_cache.insert(alloc_id, static_id); + if let Some(old) = inner.alloc_cache.insert(static_id, alloc_id) { bug!("tried to cache {:?}, but was already existing as {:#?}", static_id, old); } } @@ -971,15 +978,15 @@ impl<'tcx> InterpretInterner<'tcx> { &self, ptr: interpret::AllocId, ) -> Option { - self.global_cache.get(&ptr).cloned() + self.inner.borrow().global_cache.get(&ptr).cloned() } pub fn intern_at_reserved( - &mut self, + &self, id: interpret::AllocId, alloc: &'tcx interpret::Allocation, ) { - if let Some(old) = self.alloc_by_id.insert(id, alloc) { + if let Some(old) = self.inner.borrow_mut().alloc_by_id.insert(id, alloc) { bug!("tried to intern allocation at {}, but was already existing as {:#?}", id, old); } } @@ -987,10 +994,11 @@ impl<'tcx> InterpretInterner<'tcx> { /// obtains a new allocation ID that can be referenced but does not /// yet have an allocation backing it. pub fn reserve( - &mut self, + &self, ) -> interpret::AllocId { - let next = self.next_id; - self.next_id.0 = self.next_id.0 + let mut inner = self.inner.borrow_mut(); + let next = inner.next_id; + inner.next_id.0 = inner.next_id.0 .checked_add(1) .expect("You overflowed a u64 by incrementing by 1... \ You've just earned yourself a free drink if we ever meet. \ @@ -1070,12 +1078,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self, alloc: interpret::Allocation, ) -> &'gcx interpret::Allocation { - if let Some(alloc) = self.interpret_interner.borrow().allocs.get(&alloc) { + if let Some(alloc) = self.interpret_interner.inner.borrow().allocs.get(&alloc) { return alloc; } let interned = self.global_arenas.const_allocs.alloc(alloc); - if let Some(prev) = self.interpret_interner.borrow_mut().allocs.replace(interned) { + if let Some(prev) = self.interpret_interner.inner.borrow_mut().allocs.replace(interned) { bug!("Tried to overwrite interned Allocation: {:#?}", prev) } interned @@ -1084,20 +1092,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Allocates a byte or string literal for `mir::interpret` pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId { // check whether we already allocated this literal or a constant with the same memory - if let Some(&alloc_id) = self.interpret_interner.borrow().literal_alloc_cache.get(bytes) { + if let Some(&alloc_id) = self.interpret_interner.inner.borrow().literal_alloc_cache.get(bytes) { return alloc_id; } // create an allocation that just contains these bytes let alloc = interpret::Allocation::from_bytes(bytes); let alloc = self.intern_const_alloc(alloc); - let mut int = self.interpret_interner.borrow_mut(); // the next unique id - let id = int.reserve(); + let id = self.interpret_interner.reserve(); // make the allocation identifiable - int.alloc_by_id.insert(id, alloc); + self.interpret_interner.inner.borrow_mut().alloc_by_id.insert(id, alloc); // cache it for the future - int.literal_alloc_cache.insert(bytes.to_owned(), id); + self.interpret_interner.inner.borrow_mut().literal_alloc_cache.insert(bytes.to_owned(), id); id } @@ -1724,7 +1731,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("Region interner: #{}", self.interners.region.borrow().len()); println!("Stability interner: #{}", self.stability_interner.borrow().len()); - println!("Interpret interner: #{}", self.interpret_interner.borrow().allocs.len()); + println!("Interpret interner: #{}", self.interpret_interner.inner.borrow().allocs.len()); println!("Layout interner: #{}", self.layout_interner.borrow().len()); } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index dcc2e4280f5bd..25e0475304a9d 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -550,11 +550,10 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, ' fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; let tcx = self.tcx; - let interpret_interner = || tcx.interpret_interner.borrow_mut(); let pos = TyDecoder::position(self); match usize::decode(self)? { ::std::usize::MAX => { - let alloc_id = interpret_interner().reserve(); + let alloc_id = tcx.interpret_interner.reserve(); trace!("creating alloc id {:?} at {}", alloc_id, pos); // insert early to allow recursive allocs self.interpret_alloc_cache.insert(pos, alloc_id); @@ -562,10 +561,10 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, ' let allocation = interpret::Allocation::decode(self)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.intern_const_alloc(allocation); - interpret_interner().intern_at_reserved(alloc_id, allocation); + tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); if let Some(glob) = Option::::decode(self)? { - interpret_interner().cache(glob, alloc_id); + tcx.interpret_interner.cache(glob, alloc_id); } Ok(alloc_id) @@ -574,7 +573,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, ' trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; trace!("decoded fn alloc instance: {:?}", instance); - let id = interpret_interner().create_fn_alloc(instance); + let id = tcx.interpret_interner.create_fn_alloc(instance); trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) @@ -793,14 +792,14 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder< // cache the allocation shorthand now, because the allocation itself might recursively // point to itself. self.interpret_alloc_shorthands.insert(*alloc_id, start); - if let Some(alloc) = self.tcx.interpret_interner.borrow().get_alloc(*alloc_id) { + if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - self.tcx.interpret_interner.borrow() + self.tcx.interpret_interner .get_corresponding_static_def_id(*alloc_id) .encode(self)?; - } else if let Some(fn_instance) = self.tcx.interpret_interner.borrow().get_fn(*alloc_id) { + } else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f9045a0ffb5eb..60a707dfcd2c3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -283,12 +283,11 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; - let tcx = self.tcx; - let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut(); + let tcx = self.tcx.unwrap(); let pos = self.position(); match usize::decode(self)? { ::std::usize::MAX => { - let alloc_id = interpret_interner().reserve(); + let alloc_id = tcx.interpret_interner.reserve(); trace!("creating alloc id {:?} at {}", alloc_id, pos); // insert early to allow recursive allocs self.interpret_alloc_cache.insert(pos, alloc_id); @@ -296,10 +295,10 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx let allocation = interpret::Allocation::decode(self)?; trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner().intern_at_reserved(alloc_id, allocation); + tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); if let Some(glob) = Option::::decode(self)? { - interpret_interner().cache(glob, alloc_id); + tcx.interpret_interner.cache(glob, alloc_id); } Ok(alloc_id) @@ -308,7 +307,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; trace!("decoded fn alloc instance: {:?}", instance); - let id = interpret_interner().create_fn_alloc(instance); + let id = tcx.interpret_interner.create_fn_alloc(instance); trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 5a72af1255829..0fd7d7f70554b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -204,14 +204,14 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx // cache the allocation shorthand now, because the allocation itself might recursively // point to itself. self.interpret_alloc_shorthands.insert(*alloc_id, start); - if let Some(alloc) = self.tcx.interpret_interner.borrow().get_alloc(*alloc_id) { + if let Some(alloc) = self.tcx.interpret_interner.get_alloc(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; - self.tcx.interpret_interner.borrow() + self.tcx.interpret_interner .get_corresponding_static_def_id(*alloc_id) .encode(self)?; - } else if let Some(fn_instance) = self.tcx.interpret_interner.borrow().get_fn(*alloc_id) { + } else if let Some(fn_instance) = self.tcx.interpret_interner.get_fn(*alloc_id) { trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 2b0d5764958a2..33862ffeda270 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -263,7 +263,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { self.tcx() .interpret_interner - .borrow() .get_fn(p.alloc_id) .map(|instance| instance.def_id()) }, @@ -1043,7 +1042,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .. }) => match val { ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { - let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id); + let inst = self.tcx().interpret_interner.get_fn(p.alloc_id); inst.map_or(false, |inst| { Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() }) diff --git a/src/librustc_mir/const_eval/_match.rs b/src/librustc_mir/const_eval/_match.rs index 974338393bfd1..8128c3abd9f5d 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -192,7 +192,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { assert!(is_array_ptr); let alloc = tcx .interpret_interner - .borrow() .get_alloc(ptr.alloc_id) .unwrap(); assert_eq!(ptr.offset, 0); @@ -568,7 +567,6 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( if is_array_ptr { let alloc = cx.tcx .interpret_interner - .borrow() .get_alloc(ptr.alloc_id) .unwrap(); max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); @@ -958,7 +956,6 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, assert!(is_array_ptr); tcx .interpret_interner - .borrow() .get_alloc(ptr.alloc_id) .unwrap() .bytes @@ -1099,7 +1096,6 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( assert!(is_array_ptr); let data_len = cx.tcx .interpret_interner - .borrow() .get_alloc(ptr.alloc_id) .unwrap() .bytes diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index c7669c298ff5c..4f969ab238ce9 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -106,7 +106,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( mir = &mir.promoted[index]; } let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let alloc = tcx.interpret_interner.borrow().get_cached(cid.instance.def_id()); + let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); let alloc = match alloc { Some(alloc) => { assert!(cid.promoted.is_none()); @@ -121,7 +121,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( None, )?; if tcx.is_static(cid.instance.def_id()).is_some() { - tcx.interpret_interner.borrow_mut().cache(cid.instance.def_id(), ptr.alloc_id); + tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); } let span = tcx.def_span(cid.instance.def_id()); let internally_mutable = !layout.ty.is_freeze(tcx, param_env, span); @@ -343,7 +343,6 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { Ok(ecx .tcx .interpret_interner - .borrow() .get_cached(cid.instance.def_id()) .expect("uncached static")) } @@ -457,13 +456,13 @@ pub fn const_eval_provider<'a, 'tcx>( let span = tcx.def_span(def_id); if tcx.is_foreign_item(def_id) { - let id = tcx.interpret_interner.borrow().get_cached(def_id); + let id = tcx.interpret_interner.get_cached(def_id); let id = match id { // FIXME: due to caches this shouldn't happen, add some assertions Some(id) => id, None => { - let id = tcx.interpret_interner.borrow_mut().reserve(); - tcx.interpret_interner.borrow_mut().cache(def_id, id); + let id = tcx.interpret_interner.reserve(); + tcx.interpret_interner.cache(def_id, id); id }, }; diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index aea6ebf01bdd6..e72e59efd0e21 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -941,7 +941,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let cached = self .tcx .interpret_interner - .borrow() .get_cached(gid.instance.def_id()); if let Some(alloc_id) = cached { let layout = self.layout_of(ty)?; diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index f204ddc46a5cc..eb5bbd5e73e14 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -75,7 +75,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer { - let id = self.tcx.interpret_interner.borrow_mut().create_fn_alloc(instance); + let id = self.tcx.interpret_interner.create_fn_alloc(instance); MemoryPointer::new(id, 0) } @@ -107,7 +107,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { align, mutable: false, }; - let id = self.tcx.interpret_interner.borrow_mut().reserve(); + let id = self.tcx.interpret_interner.reserve(); M::add_lock(self, id); match kind { Some(kind @ MemoryKind::Stack) | @@ -186,12 +186,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { "uninitializedstatic".to_string(), format!("{:?}", kind), )) - } else if self.tcx.interpret_interner.borrow().get_fn(ptr.alloc_id).is_some() { + } else if self.tcx.interpret_interner.get_fn(ptr.alloc_id).is_some() { return err!(DeallocatedWrongMemoryKind( "function".to_string(), format!("{:?}", kind), )) - } else if self.tcx.interpret_interner.borrow().get_alloc(ptr.alloc_id).is_some() { + } else if self.tcx.interpret_interner.get_alloc(ptr.alloc_id).is_some() { return err!(DeallocatedWrongMemoryKind( "static".to_string(), format!("{:?}", kind), @@ -295,11 +295,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { None => match self.uninitialized_statics.get(&id) { Some(alloc) => Ok(alloc), None => { - let int = self.tcx.interpret_interner.borrow(); // static alloc? - int.get_alloc(id) + self.tcx.interpret_interner.get_alloc(id) // no alloc? produce an error - .ok_or_else(|| if int.get_fn(id).is_some() { + .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() { EvalErrorKind::DerefFunctionPointer.into() } else { EvalErrorKind::DanglingPointerDeref.into() @@ -320,11 +319,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { None => match self.uninitialized_statics.get_mut(&id) { Some(alloc) => Ok(alloc), None => { - let int = self.tcx.interpret_interner.borrow(); // no alloc or immutable alloc? produce an error - if int.get_alloc(id).is_some() { + if self.tcx.interpret_interner.get_alloc(id).is_some() { err!(ModifiedConstantMemory) - } else if int.get_fn(id).is_some() { + } else if self.tcx.interpret_interner.get_fn(id).is_some() { err!(DerefFunctionPointer) } else { err!(DanglingPointerDeref) @@ -341,7 +339,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { debug!("reading fn ptr: {}", ptr.alloc_id); self.tcx .interpret_interner - .borrow() .get_fn(ptr.alloc_id) .ok_or(EvalErrorKind::ExecuteMemory.into()) } @@ -376,9 +373,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Some(a) => (a, " (static in the process of initialization)".to_owned()), None => { // static alloc? - match self.tcx.interpret_interner.borrow().get_alloc(id) { + match self.tcx.interpret_interner.get_alloc(id) { Some(a) => (a, "(immutable)".to_owned()), - None => if let Some(func) = self.tcx.interpret_interner.borrow().get_fn(id) { + None => if let Some(func) = self.tcx.interpret_interner.get_fn(id) { trace!("{} {}", msg, func); continue; } else { @@ -549,7 +546,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // ensure llvm knows not to put this into immutable memroy alloc.mutable = mutability == Mutability::Mutable; let alloc = self.tcx.intern_const_alloc(alloc); - self.tcx.interpret_interner.borrow_mut().intern_at_reserved(alloc_id, alloc); + self.tcx.interpret_interner.intern_at_reserved(alloc_id, alloc); // recurse into inner allocations for &alloc in alloc.relocations.values() { self.mark_inner_allocation_initialized(alloc, mutability)?; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index dd8dfbfe92690..4ca68068728d7 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -200,7 +200,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let alloc = self .tcx .interpret_interner - .borrow() .get_cached(static_.def_id); let layout = self.layout_of(self.place_ty(mir_place))?; if let Some(alloc) = alloc { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 809dc077204ab..44729fad50c57 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1120,12 +1120,12 @@ fn collect_miri<'a, 'tcx>( alloc_id: AllocId, output: &mut Vec>, ) { - if let Some(alloc) = tcx.interpret_interner.borrow().get_alloc(alloc_id) { + if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &inner in alloc.relocations.values() { collect_miri(tcx, inner, output); } - } else if let Some(fn_instance) = tcx.interpret_interner.borrow().get_fn(alloc_id) { + } else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) { if should_monomorphize_locally(tcx, &fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(fn_instance)); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1ca9bd81893aa..1d04e30eb3e83 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -151,18 +151,17 @@ pub fn primval_to_llvm(cx: &CodegenCx, } }, PrimVal::Ptr(ptr) => { - if let Some(fn_instance) = cx.tcx.interpret_interner.borrow().get_fn(ptr.alloc_id) { + if let Some(fn_instance) = cx.tcx.interpret_interner.get_fn(ptr.alloc_id) { callee::get_fn(cx, fn_instance) } else { let static_ = cx .tcx .interpret_interner - .borrow() .get_corresponding_static_def_id(ptr.alloc_id); let base_addr = if let Some(def_id) = static_ { assert!(cx.tcx.is_static(def_id).is_some()); consts::get_static(cx, def_id) - } else if let Some(alloc) = cx.tcx.interpret_interner.borrow() + } else if let Some(alloc) = cx.tcx.interpret_interner .get_alloc(ptr.alloc_id) { let init = global_initializer(cx, alloc); if alloc.mutable { @@ -239,14 +238,12 @@ pub fn trans_static_initializer<'a, 'tcx>( let alloc_id = cx .tcx .interpret_interner - .borrow() .get_cached(def_id) .expect("global not cached"); let alloc = cx .tcx .interpret_interner - .borrow() .get_alloc(alloc_id) .expect("miri allocation never successfully created"); Ok(global_initializer(cx, alloc)) From 039f35b4c661124bd18e035e1d348d477202d6bc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 13:23:44 +0100 Subject: [PATCH 039/115] Satisfy tidy --- src/librustc/ty/context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 80708808f5633..46734d4f1f825 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1092,7 +1092,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Allocates a byte or string literal for `mir::interpret` pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId { // check whether we already allocated this literal or a constant with the same memory - if let Some(&alloc_id) = self.interpret_interner.inner.borrow().literal_alloc_cache.get(bytes) { + if let Some(&alloc_id) = self.interpret_interner.inner.borrow() + .literal_alloc_cache.get(bytes) { return alloc_id; } // create an allocation that just contains these bytes From e9c3cb85eed723f8ed297a27825c2a2031849993 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 13:45:57 +0100 Subject: [PATCH 040/115] Wrap the miri ErrorKind in an Rc to reduce work in queries --- src/librustc/ich/impls_ty.rs | 4 ++-- src/librustc/mir/interpret/error.rs | 9 +++++---- src/librustc/ty/structural_impls.rs | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index b9d896166fde2..b12bb5bbff338 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -468,9 +468,9 @@ for ::mir::interpret::EvalError<'gcx> { hasher: &mut StableHasher) { use mir::interpret::EvalErrorKind::*; - mem::discriminant(&self.kind).hash_stable(hcx, hasher); + mem::discriminant(&*self.kind).hash_stable(hcx, hasher); - match self.kind { + match *self.kind { DanglingPointerDeref | DoubleFree | InvalidMemoryAccess | diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 977e617968aa4..702fd85794fff 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -1,5 +1,6 @@ use std::error::Error; use std::{fmt, env}; +use std::rc::Rc; use mir; use ty::{FnSig, Ty, layout}; @@ -14,7 +15,7 @@ use backtrace::Backtrace; #[derive(Debug, Clone)] pub struct EvalError<'tcx> { - pub kind: EvalErrorKind<'tcx>, + pub kind: Rc>, pub backtrace: Option, } @@ -25,7 +26,7 @@ impl<'tcx> From> for EvalError<'tcx> { _ => None }; EvalError { - kind, + kind: Rc::new(kind), backtrace, } } @@ -131,7 +132,7 @@ pub type EvalResult<'tcx, T = ()> = Result>; impl<'tcx> Error for EvalError<'tcx> { fn description(&self) -> &str { use self::EvalErrorKind::*; - match self.kind { + match *self.kind { MachineError(ref inner) => inner, FunctionPointerTyMismatch(..) => "tried to call a function through a function pointer of a different type", @@ -252,7 +253,7 @@ impl<'tcx> Error for EvalError<'tcx> { impl<'tcx> fmt::Display for EvalError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::EvalErrorKind::*; - match self.kind { + match *self.kind { PointerOutOfBounds { ptr, access, allocation_size } => { write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", if access { "memory access" } else { "pointer computed" }, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 33964b1092520..93024d51f2b48 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -612,7 +612,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { type Lifted = interpret::EvalError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { use ::mir::interpret::EvalErrorKind::*; - let kind = match self.kind { + let kind = match *self.kind { MachineError(ref err) => MachineError(err.clone()), FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( tcx.lift(&a)?, @@ -712,7 +712,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { TypeckError => TypeckError, }; Some(interpret::EvalError { - kind, + kind: Rc::new(kind), backtrace: self.backtrace.clone(), }) } From b0fd1cf57ea7241028f954cb51ebd9db7fd1d9fd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 14:15:12 +0100 Subject: [PATCH 041/115] Add test for attempting to use array indexing for conditional const eval --- .../const-eval/conditional_array_execution.rs | 17 ++++++++++++ .../conditional_array_execution.stderr | 26 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/ui/const-eval/conditional_array_execution.rs create mode 100644 src/test/ui/const-eval/conditional_array_execution.stderr diff --git a/src/test/ui/const-eval/conditional_array_execution.rs b/src/test/ui/const-eval/conditional_array_execution.rs new file mode 100644 index 0000000000000..41ceb609df5bd --- /dev/null +++ b/src/test/ui/const-eval/conditional_array_execution.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const X: u32 = 5; +const Y: u32 = 6; +const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 + +fn main() { + println!("{}", FOO); //~ E0080 +} diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr new file mode 100644 index 0000000000000..0e26db7ac0858 --- /dev/null +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -0,0 +1,26 @@ +error[E0080]: constant evaluation error + --> $DIR/conditional_array_execution.rs:13:19 + | +13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 + | ^^^^^ attempt to subtract with overflow + | +note: inside call to FOO + --> $DIR/conditional_array_execution.rs:13:1 + | +13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: constant evaluation error + --> $DIR/conditional_array_execution.rs:16:20 + | +16 | println!("{}", FOO); //~ E0080 + | ^^^ attempt to subtract with overflow + | +note: inside call to main + --> $DIR/conditional_array_execution.rs:16:20 + | +16 | println!("{}", FOO); //~ E0080 + | ^^^ + +error: aborting due to 2 previous errors + From 5b3cff14cc9eae7b6494a6e2709af7c06eec210d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 14:15:28 +0100 Subject: [PATCH 042/115] Add test for #45044 --- src/test/run-pass/ctfe/repeat_match.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/run-pass/ctfe/repeat_match.rs diff --git a/src/test/run-pass/ctfe/repeat_match.rs b/src/test/run-pass/ctfe/repeat_match.rs new file mode 100644 index 0000000000000..dedf5defebb7c --- /dev/null +++ b/src/test/run-pass/ctfe/repeat_match.rs @@ -0,0 +1,20 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// https://github.com/rust-lang/rust/issues/45044 + +const X: [u8; 1] = [0; 1]; + +fn main() { + match &X { + &X => println!("a"), + _ => println!("b"), + }; +} From fa82773f7d6115a79030da32c0ed443a5b1a37a8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 14:15:56 +0100 Subject: [PATCH 043/115] Destructure Rc wrapped ErrorKind in miri --- src/librustc_mir/interpret/const_eval.rs | 14 ++++++++------ src/librustc_mir/interpret/eval_context.rs | 11 ++++++----- src/librustc_mir/transform/instcombine.rs | 6 +----- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 4f969ab238ce9..66c8f47afe5e3 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -235,13 +235,15 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { } let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, - Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - return Err( - ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) - .into(), - ); + Err(err) => { + if let EvalErrorKind::NoMirFor(ref path) = *err.kind { + return Err( + ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) + .into(), + ); + } + return Err(err); } - Err(other) => return Err(other), }; let (return_place, return_to_block) = match destination { Some((place, block)) => (place, StackPopCleanup::Goto(block)), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e72e59efd0e21..eacff1491eab2 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1509,11 +1509,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M write!(msg, ":").unwrap(); match self.stack[frame].get_local(local) { - Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => { - write!(msg, " is dead").unwrap(); - } Err(err) => { - panic!("Failed to access local: {:?}", err); + if let EvalErrorKind::DeadLocal = *err.kind { + write!(msg, " is dead").unwrap(); + } else { + panic!("Failed to access local: {:?}", err); + } } Ok(Value::ByRef(ptr, align)) => { match ptr.into_inner_primval() { @@ -1572,7 +1573,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { - if let EvalErrorKind::TypeckError = e.kind { + if let EvalErrorKind::TypeckError = *e.kind { return; } if let Some(ref mut backtrace) = e.backtrace { diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 25787608e39ca..640fd7cadab2c 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -362,12 +362,8 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { ) } else { if overflow { - use rustc::mir::interpret::EvalError; use rustc::mir::interpret::EvalErrorKind; - let mut err = EvalError { - kind: EvalErrorKind::OverflowingMath, - backtrace: None, - }; + let mut err = EvalErrorKind::OverflowingMath.into(); ecx.report(&mut err, false, Some(span)); return None; } From 3f0b0672ebfca81ca6e8e4fbf85c78237679af1a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 14:56:34 +0100 Subject: [PATCH 044/115] Rename ConstVal::to_u128 to to_raw_bits --- src/librustc/middle/const_val.rs | 4 ++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/const_eval/_match.rs | 2 +- src/librustc_mir/transform/simplify_branches.rs | 2 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 35c51c0c206b0..a40147aa2a1f4 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -39,7 +39,7 @@ pub struct ByteArray<'tcx> { impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {} impl<'tcx> ConstVal<'tcx> { - pub fn to_u128(&self) -> Option { + pub fn to_raw_bits(&self) -> Option { match *self { ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { Some(b) @@ -48,7 +48,7 @@ impl<'tcx> ConstVal<'tcx> { } } pub fn unwrap_u64(&self) -> u64 { - match self.to_u128() { + match self.to_raw_bits() { Some(val) => { assert_eq!(val as u64 as u128, val); val as u64 diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a33ddd5844d2b..b763504f77584 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -912,7 +912,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true, + ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index bfaa661b2432d..3e653cf126a8d 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_u128() { + match len.val.to_raw_bits() { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 3b9fbc5c867a1..4a5d9e228815e 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -127,7 +127,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { indices.entry(value) .or_insert_with(|| { - options.push(value.val.to_u128().expect("switching on int")); + options.push(value.val.to_raw_bits().expect("switching on int")); options.len() - 1 }); true diff --git a/src/librustc_mir/const_eval/_match.rs b/src/librustc_mir/const_eval/_match.rs index 8128c3abd9f5d..af50d11b889cd 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -446,7 +446,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, })) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => { + ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => { let len = len.val.unwrap_u64(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index a91f40491e92a..4d64fa9e20cc0 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -41,7 +41,7 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(constint) = value.val.to_u128() { + if let Some(constint) = value.val.to_raw_bits() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; for (&v, t) in values.iter().zip(targets.iter()) { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 54e60ee8b7f9c..5b3b58554ca56 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -800,7 +800,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_u128().map(|i| i as u64)), + ety, size.val.to_raw_bits().map(|i| i as u64)), ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0db3d63a4c7e4..3237f8875cc7e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4041,7 +4041,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1); + let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: From 8751339b182f408a364e8dbbf1aedd5600c7e75e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 25 Jan 2018 16:44:45 +0100 Subject: [PATCH 045/115] Nuke ConstInt and Const*size --- src/librustc/ich/impls_const_math.rs | 27 - src/librustc/middle/const_val.rs | 14 - src/librustc/mir/mod.rs | 4 +- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 14 +- src/librustc/ty/context.rs | 8 +- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/mod.rs | 42 +- src/librustc/ty/util.rs | 158 +++-- src/librustc_const_math/int.rs | 590 ------------------ src/librustc_const_math/isize.rs | 56 -- src/librustc_const_math/lib.rs | 6 - src/librustc_const_math/usize.rs | 56 -- .../borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 63 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/const_eval/pattern.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 +- src/librustc_mir/hair/cx/mod.rs | 17 +- src/librustc_mir/hair/mod.rs | 3 +- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/shim.rs | 9 +- src/librustc_mir/util/elaborate_drops.rs | 2 +- src/librustc_passes/mir_stats.rs | 8 - src/librustc_trans/base.rs | 8 - src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/mir/constant.rs | 109 +--- src/librustc_trans/mir/place.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 10 - src/librustc_typeck/check/mod.rs | 8 +- src/librustc_typeck/collect.rs | 19 +- src/test/compile-fail/issue-27592.rs | 1 + src/test/ui/issue-15524.rs | 6 +- src/test/ui/issue-15524.stderr | 18 +- 34 files changed, 168 insertions(+), 1110 deletions(-) delete mode 100644 src/librustc_const_math/int.rs delete mode 100644 src/librustc_const_math/isize.rs delete mode 100644 src/librustc_const_math/usize.rs diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs index 6790c2ac7dece..5f3ff461c0c7e 100644 --- a/src/librustc/ich/impls_const_math.rs +++ b/src/librustc/ich/impls_const_math.rs @@ -16,33 +16,6 @@ impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat { bits }); -impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { - I8(val), - I16(val), - I32(val), - I64(val), - I128(val), - Isize(val), - U8(val), - U16(val), - U32(val), - U64(val), - U128(val), - Usize(val) -}); - -impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { - Is16(i16), - Is32(i32), - Is64(i64) -}); - -impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { - Us16(i16), - Us32(i32), - Us64(i64) -}); - impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { NotInRange, CmpBetweenUnequalTypes, diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index a40147aa2a1f4..06d4540a455e8 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use rustc_const_math::ConstInt; - use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; @@ -56,18 +54,6 @@ impl<'tcx> ConstVal<'tcx> { None => bug!("expected constant u64, got {:#?}", self), } } - pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { - match *self { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - assert_eq!(b as u64 as u128, b); - match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { - Ok(val) => val, - Err(e) => bug!("{:#?} is not a usize {:?}", self, e), - } - }, - _ => bug!("expected constant u64, got {:#?}", self), - } - } } #[derive(Clone, Debug)] diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 37d1239110012..5a410a3f92257 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::{ConstUsize, ConstMathErr}; +use rustc_const_math::ConstMathErr; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; @@ -1464,7 +1464,7 @@ pub enum Rvalue<'tcx> { Use(Operand<'tcx>), /// [x; 32] - Repeat(Operand<'tcx>, ConstUsize), + Repeat(Operand<'tcx>, u64), /// &x or &mut x Ref(Region<'tcx>, BorrowKind, Place<'tcx>), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 4a7bdacb70fca..d571922b6920f 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -149,7 +149,7 @@ impl<'tcx> Rvalue<'tcx> { match *self { Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), Rvalue::Repeat(ref operand, count) => { - tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count) + tcx.mk_array(operand.ty(local_decls, tcx), count) } Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).to_ty(tcx); diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c6a04a52dd588..6dd9e1ff1d5e8 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -12,7 +12,6 @@ use hir::def_id::DefId; use ty::subst::Substs; use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; use mir::*; -use rustc_const_math::ConstUsize; use syntax_pos::Span; // # The MIR Visitor @@ -243,12 +242,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_usize(&mut self, - const_usize: & $($mutability)* ConstUsize, - _: Location) { - self.super_const_usize(const_usize); - } - fn visit_local_decl(&mut self, local: Local, local_decl: & $($mutability)* LocalDecl<'tcx>) { @@ -523,10 +516,8 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); } - Rvalue::Repeat(ref $($mutability)* value, - ref $($mutability)* length) => { + Rvalue::Repeat(ref $($mutability)* value, _) => { self.visit_operand(value, location); - self.visit_const_usize(length, location); } Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => { @@ -783,9 +774,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) { - } - // Convenience methods fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 46734d4f1f825..9dc514161f1ce 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -54,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; use arena::{TypedArena, DroplessArena}; -use rustc_const_math::ConstUsize; use rustc_data_structures::indexed_vec::IndexVec; use std::any::Any; use std::borrow::Borrow; @@ -2044,13 +2043,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap(); - self.mk_array_const_usize(ty, n) - } - - pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))), + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))), ty: self.types.usize }))) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a74029aa0a2e6..1e27e696f8c71 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1537,7 +1537,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) { continue; } - let x = discr.to_u128_unchecked() as i128; + let x = discr.val as i128; if x < min { min = x; } if x > max { max = x; } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 19109504ebb62..26fb5c21afd4d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -32,7 +32,7 @@ use session::CrateDisambiguator; use traits; use ty; use ty::subst::{Subst, Substs}; -use ty::util::IntTypeExt; +use ty::util::{IntTypeExt, Discr}; use ty::walk::TypeWalker; use util::common::ErrorReported; use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; @@ -54,7 +54,6 @@ use syntax::attr; use syntax::ext::hygiene::{Mark, SyntaxContext}; 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 rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -1781,13 +1780,13 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> impl Iterator + 'a { + -> impl Iterator> + 'a { let param_env = ParamEnv::empty(traits::Reveal::UserFacing); let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx.global_tcx()); - let mut prev_discr = None::; + let mut prev_discr = None::>; 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(tcx)); if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); let instance = ty::Instance::new(expr_did, substs); @@ -1801,12 +1800,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { .. }) => { trace!("discriminants: {} ({:?})", b, repr_type); - use syntax::attr::IntType; - discr = match repr_type { - IntType::SignedInt(int_type) => ConstInt::new_signed( - b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), - IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( - b, uint_type, tcx.sess.target.usize_ty).unwrap(), + discr = Discr { + val: b, + ty: repr_type.to_ty(tcx), }; } _ => { @@ -1832,7 +1828,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { pub fn discriminant_for_variant(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, variant_index: usize) - -> ConstInt { + -> Discr<'tcx> { let param_env = ParamEnv::empty(traits::Reveal::UserFacing); let repr_type = self.repr.discr_type(); let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); @@ -1856,12 +1852,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { .. }) => { trace!("discriminants: {} ({:?})", b, repr_type); - use syntax::attr::IntType; - explicit_value = match repr_type { - IntType::SignedInt(int_type) => ConstInt::new_signed( - b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), - IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( - b, uint_type, tcx.sess.target.usize_ty).unwrap(), + explicit_value = Discr { + val: b, + ty: repr_type.to_ty(tcx), }; break; } @@ -1880,18 +1873,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } } - 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.usize_ty) - } - attr::SignedInt(ty) => { - ConstInt::new_signed_truncating(discr as i128, ty, - tcx.sess.target.isize_ty) - } - } + explicit_value.checked_add(tcx, (variant_index - explicit_index) as u128).0 } pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 29569423947e4..afa7ca6e7ef72 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -25,57 +25,95 @@ use util::common::ErrorReported; use middle::lang_items; use mir::interpret::{Value, PrimVal}; -use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; use rustc_data_structures::fx::FxHashMap; -use std::cmp; +use std::{cmp, fmt}; use std::hash::Hash; use std::intrinsics; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Name, UintTy, IntTy}; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; -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; +#[derive(Copy, Clone, Debug)] +pub struct Discr<'tcx> { + pub val: u128, + pub ty: Ty<'tcx> } +impl<'tcx> fmt::Display for Discr<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if self.ty.is_signed() { + write!(fmt, "{}", self.val as i128) + } else { + write!(fmt, "{}", self.val) + } + } +} -macro_rules! typed_literal { - ($tcx:expr, $ty:expr, $lit:expr) => { - match $ty { - SignedInt(ast::IntTy::I8) => ConstInt::I8($lit), - SignedInt(ast::IntTy::I16) => ConstInt::I16($lit), - SignedInt(ast::IntTy::I32) => ConstInt::I32($lit), - SignedInt(ast::IntTy::I64) => ConstInt::I64($lit), - SignedInt(ast::IntTy::I128) => ConstInt::I128($lit), - SignedInt(ast::IntTy::Isize) => match $tcx.sess.target.isize_ty { - ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)), - ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)), - ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)), - _ => bug!(), - }, - UnsignedInt(ast::UintTy::U8) => ConstInt::U8($lit), - UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit), - UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit), - UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit), - UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit), - UnsignedInt(ast::UintTy::Usize) => match $tcx.sess.target.usize_ty { - ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)), - ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)), - ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)), - _ => bug!(), - }, +impl<'tcx> Discr<'tcx> { + /// Adds 1 to the value and wraps around if the maximum for the type is reached + pub fn wrap_incr<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { + self.checked_add(tcx, 1).0 + } + pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Self, bool) { + let ty = match self.ty.sty { + TyInt(IntTy::Isize) => tcx.mk_mach_int(tcx.sess.target.isize_ty), + TyUint(UintTy::Usize) => tcx.mk_mach_uint(tcx.sess.target.usize_ty), + _ => self.ty, + }; + let (min, max) = match ty.sty { + TyInt(IntTy::I8) => (i8::min_value() as i128 as u128, i8::max_value() as u128), + TyInt(IntTy::I16) => (i16::min_value() as i128 as u128, i16::max_value() as u128), + TyInt(IntTy::I32) => (i32::min_value() as i128 as u128, i32::max_value() as u128), + TyInt(IntTy::I64) => (i64::min_value() as i128 as u128, i64::max_value() as u128), + TyInt(IntTy::I128) => (i128::min_value() as i128 as u128, i128::max_value() as u128), + TyInt(IntTy::Isize) => unreachable!(), + TyUint(UintTy::U8) => (u8::min_value() as u128, u8::max_value() as u128), + TyUint(UintTy::U16) => (u16::min_value() as u128, u16::max_value() as u128), + TyUint(UintTy::U32) => (u32::min_value() as u128, u32::max_value() as u128), + TyUint(UintTy::U64) => (u64::min_value() as u128, u64::max_value() as u128), + TyUint(UintTy::U128) => (u128::min_value() as u128, u128::max_value()), + TyUint(UintTy::Usize) => unreachable!(), + _ => bug!("not a valid discriminant type: {}", ty) + }; + if ty.is_signed() { + let val = self.val as i128; + let n = n as i128; + let max = max as i128; + let min = min as i128; + let oflo = val > max - n; + let val = if oflo { + min + (n - (max - val)) + } else { + val + n + }; + (Self { + val: val as u128, + ty: self.ty, + }, oflo) + } else { + let oflo = self.val > max - n; + let val = if oflo { + min + (n - (max - self.val)) + } else { + self.val + n + }; + (Self { + val, + ty: self.ty, + }, oflo) } } } +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 initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx>; +} + impl IntTypeExt for attr::IntType { fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match *self { @@ -94,33 +132,26 @@ impl IntTypeExt for attr::IntType { } } - fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { - typed_literal!(tcx, *self, 0) - } - - 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::Isize), 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::Usize), ConstInt::Usize(_)) => {}, - _ => bug!("disr type mismatch: {:?} vs {:?}", self, val), + fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx> { + Discr { + val: 0, + ty: self.to_ty(tcx) } } - fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option) - -> Option { + 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 + typed_literal!(tcx, *self, 1)).ok() + assert_eq!(self.to_ty(tcx), val.ty); + let (new, oflo) = val.checked_add(tcx, 1); + if oflo { + None + } else { + Some(new) + } } else { Some(self.initial_discriminant(tcx)) } @@ -677,15 +708,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn const_usize(&self, val: u16) -> ConstInt { - match self.sess.target.usize_ty { - ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)), - ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)), - ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)), - _ => bug!(), - } - } - /// Return whether the node pointed to by def_id is a static item, and its mutability pub fn is_static(&self, def_id: DefId) -> Option { if let Some(node) = self.hir.get_if_local(def_id) { diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs deleted file mode 100644 index 4ec27d7ade560..0000000000000 --- a/src/librustc_const_math/int.rs +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cmp::Ordering; -use syntax::attr::IntType; -use syntax::ast::{IntTy, UintTy}; - -use super::isize::*; -use super::usize::*; -use super::err::*; - -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)] -pub enum ConstInt { - I8(i8), - I16(i16), - I32(i32), - I64(i64), - I128(i128), - Isize(ConstIsize), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - U128(u128), - Usize(ConstUsize), -} -pub use self::ConstInt::*; - - -macro_rules! bounds { - ($ct: ty, $($t:ident $min:ident $max:ident)*) => { - $( - pub const $min: $ct = $t::min_value() as $ct; - pub const $max: $ct = $t::max_value() as $ct; - )* - }; - ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => { - $( - pub const $min: $ct = $min_val; - pub const $max: $ct = $t::max_value() as $ct; - )* - } -} - -mod ubounds { - #![allow(dead_code)] - bounds!{u128: 0, - i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX - u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX - // do not add constants for isize/usize, because these are guaranteed to be wrong for - // arbitrary host/target combinations - } -} - -mod ibounds { - #![allow(dead_code)] - bounds!(i128, u64 U64MIN U64MAX); - - pub const U128MIN: i128 = 0; - pub const U128MAX: i128 = i128::max_value(); - - bounds!{i128, - i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX - u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX - // do not add constants for isize/usize, because these are guaranteed to be wrong for - // arbitrary host/target combinations - } -} - -impl ConstInt { - /// 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 { - match ty { - UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)), - UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)), - UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)), - UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)), - UintTy::Usize if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok() - .map(Usize), - UintTy::U128 => Some(U128(val)), - _ => None - } - } - - /// Creates a new signed ConstInt with matching type while also checking that overflow does - /// not happen. - pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option { - match ty { - IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)), - IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)), - IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)), - IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)), - IntTy::Isize if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok() - .map(Isize), - IntTy::I128 => Some(I128(val)), - _ => None - } - } - - /// Creates a new unsigned ConstInt with matching type. - pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt { - match ty { - UintTy::U8 => U8(val as u8), - UintTy::U16 => U16(val as u16), - UintTy::U32 => U32(val as u32), - UintTy::U64 => U64(val as u64), - UintTy::Usize => Usize(ConstUsize::new_truncating(val, usize_ty)), - UintTy::U128 => U128(val) - } - } - - /// Creates a new signed ConstInt with matching type. - pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt { - match ty { - IntTy::I8 => I8(val as i8), - IntTy::I16 => I16(val as i16), - IntTy::I32 => I32(val as i32), - IntTy::I64 => I64(val as i64), - IntTy::Isize => Isize(ConstIsize::new_truncating(val, isize_ty)), - IntTy::I128 => I128(val) - } - } - - /// Description of the type, not the value - pub fn description(&self) -> &'static str { - match *self { - I8(_) => "i8", - I16(_) => "i16", - I32(_) => "i32", - I64(_) => "i64", - I128(_) => "i128", - Isize(_) => "isize", - U8(_) => "u8", - U16(_) => "u16", - U32(_) => "u32", - U64(_) => "u64", - U128(_) => "u128", - Usize(_) => "usize", - } - } - - /// Erases the type and returns a u128. - /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128` - pub fn to_u128_unchecked(self) -> u128 { - match self { - I8(i) => i as i128 as u128, - I16(i) => i as i128 as u128, - I32(i) => i as i128 as u128, - I64(i) => i as i128 as u128, - I128(i) => i as i128 as u128, - Isize(Is16(i)) => i as i128 as u128, - Isize(Is32(i)) => i as i128 as u128, - Isize(Is64(i)) => i as i128 as u128, - U8(i) => i as u128, - U16(i) => i as u128, - U32(i) => i as u128, - U64(i) => i as u128, - U128(i) => i as u128, - Usize(Us16(i)) => i as u128, - Usize(Us32(i)) => i as u128, - Usize(Us64(i)) => i as u128, - } - } - - /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX - pub fn to_u32(&self) -> Option { - self.to_u128().and_then(|v| if v <= u32::max_value() as u128 { - Some(v as u32) - } else { - None - }) - } - - /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX - pub fn to_u64(&self) -> Option { - self.to_u128().and_then(|v| if v <= u64::max_value() as u128 { - Some(v as u64) - } else { - None - }) - } - - /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX - pub fn to_u128(&self) -> Option { - match *self { - I8(v) if v >= 0 => Some(v as u128), - I16(v) if v >= 0 => Some(v as u128), - I32(v) if v >= 0 => Some(v as u128), - I64(v) if v >= 0 => Some(v as u128), - I128(v) if v >= 0 => Some(v as u128), - Isize(Is16(v)) if v >= 0 => Some(v as u128), - Isize(Is32(v)) if v >= 0 => Some(v as u128), - Isize(Is64(v)) if v >= 0 => Some(v as u128), - U8(v) => Some(v as u128), - U16(v) => Some(v as u128), - U32(v) => Some(v as u128), - U64(v) => Some(v as u128), - U128(v) => Some(v as u128), - Usize(Us16(v)) => Some(v as u128), - Usize(Us32(v)) => Some(v as u128), - Usize(Us64(v)) => Some(v as u128), - _ => None, - } - } - - pub fn is_negative(&self) -> bool { - match *self { - I8(v) => v < 0, - I16(v) => v < 0, - I32(v) => v < 0, - I64(v) => v < 0, - I128(v) => v < 0, - Isize(Is16(v)) => v < 0, - Isize(Is32(v)) => v < 0, - Isize(Is64(v)) => v < 0, - _ => false, - } - } - - /// Compares the values if they are of the same type - pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> { - match (self, rhs) { - (I8(a), I8(b)) => Ok(a.cmp(&b)), - (I16(a), I16(b)) => Ok(a.cmp(&b)), - (I32(a), I32(b)) => Ok(a.cmp(&b)), - (I64(a), I64(b)) => Ok(a.cmp(&b)), - (I128(a), I128(b)) => Ok(a.cmp(&b)), - (Isize(Is16(a)), Isize(Is16(b))) => Ok(a.cmp(&b)), - (Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)), - (Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)), - (U8(a), U8(b)) => Ok(a.cmp(&b)), - (U16(a), U16(b)) => Ok(a.cmp(&b)), - (U32(a), U32(b)) => Ok(a.cmp(&b)), - (U64(a), U64(b)) => Ok(a.cmp(&b)), - (U128(a), U128(b)) => Ok(a.cmp(&b)), - (Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)), - (Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)), - (Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)), - _ => Err(CmpBetweenUnequalTypes), - } - } - - /// Adds 1 to the value and wraps around if the maximum for the type is reached - pub fn wrap_incr(self) -> Self { - macro_rules! add1 { - ($e:expr) => { ($e).wrapping_add(1) } - } - match self { - ConstInt::I8(i) => ConstInt::I8(add1!(i)), - ConstInt::I16(i) => ConstInt::I16(add1!(i)), - ConstInt::I32(i) => ConstInt::I32(add1!(i)), - ConstInt::I64(i) => ConstInt::I64(add1!(i)), - ConstInt::I128(i) => ConstInt::I128(add1!(i)), - ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))), - ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))), - ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))), - ConstInt::U8(i) => ConstInt::U8(add1!(i)), - ConstInt::U16(i) => ConstInt::U16(add1!(i)), - ConstInt::U32(i) => ConstInt::U32(add1!(i)), - ConstInt::U64(i) => ConstInt::U64(add1!(i)), - ConstInt::U128(i) => ConstInt::U128(add1!(i)), - ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))), - ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))), - ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))), - } - } - - pub fn int_type(self) -> IntType { - match self { - ConstInt::I8(_) => IntType::SignedInt(IntTy::I8), - ConstInt::I16(_) => IntType::SignedInt(IntTy::I16), - ConstInt::I32(_) => IntType::SignedInt(IntTy::I32), - ConstInt::I64(_) => IntType::SignedInt(IntTy::I64), - ConstInt::I128(_) => IntType::SignedInt(IntTy::I128), - ConstInt::Isize(_) => IntType::SignedInt(IntTy::Isize), - ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8), - ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16), - ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32), - ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64), - ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128), - ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Usize), - } - } -} - -impl ::std::cmp::PartialOrd for ConstInt { - fn partial_cmp(&self, other: &Self) -> Option { - self.try_cmp(*other).ok() - } -} - -impl ::std::cmp::Ord for ConstInt { - fn cmp(&self, other: &Self) -> Ordering { - self.try_cmp(*other).unwrap() - } -} - -impl ::std::fmt::Display for ConstInt { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - match *self { - I8(i) => write!(fmt, "{}i8", i), - I16(i) => write!(fmt, "{}i16", i), - I32(i) => write!(fmt, "{}i32", i), - I64(i) => write!(fmt, "{}i64", i), - I128(i) => write!(fmt, "{}i128", i), - Isize(i) => write!(fmt, "{}isize", i), - U8(i) => write!(fmt, "{}u8", i), - U16(i) => write!(fmt, "{}u16", i), - U32(i) => write!(fmt, "{}u32", i), - U64(i) => write!(fmt, "{}u64", i), - U128(i) => write!(fmt, "{}u128", i), - Usize(i) => write!(fmt, "{}usize", i), - } - } -} - -macro_rules! overflowing { - ($e:expr, $err:expr) => {{ - if $e.1 { - return Err(Overflow($err)); - } else { - $e.0 - } - }} -} - -macro_rules! impl_binop { - ($op:ident, $func:ident, $checked_func:ident) => { - impl ::std::ops::$op for ConstInt { - type Output = Result; - fn $func(self, rhs: Self) -> Result { - match (self, rhs) { - (I8(a), I8(b)) => a.$checked_func(b).map(I8), - (I16(a), I16(b)) => a.$checked_func(b).map(I16), - (I32(a), I32(b)) => a.$checked_func(b).map(I32), - (I64(a), I64(b)) => a.$checked_func(b).map(I64), - (I128(a), I128(b)) => a.$checked_func(b).map(I128), - (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize), - (Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize), - (Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize), - (U8(a), U8(b)) => a.$checked_func(b).map(U8), - (U16(a), U16(b)) => a.$checked_func(b).map(U16), - (U32(a), U32(b)) => a.$checked_func(b).map(U32), - (U64(a), U64(b)) => a.$checked_func(b).map(U64), - (U128(a), U128(b)) => a.$checked_func(b).map(U128), - (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize), - (Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize), - (Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize), - _ => return Err(UnequalTypes(Op::$op)), - }.ok_or(Overflow(Op::$op)) - } - } - } -} - -macro_rules! derive_binop { - ($op:ident, $func:ident) => { - impl ::std::ops::$op for ConstInt { - type Output = Result; - fn $func(self, rhs: Self) -> Result { - match (self, rhs) { - (I8(a), I8(b)) => Ok(I8(a.$func(b))), - (I16(a), I16(b)) => Ok(I16(a.$func(b))), - (I32(a), I32(b)) => Ok(I32(a.$func(b))), - (I64(a), I64(b)) => Ok(I64(a.$func(b))), - (I128(a), I128(b)) => Ok(I128(a.$func(b))), - (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a.$func(b)))), - (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))), - (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))), - (U8(a), U8(b)) => Ok(U8(a.$func(b))), - (U16(a), U16(b)) => Ok(U16(a.$func(b))), - (U32(a), U32(b)) => Ok(U32(a.$func(b))), - (U64(a), U64(b)) => Ok(U64(a.$func(b))), - (U128(a), U128(b)) => Ok(U128(a.$func(b))), - (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))), - (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))), - (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))), - _ => Err(UnequalTypes(Op::$op)), - } - } - } - } -} - -impl_binop!(Add, add, checked_add); -impl_binop!(Sub, sub, checked_sub); -impl_binop!(Mul, mul, checked_mul); -derive_binop!(BitAnd, bitand); -derive_binop!(BitOr, bitor); -derive_binop!(BitXor, bitxor); - -const I128_MIN: i128 = ::std::i128::MIN; - -fn check_division( - lhs: ConstInt, - rhs: ConstInt, - op: Op, - zerr: ConstMathErr, -) -> Result<(), ConstMathErr> { - match (lhs, rhs) { - (I8(_), I8(0)) => Err(zerr), - (I16(_), I16(0)) => Err(zerr), - (I32(_), I32(0)) => Err(zerr), - (I64(_), I64(0)) => Err(zerr), - (I128(_), I128(0)) => Err(zerr), - (Isize(_), Isize(Is16(0))) => Err(zerr), - (Isize(_), Isize(Is32(0))) => Err(zerr), - (Isize(_), Isize(Is64(0))) => Err(zerr), - - (U8(_), U8(0)) => Err(zerr), - (U16(_), U16(0)) => Err(zerr), - (U32(_), U32(0)) => Err(zerr), - (U64(_), U64(0)) => Err(zerr), - (U128(_), U128(0)) => Err(zerr), - (Usize(_), Usize(Us16(0))) => Err(zerr), - (Usize(_), Usize(Us32(0))) => Err(zerr), - (Usize(_), Usize(Us64(0))) => Err(zerr), - - (I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)), - (I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)), - (I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)), - (I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)), - (I128(I128_MIN), I128(-1)) => Err(Overflow(op)), - (Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)), - (Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)), - (Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)), - - _ => Ok(()), - } -} - -impl ::std::ops::Div for ConstInt { - type Output = Result; - fn div(self, rhs: Self) -> Result { - let (lhs, rhs) = (self, rhs); - check_division(lhs, rhs, Op::Div, DivisionByZero)?; - match (lhs, rhs) { - (I8(a), I8(b)) => Ok(I8(a/b)), - (I16(a), I16(b)) => Ok(I16(a/b)), - (I32(a), I32(b)) => Ok(I32(a/b)), - (I64(a), I64(b)) => Ok(I64(a/b)), - (I128(a), I128(b)) => Ok(I128(a/b)), - (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))), - (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))), - (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))), - - (U8(a), U8(b)) => Ok(U8(a/b)), - (U16(a), U16(b)) => Ok(U16(a/b)), - (U32(a), U32(b)) => Ok(U32(a/b)), - (U64(a), U64(b)) => Ok(U64(a/b)), - (U128(a), U128(b)) => Ok(U128(a/b)), - (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))), - (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))), - (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))), - - _ => Err(UnequalTypes(Op::Div)), - } - } -} - -impl ::std::ops::Rem for ConstInt { - type Output = Result; - fn rem(self, rhs: Self) -> Result { - let (lhs, rhs) = (self, rhs); - // should INT_MIN%-1 be zero or an error? - check_division(lhs, rhs, Op::Rem, RemainderByZero)?; - match (lhs, rhs) { - (I8(a), I8(b)) => Ok(I8(a%b)), - (I16(a), I16(b)) => Ok(I16(a%b)), - (I32(a), I32(b)) => Ok(I32(a%b)), - (I64(a), I64(b)) => Ok(I64(a%b)), - (I128(a), I128(b)) => Ok(I128(a%b)), - (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))), - (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))), - (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))), - - (U8(a), U8(b)) => Ok(U8(a%b)), - (U16(a), U16(b)) => Ok(U16(a%b)), - (U32(a), U32(b)) => Ok(U32(a%b)), - (U64(a), U64(b)) => Ok(U64(a%b)), - (U128(a), U128(b)) => Ok(U128(a%b)), - (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))), - (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))), - (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))), - - _ => Err(UnequalTypes(Op::Rem)), - } - } -} - -impl ::std::ops::Shl for ConstInt { - type Output = Result; - fn shl(self, rhs: Self) -> Result { - let b = rhs.to_u32().ok_or(ShiftNegative)?; - match self { - I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))), - I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))), - I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))), - I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))), - I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))), - Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shl(b), Op::Shl)))), - Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))), - Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))), - U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))), - U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))), - U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))), - U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))), - U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))), - Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))), - Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))), - Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))), - } - } -} - -impl ::std::ops::Shr for ConstInt { - type Output = Result; - fn shr(self, rhs: Self) -> Result { - let b = rhs.to_u32().ok_or(ShiftNegative)?; - match self { - I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))), - I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))), - I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))), - I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shr))), - I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))), - Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))), - Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))), - Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))), - U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))), - U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))), - U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))), - U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))), - U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))), - Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))), - Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))), - Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))), - } - } -} - -impl ::std::ops::Neg for ConstInt { - type Output = Result; - fn neg(self) -> Result { - match self { - I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))), - I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))), - I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))), - I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))), - I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))), - Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_neg(), Op::Neg)))), - Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))), - Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))), - a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) | - a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a), - U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation), - } - } -} - -impl ::std::ops::Not for ConstInt { - type Output = Result; - fn not(self) -> Result { - match self { - I8(a) => Ok(I8(!a)), - I16(a) => Ok(I16(!a)), - I32(a) => Ok(I32(!a)), - I64(a) => Ok(I64(!a)), - I128(a) => Ok(I128(!a)), - Isize(Is16(a)) => Ok(Isize(Is16(!a))), - Isize(Is32(a)) => Ok(Isize(Is32(!a))), - Isize(Is64(a)) => Ok(Isize(Is64(!a))), - U8(a) => Ok(U8(!a)), - U16(a) => Ok(U16(!a)), - U32(a) => Ok(U32(!a)), - U64(a) => Ok(U64(!a)), - U128(a) => Ok(U128(!a)), - Usize(Us16(a)) => Ok(Usize(Us16(!a))), - Usize(Us32(a)) => Ok(Usize(Us32(!a))), - Usize(Us64(a)) => Ok(Usize(Us64(!a))), - } - } -} diff --git a/src/librustc_const_math/isize.rs b/src/librustc_const_math/isize.rs deleted file mode 100644 index 18acc782775d8..0000000000000 --- a/src/librustc_const_math/isize.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax::ast; -use super::err::*; - -/// Depending on the target only one variant is ever used in a compilation. -/// Anything else is an error. This invariant is checked at several locations -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)] -pub enum ConstIsize { - Is16(i16), - Is32(i32), - Is64(i64), -} -pub use self::ConstIsize::*; - -impl ::std::fmt::Display for ConstIsize { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - write!(fmt, "{}", self.as_i64()) - } -} - -impl ConstIsize { - pub fn as_i64(self) -> i64 { - match self { - Is16(i) => i as i64, - Is32(i) => i as i64, - Is64(i) => i, - } - } - pub fn new(i: i64, isize_ty: ast::IntTy) -> Result { - match isize_ty { - ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)), - ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Isize)), - ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)), - ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Isize)), - ast::IntTy::I64 => Ok(Is64(i)), - _ => unreachable!(), - } - } - pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self { - match isize_ty { - ast::IntTy::I16 => Is16(i as i16), - ast::IntTy::I32 => Is32(i as i32), - ast::IntTy::I64 => Is64(i as i64), - _ => unreachable!(), - } - } -} diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 2d98bc48d2816..5555e727a9552 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -29,13 +29,7 @@ extern crate syntax; extern crate serialize as rustc_serialize; // used by deriving mod float; -mod int; -mod usize; -mod isize; mod err; pub use float::*; -pub use int::*; -pub use usize::*; -pub use isize::*; pub use err::{ConstMathErr, Op}; diff --git a/src/librustc_const_math/usize.rs b/src/librustc_const_math/usize.rs deleted file mode 100644 index 56995f08f05b8..0000000000000 --- a/src/librustc_const_math/usize.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use syntax::ast; -use super::err::*; - -/// Depending on the target only one variant is ever used in a compilation. -/// Anything else is an error. This invariant is checked at several locations -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)] -pub enum ConstUsize { - Us16(u16), - Us32(u32), - Us64(u64), -} -pub use self::ConstUsize::*; - -impl ::std::fmt::Display for ConstUsize { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - write!(fmt, "{}", self.as_u64()) - } -} - -impl ConstUsize { - pub fn as_u64(self) -> u64 { - match self { - Us16(i) => i as u64, - Us32(i) => i as u64, - Us64(i) => i, - } - } - pub fn new(i: u64, usize_ty: ast::UintTy) -> Result { - match usize_ty { - ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)), - ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Usize)), - ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)), - ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Usize)), - ast::UintTy::U64 => Ok(Us64(i)), - _ => unreachable!(), - } - } - pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self { - match usize_ty { - ast::UintTy::U16 => Us16(i as u16), - ast::UintTy::U32 => Us32(i as u32), - ast::UintTy::U64 => Us64(i as u64), - _ => unreachable!(), - } - } -} diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 33862ffeda270..82c317bba8b22 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1303,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.check_aggregate_rvalue(mir, rvalue, ak, ops, location) } - Rvalue::Repeat(operand, const_usize) => if const_usize.as_u64() > 1 { + Rvalue::Repeat(operand, len) => if *len > 1 { let operand_ty = operand.ty(mir, tcx); let trait_ref = ty::TraitRef { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index ca6e7c2c41580..e2cc58b1fb050 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -10,8 +10,6 @@ //! See docs in build/expr/mod.rs -use std; - use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -19,7 +17,6 @@ use rustc_data_structures::indexed_vec::Idx; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use hair::*; -use rustc_const_math::{ConstInt, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; @@ -385,31 +382,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = match ty.sty { - ty::TyInt(ity) => { - let val = match ity { - ast::IntTy::I8 => ConstInt::I8(-1), - ast::IntTy::I16 => ConstInt::I16(-1), - ast::IntTy::I32 => ConstInt::I32(-1), - ast::IntTy::I64 => ConstInt::I64(-1), - ast::IntTy::I128 => ConstInt::I128(-1), - ast::IntTy::Isize => { - let int_ty = self.hir.tcx().sess.target.isize_ty; - let val = ConstIsize::new(-1, int_ty).unwrap(); - ConstInt::Isize(val) - } - }; - - Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))), - ty - }) - } - } - _ => { - span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty) - } + let literal = Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(-1i128 as u128))), + ty + }) }; self.literal_operand(span, ty, literal) @@ -419,30 +396,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let literal = match ty.sty { ty::TyInt(ity) => { + let ity = match ity { + ast::IntTy::Isize => self.hir.tcx().sess.target.isize_ty, + other => other, + }; let val = match ity { - ast::IntTy::I8 => ConstInt::I8(i8::min_value()), - ast::IntTy::I16 => ConstInt::I16(i16::min_value()), - ast::IntTy::I32 => ConstInt::I32(i32::min_value()), - ast::IntTy::I64 => ConstInt::I64(i64::min_value()), - ast::IntTy::I128 => ConstInt::I128(i128::min_value()), - ast::IntTy::Isize => { - let int_ty = self.hir.tcx().sess.target.isize_ty; - let min = match int_ty { - ast::IntTy::I16 => std::i16::MIN as i64, - ast::IntTy::I32 => std::i32::MIN as i64, - ast::IntTy::I64 => std::i64::MIN, - _ => unreachable!() - }; - let val = ConstIsize::new(min, int_ty).unwrap(); - ConstInt::Isize(val) - } + ast::IntTy::I8 => i8::min_value() as i128, + ast::IntTy::I16 => i16::min_value() as i128, + ast::IntTy::I32 => i32::min_value() as i128, + ast::IntTy::I64 => i64::min_value() as i128, + ast::IntTy::I128 => i128::min_value() as i128, + ast::IntTy::Isize => unreachable!(), }; Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes( - val.to_u128_unchecked() - ))), + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))), ty }) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 4a5d9e228815e..09579eaecb2de 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -197,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { target_blocks.place_back() <- if variants.contains(idx) { - values.push(discr.to_u128_unchecked()); + values.push(discr.val); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 7ac96a634cf98..b4807148ddf0d 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -799,7 +799,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ).unwrap(); let variant_index = adt_def .discriminants(self.tcx) - .position(|var| var.to_u128_unchecked() == discr) + .position(|var| var.val == discr) .unwrap(); PatternKind::Variant { adt_def, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 0ab3be019781d..6f4a828a929e4 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -521,10 +521,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, promoted: None }; let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) { - Ok(cv) => cv.val.unwrap_usize(cx.tcx), + Ok(cv) => cv.val.unwrap_u64(), Err(e) => { e.report(cx.tcx, cx.tcx.def_span(def_id), "array length"); - ConstUsize::new(0, cx.tcx.sess.target.usize_ty).unwrap() + 0 }, }; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index f65029fed0a9a..706c53b077eb6 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -29,7 +29,7 @@ use syntax::ast::{self, LitKind}; use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; -use rustc_const_math::{ConstUsize, ConstFloat}; +use rustc_const_math::ConstFloat; use rustc::mir::interpret::{Value, PrimVal}; use std::rc::Rc; @@ -115,16 +115,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> { - match ConstUsize::new(value, self.tcx.sess.target.usize_ty) { - Ok(val) => { - Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.as_u64() as u128))), - ty: self.tcx.types.usize - }) - } - } - Err(_) => bug!("usize literal out of range for target"), + Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))), + ty: self.tcx.types.usize + }) } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 329365c4415e8..a7cfa94f6961d 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,7 +14,6 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc_const_math::ConstUsize; use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp}; use rustc::hir::def_id::DefId; use rustc::middle::region; @@ -246,7 +245,7 @@ pub enum ExprKind<'tcx> { }, Repeat { value: ExprRef<'tcx>, - count: ConstUsize, + count: u64, }, Array { fields: Vec>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index eacff1491eab2..565c5df8878f4 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -756,7 +756,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M if let ty::TyAdt(adt_def, _) = ty.sty { trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::>()); if adt_def.discriminants(self.tcx).all(|v| { - discr_val != v.to_u128_unchecked() + discr_val != v.val }) { return err!(InvalidDiscriminant); @@ -912,7 +912,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M layout::Variants::Tagged { .. } => { let discr_val = dest_ty.ty_adt_def().unwrap() .discriminant_for_variant(self.tcx, variant_index) - .to_u128_unchecked(); + .val; let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 141f3e3fddd8f..28b84501da786 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -16,7 +16,6 @@ use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; -use rustc_const_math::ConstUsize; use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -508,13 +507,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: { - let value = ConstUsize::new( - value, - self.tcx.sess.target.usize_ty, - ).unwrap().as_u64(); - ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) - }, + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))), ty: self.tcx.types.usize, }) } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 5b3b58554ca56..2c70110db438d 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -426,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path, &adt.variants[variant_index], substs); - values.push(discr.to_u128().unwrap()); + values.push(discr.val); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original // drop ladder, because this breaks the diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index b379a174b23f6..582d98c1c8578 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -12,7 +12,6 @@ // pieces of MIR. The resulting numbers are good approximations but not // completely accurate (some things might be counted twice, others missed). -use rustc_const_math::{ConstUsize}; use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; use rustc::mir::{Constant, Literal, Location, Local, LocalDecl}; use rustc::mir::{Place, PlaceElem, PlaceProjection}; @@ -264,13 +263,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.super_const(constant); } - fn visit_const_usize(&mut self, - const_usize: &ConstUsize, - _: Location) { - self.record("ConstUsize", const_usize); - self.super_const_usize(const_usize); - } - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index d886be1f953ab..233120f2bf30d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -335,14 +335,6 @@ pub fn cast_shift_expr_rhs( cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b)) } -pub fn cast_shift_const_rhs(op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - cast_shift_rhs(op, - lhs, - rhs, - |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) }, - |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) }) -} - fn cast_shift_rhs(op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 6111b243720ff..63178f7c57d7d 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1378,7 +1378,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, DIB(cx), name.as_ptr(), // FIXME: what if enumeration has i128 discriminant? - discr.to_u128_unchecked() as u64) + discr.val as u64) } }) .collect(); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1d04e30eb3e83..954abf4c5d703 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -9,7 +9,6 @@ // except according to those terms. use llvm::{self, ValueRef}; -use rustc_const_math::{ConstInt, ConstMathErr}; use rustc::middle::const_val::{ConstVal, ConstEvalErr}; use rustc_mir::interpret::{read_target_uint, const_val_field}; use rustc::hir::def_id::DefId; @@ -17,13 +16,11 @@ use rustc::traits; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; -use base; use builder::Builder; use common::{CodegenCx}; use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; -use common::const_to_opt_u128; use consts; use type_of::LayoutLlvmExt; use type_::Type; @@ -31,110 +28,6 @@ use type_::Type; use super::super::callee; use super::FunctionCx; -fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { - match t.sty { - ty::TyInt(int_type) => const_to_opt_u128(value, true) - .and_then(|input| ConstInt::new_signed(input as i128, int_type, - tcx.sess.target.isize_ty)), - ty::TyUint(uint_type) => const_to_opt_u128(value, false) - .and_then(|input| ConstInt::new_unsigned(input, uint_type, - tcx.sess.target.usize_ty)), - _ => None - - } -} - -pub fn const_scalar_binop(op: mir::BinOp, - lhs: ValueRef, - rhs: ValueRef, - input_ty: Ty) -> ValueRef { - assert!(!input_ty.is_simd()); - let is_float = input_ty.is_fp(); - let signed = input_ty.is_signed(); - - unsafe { - match op { - mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs), - mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs), - - mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs), - mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs), - - mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs), - mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs), - - mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs), - mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs), - mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs), - - mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs), - mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs), - mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs), - - mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs), - mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs), - mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs), - mir::BinOp::Shl => { - let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs); - llvm::LLVMConstShl(lhs, rhs) - } - mir::BinOp::Shr => { - let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs); - if signed { llvm::LLVMConstAShr(lhs, rhs) } - else { llvm::LLVMConstLShr(lhs, rhs) } - } - mir::BinOp::Eq | mir::BinOp::Ne | - mir::BinOp::Lt | mir::BinOp::Le | - mir::BinOp::Gt | mir::BinOp::Ge => { - if is_float { - let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop()); - llvm::LLVMConstFCmp(cmp, lhs, rhs) - } else { - let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(), - signed); - llvm::LLVMConstICmp(cmp, lhs, rhs) - } - } - mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!") - } - } -} - -pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - op: mir::BinOp, - lllhs: ValueRef, - llrhs: ValueRef, - input_ty: Ty<'tcx>) - -> Option<(ValueRef, bool)> { - if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx), - to_const_int(llrhs, input_ty, tcx)) { - let result = match op { - mir::BinOp::Add => lhs + rhs, - mir::BinOp::Sub => lhs - rhs, - mir::BinOp::Mul => lhs * rhs, - mir::BinOp::Shl => lhs << rhs, - mir::BinOp::Shr => lhs >> rhs, - _ => { - bug!("Operator `{:?}` is not a checkable operator", op) - } - }; - - let of = match result { - Ok(_) => false, - Err(ConstMathErr::Overflow(_)) | - Err(ConstMathErr::ShiftNegative) => true, - Err(err) => { - bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}", - op, lhs, rhs, err.description()); - } - }; - - Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of)) - } else { - None - } -} - pub fn primval_to_llvm(cx: &CodegenCx, cv: PrimVal, scalar: &Scalar, diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index 99770476e12f9..b340d91b02708 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -328,7 +328,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let ptr = self.project_field(bx, 0); let to = self.layout.ty.ty_adt_def().unwrap() .discriminant_for_variant(bx.tcx(), variant_index) - .to_u128_unchecked() as u64; + .val as u64; bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64), ptr.llval, ptr.align); } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 38df7ce30fdd3..62097dc436d04 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -30,7 +30,6 @@ use type_of::LayoutLlvmExt; use value::Value; use super::{FunctionCx, LocalRef}; -use super::constant::const_scalar_checked_binop; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -122,7 +121,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - let count = count.as_u64(); let count = C_usize(bx.cx, count); let end = dest.project_index(&bx, count).llval; @@ -641,14 +639,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { return OperandValue::Pair(val, C_bool(bx.cx, false)); } - // First try performing the operation on constants, which - // will only succeed if both operands are constant. - // This is necessary to determine when an overflow Assert - // will always panic at runtime, and produce a warning. - if let Some((val, of)) = const_scalar_checked_binop(bx.tcx(), op, lhs, rhs, input_ty) { - return OperandValue::Pair(val, C_bool(bx.cx, of)); - } - let (val, of) = match op { // These are checked using intrinsics mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3237f8875cc7e..0197988f56669 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,7 +100,8 @@ use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::TypeFoldable; use rustc::ty::maps::Providers; -use rustc::ty::util::{Representability, IntTypeExt}; +use rustc::ty::util::{Representability, IntTypeExt, Discr}; +use rustc::ty::layout::LayoutOf; use errors::{DiagnosticBuilder, DiagnosticId}; use require_c_abi_if_variadic; @@ -133,7 +134,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map::Node; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; -use rustc_const_math::ConstInt; mod autoderef; pub mod dropck; @@ -1616,10 +1616,10 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let mut disr_vals: Vec = Vec::new(); + let mut disr_vals: Vec> = Vec::new(); for (discr, v) in def.discriminants(tcx).zip(vs) { // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x == discr) { + if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { let variant_i_node_id = tcx.hir.as_local_node_id(def.variants[i].did).unwrap(); let variant_i = tcx.hir.expect_variant(variant_i_node_id); let i_span = match variant_i.node.disr_expr { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1cab5b7f6350a..0aef3a2f4e905 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -37,10 +37,9 @@ use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::ty::util::Discr; use util::nodemap::FxHashMap; -use rustc_const_math::ConstInt; - use syntax::{abi, ast}; use syntax::codemap::Spanned; use syntax::symbol::{Symbol, keywords}; @@ -518,11 +517,11 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); - let mut prev_discr = None::; + let mut prev_discr = None::>; // fill the discriminant values and field types for variant in variants { - let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); + let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx)); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let substs = Substs::identity_for_item(tcx, expr_did); @@ -537,19 +536,17 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // so we need to report the real error if let Err(ref err) = result { err.report(tcx, variant.span, "enum discriminant"); -} + } match result { + // FIXME: just use `to_raw_bits` here? Ok(&ty::Const { val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), .. }) => { - use syntax::attr::IntType; - Some(match repr_type { - IntType::SignedInt(int_type) => ConstInt::new_signed( - b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), - IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( - b, uint_type, tcx.sess.target.usize_ty).unwrap(), + Some(Discr { + val: b, + ty: initial.ty, }) } _ => None diff --git a/src/test/compile-fail/issue-27592.rs b/src/test/compile-fail/issue-27592.rs index 731d4fb2bf693..bc29594114746 100644 --- a/src/test/compile-fail/issue-27592.rs +++ b/src/test/compile-fail/issue-27592.rs @@ -26,4 +26,5 @@ fn main() { write(|| format_args!("{}", String::from("Hello world"))); //~^ ERROR borrowed value does not live long enough //~| ERROR borrowed value does not live long enough + //~| ERROR borrowed value does not live long enough } diff --git a/src/test/ui/issue-15524.rs b/src/test/ui/issue-15524.rs index 85214bd86336c..7e696c97595aa 100644 --- a/src/test/ui/issue-15524.rs +++ b/src/test/ui/issue-15524.rs @@ -13,13 +13,13 @@ const N: isize = 1; enum Foo { A = 1, B = 1, - //~^ ERROR discriminant value `1isize` already exists + //~^ ERROR discriminant value `1` already exists C = 0, D, - //~^ ERROR discriminant value `1isize` already exists + //~^ ERROR discriminant value `1` already exists E = N, - //~^ ERROR discriminant value `1isize` already exists + //~^ ERROR discriminant value `1` already exists } diff --git a/src/test/ui/issue-15524.stderr b/src/test/ui/issue-15524.stderr index 9c77752be2022..a23a586122f52 100644 --- a/src/test/ui/issue-15524.stderr +++ b/src/test/ui/issue-15524.stderr @@ -1,28 +1,28 @@ -error[E0081]: discriminant value `1isize` already exists +error[E0081]: discriminant value `1` already exists --> $DIR/issue-15524.rs:15:9 | 14 | A = 1, - | - first use of `1isize` + | - first use of `1` 15 | B = 1, - | ^ enum already has `1isize` + | ^ enum already has `1` -error[E0081]: discriminant value `1isize` already exists +error[E0081]: discriminant value `1` already exists --> $DIR/issue-15524.rs:18:5 | 14 | A = 1, - | - first use of `1isize` + | - first use of `1` ... 18 | D, - | ^ enum already has `1isize` + | ^ enum already has `1` -error[E0081]: discriminant value `1isize` already exists +error[E0081]: discriminant value `1` already exists --> $DIR/issue-15524.rs:21:9 | 14 | A = 1, - | - first use of `1isize` + | - first use of `1` ... 21 | E = N, - | ^ enum already has `1isize` + | ^ enum already has `1` error: aborting due to 3 previous errors From f246c42b7b2e0a2efa6037ff85c6ee35a4784a84 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 13:37:46 +0100 Subject: [PATCH 046/115] Use layout::Integer over manual *size resolving --- src/librustc/ty/util.rs | 53 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index afa7ca6e7ef72..02077615abd5d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -21,6 +21,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; +use ty::layout::Integer; use util::common::ErrorReported; use middle::lang_items; use mir::interpret::{Value, PrimVal}; @@ -31,7 +32,7 @@ use rustc_data_structures::fx::FxHashMap; use std::{cmp, fmt}; use std::hash::Hash; use std::intrinsics; -use syntax::ast::{self, Name, UintTy, IntTy}; +use syntax::ast::{self, Name}; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; @@ -57,31 +58,21 @@ impl<'tcx> Discr<'tcx> { self.checked_add(tcx, 1).0 } pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Self, bool) { - let ty = match self.ty.sty { - TyInt(IntTy::Isize) => tcx.mk_mach_int(tcx.sess.target.isize_ty), - TyUint(UintTy::Usize) => tcx.mk_mach_uint(tcx.sess.target.usize_ty), - _ => self.ty, + let (int, signed) = match self.ty.sty { + TyInt(ity) => (Integer::from_attr(tcx, SignedInt(ity)), true), + TyUint(uty) => (Integer::from_attr(tcx, UnsignedInt(uty)), false), + _ => bug!("non integer discriminant"), }; - let (min, max) = match ty.sty { - TyInt(IntTy::I8) => (i8::min_value() as i128 as u128, i8::max_value() as u128), - TyInt(IntTy::I16) => (i16::min_value() as i128 as u128, i16::max_value() as u128), - TyInt(IntTy::I32) => (i32::min_value() as i128 as u128, i32::max_value() as u128), - TyInt(IntTy::I64) => (i64::min_value() as i128 as u128, i64::max_value() as u128), - TyInt(IntTy::I128) => (i128::min_value() as i128 as u128, i128::max_value() as u128), - TyInt(IntTy::Isize) => unreachable!(), - TyUint(UintTy::U8) => (u8::min_value() as u128, u8::max_value() as u128), - TyUint(UintTy::U16) => (u16::min_value() as u128, u16::max_value() as u128), - TyUint(UintTy::U32) => (u32::min_value() as u128, u32::max_value() as u128), - TyUint(UintTy::U64) => (u64::min_value() as u128, u64::max_value() as u128), - TyUint(UintTy::U128) => (u128::min_value() as u128, u128::max_value()), - TyUint(UintTy::Usize) => unreachable!(), - _ => bug!("not a valid discriminant type: {}", ty) - }; - if ty.is_signed() { + if signed { + let (min, max) = match int { + Integer::I8 => (i8::min_value() as i128, i8::max_value() as i128), + Integer::I16 => (i16::min_value() as i128, i16::max_value() as i128), + Integer::I32 => (i32::min_value() as i128, i32::max_value() as i128), + Integer::I64 => (i64::min_value() as i128, i64::max_value() as i128), + Integer::I128 => (i128::min_value(), i128::max_value()), + }; let val = self.val as i128; let n = n as i128; - let max = max as i128; - let min = min as i128; let oflo = val > max - n; let val = if oflo { min + (n - (max - val)) @@ -93,14 +84,22 @@ impl<'tcx> Discr<'tcx> { ty: self.ty, }, oflo) } else { - let oflo = self.val > max - n; + let (min, max) = match int { + Integer::I8 => (u8::min_value() as u128, u8::max_value() as u128), + Integer::I16 => (u16::min_value() as u128, u16::max_value() as u128), + Integer::I32 => (u32::min_value() as u128, u32::max_value() as u128), + Integer::I64 => (u64::min_value() as u128, u64::max_value() as u128), + Integer::I128 => (u128::min_value(), u128::max_value()), + }; + let val = self.val; + let oflo = val > max - n; let val = if oflo { - min + (n - (max - self.val)) + min + (n - (max - val)) } else { - self.val + n + val + n }; (Self { - val, + val: val, ty: self.ty, }, oflo) } From 2299b7cb6ae53c40b616112b0bd7670a75c65fd3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 13:45:41 +0100 Subject: [PATCH 047/115] Rename simd shuffle function and adjust comment --- src/librustc_trans/mir/block.rs | 2 +- src/librustc_trans/mir/constant.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index d0121ebe1e011..9f69442bd5b7d 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -530,7 +530,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { span_bug!(span, "shuffle indices must be constant"); } mir::Operand::Constant(ref constant) => { - let (llval, ty) = self.remove_me_shuffle_indices( + let (llval, ty) = self.simd_shuffle_indices( &bx, constant, ); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 954abf4c5d703..1b470665cd9c5 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -184,12 +184,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { }.and_then(|c| self.const_to_miri_value(bx, c)) } - // Old version of trans_constant now used just for SIMD shuffle - pub fn remove_me_shuffle_indices(&mut self, - bx: &Builder<'a, 'tcx>, - constant: &mir::Constant<'tcx>) - -> (ValueRef, Ty<'tcx>) - { + /// process constant containing SIMD shuffle indices + pub fn simd_shuffle_indices( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>, + ) -> (ValueRef, Ty<'tcx>) { let layout = bx.cx.layout_of(constant.ty); self.mir_constant_to_miri_value(bx, constant) .and_then(|c| { From 6aaadeb1de4e4c98dc82a92972dbd42a900249f8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 13:50:42 +0100 Subject: [PATCH 048/115] Stop emitting `miri failed` in error messages --- src/librustc/middle/const_val.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 06d4540a455e8..5b18b7d5fd918 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { TypeckError => simple!("type-checking failed"), CheckMatchError => simple!("match-checking failed"), // FIXME: report a full backtrace - Miri(ref err) => simple!("miri failed: {}", err), + Miri(ref err) => simple!("{}", err), } } From 3d8f911900f169df9cd5234b6e86098891eafd4c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 13:54:51 +0100 Subject: [PATCH 049/115] Prefer enum instead of magic numbers --- src/librustc/ich/impls_ty.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index b12bb5bbff338..ab766fe312258 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -347,6 +347,17 @@ impl_stable_hash_for!(struct mir::interpret::MemoryPointer { offset }); +enum AllocDiscriminant { + Static, + Constant, + Function, +} +impl_stable_hash_for!(enum self::AllocDiscriminant { + Static, + Constant, + Function +}); + impl<'a> HashStable> for mir::interpret::AllocId { fn hash_stable( &self, @@ -356,15 +367,15 @@ impl<'a> HashStable> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { let tcx = tcx.expect("can't hash AllocIds during hir lowering"); if let Some(def_id) = tcx.interpret_interner.get_corresponding_static_def_id(*self) { - 0.hash_stable(hcx, hasher); + AllocDiscriminant::Static.hash_stable(hcx, hasher); // statics are unique via their DefId def_id.hash_stable(hcx, hasher); } else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) { // not a static, can't be recursive, hash the allocation - 1.hash_stable(hcx, hasher); + AllocDiscriminant::Constant.hash_stable(hcx, hasher); alloc.hash_stable(hcx, hasher); } else if let Some(inst) = tcx.interpret_interner.get_fn(*self) { - 2.hash_stable(hcx, hasher); + AllocDiscriminant::Function.hash_stable(hcx, hasher); inst.hash_stable(hcx, hasher); } else { bug!("no allocation for {}", self); From 404e07873d3f8fc13040a5ddfcbeb911006dcbd8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 14:28:58 +0100 Subject: [PATCH 050/115] Use Mutability enum instead of bool --- src/librustc/ich/impls_ty.rs | 7 ++++++- src/librustc/mir/interpret/mod.rs | 9 ++++++--- src/librustc_mir/interpret/memory.rs | 4 ++-- src/librustc_trans/mir/constant.rs | 3 ++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index ab766fe312258..8ac2f929b8da6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -396,10 +396,15 @@ impl<'a> HashStable> for mir::interpret::Allocation { } self.undef_mask.hash_stable(hcx, hasher); self.align.hash_stable(hcx, hasher); - self.mutable.hash_stable(hcx, hasher); + self.runtime_mutability.hash_stable(hcx, hasher); } } +impl_stable_hash_for!(enum ::syntax::ast::Mutability { + Immutable, + Mutable +}); + impl_stable_hash_for!(struct mir::interpret::Pointer{primval}); impl_stable_hash_for!(enum mir::interpret::PrimVal { diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index a41ad94f00a0b..48db9cebf38b0 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -19,6 +19,7 @@ use ty; use ty::layout::{self, Align, HasDataLayout}; use middle::region; use std::iter; +use syntax::ast::Mutability; #[derive(Clone, Debug, PartialEq)] pub enum Lock { @@ -169,8 +170,10 @@ pub struct Allocation { pub undef_mask: UndefMask, /// The alignment of the allocation to detect unaligned reads. pub align: Align, - /// Whether the allocation should be put into mutable memory when translating via llvm - pub mutable: bool, + /// Whether the allocation (of a static) should be put into mutable memory when translating + /// + /// Only happens for `static mut` or `static` with interior mutability + pub runtime_mutability: Mutability, } impl Allocation { @@ -182,7 +185,7 @@ impl Allocation { relocations: BTreeMap::new(), undef_mask, align: Align::from_bytes(1, 1).unwrap(), - mutable: false, + runtime_mutability: Mutability::Immutable, } } } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index eb5bbd5e73e14..711bd3dd57e93 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { relocations: BTreeMap::new(), undef_mask: UndefMask::new(size), align, - mutable: false, + runtime_mutability: Mutability::Immutable, }; let id = self.tcx.interpret_interner.reserve(); M::add_lock(self, id); @@ -544,7 +544,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { let uninit = self.uninitialized_statics.remove(&alloc_id); if let Some(mut alloc) = alloc.or(uninit) { // ensure llvm knows not to put this into immutable memroy - alloc.mutable = mutability == Mutability::Mutable; + alloc.runtime_mutability = mutability; let alloc = self.tcx.intern_const_alloc(alloc); self.tcx.interpret_interner.intern_at_reserved(alloc_id, alloc); // recurse into inner allocations diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1b470665cd9c5..c7a0724c1e72b 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -24,6 +24,7 @@ use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; use consts; use type_of::LayoutLlvmExt; use type_::Type; +use syntax::ast::Mutability; use super::super::callee; use super::FunctionCx; @@ -57,7 +58,7 @@ pub fn primval_to_llvm(cx: &CodegenCx, } else if let Some(alloc) = cx.tcx.interpret_interner .get_alloc(ptr.alloc_id) { let init = global_initializer(cx, alloc); - if alloc.mutable { + if alloc.runtime_mutability == Mutability::Mutable { consts::addr_of_mut(cx, init, alloc.align, "byte_str") } else { consts::addr_of(cx, init, alloc.align, "byte_str") From aceed8d09650716b3594f81603f3c9cf452f594b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:19:01 +0100 Subject: [PATCH 051/115] Reduce noise in error reporting --- src/librustc/mir/interpret/error.rs | 2 +- src/librustc/ty/util.rs | 4 +-- src/librustc_mir/interpret/const_eval.rs | 2 +- src/test/compile-fail/E0081.rs | 2 +- src/test/compile-fail/issue-27592.rs | 1 - src/test/run-pass/ctfe/promotion.rs | 17 ++++++++++ src/test/ui/const-eval-overflow-2.stderr | 2 +- src/test/ui/const-eval-overflow-4.stderr | 2 +- src/test/ui/const-fn-error.stderr | 2 +- .../const-len-underflow-separate-spans.stderr | 2 +- src/test/ui/discrim-overflow-2.stderr | 32 +++++++++---------- src/test/ui/discrim-overflow.rs | 10 +++--- src/test/ui/discrim-overflow.stderr | 32 +++++++++---------- .../ui/infinite-recursion-const-fn.stderr | 2 +- 14 files changed, 64 insertions(+), 48 deletions(-) create mode 100644 src/test/run-pass/ctfe/promotion.rs diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 702fd85794fff..3e8aeaff57e62 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -306,7 +306,7 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { PathNotFound(ref path) => write!(f, "Cannot find path {:?}", path), MachineError(ref inner) => - write!(f, "machine error: {}", inner), + write!(f, "{}", inner), IncorrectAllocationInformation(size, size2, align, align2) => write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2), _ => write!(f, "{}", self.description()), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 02077615abd5d..c70df5ce1801b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -75,7 +75,7 @@ impl<'tcx> Discr<'tcx> { let n = n as i128; let oflo = val > max - n; let val = if oflo { - min + (n - (max - val)) + min + (n - (max - val) - 1) } else { val + n }; @@ -94,7 +94,7 @@ impl<'tcx> Discr<'tcx> { let val = self.val; let oflo = val > max - n; let val = if oflo { - min + (n - (max - val)) + min + (n - (max - val) - 1) } else { val + n }; diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 66c8f47afe5e3..d7bef752cb339 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -183,7 +183,7 @@ impl fmt::Display for ConstEvalError { msg ) } - NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), + NotConst(ref msg) => write!(f, "{}", msg), } } } diff --git a/src/test/compile-fail/E0081.rs b/src/test/compile-fail/E0081.rs index 3b571667336ac..c0cdad258687d 100644 --- a/src/test/compile-fail/E0081.rs +++ b/src/test/compile-fail/E0081.rs @@ -11,7 +11,7 @@ enum Enum { P = 3, X = 3, - //~^ ERROR discriminant value `3isize` already exists + //~^ ERROR discriminant value `3` already exists Y = 5 } diff --git a/src/test/compile-fail/issue-27592.rs b/src/test/compile-fail/issue-27592.rs index bc29594114746..731d4fb2bf693 100644 --- a/src/test/compile-fail/issue-27592.rs +++ b/src/test/compile-fail/issue-27592.rs @@ -26,5 +26,4 @@ fn main() { write(|| format_args!("{}", String::from("Hello world"))); //~^ ERROR borrowed value does not live long enough //~| ERROR borrowed value does not live long enough - //~| ERROR borrowed value does not live long enough } diff --git a/src/test/run-pass/ctfe/promotion.rs b/src/test/run-pass/ctfe/promotion.rs new file mode 100644 index 0000000000000..2d228408254aa --- /dev/null +++ b/src/test/run-pass/ctfe/promotion.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(_: &'static [&'static str]) {} +fn bar(_: &'static [&'static str; 3]) {} + +fn main() { + foo(&["a", "b", "c"]); + bar(&["d", "e", "f"]); +} diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr index e92754fc13582..bf72b9960c6df 100644 --- a/src/test/ui/const-eval-overflow-2.stderr +++ b/src/test/ui/const-eval-overflow-2.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-2.rs:21:1 | 21 | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: attempt to negate with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to negate with overflow | note: for pattern here --> $DIR/const-eval-overflow-2.rs:26:9 diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr index 2f8bf78758a0f..1ccac3cd01ee5 100644 --- a/src/test/ui/const-eval-overflow-4.stderr +++ b/src/test/ui/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-4.rs:23:13 | 23 | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ miri failed: attempt to add with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow error: aborting due to previous error diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index e313128aa7803..f17447e4f7301 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -20,7 +20,7 @@ error[E0080]: constant evaluation error --> $DIR/const-fn-error.rs:28:19 | 28 | let a : [i32; f(X)]; - | ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `>::into_iter`" + | ^^^^ calling non-const fn `>::into_iter` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 6b2789c145444..5409ff545fe43 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -14,7 +14,7 @@ error[E0080]: constant evaluation error --> $DIR/const-len-underflow-separate-spans.rs:21:17 | 21 | let a: [i8; LEN] = unimplemented!(); - | ^^^ miri failed: attempt to subtract with overflow + | ^^^ attempt to subtract with overflow error: aborting due to 2 previous errors diff --git a/src/test/ui/discrim-overflow-2.stderr b/src/test/ui/discrim-overflow-2.stderr index 660110cd73715..5e6d0a7de6df0 100644 --- a/src/test/ui/discrim-overflow-2.stderr +++ b/src/test/ui/discrim-overflow-2.stderr @@ -2,65 +2,65 @@ error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:27:9 | 27 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 127i8 + | ^^^^ overflowed on value after 127 | - = note: explicitly set `OhNo = -128i8` if that is desired outcome + = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:36:9 | 36 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 255u8 + | ^^^^ overflowed on value after 255 | - = note: explicitly set `OhNo = 0u8` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:45:9 | 45 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 32767i16 + | ^^^^ overflowed on value after 32767 | - = note: explicitly set `OhNo = -32768i16` if that is desired outcome + = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:54:9 | 54 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 65535u16 + | ^^^^ overflowed on value after 65535 | - = note: explicitly set `OhNo = 0u16` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:63:9 | 63 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 2147483647i32 + | ^^^^ overflowed on value after 2147483647 | - = note: explicitly set `OhNo = -2147483648i32` if that is desired outcome + = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:72:9 | 72 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 4294967295u32 + | ^^^^ overflowed on value after 4294967295 | - = note: explicitly set `OhNo = 0u32` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:81:9 | 81 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 9223372036854775807i64 + | ^^^^ overflowed on value after 9223372036854775807 | - = note: explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome + = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow-2.rs:90:9 | 90 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 18446744073709551615u64 + | ^^^^ overflowed on value after 18446744073709551615 | - = note: explicitly set `OhNo = 0u64` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error: aborting due to 8 previous errors diff --git a/src/test/ui/discrim-overflow.rs b/src/test/ui/discrim-overflow.rs index 0b31d9f97f174..16b417c61a517 100644 --- a/src/test/ui/discrim-overflow.rs +++ b/src/test/ui/discrim-overflow.rs @@ -56,7 +56,7 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo, //~ ERROR enum discriminant overflowed [E0370] - //~| overflowed on value after 65535u16 + //~| overflowed on value after 65535 } let x = A::Ok; @@ -68,7 +68,7 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo, //~ ERROR enum discriminant overflowed [E0370] - //~| overflowed on value after 2147483647i32 + //~| overflowed on value after 2147483647 } let x = A::Ok; @@ -80,7 +80,7 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo, //~ ERROR enum discriminant overflowed [E0370] - //~| overflowed on value after 4294967295u32 + //~| overflowed on value after 4294967295 } let x = A::Ok; @@ -92,7 +92,7 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo, //~ ERROR enum discriminant overflowed [E0370] - //~| overflowed on value after 9223372036854775807i64 + //~| overflowed on value after 9223372036854775807 } let x = A::Ok; @@ -104,7 +104,7 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo, //~ ERROR enum discriminant overflowed [E0370] - //~| overflowed on value after 18446744073709551615u64 + //~| overflowed on value after 18446744073709551615 } let x = A::Ok; diff --git a/src/test/ui/discrim-overflow.stderr b/src/test/ui/discrim-overflow.stderr index 733810006d74a..445eff1a4de63 100644 --- a/src/test/ui/discrim-overflow.stderr +++ b/src/test/ui/discrim-overflow.stderr @@ -2,65 +2,65 @@ error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:25:9 | 25 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 127i8 + | ^^^^ overflowed on value after 127 | - = note: explicitly set `OhNo = -128i8` if that is desired outcome + = note: explicitly set `OhNo = -128` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:36:9 | 36 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 255u8 + | ^^^^ overflowed on value after 255 | - = note: explicitly set `OhNo = 0u8` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:47:9 | 47 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 32767i16 + | ^^^^ overflowed on value after 32767 | - = note: explicitly set `OhNo = -32768i16` if that is desired outcome + = note: explicitly set `OhNo = -32768` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:58:9 | 58 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 65535u16 + | ^^^^ overflowed on value after 65535 | - = note: explicitly set `OhNo = 0u16` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:70:9 | 70 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 2147483647i32 + | ^^^^ overflowed on value after 2147483647 | - = note: explicitly set `OhNo = -2147483648i32` if that is desired outcome + = note: explicitly set `OhNo = -2147483648` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:82:9 | 82 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 4294967295u32 + | ^^^^ overflowed on value after 4294967295 | - = note: explicitly set `OhNo = 0u32` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:94:9 | 94 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 9223372036854775807i64 + | ^^^^ overflowed on value after 9223372036854775807 | - = note: explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome + = note: explicitly set `OhNo = -9223372036854775808` if that is desired outcome error[E0370]: enum discriminant overflowed --> $DIR/discrim-overflow.rs:106:9 | 106 | OhNo, //~ ERROR enum discriminant overflowed [E0370] - | ^^^^ overflowed on value after 18446744073709551615u64 + | ^^^^ overflowed on value after 18446744073709551615 | - = note: explicitly set `OhNo = 0u64` if that is desired outcome + = note: explicitly set `OhNo = 0` if that is desired outcome error: aborting due to 8 previous errors diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index ce1b35aac7ecc..e0a403cd1f11f 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/infinite-recursion-const-fn.rs:16:18 | 16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error - | ^^^ miri failed: reached the configured maximum number of stack frames + | ^^^ reached the configured maximum number of stack frames error: aborting due to previous error From d401b1d08b7f2c1ef740c8a690b99ac9323ff242 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:27:38 +0100 Subject: [PATCH 052/115] Move compare_const_vals out of `eval` --- src/librustc_mir/const_eval/_match.rs | 3 +-- src/librustc_mir/const_eval/eval.rs | 31 -------------------------- src/librustc_mir/const_eval/pattern.rs | 31 +++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/librustc_mir/const_eval/_match.rs b/src/librustc_mir/const_eval/_match.rs index af50d11b889cd..332481c0d4f53 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -13,13 +13,12 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc::middle::const_val::ConstVal; -use const_eval::eval::{compare_const_vals}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use const_eval::pattern::{FieldPattern, Pattern, PatternKind}; -use const_eval::pattern::{PatternFoldable, PatternFolder}; +use const_eval::pattern::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; diff --git a/src/librustc_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs index 25a9e52236773..32f834daa4c78 100644 --- a/src/librustc_mir/const_eval/eval.rs +++ b/src/librustc_mir/const_eval/eval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::middle::const_val::ConstVal::*; use rustc::middle::const_val::ConstVal; use rustc::hir::def_id::DefId; @@ -17,8 +16,6 @@ use rustc::ty::subst::Substs; use syntax::ast; -use std::cmp::Ordering; - use rustc_const_math::*; /// * `DefId` is the id of the constant. @@ -128,31 +125,3 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) -> Result { ConstFloat::from_str(num, fty).map_err(|_| ()) } - -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { - trace!("compare_const_vals: {:?}, {:?}", a, b); - use rustc::mir::interpret::{Value, PrimVal}; - match (a, b) { - (&Value(Value::ByVal(PrimVal::Bytes(a))), - &Value(Value::ByVal(PrimVal::Bytes(b)))) => { - match ty.sty { - ty::TyFloat(ty) => { - let l = ConstFloat { - bits: a, - ty, - }; - let r = ConstFloat { - bits: b, - ty, - }; - // FIXME(oli-obk): report cmp errors? - l.try_cmp(r).ok() - }, - ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), - _ => Some(a.cmp(&b)), - } - }, - _ if a == b => Some(Ordering::Equal), - _ => None, - } -} diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index b4807148ddf0d..5afed5e2e3ce7 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -18,10 +18,10 @@ use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use const_eval::eval::compare_const_vals; use rustc_data_structures::indexed_vec::Idx; +use std::cmp::Ordering; use std::fmt; use syntax::ast; use syntax::ptr::P; @@ -1060,3 +1060,32 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } } + +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + use rustc_const_math::ConstFloat; + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { + (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), + &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { + match ty.sty { + ty::TyFloat(ty) => { + let l = ConstFloat { + bits: a, + ty, + }; + let r = ConstFloat { + bits: b, + ty, + }; + // FIXME(oli-obk): report cmp errors? + l.try_cmp(r).ok() + }, + ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), + _ => Some(a.cmp(&b)), + } + }, + _ if a == b => Some(Ordering::Equal), + _ => None, + } +} From a414e330ce06b79453df3f2c61db2aa965a3496e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:28:45 +0100 Subject: [PATCH 053/115] Remove unused function --- src/librustc_mir/const_eval/eval.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/librustc_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs index 32f834daa4c78..29c0cd499b3aa 100644 --- a/src/librustc_mir/const_eval/eval.rs +++ b/src/librustc_mir/const_eval/eval.rs @@ -18,19 +18,6 @@ use syntax::ast; use rustc_const_math::*; -/// * `DefId` is the id of the constant. -/// * `Substs` is the monomorphized substitutions for the expression. -pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) - -> Option<(DefId, &'tcx Substs<'tcx>)> { - ty::Instance::resolve( - tcx, - key.param_env, - key.value.0, - key.value.1, - ).map(|instance| (instance.def_id(), instance.substs)) -} - pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, From c10fbec64c7aeb6bd73196f9df500b1248d4f590 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:31:39 +0100 Subject: [PATCH 054/115] Move lit_to_const to `pattern` and remove the now-empty `eval` module --- src/librustc_mir/const_eval/eval.rs | 114 ------------------------- src/librustc_mir/const_eval/mod.rs | 3 - src/librustc_mir/const_eval/pattern.rs | 100 +++++++++++++++++++++- 3 files changed, 98 insertions(+), 119 deletions(-) delete mode 100644 src/librustc_mir/const_eval/eval.rs diff --git a/src/librustc_mir/const_eval/eval.rs b/src/librustc_mir/const_eval/eval.rs deleted file mode 100644 index 29c0cd499b3aa..0000000000000 --- a/src/librustc_mir/const_eval/eval.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2012-2016 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 or the MIT license -// , 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::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::Substs; - -use syntax::ast; - -use rustc_const_math::*; - -pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - neg: bool) - -> Result, ()> { - use syntax::ast::*; - - use rustc::mir::interpret::*; - let lit = match *lit { - LitKind::Str(ref s, _) => { - let s = s.as_str(); - let id = tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - ) - }, - LitKind::ByteStr(ref data) => { - let id = tcx.allocate_cached(data); - let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) - }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), - LitKind::Int(n, _) => { - enum Int { - Signed(IntTy), - Unsigned(UintTy), - } - let ty = match ty.sty { - ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty), - ty::TyInt(other) => Int::Signed(other), - ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), - ty::TyUint(other) => Int::Unsigned(other), - _ => bug!(), - }; - let n = match ty { - // FIXME(oli-obk): are these casts correct? - Int::Signed(IntTy::I8) if neg => - (n as i128 as i8).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I16) if neg => - (n as i128 as i16).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I32) if neg => - (n as i128 as i32).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I64) if neg => - (n as i128 as i64).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I128) if neg => - (n as i128).overflowing_neg().0 as u128, - Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, - Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, - Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, - Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, - Int::Signed(IntTy::I128) => n, - Int::Unsigned(UintTy::U8) => n as u8 as u128, - Int::Unsigned(UintTy::U16) => n as u16 as u128, - Int::Unsigned(UintTy::U32) => n as u32 as u128, - Int::Unsigned(UintTy::U64) => n as u64 as u128, - Int::Unsigned(UintTy::U128) => n, - _ => bug!(), - }; - Value::ByVal(PrimVal::Bytes(n)) - }, - LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::FloatUnsuffixed(n) => { - let fty = match ty.sty { - ty::TyFloat(fty) => fty, - _ => bug!() - }; - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), - }; - Ok(ConstVal::Value(lit)) -} - -fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) - -> Result { - ConstFloat::from_str(num, fty).map_err(|_| ()) -} diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index f47dc61c27c4d..fff1122387f25 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -10,10 +10,7 @@ //! constant evaluation on the HIR and code to validate patterns/matches -mod eval; mod _match; pub mod check_match; pub mod pattern; pub mod check; - -pub use self::eval::*; diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/const_eval/pattern.rs index 5afed5e2e3ce7..0cbbf129b9b1e 100644 --- a/src/librustc_mir/const_eval/pattern.rs +++ b/src/librustc_mir/const_eval/pattern.rs @@ -20,6 +20,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc_data_structures::indexed_vec::Idx; +use rustc_const_math::ConstFloat; use std::cmp::Ordering; use std::fmt; @@ -716,7 +717,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { match expr.node { hir::ExprLit(ref lit) => { let ty = self.tables.expr_ty(expr); - match super::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + match lit_to_const(&lit.node, self.tcx, ty, false) { Ok(val) => { let instance = ty::Instance::new( self.tables.local_id_root.expect("literal outside any scope"), @@ -738,7 +739,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { hir::ExprLit(ref lit) => lit, _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; - match super::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + match lit_to_const(&lit.node, self.tcx, ty, true) { Ok(val) => { let instance = ty::Instance::new( self.tables.local_id_root.expect("literal outside any scope"), @@ -1089,3 +1090,98 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option None, } } + +fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + neg: bool) + -> Result, ()> { + use syntax::ast::*; + + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(id, 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(id, 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) => { + enum Int { + Signed(IntTy), + Unsigned(UintTy), + } + let ty = match ty.sty { + ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty), + ty::TyInt(other) => Int::Signed(other), + ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), + ty::TyUint(other) => Int::Unsigned(other), + _ => bug!(), + }; + let n = match ty { + // FIXME(oli-obk): are these casts correct? + Int::Signed(IntTy::I8) if neg => + (n as i128 as i8).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I16) if neg => + (n as i128 as i16).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I32) if neg => + (n as i128 as i32).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I64) if neg => + (n as i128 as i64).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I128) if neg => + (n as i128).overflowing_neg().0 as u128, + Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, + Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, + Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, + Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, + Int::Signed(IntTy::I128) => n, + Int::Unsigned(UintTy::U8) => n as u8 as u128, + Int::Unsigned(UintTy::U16) => n as u16 as u128, + Int::Unsigned(UintTy::U32) => n as u32 as u128, + Int::Unsigned(UintTy::U64) => n as u64 as u128, + Int::Unsigned(UintTy::U128) => n, + _ => bug!(), + }; + Value::ByVal(PrimVal::Bytes(n)) + }, + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + Ok(ConstVal::Value(lit)) +} + +fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) + -> Result { + ConstFloat::from_str(num, fty).map_err(|_| ()) +} From db0c9b854982f96a5e414088b5f9811e6e13032c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:51:33 +0100 Subject: [PATCH 055/115] The `const_eval` module is no more --- src/librustc_driver/driver.rs | 5 ++--- src/librustc_mir/build/mod.rs | 2 +- .../{const_eval/check.rs => check_const_err.rs} | 0 src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/lib.rs | 5 +++-- src/librustc_mir/{const_eval => pattern}/_match.rs | 4 ++-- src/librustc_mir/{const_eval => pattern}/check_match.rs | 8 ++++---- src/librustc_mir/{const_eval => pattern}/mod.rs | 7 ++++--- src/librustc_mir/{const_eval => pattern}/pattern.rs | 0 9 files changed, 17 insertions(+), 16 deletions(-) rename src/librustc_mir/{const_eval/check.rs => check_const_err.rs} (100%) rename src/librustc_mir/{const_eval => pattern}/_match.rs (99%) rename src/librustc_mir/{const_eval => pattern}/check_match.rs (99%) rename src/librustc_mir/{const_eval => pattern}/mod.rs (85%) rename src/librustc_mir/{const_eval => pattern}/pattern.rs (100%) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4478e0ea4fe2b..01febbde7aad9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,6 @@ use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats}; -use rustc_mir::const_eval::check_match; use super::Compilation; use serialize::json; @@ -1033,7 +1032,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(time_passes, "match checking", - || check_match::check_crate(tcx)); + || mir::pattern::check_crate(tcx)); // this must run before MIR dump, because // "not all control paths return a value" is reported here. @@ -1076,7 +1075,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(time_passes, "MIR linting", || for def_id in tcx.body_owners() { - mir::const_eval::check::check(tcx, def_id) + mir::check_const_err::check(tcx, def_id) }); time(time_passes, "lint checking", || lint::check_crate(tcx)); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4b73484306029..1b6b33374902f 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -21,7 +21,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; use rustc_back::PanicStrategy; -use const_eval::pattern::{BindingMode, PatternKind}; +use pattern::pattern::{BindingMode, PatternKind}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use shim; use std::mem; diff --git a/src/librustc_mir/const_eval/check.rs b/src/librustc_mir/check_const_err.rs similarity index 100% rename from src/librustc_mir/const_eval/check.rs rename to src/librustc_mir/check_const_err.rs diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index a7cfa94f6961d..3eeaad8710157 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -26,7 +26,7 @@ use self::cx::Cx; pub mod cx; -pub use const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; +pub use pattern::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; #[derive(Copy, Clone, Debug)] pub enum LintLevel { diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index aa6bc2639aaec..f3c70c025d5fb 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -71,7 +71,8 @@ pub mod transform; pub mod util; pub mod interpret; pub mod monomorphize; -pub mod const_eval; +pub mod pattern; +pub mod check_const_err; use rustc::ty::maps::Providers; @@ -80,7 +81,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); providers.const_eval = interpret::const_eval_provider; - providers.check_match = const_eval::check_match::check_match; + providers.check_match = pattern::check_match::check_match; } #[cfg(not(stage0))] // remove after the next snapshot diff --git a/src/librustc_mir/const_eval/_match.rs b/src/librustc_mir/pattern/_match.rs similarity index 99% rename from src/librustc_mir/const_eval/_match.rs rename to src/librustc_mir/pattern/_match.rs index 332481c0d4f53..f0d5771c380d3 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/pattern/_match.rs @@ -17,8 +17,8 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; -use const_eval::pattern::{FieldPattern, Pattern, PatternKind}; -use const_eval::pattern::{PatternFoldable, PatternFolder, compare_const_vals}; +use super::pattern::{FieldPattern, Pattern, PatternKind}; +use super::pattern::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; diff --git a/src/librustc_mir/const_eval/check_match.rs b/src/librustc_mir/pattern/check_match.rs similarity index 99% rename from src/librustc_mir/const_eval/check_match.rs rename to src/librustc_mir/pattern/check_match.rs index 6524ad6945c30..d3d44ca87d954 100644 --- a/src/librustc_mir/const_eval/check_match.rs +++ b/src/librustc_mir/pattern/check_match.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use const_eval::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; -use const_eval::_match::Usefulness::*; -use const_eval::_match::WitnessPreference::*; +use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; +use super::_match::Usefulness::*; +use super::_match::WitnessPreference::*; -use const_eval::pattern::{Pattern, PatternContext, PatternError, PatternKind}; +use super::pattern::{Pattern, PatternContext, PatternError, PatternKind}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/pattern/mod.rs similarity index 85% rename from src/librustc_mir/const_eval/mod.rs rename to src/librustc_mir/pattern/mod.rs index fff1122387f25..ff5ddc93a4bae 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/pattern/mod.rs @@ -11,6 +11,7 @@ //! constant evaluation on the HIR and code to validate patterns/matches mod _match; -pub mod check_match; -pub mod pattern; -pub mod check; +pub(crate) mod check_match; +pub(crate) mod pattern; + +pub use self::check_match::check_crate; diff --git a/src/librustc_mir/const_eval/pattern.rs b/src/librustc_mir/pattern/pattern.rs similarity index 100% rename from src/librustc_mir/const_eval/pattern.rs rename to src/librustc_mir/pattern/pattern.rs From 7912fe5891810c752880d561dd1093bb4de2666e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 15:55:12 +0100 Subject: [PATCH 056/115] only export the two check* functions from check_match --- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/pattern/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f3c70c025d5fb..54ca8c7ad4f6f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -81,7 +81,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); providers.const_eval = interpret::const_eval_provider; - providers.check_match = pattern::check_match::check_match; + providers.check_match = pattern::check_match; } #[cfg(not(stage0))] // remove after the next snapshot diff --git a/src/librustc_mir/pattern/mod.rs b/src/librustc_mir/pattern/mod.rs index ff5ddc93a4bae..c99dc4a7658d9 100644 --- a/src/librustc_mir/pattern/mod.rs +++ b/src/librustc_mir/pattern/mod.rs @@ -11,7 +11,8 @@ //! constant evaluation on the HIR and code to validate patterns/matches mod _match; -pub(crate) mod check_match; +mod check_match; pub(crate) mod pattern; pub use self::check_match::check_crate; +pub(crate) use self::check_match::check_match; From f18972b32961ec38b2f1ac16f1a62be1396759b8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 16:12:07 +0100 Subject: [PATCH 057/115] Move the pattern checking code to hair --- src/librustc_driver/driver.rs | 2 +- src/librustc_mir/build/mod.rs | 3 +- src/librustc_mir/hair/mod.rs | 3 +- src/librustc_mir/{ => hair}/pattern/_match.rs | 4 +- .../{ => hair}/pattern/check_match.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 1186 +++++++++++++++++ .../{ => hair}/pattern/pattern.rs | 0 src/librustc_mir/lib.rs | 4 +- src/librustc_mir/pattern/mod.rs | 18 - 9 files changed, 1195 insertions(+), 27 deletions(-) rename src/librustc_mir/{ => hair}/pattern/_match.rs (99%) rename src/librustc_mir/{ => hair}/pattern/check_match.rs (99%) create mode 100644 src/librustc_mir/hair/pattern/mod.rs rename src/librustc_mir/{ => hair}/pattern/pattern.rs (100%) delete mode 100644 src/librustc_mir/pattern/mod.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 01febbde7aad9..c3821517b59bc 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1032,7 +1032,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, time(time_passes, "match checking", - || mir::pattern::check_crate(tcx)); + || mir::matchck_crate(tcx)); // this must run before MIR dump, because // "not all control paths return a value" is reported here. diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1b6b33374902f..6ba6a8f0f83e2 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -11,7 +11,7 @@ use build; use hair::cx::Cx; -use hair::LintLevel; +use hair::{LintLevel, BindingMode, PatternKind}; use rustc::hir; use rustc::hir::def_id::{DefId, LocalDefId}; use rustc::middle::region; @@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; use rustc_back::PanicStrategy; -use pattern::pattern::{BindingMode, PatternKind}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use shim; use std::mem; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 3eeaad8710157..5f60a134fb130 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -26,7 +26,8 @@ use self::cx::Cx; pub mod cx; -pub use pattern::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; +pub mod pattern; +pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; #[derive(Copy, Clone, Debug)] pub enum LintLevel { diff --git a/src/librustc_mir/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs similarity index 99% rename from src/librustc_mir/pattern/_match.rs rename to src/librustc_mir/hair/pattern/_match.rs index f0d5771c380d3..e5acbc369ad7d 100644 --- a/src/librustc_mir/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -17,8 +17,8 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; -use super::pattern::{FieldPattern, Pattern, PatternKind}; -use super::pattern::{PatternFoldable, PatternFolder, compare_const_vals}; +use super::{FieldPattern, Pattern, PatternKind}; +use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; use rustc::hir::RangeEnd; diff --git a/src/librustc_mir/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs similarity index 99% rename from src/librustc_mir/pattern/check_match.rs rename to src/librustc_mir/hair/pattern/check_match.rs index d3d44ca87d954..cbe97632e9fdc 100644 --- a/src/librustc_mir/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -12,7 +12,7 @@ use super::_match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; use super::_match::Usefulness::*; use super::_match::WitnessPreference::*; -use super::pattern::{Pattern, PatternContext, PatternError, PatternKind}; +use super::{Pattern, PatternContext, PatternError, PatternKind}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs new file mode 100644 index 0000000000000..1141425c554a9 --- /dev/null +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -0,0 +1,1186 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Code to validate patterns/matches + +mod _match; +mod check_match; + +pub use self::check_match::check_crate; +pub(crate) use self::check_match::check_match; + +use interpret::{const_val_field, const_discr}; + +use rustc::middle::const_val::ConstVal; +use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; +use rustc::ty::subst::{Substs, Kind}; +use rustc::hir::{self, PatKind, RangeEnd}; +use rustc::hir::def::{Def, CtorKind}; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; + +use rustc_data_structures::indexed_vec::Idx; +use rustc_const_math::ConstFloat; + +use std::cmp::Ordering; +use std::fmt; +use syntax::ast; +use syntax::ptr::P; +use syntax_pos::Span; + +#[derive(Clone, Debug)] +pub enum PatternError { + StaticInPattern(Span), + FloatBug, + NonConstPath(Span), +} + +#[derive(Copy, Clone, Debug)] +pub enum BindingMode<'tcx> { + ByValue, + ByRef(Region<'tcx>, BorrowKind), +} + +#[derive(Clone, Debug)] +pub struct FieldPattern<'tcx> { + pub field: Field, + pub pattern: Pattern<'tcx>, +} + +#[derive(Clone, Debug)] +pub struct Pattern<'tcx> { + pub ty: Ty<'tcx>, + pub span: Span, + pub kind: Box>, +} + +#[derive(Clone, Debug)] +pub enum PatternKind<'tcx> { + Wild, + + /// x, ref x, x @ P, etc + Binding { + mutability: Mutability, + name: ast::Name, + mode: BindingMode<'tcx>, + var: ast::NodeId, + ty: Ty<'tcx>, + subpattern: Option>, + }, + + /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants + Variant { + adt_def: &'tcx AdtDef, + substs: &'tcx Substs<'tcx>, + variant_index: usize, + subpatterns: Vec>, + }, + + /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant + Leaf { + subpatterns: Vec>, + }, + + /// box P, &P, &mut P, etc + Deref { + subpattern: Pattern<'tcx>, + }, + + Constant { + value: &'tcx ty::Const<'tcx>, + }, + + Range { + lo: &'tcx ty::Const<'tcx>, + hi: &'tcx ty::Const<'tcx>, + end: RangeEnd, + }, + + /// matches against a slice, checking the length and extracting elements. + /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. + /// e.g. `&[ref xs..]`. + Slice { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, + + /// fixed match against an array, irrefutable + Array { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, +} + +fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { + match value.val { + ConstVal::Value(v) => print_miri_value(v, value.ty, f), + ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) + } +} + +fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { + use rustc::ty::TypeVariants::*; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + _ => bug!("{:?}: {} not printable in a pattern", value, ty), + } +} + +impl<'tcx> fmt::Display for Pattern<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self.kind { + PatternKind::Wild => write!(f, "_"), + PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => { + let is_mut = match mode { + BindingMode::ByValue => mutability == Mutability::Mut, + BindingMode::ByRef(_, bk) => { + write!(f, "ref ")?; + bk == BorrowKind::Mut + } + }; + if is_mut { + write!(f, "mut ")?; + } + write!(f, "{}", name)?; + if let Some(ref subpattern) = *subpattern { + write!(f, " @ {}", subpattern)?; + } + Ok(()) + } + PatternKind::Variant { ref subpatterns, .. } | + PatternKind::Leaf { ref subpatterns } => { + let variant = match *self.kind { + PatternKind::Variant { adt_def, variant_index, .. } => { + Some(&adt_def.variants[variant_index]) + } + _ => if let ty::TyAdt(adt, _) = self.ty.sty { + if !adt.is_enum() { + Some(&adt.variants[0]) + } else { + None + } + } else { + None + } + }; + + let mut first = true; + let mut start_or_continue = || if first { first = false; "" } else { ", " }; + + if let Some(variant) = variant { + write!(f, "{}", variant.name)?; + + // Only for TyAdt we can have `S {...}`, + // which we handle separately here. + if variant.ctor_kind == CtorKind::Fictive { + write!(f, " {{ ")?; + + let mut printed = 0; + for p in subpatterns { + if let PatternKind::Wild = *p.pattern.kind { + continue; + } + let name = variant.fields[p.field.index()].name; + write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?; + printed += 1; + } + + if printed < variant.fields.len() { + write!(f, "{}..", start_or_continue())?; + } + + return write!(f, " }}"); + } + } + + let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); + if num_fields != 0 || variant.is_none() { + write!(f, "(")?; + for i in 0..num_fields { + write!(f, "{}", start_or_continue())?; + + // Common case: the field is where we expect it. + if let Some(p) = subpatterns.get(i) { + if p.field.index() == i { + write!(f, "{}", p.pattern)?; + continue; + } + } + + // Otherwise, we have to go looking for it. + if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { + write!(f, "{}", p.pattern)?; + } else { + write!(f, "_")?; + } + } + write!(f, ")")?; + } + + Ok(()) + } + PatternKind::Deref { ref subpattern } => { + match self.ty.sty { + ty::TyAdt(def, _) if def.is_box() => write!(f, "box ")?, + ty::TyRef(_, mt) => { + write!(f, "&")?; + if mt.mutbl == hir::MutMutable { + write!(f, "mut ")?; + } + } + _ => bug!("{} is a bad Deref pattern type", self.ty) + } + write!(f, "{}", subpattern) + } + PatternKind::Constant { value } => { + print_const_val(value, f) + } + PatternKind::Range { lo, hi, end } => { + print_const_val(lo, f)?; + match end { + RangeEnd::Included => write!(f, "...")?, + RangeEnd::Excluded => write!(f, "..")?, + } + print_const_val(hi, f) + } + PatternKind::Slice { ref prefix, ref slice, ref suffix } | + PatternKind::Array { ref prefix, ref slice, ref suffix } => { + let mut first = true; + let mut start_or_continue = || if first { first = false; "" } else { ", " }; + write!(f, "[")?; + for p in prefix { + write!(f, "{}{}", start_or_continue(), p)?; + } + if let Some(ref slice) = *slice { + write!(f, "{}", start_or_continue())?; + match *slice.kind { + PatternKind::Wild => {} + _ => write!(f, "{}", slice)? + } + write!(f, "..")?; + } + for p in suffix { + write!(f, "{}{}", start_or_continue(), p)?; + } + write!(f, "]") + } + } + } +} + +pub struct PatternContext<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub tables: &'a ty::TypeckTables<'tcx>, + pub substs: &'tcx Substs<'tcx>, + pub errors: Vec, +} + +impl<'a, 'tcx> Pattern<'tcx> { + pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>, + pat: &'tcx hir::Pat) -> Self { + let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); + let result = pcx.lower_pattern(pat); + if !pcx.errors.is_empty() { + let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); + tcx.sess.delay_span_bug(pat.span, &msg); + } + debug!("Pattern::from_hir({:?}) = {:?}", pat, result); + result + } +} + +impl<'a, 'tcx> PatternContext<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>) -> Self { + PatternContext { + tcx, + param_env: param_env_and_substs.param_env, + tables, + substs: param_env_and_substs.value, + errors: vec![] + } + } + + pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { + // When implicit dereferences have been inserted in this pattern, the unadjusted lowered + // pattern has the type that results *after* dereferencing. For example, in this code: + // + // ``` + // match &&Some(0i32) { + // Some(n) => { ... }, + // _ => { ... }, + // } + // ``` + // + // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option` (this is + // determined in rustc_typeck::check::match). The adjustments would be + // + // `vec![&&Option, &Option]`. + // + // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So + // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the + // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted + // gets the least-dereferenced type). + let unadjusted_pat = self.lower_pattern_unadjusted(pat); + self.tables + .pat_adjustments() + .get(pat.hir_id) + .unwrap_or(&vec![]) + .iter() + .rev() + .fold(unadjusted_pat, |pat, ref_ty| { + debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); + Pattern { + span: pat.span, + ty: ref_ty, + kind: Box::new(PatternKind::Deref { subpattern: pat }), + } + }, + ) + } + + fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { + let mut ty = self.tables.node_id_to_type(pat.hir_id); + + let kind = match pat.node { + PatKind::Wild => PatternKind::Wild, + + PatKind::Lit(ref value) => self.lower_lit(value), + + PatKind::Range(ref lo_expr, ref hi_expr, end) => { + match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) { + (PatternKind::Constant { value: lo }, + PatternKind::Constant { value: hi }) => { + use std::cmp::Ordering; + match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { + (RangeEnd::Excluded, Ordering::Less) => {}, + (RangeEnd::Excluded, _) => span_err!( + self.tcx.sess, + lo_expr.span, + E0579, + "lower range bound must be less than upper", + ), + (RangeEnd::Included, Ordering::Greater) => { + struct_span_err!(self.tcx.sess, lo_expr.span, E0030, + "lower range bound must be less than or equal to upper") + .span_label(lo_expr.span, "lower bound larger than upper bound") + .emit(); + }, + (RangeEnd::Included, _) => {} + } + PatternKind::Range { lo, hi, end } + } + _ => PatternKind::Wild + } + } + + PatKind::Path(ref qpath) => { + return self.lower_path(qpath, pat.hir_id, pat.span); + } + + PatKind::Ref(ref subpattern, _) | + PatKind::Box(ref subpattern) => { + PatternKind::Deref { subpattern: self.lower_pattern(subpattern) } + } + + PatKind::Slice(ref prefix, ref slice, ref suffix) => { + let ty = self.tables.node_id_to_type(pat.hir_id); + match ty.sty { + ty::TyRef(_, mt) => + PatternKind::Deref { + subpattern: Pattern { + ty: mt.ty, + span: pat.span, + kind: Box::new(self.slice_or_array_pattern( + pat.span, mt.ty, prefix, slice, suffix)) + }, + }, + + ty::TySlice(..) | + ty::TyArray(..) => + self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), + + ref sty => + span_bug!( + pat.span, + "unexpanded type for vector pattern: {:?}", + sty), + } + } + + PatKind::Tuple(ref subpatterns, ddpos) => { + let ty = self.tables.node_id_to_type(pat.hir_id); + match ty.sty { + ty::TyTuple(ref tys, _) => { + let subpatterns = + subpatterns.iter() + .enumerate_and_adjust(tys.len(), ddpos) + .map(|(i, subpattern)| FieldPattern { + field: Field::new(i), + pattern: self.lower_pattern(subpattern) + }) + .collect(); + + PatternKind::Leaf { subpatterns: subpatterns } + } + + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), + } + } + + PatKind::Binding(_, id, ref ident, ref sub) => { + let var_ty = self.tables.node_id_to_type(pat.hir_id); + let region = match var_ty.sty { + ty::TyRef(r, _) => Some(r), + _ => None, + }; + let bm = *self.tables.pat_binding_modes().get(pat.hir_id) + .expect("missing binding mode"); + let (mutability, mode) = match bm { + ty::BindByValue(hir::MutMutable) => + (Mutability::Mut, BindingMode::ByValue), + ty::BindByValue(hir::MutImmutable) => + (Mutability::Not, BindingMode::ByValue), + ty::BindByReference(hir::MutMutable) => + (Mutability::Not, BindingMode::ByRef( + region.unwrap(), BorrowKind::Mut)), + ty::BindByReference(hir::MutImmutable) => + (Mutability::Not, BindingMode::ByRef( + region.unwrap(), BorrowKind::Shared)), + }; + + // A ref x pattern is the same node used for x, and as such it has + // x's type, which is &T, where we want T (the type being matched). + if let ty::BindByReference(_) = bm { + if let ty::TyRef(_, mt) = ty.sty { + ty = mt.ty; + } else { + bug!("`ref {}` has wrong type {}", ident.node, ty); + } + } + + PatternKind::Binding { + mutability, + mode, + name: ident.node, + var: id, + ty: var_ty, + subpattern: self.lower_opt_pattern(sub), + } + } + + PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { + let def = self.tables.qpath_def(qpath, pat.hir_id); + let adt_def = match ty.sty { + ty::TyAdt(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), + }; + let variant_def = adt_def.variant_of_def(def); + + let subpatterns = + subpatterns.iter() + .enumerate_and_adjust(variant_def.fields.len(), ddpos) + .map(|(i, field)| FieldPattern { + field: Field::new(i), + pattern: self.lower_pattern(field), + }) + .collect(); + self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) + } + + PatKind::Struct(ref qpath, ref fields, _) => { + let def = self.tables.qpath_def(qpath, pat.hir_id); + let adt_def = match ty.sty { + ty::TyAdt(adt_def, _) => adt_def, + _ => { + span_bug!( + pat.span, + "struct pattern not applied to an ADT"); + } + }; + let variant_def = adt_def.variant_of_def(def); + + let subpatterns = + fields.iter() + .map(|field| { + let index = variant_def.index_of_field_named(field.node.name); + let index = index.unwrap_or_else(|| { + span_bug!( + pat.span, + "no field with name {:?}", + field.node.name); + }); + FieldPattern { + field: Field::new(index), + pattern: self.lower_pattern(&field.node.pat), + } + }) + .collect(); + + self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) + } + }; + + Pattern { + span: pat.span, + ty, + kind: Box::new(kind), + } + } + + fn lower_patterns(&mut self, pats: &'tcx [P]) -> Vec> { + pats.iter().map(|p| self.lower_pattern(p)).collect() + } + + fn lower_opt_pattern(&mut self, pat: &'tcx Option>) -> Option> + { + pat.as_ref().map(|p| self.lower_pattern(p)) + } + + fn flatten_nested_slice_patterns( + &mut self, + prefix: Vec>, + slice: Option>, + suffix: Vec>) + -> (Vec>, Option>, Vec>) + { + let orig_slice = match slice { + Some(orig_slice) => orig_slice, + None => return (prefix, slice, suffix) + }; + let orig_prefix = prefix; + let orig_suffix = suffix; + + // dance because of intentional borrow-checker stupidity. + let kind = *orig_slice.kind; + match kind { + PatternKind::Slice { prefix, slice, mut suffix } | + PatternKind::Array { prefix, slice, mut suffix } => { + let mut orig_prefix = orig_prefix; + + orig_prefix.extend(prefix); + suffix.extend(orig_suffix); + + (orig_prefix, slice, suffix) + } + _ => { + (orig_prefix, Some(Pattern { + kind: box kind, ..orig_slice + }), orig_suffix) + } + } + } + + fn slice_or_array_pattern( + &mut self, + span: Span, + ty: Ty<'tcx>, + prefix: &'tcx [P], + slice: &'tcx Option>, + suffix: &'tcx [P]) + -> PatternKind<'tcx> + { + let prefix = self.lower_patterns(prefix); + let slice = self.lower_opt_pattern(slice); + let suffix = self.lower_patterns(suffix); + let (prefix, slice, suffix) = + self.flatten_nested_slice_patterns(prefix, slice, suffix); + + match ty.sty { + ty::TySlice(..) => { + // matching a slice or fixed-length array + PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix } + } + + ty::TyArray(_, len) => { + // fixed-length array + let len = len.val.unwrap_u64(); + assert!(len >= prefix.len() as u64 + suffix.len() as u64); + PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } + } + + _ => { + span_bug!(span, "bad slice pattern type {:?}", ty); + } + } + } + + fn lower_variant_or_leaf( + &mut self, + def: Def, + span: Span, + ty: Ty<'tcx>, + subpatterns: Vec>) + -> PatternKind<'tcx> + { + match def { + Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { + let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); + let adt_def = self.tcx.adt_def(enum_id); + if adt_def.is_enum() { + let substs = match ty.sty { + ty::TyAdt(_, substs) | + ty::TyFnDef(_, substs) => substs, + _ => bug!("inappropriate type for def: {:?}", ty.sty), + }; + PatternKind::Variant { + adt_def, + substs, + variant_index: adt_def.variant_index_with_id(variant_id), + subpatterns, + } + } else { + PatternKind::Leaf { subpatterns: subpatterns } + } + } + + Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { + PatternKind::Leaf { subpatterns: subpatterns } + } + + _ => { + self.errors.push(PatternError::NonConstPath(span)); + PatternKind::Wild + } + } + } + + fn lower_path(&mut self, + qpath: &hir::QPath, + id: hir::HirId, + span: Span) + -> Pattern<'tcx> { + let ty = self.tables.node_id_to_type(id); + let def = self.tables.qpath_def(qpath, id); + let kind = match def { + Def::Const(def_id) | Def::AssociatedConst(def_id) => { + let substs = self.tables.node_substs(id); + match ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ) { + Some(instance) => { + let cid = GlobalId { + instance, + promoted: None, + }; + match self.tcx.at(span).const_eval(self.param_env.and(cid)) { + Ok(value) => { + return self.const_to_pat(instance, value, id, span) + }, + Err(err) => { + err.report(self.tcx, span, "pattern"); + PatternKind::Wild + }, + } + }, + None => { + self.errors.push(PatternError::StaticInPattern(span)); + PatternKind::Wild + }, + } + } + _ => self.lower_variant_or_leaf(def, span, ty, vec![]), + }; + + Pattern { + span, + ty, + kind: Box::new(kind), + } + } + + fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { + match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(val) => { + let instance = ty::Instance::new( + self.tables.local_id_root.expect("literal outside any scope"), + self.substs, + ); + let cv = self.tcx.mk_const(ty::Const { val, ty }); + *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + }, + Err(()) => { + self.errors.push(PatternError::FloatBug); + PatternKind::Wild + }, + } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(val) => { + let instance = ty::Instance::new( + self.tables.local_id_root.expect("literal outside any scope"), + self.substs, + ); + let cv = self.tcx.mk_const(ty::Const { val, ty }); + *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + }, + Err(()) => { + self.errors.push(PatternError::FloatBug); + PatternKind::Wild + }, + } + } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + } + } + + fn const_to_pat( + &self, + instance: ty::Instance<'tcx>, + cv: &'tcx ty::Const<'tcx>, + id: hir::HirId, + span: Span, + ) -> Pattern<'tcx> { + debug!("const_to_pat: cv={:#?}", cv); + let kind = match cv.ty.sty { + ty::TyFloat(_) => { + let id = self.tcx.hir.hir_to_node_id(id); + self.tcx.lint_node( + ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + "floating-point types cannot be used in patterns", + ); + PatternKind::Constant { + value: cv, + } + }, + ty::TyAdt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); + PatternKind::Wild + } + ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + let msg = format!("to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + self.tcx.item_path_str(adt_def.did), + self.tcx.item_path_str(adt_def.did)); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + }, + ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { + match cv.val { + ConstVal::Value(val) => { + let discr = const_discr( + self.tcx, self.param_env, instance, val, cv.ty + ).unwrap(); + let variant_index = adt_def + .discriminants(self.tcx) + .position(|var| var.val == discr) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, + Some(variant_index), field, miri, cv.ty, + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, id, span), + } + }).collect(), + } + }, + _ => return Pattern { + span, + ty: cv.ty, + kind: Box::new(PatternKind::Constant { + value: cv, + }), + } + } + }, + ty::TyAdt(adt_def, _) => { + let struct_var = adt_def.non_enum_variant(); + PatternKind::Leaf { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, None, field, miri, cv.ty, + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, id, span), + } + }).collect() + } + } + ty::TyTuple(fields, _) => { + PatternKind::Leaf { + subpatterns: (0..fields.len()).map(|i| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, None, field, miri, cv.ty, + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, id, span), + } + }).collect() + } + } + ty::TyArray(_, n) => { + PatternKind::Array { + prefix: (0..n.val.unwrap_u64()).map(|i| { + let i = i as usize; + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, None, field, miri, cv.ty, + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + self.const_to_pat(instance, val, id, span) + }).collect(), + slice: None, + suffix: Vec::new(), + } + } + _ => { + PatternKind::Constant { + value: cv, + } + }, + }; + + Pattern { + span, + ty: cv.ty, + kind: Box::new(kind), + } + } +} + +pub trait PatternFoldable<'tcx> : Sized { + fn fold_with>(&self, folder: &mut F) -> Self { + self.super_fold_with(folder) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self; +} + +pub trait PatternFolder<'tcx> : Sized { + fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> { + pattern.super_fold_with(self) + } + + fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> { + kind.super_fold_with(self) + } +} + + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let content: T = (**self).fold_with(folder); + box content + } +} + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { + fn super_fold_with>(&self, folder: &mut F) -> Self{ + self.as_ref().map(|t| t.fold_with(folder)) + } +} + +macro_rules! CloneImpls { + (<$lt_tcx:tt> $($ty:ty),+) => { + $( + impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { + fn super_fold_with>(&self, _: &mut F) -> Self { + Clone::clone(self) + } + } + )+ + } +} + +CloneImpls!{ <'tcx> + Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, + Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, + &'tcx Substs<'tcx>, &'tcx Kind<'tcx> +} + +impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + FieldPattern { + field: self.field.fold_with(folder), + pattern: self.pattern.fold_with(folder) + } + } +} + +impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> { + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_pattern(self) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self { + Pattern { + ty: self.ty.fold_with(folder), + span: self.span.fold_with(folder), + kind: self.kind.fold_with(folder) + } + } +} + +impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_pattern_kind(self) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + PatternKind::Wild => PatternKind::Wild, + PatternKind::Binding { + mutability, + name, + mode, + var, + ty, + ref subpattern, + } => PatternKind::Binding { + mutability: mutability.fold_with(folder), + name: name.fold_with(folder), + mode: mode.fold_with(folder), + var: var.fold_with(folder), + ty: ty.fold_with(folder), + subpattern: subpattern.fold_with(folder), + }, + PatternKind::Variant { + adt_def, + substs, + variant_index, + ref subpatterns, + } => PatternKind::Variant { + adt_def: adt_def.fold_with(folder), + substs: substs.fold_with(folder), + variant_index: variant_index.fold_with(folder), + subpatterns: subpatterns.fold_with(folder) + }, + PatternKind::Leaf { + ref subpatterns, + } => PatternKind::Leaf { + subpatterns: subpatterns.fold_with(folder), + }, + PatternKind::Deref { + ref subpattern, + } => PatternKind::Deref { + subpattern: subpattern.fold_with(folder), + }, + PatternKind::Constant { + value + } => PatternKind::Constant { + value: value.fold_with(folder) + }, + PatternKind::Range { + lo, + hi, + end, + } => PatternKind::Range { + lo: lo.fold_with(folder), + hi: hi.fold_with(folder), + end, + }, + PatternKind::Slice { + ref prefix, + ref slice, + ref suffix, + } => PatternKind::Slice { + prefix: prefix.fold_with(folder), + slice: slice.fold_with(folder), + suffix: suffix.fold_with(folder) + }, + PatternKind::Array { + ref prefix, + ref slice, + ref suffix + } => PatternKind::Array { + prefix: prefix.fold_with(folder), + slice: slice.fold_with(folder), + suffix: suffix.fold_with(folder) + }, + } + } +} + +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + use rustc_const_math::ConstFloat; + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { + (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), + &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { + match ty.sty { + ty::TyFloat(ty) => { + let l = ConstFloat { + bits: a, + ty, + }; + let r = ConstFloat { + bits: b, + ty, + }; + // FIXME(oli-obk): report cmp errors? + l.try_cmp(r).ok() + }, + ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), + _ => Some(a.cmp(&b)), + } + }, + _ if a == b => Some(Ordering::Equal), + _ => None, + } +} + +fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + neg: bool) + -> Result, ()> { + use syntax::ast::*; + + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(id, 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(id, 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) => { + enum Int { + Signed(IntTy), + Unsigned(UintTy), + } + let ty = match ty.sty { + ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty), + ty::TyInt(other) => Int::Signed(other), + ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), + ty::TyUint(other) => Int::Unsigned(other), + _ => bug!(), + }; + let n = match ty { + // FIXME(oli-obk): are these casts correct? + Int::Signed(IntTy::I8) if neg => + (n as i128 as i8).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I16) if neg => + (n as i128 as i16).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I32) if neg => + (n as i128 as i32).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I64) if neg => + (n as i128 as i64).overflowing_neg().0 as i128 as u128, + Int::Signed(IntTy::I128) if neg => + (n as i128).overflowing_neg().0 as u128, + Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, + Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, + Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, + Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, + Int::Signed(IntTy::I128) => n, + Int::Unsigned(UintTy::U8) => n as u8 as u128, + Int::Unsigned(UintTy::U16) => n as u16 as u128, + Int::Unsigned(UintTy::U32) => n as u32 as u128, + Int::Unsigned(UintTy::U64) => n as u64 as u128, + Int::Unsigned(UintTy::U128) => n, + _ => bug!(), + }; + Value::ByVal(PrimVal::Bytes(n)) + }, + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + Ok(ConstVal::Value(lit)) +} + +fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) + -> Result { + ConstFloat::from_str(num, fty).map_err(|_| ()) +} diff --git a/src/librustc_mir/pattern/pattern.rs b/src/librustc_mir/hair/pattern/pattern.rs similarity index 100% rename from src/librustc_mir/pattern/pattern.rs rename to src/librustc_mir/hair/pattern/pattern.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 54ca8c7ad4f6f..67425c9643dd4 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -71,9 +71,9 @@ pub mod transform; pub mod util; pub mod interpret; pub mod monomorphize; -pub mod pattern; pub mod check_const_err; +pub use hair::pattern::check_crate as matchck_crate; use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { @@ -81,7 +81,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); providers.const_eval = interpret::const_eval_provider; - providers.check_match = pattern::check_match; + providers.check_match = hair::pattern::check_match; } #[cfg(not(stage0))] // remove after the next snapshot diff --git a/src/librustc_mir/pattern/mod.rs b/src/librustc_mir/pattern/mod.rs deleted file mode 100644 index c99dc4a7658d9..0000000000000 --- a/src/librustc_mir/pattern/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! constant evaluation on the HIR and code to validate patterns/matches - -mod _match; -mod check_match; -pub(crate) mod pattern; - -pub use self::check_match::check_crate; -pub(crate) use self::check_match::check_match; From cab8fbe87589b03024b3e825e9ea705f429083ed Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 16:22:26 +0100 Subject: [PATCH 058/115] Remove unused error variants and const eval types --- src/librustc/ich/impls_ty.rs | 16 ----------- src/librustc/middle/const_val.rs | 42 ++--------------------------- src/librustc/ty/codec.rs | 20 -------------- src/librustc/ty/structural_impls.rs | 12 --------- 4 files changed, 2 insertions(+), 88 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 8ac2f929b8da6..4e6db5549a0bd 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -332,10 +332,6 @@ for ::middle::const_val::ConstVal<'gcx> { } } -impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> { - data -}); - impl_stable_hash_for!(enum mir::interpret::Value { ByVal(v), ByValPair(a, b), @@ -433,16 +429,7 @@ for ::middle::const_val::ErrKind<'gcx> { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - CannotCast | - MissingStructField | NonConstPath | - ExpectedConstTuple | - ExpectedConstStruct | - IndexedNonVec | - IndexNotUsize | - MiscBinaryOp | - MiscCatchAll | - IndexOpFeatureGated | TypeckError | CheckMatchError => { // nothing to do @@ -460,9 +447,6 @@ for ::middle::const_val::ErrKind<'gcx> { LayoutError(ref layout_error) => { layout_error.hash_stable(hcx, hasher); } - ErroneousReferencedConstant(ref const_val) => { - const_val.hash_stable(hcx, hasher); - } Miri(ref err) => err.hash_stable(hcx, hasher), } } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 5b18b7d5fd918..c987ed0ea5d3f 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -16,7 +16,6 @@ use mir::interpret::{Value, PrimVal}; use errors::DiagnosticBuilder; use graphviz::IntoCow; -use serialize; use syntax_pos::Span; use std::borrow::Cow; @@ -29,13 +28,6 @@ pub enum ConstVal<'tcx> { Value(Value), } -#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)] -pub struct ByteArray<'tcx> { - pub data: &'tcx [u8], -} - -impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {} - impl<'tcx> ConstVal<'tcx> { pub fn to_raw_bits(&self) -> Option { match *self { @@ -64,26 +56,14 @@ pub struct ConstEvalErr<'tcx> { #[derive(Clone, Debug)] pub enum ErrKind<'tcx> { - CannotCast, - MissingStructField, NonConstPath, UnimplementedConstVal(&'static str), - ExpectedConstTuple, - ExpectedConstStruct, - IndexedNonVec, - IndexNotUsize, IndexOutOfBounds { len: u64, index: u64 }, - MiscBinaryOp, - MiscCatchAll, - - IndexOpFeatureGated, Math(ConstMathErr), LayoutError(layout::LayoutError<'tcx>), - ErroneousReferencedConstant(Box>), - TypeckError, CheckMatchError, Miri(::mir::interpret::EvalError<'tcx>), @@ -131,28 +111,17 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { } match self.kind { - CannotCast => simple!("can't cast this type"), - MissingStructField => simple!("nonexistent struct field"), NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => simple!("unimplemented constant expression: {}", what), - ExpectedConstTuple => simple!("expected constant tuple"), - ExpectedConstStruct => simple!("expected constant struct"), - IndexedNonVec => simple!("indexing is only supported for arrays"), - IndexNotUsize => simple!("indices must be of type `usize`"), IndexOutOfBounds { len, index } => { simple!("index out of bounds: the len is {} but the index is {}", len, index) } - MiscBinaryOp => simple!("bad operands for binary"), - MiscCatchAll => simple!("unsupported constant expr"), - IndexOpFeatureGated => simple!("the index operation on const values is unstable"), Math(ref err) => Simple(err.description().into_cow()), LayoutError(ref err) => Simple(err.to_string().into_cow()), - ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), - TypeckError => simple!("type-checking failed"), CheckMatchError => simple!("match-checking failed"), // FIXME: report a full backtrace @@ -166,15 +135,8 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { primary_kind: &str) -> DiagnosticBuilder<'gcx> { - let mut err = self; - while let &ConstEvalErr { - kind: ErrKind::ErroneousReferencedConstant(box ref i_err), .. - } = err { - err = i_err; - } - - let mut diag = struct_error(tcx, err.span, "constant evaluation error"); - err.note(tcx, primary_span, primary_kind, &mut diag); + let mut diag = struct_error(tcx, self.span, "constant evaluation error"); + self.note(tcx, primary_span, primary_kind, &mut diag); diag } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index fbb14f39ade34..f98bc95356098 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -17,7 +17,6 @@ // persisting to incr. comp. caches. use hir::def_id::{DefId, CrateNum}; -use middle::const_val::ByteArray; use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque}; use std::hash::Hash; @@ -240,17 +239,6 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D) .mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) } -#[inline] -pub fn decode_byte_array<'a, 'tcx, D>(decoder: &mut D) - -> Result, D::Error> - where D: TyDecoder<'a, 'tcx>, - 'tcx: 'a, -{ - Ok(ByteArray { - data: decoder.tcx().alloc_byte_array(&Vec::decode(decoder)?) - }) -} - #[inline] pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) -> Result<&'tcx ty::Const<'tcx>, D::Error> @@ -278,7 +266,6 @@ macro_rules! implement_ty_decoder { use $crate::ty::codec::*; use $crate::ty::subst::Substs; use $crate::hir::def_id::{CrateNum}; - use $crate::middle::const_val::ByteArray; use rustc_serialize::{Decoder, SpecializedDecoder}; use std::borrow::Cow; @@ -377,13 +364,6 @@ macro_rules! implement_ty_decoder { } } - impl<$($typaram),*> SpecializedDecoder> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result, Self::Error> { - decode_byte_array(self) - } - } - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 93024d51f2b48..333028f91437e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -724,26 +724,14 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { use middle::const_val::ErrKind::*; Some(match *self { - CannotCast => CannotCast, - MissingStructField => MissingStructField, NonConstPath => NonConstPath, UnimplementedConstVal(s) => UnimplementedConstVal(s), - ExpectedConstTuple => ExpectedConstTuple, - ExpectedConstStruct => ExpectedConstStruct, - IndexedNonVec => IndexedNonVec, - IndexNotUsize => IndexNotUsize, IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, - MiscBinaryOp => MiscBinaryOp, - MiscCatchAll => MiscCatchAll, - IndexOpFeatureGated => IndexOpFeatureGated, Math(ref e) => Math(e.clone()), LayoutError(ref e) => { return tcx.lift(e).map(LayoutError) } - ErroneousReferencedConstant(ref e) => { - return tcx.lift(e).map(ErroneousReferencedConstant) - } TypeckError => TypeckError, CheckMatchError => CheckMatchError, From 556ffa68eec7f9aab50843ffb06031352614a504 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 16:24:54 +0100 Subject: [PATCH 059/115] Explain the existance of `is_binop_lang_item` --- src/librustc/ty/context.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 9dc514161f1ce..cc617fb69de51 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1269,6 +1269,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_lang_items(LOCAL_CRATE) } + /// Due to missing llvm support for lowering 128 bit math to software emulation + /// (on some targets), the lowering can be done in MIR. + /// + /// This function only exists until said support is implemented. pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> { let items = self.lang_items(); let def_id = Some(def_id); From b6a99f9eef4dcf2d2970daeafcf1c2b04e61dc6f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 16:29:37 +0100 Subject: [PATCH 060/115] Accidental paste --- src/librustc/ty/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1e27e696f8c71..6d2e85cbaaaf2 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. AlwaysSized, - /// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized. + /// A univariant, the last field of which may be coerced to unsized. MaybeUnsized, /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag). Prefixed(Size, Align), From 90f2ffecb5e1c8e09f6abfb90290105281c2a6c7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 26 Jan 2018 16:44:10 +0100 Subject: [PATCH 061/115] Simplify code around reading/writing ConstVals --- .../borrow_check/nll/type_check/mod.rs | 62 ++----------------- src/librustc_mir/build/misc.rs | 30 +++------ src/librustc_trans/mir/analyze.rs | 19 ++---- 3 files changed, 21 insertions(+), 90 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 82c317bba8b22..a6a4f4363be84 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -24,9 +24,7 @@ use rustc::traits::{self, FulfillmentContext}; use rustc::ty::error::TypeError; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; -use rustc::middle::const_val::ConstVal; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use std::fmt; @@ -259,22 +257,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - let did = match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { - self.tcx() - .interpret_interner - .get_fn(p.alloc_id) - .map(|instance| instance.def_id()) - }, - ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { - match value.ty.sty { - ty::TyFnDef(ty_def_id, _) => Some(ty_def_id), - _ => None, - } - }, - _ => None, - }; - if let Some(def_id) = did { + if let ty::TyFnDef(def_id, substs) = value.ty.sty { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -287,17 +270,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // are transitioning to the miri-based system, we // don't have a handy function for that, so for // now we just ignore `value.val` regions. - let substs = match value.ty.sty { - ty::TyFnDef(ty_def_id, substs) => { - assert_eq!(def_id, ty_def_id); - substs - } - _ => span_bug!( - self.last_span, - "unexpected type for constant function: {:?}", - value.ty - ), - }; let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); @@ -1028,35 +1000,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { - match operand { - &Operand::Constant(box Constant { - literal: - Literal::Value { - value: - &ty::Const { - val, - ty, - }, - .. - }, - .. - }) => match val { - ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { - let inst = self.tcx().interpret_interner.get_fn(p.alloc_id); - inst.map_or(false, |inst| { - Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() - }) - }, - ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { - match ty.sty { - ty::TyFnDef(ty_def_id, _) => { - Some(ty_def_id) == self.tcx().lang_items().box_free_fn() - } - _ => false, - } + match *operand { + Operand::Constant(ref c) => match c.ty.sty { + ty::TyFnDef(ty_def_id, _) => { + Some(ty_def_id) == self.tcx().lang_items().box_free_fn() } _ => false, - } + }, _ => false, } } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 78c7004ef6034..6e10c2307c8e6 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -54,30 +54,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Returns a zero literal operand for the appropriate type, works for // bool, char and integers. pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = match ty.sty { - ty::TyBool => { - self.hir.false_literal() - } - ty::TyChar => { - Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty - }) - } - } + match ty.sty { + ty::TyBool | + ty::TyChar | ty::TyUint(_) | - ty::TyInt(_) => { - Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty - }) - } - } + ty::TyInt(_) => {} _ => { span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty) } + } + let literal = Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), + ty + }) }; self.literal_operand(span, ty, literal) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index c7f8d1a69c8f4..3be7778df1e05 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -13,11 +13,9 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc::middle::const_val::ConstVal; -use rustc::mir::{self, Location, TerminatorKind, Literal}; +use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir::traversal; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty; use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; @@ -112,19 +110,12 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { location: Location) { let check = match *kind { mir::TerminatorKind::Call { - func: mir::Operand::Constant(box mir::Constant { - literal: Literal::Value { - value: &ty::Const { val, ty }, .. - }, .. - }), + func: mir::Operand::Constant(ref c), ref args, .. - } => match val { - ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { - ty::TyFnDef(did, _) => Some((did, args)), - _ => None, - }, + } => match c.ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), _ => None, - } + }, _ => None, }; if let Some((def_id, args)) = check { From 294519651d4cddfc0646f081222496c5d36b30fe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 27 Jan 2018 16:07:45 +0100 Subject: [PATCH 062/115] Add regression tests --- src/test/run-pass/ctfe/union-ice.rs | 45 ++++++++++++++++++++ src/test/ui/const-eval/index_out_of_bound.rs | 13 ++++++ 2 files changed, 58 insertions(+) create mode 100644 src/test/run-pass/ctfe/union-ice.rs create mode 100644 src/test/ui/const-eval/index_out_of_bound.rs diff --git a/src/test/run-pass/ctfe/union-ice.rs b/src/test/run-pass/ctfe/union-ice.rs new file mode 100644 index 0000000000000..f83f49f298b90 --- /dev/null +++ b/src/test/run-pass/ctfe/union-ice.rs @@ -0,0 +1,45 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] + +type Field1 = i32; +type Field2 = f32; +type Field3 = i64; + +union DummyUnion { + field1: Field1, + field2: Field2, + field3: Field3, +} + +const FLOAT1_AS_I32: i32 = 1065353216; +const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; + +const fn read_field1() -> Field1 { + const FIELD1: Field1 = unsafe { UNION.field1 }; + FIELD1 +} + +const fn read_field2() -> Field2 { + const FIELD2: Field2 = unsafe { UNION.field2 }; + FIELD2 +} + +const fn read_field3() -> Field3 { + const FIELD3: Field3 = unsafe { UNION.field3 }; + FIELD3 +} + +fn main() { + assert_eq!(read_field1(), FLOAT1_AS_I32); + assert_eq!(read_field2(), 1.0); + assert_eq!(read_field3(), unsafe { UNION.field3 }); +} diff --git a/src/test/ui/const-eval/index_out_of_bound.rs b/src/test/ui/const-eval/index_out_of_bound.rs new file mode 100644 index 0000000000000..0109f72aa1d8d --- /dev/null +++ b/src/test/ui/const-eval/index_out_of_bound.rs @@ -0,0 +1,13 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static FOO: i32 = [][0]; //~ ERROR E0080 + +fn main() {} From 7aece484cb7c35b7e481b92a9c7ac93cedc63ac4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 27 Jan 2018 17:15:40 +0100 Subject: [PATCH 063/115] Report errors in statics during collecting instead of translating --- src/librustc/ty/error.rs | 7 +- src/librustc_mir/monomorphize/collector.rs | 157 +++++++++++------- src/librustc_trans/base.rs | 2 + src/test/compile-fail/huge-array.rs | 2 +- src/test/ui/const-eval/index_out_of_bound.rs | 4 +- .../ui/const-eval/index_out_of_bound.stderr | 20 +++ src/test/ui/const-fn-error.stderr | 8 +- 7 files changed, 130 insertions(+), 70 deletions(-) create mode 100644 src/test/ui/const-eval/index_out_of_bound.stderr diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5e5ae961cae6c..8c09b8bbd2f32 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -10,9 +10,7 @@ use hir::def_id::DefId; use infer::type_variable; -use middle::const_val::ConstVal; use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt}; -use mir::interpret::{Value, PrimVal}; use std::fmt; use syntax::abi; @@ -192,9 +190,8 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - match n.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => - format!("array of {} elements", n), + match n.val.to_raw_bits() { + Some(n) => format!("array of {} elements", n), _ => "array".to_string(), } } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 44729fad50c57..17857a9d51eb8 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -201,9 +201,10 @@ use rustc::ty::subst::{Substs, Kind}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::session::config; -use rustc::mir::{self, Location}; +use rustc::mir::{self, Location, Promoted}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::MonoItem; +use rustc::mir::interpret::GlobalId; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -381,7 +382,19 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, recursion_depth_reset = None; - collect_neighbours(tcx, instance, true, &mut neighbors); + let cid = GlobalId { + instance, + promoted: None, + }; + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + + match tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(tcx, val, instance.substs, &mut neighbors), + Err(err) => { + let span = tcx.def_span(def_id); + err.report(tcx, span, "static"); + } + } } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally @@ -393,7 +406,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, recursion_depths)); check_type_length_limit(tcx, instance); - collect_neighbours(tcx, instance, false, &mut neighbors); + collect_neighbours(tcx, instance, &mut neighbors); } MonoItem::GlobalAsm(..) => { recursion_depth_reset = None; @@ -502,7 +515,6 @@ struct MirNeighborCollector<'a, 'tcx: 'a> { mir: &'a mir::Mir<'tcx>, output: &'a mut Vec>, param_substs: &'tcx Substs<'tcx>, - const_context: bool, } impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { @@ -572,27 +584,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - match constant.val { - ConstVal::Unevaluated(def_id, substs) => { - let substs = self.tcx.trans_apply_param_substs(self.param_substs, - &substs); - let instance = ty::Instance::resolve(self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap(); - collect_neighbours(self.tcx, instance, true, self.output); - }, - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { - collect_miri(self.tcx, a.alloc_id, self.output); - collect_miri(self.tcx, b.alloc_id, self.output); - } - ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) | - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) | - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) | - ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => - collect_miri(self.tcx, ptr.alloc_id, self.output), - _ => {}, - } + collect_const(self.tcx, constant, self.param_substs, self.output); self.super_const(constant); } @@ -608,30 +600,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); - - let constness = match (self.const_context, &callee_ty.sty) { - (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => { - let instance = - ty::Instance::resolve(self.tcx, - ty::ParamEnv::empty(traits::Reveal::All), - def_id, - substs).unwrap(); - Some(instance) - } - _ => None - }; - - if let Some(const_fn_instance) = constness { - // If this is a const fn, called from a const context, we - // have to visit its body in order to find any fn reifications - // it might contain. - collect_neighbours(self.tcx, - const_fn_instance, - true, - self.output); - } else { - visit_fn_use(self.tcx, callee_ty, true, &mut self.output); - } + visit_fn_use(self.tcx, callee_ty, true, &mut self.output); } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { @@ -1120,7 +1089,14 @@ fn collect_miri<'a, 'tcx>( alloc_id: AllocId, output: &mut Vec>, ) { - if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { + if let Some(did) = tcx.interpret_interner.get_corresponding_static_def_id(alloc_id) { + let instance = Instance::mono(tcx, did); + if should_monomorphize_locally(tcx, &instance) { + trace!("collecting static {:?}", did); + let node_id = tcx.hir.as_local_node_id(did).unwrap(); + output.push(MonoItem::Static(node_id)); + } + } else if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &inner in alloc.relocations.values() { collect_miri(tcx, inner, output); @@ -1138,23 +1114,29 @@ fn collect_miri<'a, 'tcx>( /// Scan the MIR in order to find function calls, closures, and drop-glue fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, - const_context: bool, output: &mut Vec>) { let mir = tcx.instance_mir(instance.def); - let mut visitor = MirNeighborCollector { + MirNeighborCollector { tcx, mir: &mir, output, param_substs: instance.substs, - const_context, - }; - - visitor.visit_mir(&mir); - for promoted in &mir.promoted { - visitor.mir = promoted; - visitor.visit_mir(promoted); + }.visit_mir(&mir); + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + for (i, promoted) in mir.promoted.iter().enumerate() { + use rustc_data_structures::indexed_vec::Idx; + let cid = GlobalId { + instance, + promoted: Some(Promoted::new(i)), + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(tcx, val, instance.substs, output), + Err(err) => { + err.report(tcx, promoted.span, "promoted"); + } + } } } @@ -1166,3 +1148,60 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, printer.push_def_path(def_id, &mut output); output } + +fn collect_const<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + constant: &ty::Const<'tcx>, + param_substs: &'tcx Substs<'tcx>, + output: &mut Vec>, +) { + debug!("visiting const {:?}", *constant); + + let val = match constant.val { + ConstVal::Unevaluated(def_id, substs) => { + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + let substs = tcx.trans_apply_param_substs(param_substs, + &substs); + let instance = ty::Instance::resolve(tcx, + param_env, + def_id, + substs).unwrap(); + + let cid = GlobalId { + instance, + promoted: None, + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(val) => val.val, + Err(err) => { + let span = tcx.def_span(def_id); + err.report(tcx, span, "constant"); + return; + } + } + }, + _ => constant.val, + }; + match val { + ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"), + ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { + collect_miri(tcx, a.alloc_id, output); + collect_miri(tcx, b.alloc_id, output); + } + ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) | + ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) | + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => + collect_miri(tcx, ptr.alloc_id, output), + ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => { + // by ref should only collect the inner allocation, not the value itself + let alloc = tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .expect("ByRef to extern static is not allowed"); + for &inner in alloc.relocations.values() { + collect_miri(tcx, inner, output); + } + } + _ => {}, + } +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 233120f2bf30d..9fc4565f8e4df 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -975,6 +975,8 @@ fn collect_and_partition_translation_items<'a, 'tcx>( collector::collect_crate_mono_items(tcx, collection_mode) }); + tcx.sess.abort_if_errors(); + ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); let strategy = if tcx.sess.opts.incremental.is_some() { diff --git a/src/test/compile-fail/huge-array.rs b/src/test/compile-fail/huge-array.rs index 029e9651cb3cd..7de84802e1d05 100644 --- a/src/test/compile-fail/huge-array.rs +++ b/src/test/compile-fail/huge-array.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:; 1518599999 +// error-pattern:; 1518600000 fn generic(t: T) { let s: [T; 1518600000] = [t; 1518600000]; diff --git a/src/test/ui/const-eval/index_out_of_bound.rs b/src/test/ui/const-eval/index_out_of_bound.rs index 0109f72aa1d8d..632804f2fd366 100644 --- a/src/test/ui/const-eval/index_out_of_bound.rs +++ b/src/test/ui/const-eval/index_out_of_bound.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -static FOO: i32 = [][0]; //~ ERROR E0080 +static FOO: i32 = [][0]; +//~^ ERROR E0080 +//~| ERROR E0080 fn main() {} diff --git a/src/test/ui/const-eval/index_out_of_bound.stderr b/src/test/ui/const-eval/index_out_of_bound.stderr new file mode 100644 index 0000000000000..53cc8d361ff95 --- /dev/null +++ b/src/test/ui/const-eval/index_out_of_bound.stderr @@ -0,0 +1,20 @@ +error[E0080]: constant evaluation error + --> $DIR/index_out_of_bound.rs:11:19 + | +11 | static FOO: i32 = [][0]; + | ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 + | +note: inside call to FOO + --> $DIR/index_out_of_bound.rs:11:1 + | +11 | static FOO: i32 = [][0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: constant evaluation error + --> $DIR/index_out_of_bound.rs:11:1 + | +11 | static FOO: i32 = [][0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index f17447e4f7301..02a8920727e67 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -5,15 +5,15 @@ error[E0016]: blocks in constant functions are limited to items and tail express | ^ error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors - --> $DIR/const-fn-error.rs:17:14 + --> $DIR/const-fn-error.rs:18:14 | -17 | for i in 0..x { //~ ERROR calls in constant functions +18 | for i in 0..x { | ^^^^ error[E0019]: constant function contains unimplemented expression type - --> $DIR/const-fn-error.rs:17:14 + --> $DIR/const-fn-error.rs:18:14 | -17 | for i in 0..x { //~ ERROR calls in constant functions +18 | for i in 0..x { | ^^^^ error[E0080]: constant evaluation error From 2872168197f5940ee55c4d2508b01c9a54ed981d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 28 Jan 2018 14:11:55 +0100 Subject: [PATCH 064/115] Don't use scary block reorderings --- src/librustc_mir/transform/instcombine.rs | 60 ++--------------------- 1 file changed, 4 insertions(+), 56 deletions(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 640fd7cadab2c..d5fa379dea00e 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -12,8 +12,8 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::{SourceInfo, ARGUMENT_VISIBILITY_SCOPE, TerminatorKind}; -use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; +use rustc::mir::TerminatorKind; +use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, TypeVariants, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; @@ -21,10 +21,8 @@ use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, Va use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::Idx; use std::mem; -use std::collections::VecDeque; use transform::{MirPass, MirSource}; use syntax::codemap::Span; -use rustc_data_structures::control_flow_graph::ControlFlowGraph; use rustc::ty::subst::Substs; pub struct InstCombine; @@ -73,7 +71,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { - debug!("Replacing `Len([_; N])`: {:?}", rvalue); + debug!("Replacing `Len([_; N])`: {:?} with {:?}", rvalue, constant); *rvalue = Rvalue::Use(Operand::Constant(box constant)); } @@ -101,6 +99,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { ) { self.super_constant(constant, location); if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) { + debug!("Replacing `{:?}` with {:?}:{:?}", constant.literal, val, ty); constant.literal = Literal::Value { value: self.tcx.mk_const(ty::Const { val: ConstVal::Value(val), @@ -464,57 +463,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { } impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { - // override to visit basic blocks in execution order - fn super_mir(&mut self, mir: &Mir<'tcx>) { - let mut seen = FxHashSet::default(); - seen.insert(mir.start_node()); - let mut sorted = Vec::new(); - let mut next = VecDeque::new(); - sorted.push(mir.start_node()); - next.push_back(mir.start_node()); - while let Some(current) = next.pop_front() { - for successor in mir.successors(current) { - trace!("checking successor of {:?}: {:?}", current, successor); - trace!("{:?}, {:?}", sorted, next); - if seen.contains(&successor) { - for &pending in &next { - // not a back-edge, just a branch merging back into a single execution - if pending == successor { - // move to the back of the queue - let i = sorted.iter().position(|&b| b == successor).unwrap(); - sorted.remove(i); - sorted.push(successor); - break; - } - } - } else { - seen.insert(successor); - sorted.push(successor); - next.push_back(successor); - } - } - } - trace!("checking basic blocks: {:?}", sorted); - for bb in sorted { - self.visit_basic_block_data(bb, &mir[bb]); - } - - for scope in &mir.visibility_scopes { - self.visit_visibility_scope_data(scope); - } - - self.visit_ty(&mir.return_ty(), TyContext::ReturnTy(SourceInfo { - span: mir.span, - scope: ARGUMENT_VISIBILITY_SCOPE, - })); - - for local in mir.local_decls.indices() { - self.visit_local_decl(local, &mir.local_decls[local]); - } - - self.visit_span(&mir.span); - } - fn visit_constant( &mut self, constant: &Constant<'tcx>, From ec4924e7ba4c82133aa1bd6d01ab67987bd4f39a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 28 Jan 2018 14:41:17 +0100 Subject: [PATCH 065/115] Split const prop into its own pass --- src/librustc_mir/transform/const_prop.rs | 513 ++++++++++++++++++++++ src/librustc_mir/transform/instcombine.rs | 444 +------------------ src/librustc_mir/transform/mod.rs | 2 + 3 files changed, 520 insertions(+), 439 deletions(-) create mode 100644 src/librustc_mir/transform/const_prop.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs new file mode 100644 index 0000000000000..652b921e80a74 --- /dev/null +++ b/src/librustc_mir/transform/const_prop.rs @@ -0,0 +1,513 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Propagates constants for early reporting of statically known +//! assertion failures + + + +use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; +use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; +use rustc::mir::TerminatorKind; +use rustc::mir::visit::{MutVisitor, Visitor}; +use rustc::middle::const_val::ConstVal; +use rustc::ty::{TyCtxt, self, Instance}; +use rustc::mir::interpret::{Value, PrimVal, GlobalId}; +use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; +use rustc::util::nodemap::FxHashMap; +use transform::{MirPass, MirSource}; +use syntax::codemap::Span; +use rustc::ty::subst::Substs; + +pub struct ConstProp; + +impl MirPass for ConstProp { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>) { + trace!("ConstProp starting for {:?}", source.def_id); + + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Place::ty()`). + let optimizations = { + let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); + optimization_finder.visit_mir(mir); + optimization_finder.optimizations + }; + + // Then carry out those optimizations. + MutVisitor::visit_mir(&mut ConstPropVisitor { optimizations, tcx }, mir); + trace!("ConstProp done for {:?}", source.def_id); + } +} + +type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); + +pub struct ConstPropVisitor<'a, 'tcx: 'a> { + optimizations: OptimizationList<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> MutVisitor<'tcx> for ConstPropVisitor<'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if let Some((value, ty, span)) = self.optimizations.const_prop.remove(&location) { + let value = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + }); + debug!("Replacing `{:?}` with {:?}", rvalue, value); + let constant = Constant { + ty, + literal: Literal::Value { value }, + span, + }; + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } + + self.super_rvalue(rvalue, location) + } + + fn visit_constant( + &mut self, + constant: &mut Constant<'tcx>, + location: Location, + ) { + self.super_constant(constant, location); + if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) { + debug!("Replacing `{:?}` with {:?}:{:?}", constant.literal, val, ty); + constant.literal = Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Value(val), + ty, + }), + }; + } + } + + fn visit_operand( + &mut self, + operand: &mut Operand<'tcx>, + location: Location, + ) { + self.super_operand(operand, location); + let new = match operand { + Operand::Move(Place::Local(local)) | + Operand::Copy(Place::Local(local)) => { + trace!("trying to read {:?}", local); + self.optimizations.places.get(&local).cloned() + }, + _ => return, + }; + if let Some((value, ty, span)) = new { + let value = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + }); + debug!("Replacing `{:?}` with {:?}", operand, value); + let constant = Constant { + ty, + literal: Literal::Value { value }, + span, + }; + *operand = Operand::Constant(box constant); + } + } + + fn visit_terminator_kind( + &mut self, + block: BasicBlock, + kind: &mut TerminatorKind<'tcx>, + location: Location, + ) { + match kind { + TerminatorKind::SwitchInt { discr: value, .. } | + TerminatorKind::Yield { value, .. } | + TerminatorKind::Assert { cond: value, .. } => { + if let Some((new, ty, span)) = self.optimizations.terminators.remove(&block) { + let new = self.tcx.mk_const(ty::Const { + val: ConstVal::Value(new), + ty, + }); + debug!("Replacing `{:?}` with {:?}", value, new); + let constant = Constant { + ty, + literal: Literal::Value { value: new }, + span, + }; + *value = Operand::Constant(box constant); + } + } + // FIXME: do this optimization for function calls + _ => {}, + } + self.super_terminator_kind(block, kind, location) + } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + optimizations: OptimizationList<'tcx>, +} + +impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { + fn new( + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + ) -> OptimizationFinder<'b, 'a, 'tcx> { + OptimizationFinder { + mir, + tcx, + source, + optimizations: OptimizationList::default(), + } + } + + fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { + if let Some(&val) = self.optimizations.constants.get(c) { + return Some(val); + } + match c.literal { + Literal::Value { value } => match value.val { + ConstVal::Value(v) => Some((v, value.ty, c.span)), + ConstVal::Unevaluated(did, substs) => { + let param_env = self.tcx.param_env(self.source.def_id); + let instance = Instance::resolve( + self.tcx, + param_env, + did, + substs, + )?; + let cid = GlobalId { + instance, + promoted: None, + }; + let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; + let val = (value, ty, c.span); + trace!("evaluated {:?} to {:?}", c, val); + self.optimizations.constants.insert(c.clone(), val); + Some(val) + }, + }, + // evaluate the promoted and replace the constant with the evaluated result + Literal::Promoted { index } => { + let generics = self.tcx.generics_of(self.source.def_id); + if generics.parent_types as usize + generics.types.len() > 0 { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let cid = GlobalId { + instance, + promoted: Some(index), + }; + let param_env = self.tcx.param_env(self.source.def_id); + let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; + let val = (value, ty, c.span); + trace!("evaluated {:?} to {:?}", c, val); + self.optimizations.constants.insert(c.clone(), val); + Some(val) + } + } + } + + fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { + match *op { + Operand::Constant(ref c) => self.eval_constant(c), + Operand::Move(ref place) | Operand::Copy(ref place) => match *place { + Place::Local(loc) => self.optimizations.places.get(&loc).cloned(), + // FIXME(oli-obk): field and index projections + Place::Projection(_) => None, + _ => None, + }, + } + } + + fn simplify_operand(&mut self, op: &Operand<'tcx>) -> Option> { + match *op { + Operand::Constant(ref c) => match c.literal { + Literal::Value { .. } => None, + _ => self.eval_operand(op), + }, + _ => self.eval_operand(op), + } + } + + fn const_prop( + &mut self, + rvalue: &Rvalue<'tcx>, + place_ty: ty::Ty<'tcx>, + span: Span, + ) -> Option> { + match *rvalue { + // No need to overwrite an already evaluated constant + Rvalue::Use(Operand::Constant(box Constant { + literal: Literal::Value { + value: &ty::Const { + val: ConstVal::Value(_), + .. + }, + }, + .. + })) => None, + // This branch exists for the sanity type check + Rvalue::Use(Operand::Constant(ref c)) => { + assert_eq!(c.ty, place_ty); + self.eval_constant(c) + }, + Rvalue::Use(ref op) => { + self.eval_operand(op) + }, + Rvalue::Repeat(..) | + Rvalue::Ref(..) | + Rvalue::Cast(..) | + Rvalue::Aggregate(..) | + Rvalue::NullaryOp(NullOp::Box, _) | + Rvalue::Discriminant(..) => None, + // FIXME(oli-obk): evaluate static/constant slice lengths + Rvalue::Len(_) => None, + Rvalue::NullaryOp(NullOp::SizeOf, ty) => { + let param_env = self.tcx.param_env(self.source.def_id); + type_size_of(self.tcx, param_env, ty).map(|n| ( + Value::ByVal(PrimVal::Bytes(n as u128)), + self.tcx.types.usize, + span, + )) + } + Rvalue::UnaryOp(op, ref arg) => { + let def_id = if self.tcx.is_closure(self.source.def_id) { + self.tcx.closure_base_def_id(self.source.def_id) + } else { + self.source.def_id + }; + let generics = self.tcx.generics_of(def_id); + if generics.parent_types as usize + generics.types.len() > 0 { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); + + let val = self.eval_operand(arg)?; + let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; + let kind = ecx.ty_to_primval_kind(val.1).ok()?; + match unary_op(op, prim, kind) { + Ok(val) => Some((Value::ByVal(val), place_ty, span)), + Err(mut err) => { + ecx.report(&mut err, false, Some(span)); + None + }, + } + } + Rvalue::CheckedBinaryOp(op, ref left, ref right) | + Rvalue::BinaryOp(op, ref left, ref right) => { + trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); + let left = self.eval_operand(left)?; + let right = self.eval_operand(right)?; + let def_id = if self.tcx.is_closure(self.source.def_id) { + self.tcx.closure_base_def_id(self.source.def_id) + } else { + self.source.def_id + }; + let generics = self.tcx.generics_of(def_id); + let has_generics = generics.parent_types as usize + generics.types.len() > 0; + if has_generics { + // FIXME: can't handle code with generics + return None; + } + let substs = Substs::identity_for_item(self.tcx, self.source.def_id); + let instance = Instance::new(self.source.def_id, substs); + let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); + + let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; + let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); + match ecx.binary_op(op, l, left.1, r, right.1) { + Ok((val, overflow)) => { + let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { + Value::ByValPair( + val, + PrimVal::from_bool(overflow), + ) + } else { + if overflow { + use rustc::mir::interpret::EvalErrorKind; + let mut err = EvalErrorKind::OverflowingMath.into(); + ecx.report(&mut err, false, Some(span)); + return None; + } + Value::ByVal(val) + }; + Some((val, place_ty, span)) + }, + Err(mut err) => { + ecx.report(&mut err, false, Some(span)); + None + }, + } + }, + } + } +} + +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Ty<'tcx>) -> Option { + use rustc::ty::layout::LayoutOf; + (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) +} + +struct CanConstProp { + local: Local, + can_const_prop: bool, + // false at the beginning, once set, there are not allowed to be any more assignments + found_assignment: bool, +} + +impl CanConstProp { + /// returns true if `local` can be propagated + fn check<'tcx>(local: Local, mir: &Mir<'tcx>) -> bool { + let mut cpv = CanConstProp { + local, + can_const_prop: true, + found_assignment: false, + }; + cpv.visit_mir(mir); + cpv.can_const_prop + } + + fn is_our_local(&mut self, mut place: &Place) -> bool { + while let Place::Projection(ref proj) = place { + place = &proj.base; + } + if let Place::Local(local) = *place { + local == self.local + } else { + false + } + } +} + +impl<'tcx> Visitor<'tcx> for CanConstProp { + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + self.super_statement(block, statement, location); + match statement.kind { + StatementKind::SetDiscriminant { ref place, .. } | + StatementKind::Assign(ref place, _) => { + if self.is_our_local(place) { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true + } + } + }, + StatementKind::InlineAsm { ref outputs, .. } => { + for place in outputs { + if self.is_our_local(place) { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true + } + return; + } + } + } + _ => {} + } + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + if let Rvalue::Ref(_, _, ref place) = *rvalue { + if self.is_our_local(place) { + self.can_const_prop = false; + } + } + } +} + +impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { + fn visit_constant( + &mut self, + constant: &Constant<'tcx>, + location: Location, + ) { + trace!("visit_constant: {:?}", constant); + self.super_constant(constant, location); + self.eval_constant(constant); + } + + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + trace!("visit_statement: {:?}", statement); + if let StatementKind::Assign(ref place, ref rval) = statement.kind { + let place_ty = place + .ty(&self.mir.local_decls, self.tcx) + .to_ty(self.tcx); + let span = statement.source_info.span; + if let Some(value) = self.const_prop(rval, place_ty, span) { + self.optimizations.const_prop.insert(location, value); + if let Place::Local(local) = *place { + if self.mir.local_kind(local) == LocalKind::Temp + && CanConstProp::check(local, self.mir) { + trace!("storing {:?} to {:?}", value, local); + assert!(self.optimizations.places.insert(local, value).is_none()); + } + } + } + } + self.super_statement(block, statement, location); + } + + fn visit_terminator_kind( + &mut self, + block: BasicBlock, + kind: &TerminatorKind<'tcx>, + _location: Location, + ) { + match kind { + TerminatorKind::SwitchInt { discr: value, .. } | + TerminatorKind::Yield { value, .. } | + TerminatorKind::Assert { cond: value, .. } => { + if let Some(value) = self.simplify_operand(value) { + self.optimizations.terminators.insert(block, value); + } + } + // FIXME: do this optimization for function calls + _ => {}, + } + } +} + +#[derive(Default)] +struct OptimizationList<'tcx> { + const_prop: FxHashMap>, + /// Terminators that get their Operand(s) turned into constants. + terminators: FxHashMap>, + places: FxHashMap>, + constants: FxHashMap, Const<'tcx>>, +} diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index d5fa379dea00e..d1c2c7a61d495 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,19 +11,12 @@ //! Performs various peephole optimizations. use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}; -use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::TerminatorKind; use rustc::mir::visit::{MutVisitor, Visitor}; -use rustc::middle::const_val::ConstVal; -use rustc::ty::{TyCtxt, TypeVariants, self, Instance}; -use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; +use rustc::ty::{TyCtxt, TypeVariants}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::Idx; use std::mem; use transform::{MirPass, MirSource}; -use syntax::codemap::Span; -use rustc::ty::subst::Substs; pub struct InstCombine; @@ -38,25 +31,22 @@ impl MirPass for InstCombine { // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). let optimizations = { - let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); + let mut optimization_finder = OptimizationFinder::new(mir, tcx); optimization_finder.visit_mir(mir); optimization_finder.optimizations }; // Then carry out those optimizations. - MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations, tcx }, mir); + MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir); trace!("InstCombine done for {:?}", source.def_id); } } -type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); - -pub struct InstCombineVisitor<'a, 'tcx: 'a> { +pub struct InstCombineVisitor<'tcx> { optimizations: OptimizationList<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { +impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { if self.optimizations.and_stars.remove(&location) { debug!("Replacing `&*`: {:?}", rvalue); @@ -75,105 +65,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for InstCombineVisitor<'a, 'tcx> { *rvalue = Rvalue::Use(Operand::Constant(box constant)); } - if let Some((value, ty, span)) = self.optimizations.const_prop.remove(&location) { - let value = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(value), - ty, - }); - debug!("Replacing `{:?}` with {:?}", rvalue, value); - let constant = Constant { - ty, - literal: Literal::Value { value }, - span, - }; - *rvalue = Rvalue::Use(Operand::Constant(box constant)); - } - self.super_rvalue(rvalue, location) } - - fn visit_constant( - &mut self, - constant: &mut Constant<'tcx>, - location: Location, - ) { - self.super_constant(constant, location); - if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) { - debug!("Replacing `{:?}` with {:?}:{:?}", constant.literal, val, ty); - constant.literal = Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(val), - ty, - }), - }; - } - } - - fn visit_operand( - &mut self, - operand: &mut Operand<'tcx>, - location: Location, - ) { - self.super_operand(operand, location); - let new = match operand { - Operand::Move(Place::Local(local)) | - Operand::Copy(Place::Local(local)) => { - trace!("trying to read {:?}", local); - self.optimizations.places.get(&local).cloned() - }, - _ => return, - }; - if let Some((value, ty, span)) = new { - let value = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(value), - ty, - }); - debug!("Replacing `{:?}` with {:?}", operand, value); - let constant = Constant { - ty, - literal: Literal::Value { value }, - span, - }; - *operand = Operand::Constant(box constant); - } - } - - fn visit_terminator_kind( - &mut self, - block: BasicBlock, - kind: &mut TerminatorKind<'tcx>, - location: Location, - ) { - match kind { - TerminatorKind::SwitchInt { discr: value, .. } | - TerminatorKind::Yield { value, .. } | - TerminatorKind::Assert { cond: value, .. } => { - if let Some((new, ty, span)) = self.optimizations.terminators.remove(&block) { - let new = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(new), - ty, - }); - debug!("Replacing `{:?}` with {:?}", value, new); - let constant = Constant { - ty, - literal: Literal::Value { value: new }, - span, - }; - *value = Operand::Constant(box constant); - } - } - // FIXME: do this optimization for function calls - _ => {}, - } - self.super_terminator_kind(block, kind, location) - } } /// Finds optimization opportunities on the MIR. struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, optimizations: OptimizationList<'tcx>, } @@ -181,325 +80,16 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { fn new( mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, ) -> OptimizationFinder<'b, 'a, 'tcx> { OptimizationFinder { mir, tcx, - source, optimizations: OptimizationList::default(), } } - - fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { - if let Some(&val) = self.optimizations.constants.get(c) { - return Some(val); - } - match c.literal { - Literal::Value { value } => match value.val { - ConstVal::Value(v) => Some((v, value.ty, c.span)), - ConstVal::Unevaluated(did, substs) => { - let param_env = self.tcx.param_env(self.source.def_id); - let instance = Instance::resolve( - self.tcx, - param_env, - did, - substs, - )?; - let cid = GlobalId { - instance, - promoted: None, - }; - let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; - let val = (value, ty, c.span); - trace!("evaluated {:?} to {:?}", c, val); - self.optimizations.constants.insert(c.clone(), val); - Some(val) - }, - }, - // evaluate the promoted and replace the constant with the evaluated result - Literal::Promoted { index } => { - let generics = self.tcx.generics_of(self.source.def_id); - if generics.parent_types as usize + generics.types.len() > 0 { - // FIXME: can't handle code with generics - return None; - } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let cid = GlobalId { - instance, - promoted: Some(index), - }; - let param_env = self.tcx.param_env(self.source.def_id); - let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; - let val = (value, ty, c.span); - trace!("evaluated {:?} to {:?}", c, val); - self.optimizations.constants.insert(c.clone(), val); - Some(val) - } - } - } - - fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { - match *op { - Operand::Constant(ref c) => self.eval_constant(c), - Operand::Move(ref place) | Operand::Copy(ref place) => match *place { - Place::Local(loc) => self.optimizations.places.get(&loc).cloned(), - // FIXME(oli-obk): field and index projections - Place::Projection(_) => None, - _ => None, - }, - } - } - - fn simplify_operand(&mut self, op: &Operand<'tcx>) -> Option> { - match *op { - Operand::Constant(ref c) => match c.literal { - Literal::Value { .. } => None, - _ => self.eval_operand(op), - }, - _ => self.eval_operand(op), - } - } - - fn const_prop( - &mut self, - rvalue: &Rvalue<'tcx>, - place_ty: ty::Ty<'tcx>, - span: Span, - ) -> Option> { - match *rvalue { - // No need to overwrite an already evaluated constant - Rvalue::Use(Operand::Constant(box Constant { - literal: Literal::Value { - value: &ty::Const { - val: ConstVal::Value(_), - .. - }, - }, - .. - })) => None, - // This branch exists for the sanity type check - Rvalue::Use(Operand::Constant(ref c)) => { - assert_eq!(c.ty, place_ty); - self.eval_constant(c) - }, - Rvalue::Use(ref op) => { - self.eval_operand(op) - }, - Rvalue::Repeat(..) | - Rvalue::Ref(..) | - Rvalue::Cast(..) | - Rvalue::Aggregate(..) | - Rvalue::NullaryOp(NullOp::Box, _) | - Rvalue::Discriminant(..) => None, - // FIXME(oli-obk): evaluate static/constant slice lengths - Rvalue::Len(_) => None, - Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - let param_env = self.tcx.param_env(self.source.def_id); - type_size_of(self.tcx, param_env, ty).map(|n| ( - Value::ByVal(PrimVal::Bytes(n as u128)), - self.tcx.types.usize, - span, - )) - } - Rvalue::UnaryOp(op, ref arg) => { - let def_id = if self.tcx.is_closure(self.source.def_id) { - self.tcx.closure_base_def_id(self.source.def_id) - } else { - self.source.def_id - }; - let generics = self.tcx.generics_of(def_id); - if generics.parent_types as usize + generics.types.len() > 0 { - // FIXME: can't handle code with generics - return None; - } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - - let val = self.eval_operand(arg)?; - let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; - let kind = ecx.ty_to_primval_kind(val.1).ok()?; - match unary_op(op, prim, kind) { - Ok(val) => Some((Value::ByVal(val), place_ty, span)), - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } - } - Rvalue::CheckedBinaryOp(op, ref left, ref right) | - Rvalue::BinaryOp(op, ref left, ref right) => { - trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); - let left = self.eval_operand(left)?; - let right = self.eval_operand(right)?; - let def_id = if self.tcx.is_closure(self.source.def_id) { - self.tcx.closure_base_def_id(self.source.def_id) - } else { - self.source.def_id - }; - let generics = self.tcx.generics_of(def_id); - let has_generics = generics.parent_types as usize + generics.types.len() > 0; - if has_generics { - // FIXME: can't handle code with generics - return None; - } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - - let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; - let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; - trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); - match ecx.binary_op(op, l, left.1, r, right.1) { - Ok((val, overflow)) => { - let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { - Value::ByValPair( - val, - PrimVal::from_bool(overflow), - ) - } else { - if overflow { - use rustc::mir::interpret::EvalErrorKind; - let mut err = EvalErrorKind::OverflowingMath.into(); - ecx.report(&mut err, false, Some(span)); - return None; - } - Value::ByVal(val) - }; - Some((val, place_ty, span)) - }, - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } - }, - } - } -} - -fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Ty<'tcx>) -> Option { - use rustc::ty::layout::LayoutOf; - (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) -} - -struct ConstPropVisitor { - local: Local, - can_const_prop: bool, - // false at the beginning, once set, there are not allowed to be any more assignments - found_assignment: bool, -} - -impl ConstPropVisitor { - /// returns true if `local` can be propagated - fn check<'tcx>(local: Local, mir: &Mir<'tcx>) -> bool { - let mut cpv = ConstPropVisitor { - local, - can_const_prop: true, - found_assignment: false, - }; - cpv.visit_mir(mir); - cpv.can_const_prop - } - - fn is_our_local(&mut self, mut place: &Place) -> bool { - while let Place::Projection(ref proj) = place { - place = &proj.base; - } - if let Place::Local(local) = *place { - local == self.local - } else { - false - } - } -} - -impl<'tcx> Visitor<'tcx> for ConstPropVisitor { - fn visit_statement( - &mut self, - block: BasicBlock, - statement: &Statement<'tcx>, - location: Location, - ) { - self.super_statement(block, statement, location); - match statement.kind { - StatementKind::SetDiscriminant { ref place, .. } | - StatementKind::Assign(ref place, _) => { - if self.is_our_local(place) { - if self.found_assignment { - self.can_const_prop = false; - } else { - self.found_assignment = true - } - } - }, - StatementKind::InlineAsm { ref outputs, .. } => { - for place in outputs { - if self.is_our_local(place) { - if self.found_assignment { - self.can_const_prop = false; - } else { - self.found_assignment = true - } - return; - } - } - } - _ => {} - } - } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - if let Rvalue::Ref(_, _, ref place) = *rvalue { - if self.is_our_local(place) { - self.can_const_prop = false; - } - } - } } impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { - fn visit_constant( - &mut self, - constant: &Constant<'tcx>, - location: Location, - ) { - trace!("visit_constant: {:?}", constant); - self.super_constant(constant, location); - self.eval_constant(constant); - } - - fn visit_statement( - &mut self, - block: BasicBlock, - statement: &Statement<'tcx>, - location: Location, - ) { - trace!("visit_statement: {:?}", statement); - if let StatementKind::Assign(ref place, ref rval) = statement.kind { - let place_ty = place - .ty(&self.mir.local_decls, self.tcx) - .to_ty(self.tcx); - let span = statement.source_info.span; - if let Some(value) = self.const_prop(rval, place_ty, span) { - self.optimizations.const_prop.insert(location, value); - if let Place::Local(local) = *place { - if self.mir.local_kind(local) == LocalKind::Temp - && ConstPropVisitor::check(local, self.mir) { - trace!("storing {:?} to {:?}", value, local); - assert!(self.optimizations.places.insert(local, value).is_none()); - } - } - return; - } - } - self.super_statement(block, statement, location); - } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { @@ -522,34 +112,10 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { self.super_rvalue(rvalue, location) } - - fn visit_terminator_kind( - &mut self, - block: BasicBlock, - kind: &TerminatorKind<'tcx>, - _location: Location, - ) { - match kind { - TerminatorKind::SwitchInt { discr: value, .. } | - TerminatorKind::Yield { value, .. } | - TerminatorKind::Assert { cond: value, .. } => { - if let Some(value) = self.simplify_operand(value) { - self.optimizations.terminators.insert(block, value); - } - } - // FIXME: do this optimization for function calls - _ => {}, - } - } } #[derive(Default)] struct OptimizationList<'tcx> { and_stars: FxHashSet, arrays_lengths: FxHashMap>, - const_prop: FxHashMap>, - /// Terminators that get their Operand(s) turned into constants. - terminators: FxHashMap>, - places: FxHashMap>, - constants: FxHashMap, Const<'tcx>>, } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index ff3b5888e340c..74e5b273fa4d4 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -41,6 +41,7 @@ pub mod dump_mir; pub mod deaggregator; pub mod instcombine; pub mod copy_prop; +pub mod const_prop; pub mod generator; pub mod inline; pub mod lower_128bit; @@ -256,6 +257,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx // Optimizations begin. inline::Inline, instcombine::InstCombine, + const_prop::ConstProp, simplify_branches::SimplifyBranches::new("after-const-prop"), deaggregator::Deaggregator, copy_prop::CopyPropagation, From ab964008c865bdfb872f5eddeda94c1af2f1dbae Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 08:28:49 +0100 Subject: [PATCH 066/115] Update Cargo.lock --- src/Cargo.lock | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 1393dd46d6bd6..edea626fa2080 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1884,20 +1884,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rustc_const_eval" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_const_math" version = "0.0.0" @@ -1939,7 +1925,6 @@ dependencies = [ "rustc_allocator 0.0.0", "rustc_back 0.0.0", "rustc_borrowck 0.0.0", - "rustc_const_eval 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_incremental 0.0.0", @@ -1989,7 +1974,7 @@ version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_const_eval 0.0.0", + "rustc_mir 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2037,6 +2022,7 @@ dependencies = [ name = "rustc_mir" version = "0.0.0" dependencies = [ + "arena 0.0.0", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", @@ -2045,7 +2031,6 @@ dependencies = [ "rustc 0.0.0", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2071,9 +2056,9 @@ version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_errors 0.0.0", + "rustc_mir 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] From b6ff35f2583444f07a6794efe39911782aaebe5f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 08:50:47 +0100 Subject: [PATCH 067/115] Revert all changes to the instcombine pass --- src/librustc_mir/transform/instcombine.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index d1c2c7a61d495..8856d263864cd 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -23,9 +23,12 @@ pub struct InstCombine; impl MirPass for InstCombine { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: MirSource, + _: MirSource, mir: &mut Mir<'tcx>) { - trace!("InstCombine starting for {:?}", source.def_id); + // We only run when optimizing MIR (at any level). + if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { + return + } // First, find optimization opportunities. This is done in a pre-pass to keep the MIR // read-only so that we can do global analyses on the MIR in the process (e.g. @@ -38,7 +41,6 @@ impl MirPass for InstCombine { // Then carry out those optimizations. MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations }, mir); - trace!("InstCombine done for {:?}", source.def_id); } } @@ -61,7 +63,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { - debug!("Replacing `Len([_; N])`: {:?} with {:?}", rvalue, constant); + debug!("Replacing `Len([_; N])`: {:?}", rvalue); *rvalue = Rvalue::Use(Operand::Constant(box constant)); } @@ -77,10 +79,7 @@ struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { } impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { - fn new( - mir: &'b Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ) -> OptimizationFinder<'b, 'a, 'tcx> { + fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { OptimizationFinder { mir, tcx, From e9d9b967190cfb08ed4e7fd79e1a2175c2cb5f15 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 09:55:03 +0100 Subject: [PATCH 068/115] Don't actually do constant propagation if mir-opt-level=0 --- src/librustc_mir/transform/const_prop.rs | 83 ++++++++++++++++++++---- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 652b921e80a74..8cbb2afae397a 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -44,8 +44,11 @@ impl MirPass for ConstProp { optimization_finder.optimizations }; - // Then carry out those optimizations. - MutVisitor::visit_mir(&mut ConstPropVisitor { optimizations, tcx }, mir); + // We only actually run when optimizing MIR (at any level). + if tcx.sess.opts.debugging_opts.mir_opt_level != 0 { + // Then carry out those optimizations. + MutVisitor::visit_mir(&mut ConstPropVisitor { optimizations, tcx }, mir); + } trace!("ConstProp done for {:?}", source.def_id); } } @@ -236,16 +239,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } } - fn simplify_operand(&mut self, op: &Operand<'tcx>) -> Option> { - match *op { - Operand::Constant(ref c) => match c.literal { - Literal::Value { .. } => None, - _ => self.eval_operand(op), - }, - _ => self.eval_operand(op), - } - } - fn const_prop( &mut self, rvalue: &Rvalue<'tcx>, @@ -487,14 +480,76 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { &mut self, block: BasicBlock, kind: &TerminatorKind<'tcx>, - _location: Location, + location: Location, ) { match kind { TerminatorKind::SwitchInt { discr: value, .. } | TerminatorKind::Yield { value, .. } | TerminatorKind::Assert { cond: value, .. } => { - if let Some(value) = self.simplify_operand(value) { + match value { + Operand::Constant(box Constant { + literal: Literal::Value { + value: &ty::Const { + val: ConstVal::Value(_), + .. + }, + }, + .. + }) => return, + _ => {}, + } + if let Some(value) = self.eval_operand(value) { self.optimizations.terminators.insert(block, value); + if let TerminatorKind::Assert { expected, msg, .. } = kind { + if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 { + let span = self.mir[block] + .statements[location.statement_index] + .source_info + .span; + let node_id = self + .tcx + .hir + .as_local_node_id(self.source.def_id) + .expect("some part of a failing const eval must be local"); + let mut lint = self.tcx.struct_span_lint_node( + ::rustc::lint::builtin::CONST_ERR, + node_id, + span, + "constant evaluation error", + ); + use rustc::mir::AssertMessage::*; + match msg { + GeneratorResumedAfterReturn => + lint.span_label(span, "generator resumed after completion"), + GeneratorResumedAfterPanic => + lint.span_label(span, "generator resumed after panicking"), + Math(ref err) => lint.span_label(span, err.description()), + BoundsCheck { ref len, ref index } => { + let len = self.eval_operand(len).expect("len must be const"); + let len = match len.0 { + Value::ByVal(PrimVal::Bytes(n)) => n, + _ => bug!("const len not primitive: {:?}", len), + }; + let index = self + .eval_operand(index) + .expect("index must be const"); + let index = match index.0 { + Value::ByVal(PrimVal::Bytes(n)) => n, + _ => bug!("const index not primitive: {:?}", index), + }; + lint.span_label( + span, + format!( + "index out of bounds: \ + the len is {} but the index is {}", + len, + index, + ), + ) + }, + }.emit(); + } + } } } // FIXME: do this optimization for function calls From 1708574a3b8b91e917d6865a66069ab9451788b8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 09:55:12 +0100 Subject: [PATCH 069/115] nit --- src/librustc/ty/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 8c09b8bbd2f32..e67c077933bdb 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -192,7 +192,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyArray(_, n) => { match n.val.to_raw_bits() { Some(n) => format!("array of {} elements", n), - _ => "array".to_string(), + None => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), From 90008071e58e91e54ac2735837e17ce4d7eae353 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 09:58:28 +0100 Subject: [PATCH 070/115] Simplify const SIMD shuffle in trans --- src/librustc_trans/mir/constant.rs | 91 ++++++++++-------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c7a0724c1e72b..6aa8b7e5449fd 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -191,70 +191,39 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, ) -> (ValueRef, Ty<'tcx>) { - let layout = bx.cx.layout_of(constant.ty); self.mir_constant_to_miri_value(bx, constant) .and_then(|c| { - let llval = match c { - MiriValue::ByVal(val) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - primval_to_llvm(bx.cx, val, scalar, layout.immediate_llvm_type(bx.cx)) - }, - MiriValue::ByValPair(a_val, b_val) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) - }; - let a_llval = primval_to_llvm( - bx.cx, - a_val, - a_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 0), - ); - let b_llval = primval_to_llvm( - bx.cx, - b_val, - b_scalar, - layout.scalar_pair_element_llvm_type(bx.cx, 1), - ); - C_struct(bx.cx, &[a_llval, b_llval], false) - }, - MiriValue::ByRef(..) => { - let field_ty = constant.ty.builtin_index().unwrap(); - let fields = match constant.ty.sty { - ty::TyArray(_, n) => n.val.unwrap_u64(), - ref other => bug!("invalid simd shuffle type: {}", other), - }; - let values: Result, _> = (0..fields).map(|field| { - let field = const_val_field( - bx.tcx(), - ty::ParamEnv::empty(traits::Reveal::All), - self.instance, - None, - mir::Field::new(field as usize), - c, - constant.ty, - )?; - match field.val { - ConstVal::Value(MiriValue::ByVal(prim)) => { - let layout = bx.cx.layout_of(field_ty); - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - Ok(primval_to_llvm( - bx.cx, prim, scalar, - layout.immediate_llvm_type(bx.cx), - )) - }, - other => bug!("simd shuffle field {:?}, {}", other, constant.ty), - } - }).collect(); - C_struct(bx.cx, &values?, false) - }, + let field_ty = constant.ty.builtin_index().unwrap(); + let fields = match constant.ty.sty { + ty::TyArray(_, n) => n.val.unwrap_u64(), + ref other => bug!("invalid simd shuffle type: {}", other), }; + let values: Result, _> = (0..fields).map(|field| { + let field = const_val_field( + bx.tcx(), + ty::ParamEnv::empty(traits::Reveal::All), + self.instance, + None, + mir::Field::new(field as usize), + c, + constant.ty, + )?; + match field.val { + ConstVal::Value(MiriValue::ByVal(prim)) => { + let layout = bx.cx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(primval_to_llvm( + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), + )) + }, + other => bug!("simd shuffle field {:?}, {}", other, constant.ty), + } + }).collect(); + let llval = C_struct(bx.cx, &values?, false); Ok((llval, constant.ty)) }) .unwrap_or_else(|e| { From f007b5a4c562c0d0c9679d29463079c6e05fa55f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 10:18:49 +0100 Subject: [PATCH 071/115] Fix ICE in const prop --- src/librustc_mir/transform/const_prop.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8cbb2afae397a..3b9b758baf214 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -480,7 +480,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { &mut self, block: BasicBlock, kind: &TerminatorKind<'tcx>, - location: Location, + _location: Location, ) { match kind { TerminatorKind::SwitchInt { discr: value, .. } | @@ -503,7 +503,9 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { if let TerminatorKind::Assert { expected, msg, .. } = kind { if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 { let span = self.mir[block] - .statements[location.statement_index] + .terminator + .as_ref() + .unwrap() .source_info .span; let node_id = self From 36e52f546773a4988792cbf4fdfcad9ca00ad813 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 10:29:10 +0100 Subject: [PATCH 072/115] Adjust tests to more aggressive const err linting --- src/test/compile-fail/E0080.rs | 2 ++ src/test/compile-fail/const-err-early.rs | 1 + src/test/compile-fail/const-err-multi.rs | 1 + src/test/compile-fail/eval-enum.rs | 2 ++ src/test/compile-fail/issue-8460-const.rs | 20 ++++++++++++++++++++ 5 files changed, 26 insertions(+) diff --git a/src/test/compile-fail/E0080.rs b/src/test/compile-fail/E0080.rs index 6e525d4ea9ec7..c8e425711284e 100644 --- a/src/test/compile-fail/E0080.rs +++ b/src/test/compile-fail/E0080.rs @@ -13,6 +13,8 @@ enum Enum { //~| shift left with overflow Y = (1 / 0) //~ ERROR E0080 //~| const_err + //~| const_err + //~| const_err //~| divide by zero } diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 8c2e6233abfe2..2e19de0a27960 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -14,6 +14,7 @@ pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 //~^ ERROR attempt to negate with overflow //~| ERROR const_err +//~| ERROR const_err pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 pub const C: u8 = 200u8 * 4; //~ ERROR E0080 pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080 diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 668f95f2c8d73..5fa31e05322b3 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -13,6 +13,7 @@ pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow //~^ ERROR E0080 //~| ERROR const_err +//~| ERROR const_err pub const B: i8 = A; //~^ ERROR E0080 pub const C: u8 = A as u8; diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 49f76c532df54..469618407d8f9 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -13,10 +13,12 @@ enum Test { //~^ attempt to divide by zero //~| ERROR constant evaluation error //~| WARN constant evaluation error + //~| WARN constant evaluation error RemZero = 1%0, //~^ attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error //~| WARN constant evaluation error + //~| WARN constant evaluation error } fn main() {} diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index 1d59e75a0f0f0..e2cf88d5774f7 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -17,61 +17,81 @@ fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); //~^ ERROR attempt to divide with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); //~^ ERROR attempt to divide by zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with overflow //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); //~^ ERROR attempt to calculate the remainder with a divisor of zero //~| ERROR constant evaluation error + //~| ERROR constant evaluation error } From 90b49d5bc43f31753ea05860f0b1624b294e2fc3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 10:32:11 +0100 Subject: [PATCH 073/115] Deduplicate code in rustdoc --- src/librustdoc/clean/mod.rs | 62 ++++++++++++++----------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8983d3dcfd071..9a45969b7233a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2457,25 +2457,7 @@ impl Clean for hir::Ty { ty: cx.tcx.types.usize }) }); - let n = match n.val { - ConstVal::Unevaluated(def_id, _) => { - if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { - print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) - } else { - inline::print_inlined_const(cx, def_id) - } - }, - ConstVal::Value(val) => { - let mut s = String::new(); - ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); - // array lengths are obviously usize - if s.ends_with("usize") { - let n = s.len() - "usize".len(); - s.truncate(n); - } - s - }, - }; + let n = print_const(cx, n); Array(box ty.clean(cx), n) }, TyTup(ref tys) => Tuple(tys.clean(cx)), @@ -2602,25 +2584,7 @@ impl<'tcx> Clean for Ty<'tcx> { n = new_n; } }; - let n = match n.val { - ConstVal::Unevaluated(def_id, _) => { - if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { - print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) - } else { - inline::print_inlined_const(cx, def_id) - } - }, - ConstVal::Value(val) => { - let mut s = String::new(); - ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); - // array lengths are obviously usize - if s.ends_with("usize") { - let n = s.len() - "usize".len(); - s.truncate(n); - } - s - }, - }; + let n = print_const(cx, n); Array(box ty.clean(cx), n) } ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)), @@ -3526,6 +3490,28 @@ fn name_from_pat(p: &hir::Pat) -> String { } } +fn print_const(cx: &DocContext, n: &ty::Const) -> String { + match n.val { + ConstVal::Unevaluated(def_id, _) => { + if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) { + print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id)) + } else { + inline::print_inlined_const(cx, def_id) + } + }, + ConstVal::Value(val) => { + let mut s = String::new(); + ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); + // array lengths are obviously usize + if s.ends_with("usize") { + let n = s.len() - "usize".len(); + s.truncate(n); + } + s + }, + } +} + fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String { cx.tcx.hir.node_to_pretty_string(body.node_id) } From 9c2a3286e4974fa5a1eff62d34f80ab8d9256dec Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 10:38:05 +0100 Subject: [PATCH 074/115] Remove the fragile const propagator and just do linting --- src/librustc_mir/transform/const_prop.rs | 126 +---------------------- 1 file changed, 3 insertions(+), 123 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 3b9b758baf214..3b52152946a97 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -16,7 +16,7 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::TerminatorKind; -use rustc::mir::visit::{MutVisitor, Visitor}; +use rustc::mir::visit::Visitor; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; @@ -38,124 +38,15 @@ impl MirPass for ConstProp { // First, find optimization opportunities. This is done in a pre-pass to keep the MIR // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). - let optimizations = { - let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); - optimization_finder.visit_mir(mir); - optimization_finder.optimizations - }; + let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); + optimization_finder.visit_mir(mir); - // We only actually run when optimizing MIR (at any level). - if tcx.sess.opts.debugging_opts.mir_opt_level != 0 { - // Then carry out those optimizations. - MutVisitor::visit_mir(&mut ConstPropVisitor { optimizations, tcx }, mir); - } trace!("ConstProp done for {:?}", source.def_id); } } type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); -pub struct ConstPropVisitor<'a, 'tcx: 'a> { - optimizations: OptimizationList<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> MutVisitor<'tcx> for ConstPropVisitor<'a, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if let Some((value, ty, span)) = self.optimizations.const_prop.remove(&location) { - let value = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(value), - ty, - }); - debug!("Replacing `{:?}` with {:?}", rvalue, value); - let constant = Constant { - ty, - literal: Literal::Value { value }, - span, - }; - *rvalue = Rvalue::Use(Operand::Constant(box constant)); - } - - self.super_rvalue(rvalue, location) - } - - fn visit_constant( - &mut self, - constant: &mut Constant<'tcx>, - location: Location, - ) { - self.super_constant(constant, location); - if let Some(&(val, ty, _)) = self.optimizations.constants.get(constant) { - debug!("Replacing `{:?}` with {:?}:{:?}", constant.literal, val, ty); - constant.literal = Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(val), - ty, - }), - }; - } - } - - fn visit_operand( - &mut self, - operand: &mut Operand<'tcx>, - location: Location, - ) { - self.super_operand(operand, location); - let new = match operand { - Operand::Move(Place::Local(local)) | - Operand::Copy(Place::Local(local)) => { - trace!("trying to read {:?}", local); - self.optimizations.places.get(&local).cloned() - }, - _ => return, - }; - if let Some((value, ty, span)) = new { - let value = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(value), - ty, - }); - debug!("Replacing `{:?}` with {:?}", operand, value); - let constant = Constant { - ty, - literal: Literal::Value { value }, - span, - }; - *operand = Operand::Constant(box constant); - } - } - - fn visit_terminator_kind( - &mut self, - block: BasicBlock, - kind: &mut TerminatorKind<'tcx>, - location: Location, - ) { - match kind { - TerminatorKind::SwitchInt { discr: value, .. } | - TerminatorKind::Yield { value, .. } | - TerminatorKind::Assert { cond: value, .. } => { - if let Some((new, ty, span)) = self.optimizations.terminators.remove(&block) { - let new = self.tcx.mk_const(ty::Const { - val: ConstVal::Value(new), - ty, - }); - debug!("Replacing `{:?}` with {:?}", value, new); - let constant = Constant { - ty, - literal: Literal::Value { value: new }, - span, - }; - *value = Operand::Constant(box constant); - } - } - // FIXME: do this optimization for function calls - _ => {}, - } - self.super_terminator_kind(block, kind, location) - } -} - /// Finds optimization opportunities on the MIR. struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, @@ -179,9 +70,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { } fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { - if let Some(&val) = self.optimizations.constants.get(c) { - return Some(val); - } match c.literal { Literal::Value { value } => match value.val { ConstVal::Value(v) => Some((v, value.ty, c.span)), @@ -200,7 +88,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); - self.optimizations.constants.insert(c.clone(), val); Some(val) }, }, @@ -221,7 +108,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); - self.optimizations.constants.insert(c.clone(), val); Some(val) } } @@ -463,7 +349,6 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { .to_ty(self.tcx); let span = statement.source_info.span; if let Some(value) = self.const_prop(rval, place_ty, span) { - self.optimizations.const_prop.insert(location, value); if let Place::Local(local) = *place { if self.mir.local_kind(local) == LocalKind::Temp && CanConstProp::check(local, self.mir) { @@ -499,7 +384,6 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { _ => {}, } if let Some(value) = self.eval_operand(value) { - self.optimizations.terminators.insert(block, value); if let TerminatorKind::Assert { expected, msg, .. } = kind { if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 { let span = self.mir[block] @@ -562,9 +446,5 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { #[derive(Default)] struct OptimizationList<'tcx> { - const_prop: FxHashMap>, - /// Terminators that get their Operand(s) turned into constants. - terminators: FxHashMap>, places: FxHashMap>, - constants: FxHashMap, Const<'tcx>>, } From 1743bfccc5577743b627036b905829fb86d34119 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 11:24:51 +0100 Subject: [PATCH 075/115] Adjust tests to changed const err lints --- src/test/compile-fail/const-err-early.rs | 1 - src/test/compile-fail/const-err-multi.rs | 2 +- src/test/compile-fail/issue-8460-const.rs | 61 +++++++++++++------ .../compile-fail/lint-exceeding-bitshifts2.rs | 10 +-- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 2e19de0a27960..4a146d8de3cde 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -12,7 +12,6 @@ #![deny(const_err)] pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 -//~^ ERROR attempt to negate with overflow //~| ERROR const_err //~| ERROR const_err pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 5fa31e05322b3..eb24a698419eb 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -10,7 +10,7 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow +pub const A: i8 = -std::i8::MIN; //~^ ERROR E0080 //~| ERROR const_err //~| ERROR const_err diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index e2cf88d5774f7..024aca2e66d36 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -9,89 +9,110 @@ // except according to those terms. #![deny(const_err)] +//~^ NOTE lint level defined here use std::{isize, i8, i16, i32, i64}; use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow + //~^ NOTE attempt to divide with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow + //~^ NOTE attempt to divide with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow + //~^ NOTE attempt to divide with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow + //~^ NOTE attempt to divide with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow + //~^ NOTE attempt to divide with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ NOTE attempt to divide by zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ NOTE attempt to divide by zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ NOTE attempt to divide by zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ NOTE attempt to divide by zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ NOTE attempt to divide by zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow + //~^ NOTE attempt to calculate the remainder with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow + //~^ NOTE attempt to calculate the remainder with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow + //~^ NOTE attempt to calculate the remainder with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow + //~^ NOTE attempt to calculate the remainder with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow + //~^ NOTE attempt to calculate the remainder with overflow + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ NOTE attempt to calculate the remainder with a divisor of zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ NOTE attempt to calculate the remainder with a divisor of zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ NOTE attempt to calculate the remainder with a divisor of zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ NOTE attempt to calculate the remainder with a divisor of zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ NOTE attempt to calculate the remainder with a divisor of zero + //~| NOTE attempted to do overflowing math //~| ERROR constant evaluation error //~| ERROR constant evaluation error } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts2.rs b/src/test/compile-fail/lint-exceeding-bitshifts2.rs index d95e1b370aafd..0eab143fa49e0 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts2.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts2.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(exceeding_bitshifts)] -#![allow(unused_variables, const_err)] +#![deny(exceeding_bitshifts, const_err)] +#![allow(unused_variables)] #![allow(dead_code)] fn main() { let n = 1u8 << (4+3); - let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u8 << (4+4); //~ ERROR: const_err let n = 1i64 >> [63][0]; let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation @@ -22,6 +22,6 @@ fn main() { const BITS: usize = 32; #[cfg(target_pointer_width = "64")] const BITS: usize = 64; - let n = 1_isize << BITS; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1_usize << BITS; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1_isize << BITS; //~ ERROR: const_err + let n = 1_usize << BITS; //~ ERROR: const_err } From d6519783de61e2782d853ffa505876ea16df8e29 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 11:38:47 +0100 Subject: [PATCH 076/115] Remove single field struct by just using the field --- src/librustc_mir/transform/const_prop.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 3b52152946a97..3b37e755af388 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -52,7 +52,7 @@ struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, - optimizations: OptimizationList<'tcx>, + places: FxHashMap>, } impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { @@ -65,7 +65,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { mir, tcx, source, - optimizations: OptimizationList::default(), + places: FxHashMap::default(), } } @@ -117,7 +117,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { match *op { Operand::Constant(ref c) => self.eval_constant(c), Operand::Move(ref place) | Operand::Copy(ref place) => match *place { - Place::Local(loc) => self.optimizations.places.get(&loc).cloned(), + Place::Local(loc) => self.places.get(&loc).cloned(), // FIXME(oli-obk): field and index projections Place::Projection(_) => None, _ => None, @@ -353,7 +353,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { if self.mir.local_kind(local) == LocalKind::Temp && CanConstProp::check(local, self.mir) { trace!("storing {:?} to {:?}", value, local); - assert!(self.optimizations.places.insert(local, value).is_none()); + assert!(self.places.insert(local, value).is_none()); } } } @@ -443,8 +443,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { } } } - -#[derive(Default)] -struct OptimizationList<'tcx> { - places: FxHashMap>, -} From b0fb36f8824c7f6bad28879c1b89f1e47d5275ba Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 15:02:01 +0100 Subject: [PATCH 077/115] Remove redundant warnings in rustc_trans --- src/librustc_trans/mir/block.rs | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 9f69442bd5b7d..18b463a0c5120 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -351,26 +351,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { .max(tcx.data_layout.pointer_align); // Put together the arguments to the panic entry point. - let (lang_item, args, const_err) = match *msg { + let (lang_item, args) = match *msg { mir::AssertMessage::BoundsCheck { ref len, ref index } => { let len = self.trans_operand(&mut bx, len).immediate(); let index = self.trans_operand(&mut bx, index).immediate(); - let const_err = common::const_to_opt_u128(len, false) - .and_then(|len| common::const_to_opt_u128(index, false) - .map(|index| format!( - "index out of bounds: the len is {} but the index is {}", - len, index, - ))); - let file_line_col = C_struct(bx.cx, &[filename, line, col], false); let file_line_col = consts::addr_of(bx.cx, file_line_col, align, "panic_bounds_check_loc"); (lang_items::PanicBoundsCheckFnLangItem, - vec![file_line_col, index, len], - const_err) + vec![file_line_col, index, len]) } mir::AssertMessage::Math(ref err) => { let msg_str = Symbol::intern(err.description()).as_str(); @@ -383,8 +375,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { align, "panic_loc"); (lang_items::PanicFnLangItem, - vec![msg_file_line_col], - Some(err.description().to_owned())) + vec![msg_file_line_col]) } mir::AssertMessage::GeneratorResumedAfterReturn | mir::AssertMessage::GeneratorResumedAfterPanic => { @@ -403,24 +394,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { align, "panic_loc"); (lang_items::PanicFnLangItem, - vec![msg_file_line_col], - None) + vec![msg_file_line_col]) } }; - // If we know we always panic, and the error message - // is also constant, then we can produce a warning. - if const_cond == Some(!expected) { - if let Some(err) = const_err { - let mut diag = bx.tcx().sess.struct_span_warn( - span, &format!( - "this expression will panic at run-time with {:?}", - err, - )); - diag.emit(); - } - } - // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); From 2cc6a628d12a687c7a9b3f9cdc01ff6a8fbad495 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 15:10:26 +0100 Subject: [PATCH 078/115] Merge const linting pass into const prop --- src/librustc_driver/driver.rs | 7 - src/librustc_mir/check_const_err.rs | 197 ----------------------- src/librustc_mir/lib.rs | 1 - src/librustc_mir/transform/const_prop.rs | 24 ++- 4 files changed, 23 insertions(+), 206 deletions(-) delete mode 100644 src/librustc_mir/check_const_err.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c3821517b59bc..ef5b4ef60666e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1071,13 +1071,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, stability::check_unused_or_stable_features(tcx) }); - - time(time_passes, - "MIR linting", - || for def_id in tcx.body_owners() { - mir::check_const_err::check(tcx, def_id) - }); - time(time_passes, "lint checking", || lint::check_crate(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); diff --git a/src/librustc_mir/check_const_err.rs b/src/librustc_mir/check_const_err.rs deleted file mode 100644 index 9827dd58cd640..0000000000000 --- a/src/librustc_mir/check_const_err.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2017 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Lints statically known runtime failures - -use rustc::mir::*; -use rustc::hir; -use rustc::hir::map::Node; -use rustc::mir::visit::Visitor; -use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind}; -use rustc::hir::def::Def; -use rustc::traits; -use interpret::eval_body_with_mir; -use rustc::ty::{TyCtxt, ParamEnv}; -use rustc::ty::Instance; -use rustc::ty::layout::LayoutOf; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; - -fn is_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - if let Some(node) = tcx.hir.get_if_local(def_id) { - match node { - Node::NodeItem(&hir::Item { - node: hir::ItemConst(..), .. - }) => true, - _ => false - } - } else { - match tcx.describe_def(def_id) { - Some(Def::Const(_)) => true, - _ => false - } - } -} - -pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - let mir = &tcx.optimized_mir(def_id); - let substs = Substs::identity_for_item(tcx, def_id); - let instance = Instance::new(def_id, substs); - let param_env = tcx.param_env(def_id); - - if is_const(tcx, def_id) { - let cid = GlobalId { - instance, - promoted: None, - }; - eval_body_with_mir(tcx, cid, mir, param_env); - } - - ConstErrVisitor { - tcx, - mir, - }.visit_mir(mir); - let outer_def_id = if tcx.is_closure(def_id) { - tcx.closure_base_def_id(def_id) - } else { - def_id - }; - let generics = tcx.generics_of(outer_def_id); - // FIXME: miri should be able to eval stuff that doesn't need info - // from the generics - if generics.parent_types as usize + generics.types.len() > 0 { - return; - } - for i in 0.. mir.promoted.len() { - use rustc_data_structures::indexed_vec::Idx; - let cid = GlobalId { - instance, - promoted: Some(Promoted::new(i)), - }; - eval_body_with_mir(tcx, cid, mir, param_env); - } -} - -struct ConstErrVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, -} - -impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> { - fn eval_op(&self, op: &Operand<'tcx>) -> Option { - let op = match *op { - Operand::Constant(ref c) => c, - _ => return None, - }; - match op.literal { - Literal::Value { value } => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => Some(b), - _ => return None, - }, - _ => None, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ConstErrVisitor<'a, 'tcx> { - fn visit_terminator(&mut self, - block: BasicBlock, - terminator: &Terminator<'tcx>, - location: Location) { - self.super_terminator(block, terminator, location); - match terminator.kind { - TerminatorKind::Assert { ref cond, expected, ref msg, .. } => { - let cond = match self.eval_op(cond) { - Some(val) => val, - None => return, - }; - if (cond == 1) == expected { - return; - } - assert!(cond <= 1); - // If we know we always panic, and the error message - // is also constant, then we can produce a warning. - - let kind = match *msg { - AssertMessage::BoundsCheck { ref len, ref index } => { - let len = match self.eval_op(len) { - Some(val) => val, - None => return, - }; - let index = match self.eval_op(index) { - Some(val) => val, - None => return, - }; - ErrKind::IndexOutOfBounds { - len: len as u64, - index: index as u64 - } - } - AssertMessage::Math(ref err) => ErrKind::Math(err.clone()), - AssertMessage::GeneratorResumedAfterReturn | - // FIXME(oli-obk): can we report a const_err warning here? - AssertMessage::GeneratorResumedAfterPanic => return, - }; - let span = terminator.source_info.span; - let msg = ConstEvalErr{ span, kind }; - let scope_info = match self.mir.visibility_scope_info { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return, - }; - let node_id = scope_info[terminator.source_info.scope].lint_root; - self.tcx.lint_node(::rustc::lint::builtin::CONST_ERR, - node_id, - msg.span, - &msg.description().into_oneline().into_owned()); - }, - _ => {}, - } - } - fn visit_rvalue(&mut self, - rvalue: &Rvalue<'tcx>, - location: Location) { - self.super_rvalue(rvalue, location); - use rustc::mir::BinOp; - match *rvalue { - Rvalue::BinaryOp(BinOp::Shr, ref lop, ref rop) | - Rvalue::BinaryOp(BinOp::Shl, ref lop, ref rop) => { - let val = match self.eval_op(rop) { - Some(val) => val, - None => return, - }; - let ty = lop.ty(self.mir, self.tcx); - let param_env = ParamEnv::empty(traits::Reveal::All); - let bits = (self.tcx, param_env).layout_of(ty).unwrap().size.bits(); - if val >= bits as u128 { - let data = &self.mir[location.block]; - let stmt_idx = location.statement_index; - let source_info = if stmt_idx < data.statements.len() { - data.statements[stmt_idx].source_info - } else { - data.terminator().source_info - }; - let span = source_info.span; - let scope_info = match self.mir.visibility_scope_info { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return, - }; - let node_id = scope_info[source_info.scope].lint_root; - self.tcx.lint_node( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - node_id, - span, - "bitshift exceeds the type's number of bits"); - } - } - _ => {} - } - } -} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 67425c9643dd4..910085496261c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -71,7 +71,6 @@ pub mod transform; pub mod util; pub mod interpret; pub mod monomorphize; -pub mod check_const_err; pub use hair::pattern::check_crate as matchck_crate; use rustc::ty::maps::Providers; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 3b37e755af388..35fce184bebe8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -212,8 +212,30 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let instance = Instance::new(self.source.def_id, substs); let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + let param_env = ParamEnv::empty(traits::Reveal::All); + let bits = (self.tcx, param_env).layout_of(left.ty).unwrap().size.bits(); + if r >= bits as u128 { + let data = &self.mir[location.block]; + let stmt_idx = location.statement_index; + let source_info = if stmt_idx < data.statements.len() { + data.statements[stmt_idx].source_info + } else { + data.terminator().source_info + }; + let span = source_info.span; + let scope_info = match self.mir.visibility_scope_info { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return, + }; + let node_id = scope_info[source_info.scope].lint_root; + self.tcx.lint_node( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + node_id, + span, + "bitshift exceeds the type's number of bits"); + } + let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); match ecx.binary_op(op, l, left.1, r, right.1) { Ok((val, overflow)) => { From e621f00dc20711dce69142bd683bc98177bbc026 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 15:12:45 +0100 Subject: [PATCH 079/115] Use IndexVec instead of FxHashMap --- src/librustc_mir/transform/const_prop.rs | 43 +++++++++++------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 35fce184bebe8..e1a1c47373015 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -15,16 +15,17 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::TerminatorKind; +use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo}; use rustc::mir::visit::Visitor; +use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; -use rustc::util::nodemap::FxHashMap; use transform::{MirPass, MirSource}; use syntax::codemap::Span; use rustc::ty::subst::Substs; +use rustc_data_structures::indexed_vec::IndexVec; pub struct ConstProp; @@ -35,9 +36,10 @@ impl MirPass for ConstProp { mir: &mut Mir<'tcx>) { trace!("ConstProp starting for {:?}", source.def_id); - // First, find optimization opportunities. This is done in a pre-pass to keep the MIR - // read-only so that we can do global analyses on the MIR in the process (e.g. - // `Place::ty()`). + // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold + // constants, instead of just checking for const-folding succeeding. + // That would require an uniform one-def no-mutation analysis + // and RPO (or recursing when needing the value of a local). let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); optimization_finder.visit_mir(mir); @@ -52,7 +54,7 @@ struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, - places: FxHashMap>, + places: IndexVec>>, } impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { @@ -65,7 +67,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { mir, tcx, source, - places: FxHashMap::default(), + places: IndexVec::from_elem(None, &mir.local_decls), } } @@ -117,7 +119,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { match *op { Operand::Constant(ref c) => self.eval_constant(c), Operand::Move(ref place) | Operand::Copy(ref place) => match *place { - Place::Local(loc) => self.places.get(&loc).cloned(), + Place::Local(loc) => self.places[loc].clone(), // FIXME(oli-obk): field and index projections Place::Projection(_) => None, _ => None, @@ -129,8 +131,9 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { &mut self, rvalue: &Rvalue<'tcx>, place_ty: ty::Ty<'tcx>, - span: Span, + source_info: SourceInfo, ) -> Option> { + let span = source_info.span; match *rvalue { // No need to overwrite an already evaluated constant Rvalue::Use(Operand::Constant(box Constant { @@ -213,20 +216,12 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; - let param_env = ParamEnv::empty(traits::Reveal::All); - let bits = (self.tcx, param_env).layout_of(left.ty).unwrap().size.bits(); - if r >= bits as u128 { - let data = &self.mir[location.block]; - let stmt_idx = location.statement_index; - let source_info = if stmt_idx < data.statements.len() { - data.statements[stmt_idx].source_info - } else { - data.terminator().source_info - }; - let span = source_info.span; + let param_env = self.tcx.param_env(self.source.def_id); + let bits = (self.tcx, param_env).layout_of(left.1).unwrap().size.bits(); + if r.to_bytes().ok()? >= bits as u128 { let scope_info = match self.mir.visibility_scope_info { ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return, + ClearCrossCrate::Clear => return None, }; let node_id = scope_info[source_info.scope].lint_root; self.tcx.lint_node( @@ -369,13 +364,13 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { let place_ty = place .ty(&self.mir.local_decls, self.tcx) .to_ty(self.tcx); - let span = statement.source_info.span; - if let Some(value) = self.const_prop(rval, place_ty, span) { + if let Some(value) = self.const_prop(rval, place_ty, statement.source_info) { if let Place::Local(local) = *place { if self.mir.local_kind(local) == LocalKind::Temp && CanConstProp::check(local, self.mir) { trace!("storing {:?} to {:?}", value, local); - assert!(self.places.insert(local, value).is_none()); + assert!(self.places[local].is_none()); + self.places[local] = Some(value); } } } From 9e71b4eb0675ef9322432cf0a5e935e1b8f26dea Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 18:54:37 +0100 Subject: [PATCH 080/115] rustc_passes::consts -> rvalue_promotion --- src/librustc_driver/driver.rs | 6 +++--- src/librustc_passes/lib.rs | 4 ++-- src/librustc_passes/{consts.rs => rvalue_promotion.rs} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename src/librustc_passes/{consts.rs => rvalue_promotion.rs} (100%) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ef5b4ef60666e..6a998c88386b6 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -36,7 +36,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats}; +use rustc_passes::{self, ast_validation, loops, rvalue_promotion, static_recursion, hir_stats}; use super::Compilation; use serialize::json; @@ -1020,8 +1020,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, } time(time_passes, - "const checking", - || consts::check_crate(tcx)); + "rvalue promotion", + || rvalue_promotion::check_crate(tcx)); analysis.access_levels = time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 2bb4cfcbe5231..f0d7736cfa33d 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -38,7 +38,7 @@ use rustc::ty::maps::Providers; mod diagnostics; pub mod ast_validation; -pub mod consts; +pub mod rvalue_promotion; pub mod hir_stats; pub mod loops; mod mir_stats; @@ -48,5 +48,5 @@ pub mod static_recursion; __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } pub fn provide(providers: &mut Providers) { - consts::provide(providers); + rvalue_promotion::provide(providers); } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/rvalue_promotion.rs similarity index 100% rename from src/librustc_passes/consts.rs rename to src/librustc_passes/rvalue_promotion.rs From 77f84ea832ceae72a3a6854f57b364fc4b87de19 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 19:06:44 +0100 Subject: [PATCH 081/115] Only report bitshift lints on bitshift ops --- src/librustc_mir/transform/const_prop.rs | 30 +++++++++++++----------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e1a1c47373015..e0d8744f7c400 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -15,7 +15,7 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo}; +use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp}; use rustc::mir::visit::Visitor; use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; @@ -216,19 +216,21 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; - let param_env = self.tcx.param_env(self.source.def_id); - let bits = (self.tcx, param_env).layout_of(left.1).unwrap().size.bits(); - if r.to_bytes().ok()? >= bits as u128 { - let scope_info = match self.mir.visibility_scope_info { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return None, - }; - let node_id = scope_info[source_info.scope].lint_root; - self.tcx.lint_node( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - node_id, - span, - "bitshift exceeds the type's number of bits"); + if op == BinOp::Shr || op == BinOp::Shl { + let param_env = self.tcx.param_env(self.source.def_id); + let bits = (self.tcx, param_env).layout_of(left.1).unwrap().size.bits(); + if r.to_bytes().ok()? >= bits as u128 { + let scope_info = match self.mir.visibility_scope_info { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return None, + }; + let node_id = scope_info[source_info.scope].lint_root; + self.tcx.lint_node( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + node_id, + span, + "bitshift exceeds the type's number of bits"); + } } let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); From 9a2aa4aa91d5d4a19eb9108535f06d4531b9e0f3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 19:53:46 +0100 Subject: [PATCH 082/115] Report const eval errors at the correct span --- src/librustc_mir/hair/pattern/mod.rs | 21 +- src/librustc_mir/hair/pattern/pattern.rs | 1187 ----------------- src/librustc_mir/interpret/const_eval.rs | 6 +- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_trans/mir/constant.rs | 1 + .../conditional_array_execution.stderr | 22 +- .../ui/const-eval/index_out_of_bound.stderr | 6 - src/test/ui/const-eval/issue-43197.stderr | 24 - .../const-len-underflow-separate-spans.stderr | 6 - .../ui/infinite-recursion-const-fn.stderr | 10 +- 10 files changed, 37 insertions(+), 1250 deletions(-) delete mode 100644 src/librustc_mir/hair/pattern/pattern.rs diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 1141425c554a9..4723cf0f2a0f8 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -672,6 +672,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); let def = self.tables.qpath_def(qpath, id); + let is_associated_const = match def { + Def::AssociatedConst(_) => true, + _ => false, + }; let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); @@ -697,7 +701,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } }, None => { - self.errors.push(PatternError::StaticInPattern(span)); + self.errors.push(if is_associated_const { + PatternError::AssociatedConstInPattern(span) + } else { + PatternError::StaticInPattern(span) + }); PatternKind::Wild }, } @@ -814,7 +822,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, + self.tcx, self.param_env, instance, span, Some(variant_index), field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), @@ -842,7 +850,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, + self.tcx, self.param_env, instance, span, + None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -859,7 +868,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, + self.tcx, self.param_env, instance, span, + None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; @@ -877,7 +887,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, + self.tcx, self.param_env, instance, span, + None, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid tuple", cv), }; diff --git a/src/librustc_mir/hair/pattern/pattern.rs b/src/librustc_mir/hair/pattern/pattern.rs deleted file mode 100644 index 0cbbf129b9b1e..0000000000000 --- a/src/librustc_mir/hair/pattern/pattern.rs +++ /dev/null @@ -1,1187 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use interpret::{const_val_field, const_discr}; - -use rustc::middle::const_val::ConstVal; -use rustc::mir::{Field, BorrowKind, Mutability}; -use rustc::mir::interpret::{GlobalId, Value, PrimVal}; -use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; -use rustc::ty::subst::{Substs, Kind}; -use rustc::hir::{self, PatKind, RangeEnd}; -use rustc::hir::def::{Def, CtorKind}; -use rustc::hir::pat_util::EnumerateAndAdjustIterator; - -use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstFloat; - -use std::cmp::Ordering; -use std::fmt; -use syntax::ast; -use syntax::ptr::P; -use syntax_pos::Span; - -#[derive(Clone, Debug)] -pub enum PatternError { - AssociatedConstInPattern(Span), - StaticInPattern(Span), - FloatBug, - NonConstPath(Span), -} - -#[derive(Copy, Clone, Debug)] -pub enum BindingMode<'tcx> { - ByValue, - ByRef(Region<'tcx>, BorrowKind), -} - -#[derive(Clone, Debug)] -pub struct FieldPattern<'tcx> { - pub field: Field, - pub pattern: Pattern<'tcx>, -} - -#[derive(Clone, Debug)] -pub struct Pattern<'tcx> { - pub ty: Ty<'tcx>, - pub span: Span, - pub kind: Box>, -} - -#[derive(Clone, Debug)] -pub enum PatternKind<'tcx> { - Wild, - - /// x, ref x, x @ P, etc - Binding { - mutability: Mutability, - name: ast::Name, - mode: BindingMode<'tcx>, - var: ast::NodeId, - ty: Ty<'tcx>, - subpattern: Option>, - }, - - /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants - Variant { - adt_def: &'tcx AdtDef, - substs: &'tcx Substs<'tcx>, - variant_index: usize, - subpatterns: Vec>, - }, - - /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant - Leaf { - subpatterns: Vec>, - }, - - /// box P, &P, &mut P, etc - Deref { - subpattern: Pattern<'tcx>, - }, - - Constant { - value: &'tcx ty::Const<'tcx>, - }, - - Range { - lo: &'tcx ty::Const<'tcx>, - hi: &'tcx ty::Const<'tcx>, - end: RangeEnd, - }, - - /// matches against a slice, checking the length and extracting elements. - /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. - /// e.g. `&[ref xs..]`. - Slice { - prefix: Vec>, - slice: Option>, - suffix: Vec>, - }, - - /// fixed match against an array, irrefutable - Array { - prefix: Vec>, - slice: Option>, - suffix: Vec>, - }, -} - -fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { - match value.val { - ConstVal::Value(v) => print_miri_value(v, value.ty, f), - ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) - } -} - -fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { - use rustc::ty::TypeVariants::*; - match (value, &ty.sty) { - (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), - (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), - (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), - (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), - (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => - write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), - _ => bug!("{:?}: {} not printable in a pattern", value, ty), - } -} - -impl<'tcx> fmt::Display for Pattern<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self.kind { - PatternKind::Wild => write!(f, "_"), - PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => { - let is_mut = match mode { - BindingMode::ByValue => mutability == Mutability::Mut, - BindingMode::ByRef(_, bk) => { - write!(f, "ref ")?; - bk == BorrowKind::Mut - } - }; - if is_mut { - write!(f, "mut ")?; - } - write!(f, "{}", name)?; - if let Some(ref subpattern) = *subpattern { - write!(f, " @ {}", subpattern)?; - } - Ok(()) - } - PatternKind::Variant { ref subpatterns, .. } | - PatternKind::Leaf { ref subpatterns } => { - let variant = match *self.kind { - PatternKind::Variant { adt_def, variant_index, .. } => { - Some(&adt_def.variants[variant_index]) - } - _ => if let ty::TyAdt(adt, _) = self.ty.sty { - if !adt.is_enum() { - Some(&adt.variants[0]) - } else { - None - } - } else { - None - } - }; - - let mut first = true; - let mut start_or_continue = || if first { first = false; "" } else { ", " }; - - if let Some(variant) = variant { - write!(f, "{}", variant.name)?; - - // Only for TyAdt we can have `S {...}`, - // which we handle separately here. - if variant.ctor_kind == CtorKind::Fictive { - write!(f, " {{ ")?; - - let mut printed = 0; - for p in subpatterns { - if let PatternKind::Wild = *p.pattern.kind { - continue; - } - let name = variant.fields[p.field.index()].name; - write!(f, "{}{}: {}", start_or_continue(), name, p.pattern)?; - printed += 1; - } - - if printed < variant.fields.len() { - write!(f, "{}..", start_or_continue())?; - } - - return write!(f, " }}"); - } - } - - let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); - if num_fields != 0 || variant.is_none() { - write!(f, "(")?; - for i in 0..num_fields { - write!(f, "{}", start_or_continue())?; - - // Common case: the field is where we expect it. - if let Some(p) = subpatterns.get(i) { - if p.field.index() == i { - write!(f, "{}", p.pattern)?; - continue; - } - } - - // Otherwise, we have to go looking for it. - if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; - } else { - write!(f, "_")?; - } - } - write!(f, ")")?; - } - - Ok(()) - } - PatternKind::Deref { ref subpattern } => { - match self.ty.sty { - ty::TyAdt(def, _) if def.is_box() => write!(f, "box ")?, - ty::TyRef(_, mt) => { - write!(f, "&")?; - if mt.mutbl == hir::MutMutable { - write!(f, "mut ")?; - } - } - _ => bug!("{} is a bad Deref pattern type", self.ty) - } - write!(f, "{}", subpattern) - } - PatternKind::Constant { value } => { - print_const_val(value, f) - } - PatternKind::Range { lo, hi, end } => { - print_const_val(lo, f)?; - match end { - RangeEnd::Included => write!(f, "...")?, - RangeEnd::Excluded => write!(f, "..")?, - } - print_const_val(hi, f) - } - PatternKind::Slice { ref prefix, ref slice, ref suffix } | - PatternKind::Array { ref prefix, ref slice, ref suffix } => { - let mut first = true; - let mut start_or_continue = || if first { first = false; "" } else { ", " }; - write!(f, "[")?; - for p in prefix { - write!(f, "{}{}", start_or_continue(), p)?; - } - if let Some(ref slice) = *slice { - write!(f, "{}", start_or_continue())?; - match *slice.kind { - PatternKind::Wild => {} - _ => write!(f, "{}", slice)? - } - write!(f, "..")?; - } - for p in suffix { - write!(f, "{}{}", start_or_continue(), p)?; - } - write!(f, "]") - } - } - } -} - -pub struct PatternContext<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub param_env: ty::ParamEnv<'tcx>, - pub tables: &'a ty::TypeckTables<'tcx>, - pub substs: &'tcx Substs<'tcx>, - pub errors: Vec, -} - -impl<'a, 'tcx> Pattern<'tcx> { - pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, - tables: &'a ty::TypeckTables<'tcx>, - pat: &'tcx hir::Pat) -> Self { - let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); - let result = pcx.lower_pattern(pat); - if !pcx.errors.is_empty() { - let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); - tcx.sess.delay_span_bug(pat.span, &msg); - } - debug!("Pattern::from_hir({:?}) = {:?}", pat, result); - result - } -} - -impl<'a, 'tcx> PatternContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, - tables: &'a ty::TypeckTables<'tcx>) -> Self { - PatternContext { - tcx, - param_env: param_env_and_substs.param_env, - tables, - substs: param_env_and_substs.value, - errors: vec![] - } - } - - pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { - // When implicit dereferences have been inserted in this pattern, the unadjusted lowered - // pattern has the type that results *after* dereferencing. For example, in this code: - // - // ``` - // match &&Some(0i32) { - // Some(n) => { ... }, - // _ => { ... }, - // } - // ``` - // - // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option` (this is - // determined in rustc_typeck::check::match). The adjustments would be - // - // `vec![&&Option, &Option]`. - // - // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So - // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the - // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted - // gets the least-dereferenced type). - let unadjusted_pat = self.lower_pattern_unadjusted(pat); - self.tables - .pat_adjustments() - .get(pat.hir_id) - .unwrap_or(&vec![]) - .iter() - .rev() - .fold(unadjusted_pat, |pat, ref_ty| { - debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); - Pattern { - span: pat.span, - ty: ref_ty, - kind: Box::new(PatternKind::Deref { subpattern: pat }), - } - }, - ) - } - - fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { - let mut ty = self.tables.node_id_to_type(pat.hir_id); - - let kind = match pat.node { - PatKind::Wild => PatternKind::Wild, - - PatKind::Lit(ref value) => self.lower_lit(value), - - PatKind::Range(ref lo_expr, ref hi_expr, end) => { - match (self.lower_lit(lo_expr), self.lower_lit(hi_expr)) { - (PatternKind::Constant { value: lo }, - PatternKind::Constant { value: hi }) => { - use std::cmp::Ordering; - match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { - (RangeEnd::Excluded, Ordering::Less) => {}, - (RangeEnd::Excluded, _) => span_err!( - self.tcx.sess, - lo_expr.span, - E0579, - "lower range bound must be less than upper", - ), - (RangeEnd::Included, Ordering::Greater) => { - struct_span_err!(self.tcx.sess, lo_expr.span, E0030, - "lower range bound must be less than or equal to upper") - .span_label(lo_expr.span, "lower bound larger than upper bound") - .emit(); - }, - (RangeEnd::Included, _) => {} - } - PatternKind::Range { lo, hi, end } - } - _ => PatternKind::Wild - } - } - - PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.hir_id, pat.span); - } - - PatKind::Ref(ref subpattern, _) | - PatKind::Box(ref subpattern) => { - PatternKind::Deref { subpattern: self.lower_pattern(subpattern) } - } - - PatKind::Slice(ref prefix, ref slice, ref suffix) => { - let ty = self.tables.node_id_to_type(pat.hir_id); - match ty.sty { - ty::TyRef(_, mt) => - PatternKind::Deref { - subpattern: Pattern { - ty: mt.ty, - span: pat.span, - kind: Box::new(self.slice_or_array_pattern( - pat.span, mt.ty, prefix, slice, suffix)) - }, - }, - - ty::TySlice(..) | - ty::TyArray(..) => - self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), - - ref sty => - span_bug!( - pat.span, - "unexpanded type for vector pattern: {:?}", - sty), - } - } - - PatKind::Tuple(ref subpatterns, ddpos) => { - let ty = self.tables.node_id_to_type(pat.hir_id); - match ty.sty { - ty::TyTuple(ref tys, _) => { - let subpatterns = - subpatterns.iter() - .enumerate_and_adjust(tys.len(), ddpos) - .map(|(i, subpattern)| FieldPattern { - field: Field::new(i), - pattern: self.lower_pattern(subpattern) - }) - .collect(); - - PatternKind::Leaf { subpatterns: subpatterns } - } - - ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), - } - } - - PatKind::Binding(_, id, ref ident, ref sub) => { - let var_ty = self.tables.node_id_to_type(pat.hir_id); - let region = match var_ty.sty { - ty::TyRef(r, _) => Some(r), - _ => None, - }; - let bm = *self.tables.pat_binding_modes().get(pat.hir_id) - .expect("missing binding mode"); - let (mutability, mode) = match bm { - ty::BindByValue(hir::MutMutable) => - (Mutability::Mut, BindingMode::ByValue), - ty::BindByValue(hir::MutImmutable) => - (Mutability::Not, BindingMode::ByValue), - ty::BindByReference(hir::MutMutable) => - (Mutability::Not, BindingMode::ByRef( - region.unwrap(), BorrowKind::Mut)), - ty::BindByReference(hir::MutImmutable) => - (Mutability::Not, BindingMode::ByRef( - region.unwrap(), BorrowKind::Shared)), - }; - - // A ref x pattern is the same node used for x, and as such it has - // x's type, which is &T, where we want T (the type being matched). - if let ty::BindByReference(_) = bm { - if let ty::TyRef(_, mt) = ty.sty { - ty = mt.ty; - } else { - bug!("`ref {}` has wrong type {}", ident.node, ty); - } - } - - PatternKind::Binding { - mutability, - mode, - name: ident.node, - var: id, - ty: var_ty, - subpattern: self.lower_opt_pattern(sub), - } - } - - PatKind::TupleStruct(ref qpath, ref subpatterns, ddpos) => { - let def = self.tables.qpath_def(qpath, pat.hir_id); - let adt_def = match ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - subpatterns.iter() - .enumerate_and_adjust(variant_def.fields.len(), ddpos) - .map(|(i, field)| FieldPattern { - field: Field::new(i), - pattern: self.lower_pattern(field), - }) - .collect(); - self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) - } - - PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pat.hir_id); - let adt_def = match ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - pat.span, - "struct pattern not applied to an ADT"); - } - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.node.name); - let index = index.unwrap_or_else(|| { - span_bug!( - pat.span, - "no field with name {:?}", - field.node.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.lower_pattern(&field.node.pat), - } - }) - .collect(); - - self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) - } - }; - - Pattern { - span: pat.span, - ty, - kind: Box::new(kind), - } - } - - fn lower_patterns(&mut self, pats: &'tcx [P]) -> Vec> { - pats.iter().map(|p| self.lower_pattern(p)).collect() - } - - fn lower_opt_pattern(&mut self, pat: &'tcx Option>) -> Option> - { - pat.as_ref().map(|p| self.lower_pattern(p)) - } - - fn flatten_nested_slice_patterns( - &mut self, - prefix: Vec>, - slice: Option>, - suffix: Vec>) - -> (Vec>, Option>, Vec>) - { - let orig_slice = match slice { - Some(orig_slice) => orig_slice, - None => return (prefix, slice, suffix) - }; - let orig_prefix = prefix; - let orig_suffix = suffix; - - // dance because of intentional borrow-checker stupidity. - let kind = *orig_slice.kind; - match kind { - PatternKind::Slice { prefix, slice, mut suffix } | - PatternKind::Array { prefix, slice, mut suffix } => { - let mut orig_prefix = orig_prefix; - - orig_prefix.extend(prefix); - suffix.extend(orig_suffix); - - (orig_prefix, slice, suffix) - } - _ => { - (orig_prefix, Some(Pattern { - kind: box kind, ..orig_slice - }), orig_suffix) - } - } - } - - fn slice_or_array_pattern( - &mut self, - span: Span, - ty: Ty<'tcx>, - prefix: &'tcx [P], - slice: &'tcx Option>, - suffix: &'tcx [P]) - -> PatternKind<'tcx> - { - let prefix = self.lower_patterns(prefix); - let slice = self.lower_opt_pattern(slice); - let suffix = self.lower_patterns(suffix); - let (prefix, slice, suffix) = - self.flatten_nested_slice_patterns(prefix, slice, suffix); - - match ty.sty { - ty::TySlice(..) => { - // matching a slice or fixed-length array - PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix } - } - - ty::TyArray(_, len) => { - // fixed-length array - let len = len.val.unwrap_u64(); - assert!(len >= prefix.len() as u64 + suffix.len() as u64); - PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } - } - - _ => { - span_bug!(span, "bad slice pattern type {:?}", ty); - } - } - } - - fn lower_variant_or_leaf( - &mut self, - def: Def, - span: Span, - ty: Ty<'tcx>, - subpatterns: Vec>) - -> PatternKind<'tcx> - { - match def { - Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { - let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); - let adt_def = self.tcx.adt_def(enum_id); - if adt_def.is_enum() { - let substs = match ty.sty { - ty::TyAdt(_, substs) | - ty::TyFnDef(_, substs) => substs, - _ => bug!("inappropriate type for def: {:?}", ty.sty), - }; - PatternKind::Variant { - adt_def, - substs, - variant_index: adt_def.variant_index_with_id(variant_id), - subpatterns, - } - } else { - PatternKind::Leaf { subpatterns: subpatterns } - } - } - - Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { - PatternKind::Leaf { subpatterns: subpatterns } - } - - _ => { - self.errors.push(PatternError::NonConstPath(span)); - PatternKind::Wild - } - } - } - - fn lower_path(&mut self, - qpath: &hir::QPath, - id: hir::HirId, - span: Span) - -> Pattern<'tcx> { - let ty = self.tables.node_id_to_type(id); - let def = self.tables.qpath_def(qpath, id); - let is_associated_const = match def { - Def::AssociatedConst(_) => true, - _ => false, - }; - let kind = match def { - Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let substs = self.tables.node_substs(id); - match ty::Instance::resolve( - self.tcx, - self.param_env, - def_id, - substs, - ) { - Some(instance) => { - let cid = GlobalId { - instance, - promoted: None, - }; - match self.tcx.at(span).const_eval(self.param_env.and(cid)) { - Ok(value) => { - return self.const_to_pat(instance, value, id, span) - }, - Err(err) => { - err.report(self.tcx, span, "pattern"); - PatternKind::Wild - }, - } - }, - None => { - self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) - } else { - PatternError::StaticInPattern(span) - }); - PatternKind::Wild - }, - } - } - _ => self.lower_variant_or_leaf(def, span, ty, vec![]), - }; - - Pattern { - span, - ty, - kind: Box::new(kind), - } - } - - fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { - match expr.node { - hir::ExprLit(ref lit) => { - let ty = self.tables.expr_ty(expr); - match lit_to_const(&lit.node, self.tcx, ty, false) { - Ok(val) => { - let instance = ty::Instance::new( - self.tables.local_id_root.expect("literal outside any scope"), - self.substs, - ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind - }, - Err(()) => { - self.errors.push(PatternError::FloatBug); - PatternKind::Wild - }, - } - }, - hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, - hir::ExprUnary(hir::UnNeg, ref expr) => { - let ty = self.tables.expr_ty(expr); - let lit = match expr.node { - hir::ExprLit(ref lit) => lit, - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - }; - match lit_to_const(&lit.node, self.tcx, ty, true) { - Ok(val) => { - let instance = ty::Instance::new( - self.tables.local_id_root.expect("literal outside any scope"), - self.substs, - ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind - }, - Err(()) => { - self.errors.push(PatternError::FloatBug); - PatternKind::Wild - }, - } - } - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - } - } - - fn const_to_pat( - &self, - instance: ty::Instance<'tcx>, - cv: &'tcx ty::Const<'tcx>, - id: hir::HirId, - span: Span, - ) -> Pattern<'tcx> { - debug!("const_to_pat: cv={:#?}", cv); - let kind = match cv.ty.sty { - ty::TyFloat(_) => { - let id = self.tcx.hir.hir_to_node_id(id); - self.tcx.lint_node( - ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - "floating-point types cannot be used in patterns", - ); - PatternKind::Constant { - value: cv, - } - }, - ty::TyAdt(adt_def, _) if adt_def.is_union() => { - // Matching on union fields is unsafe, we can't hide it in constants - self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); - PatternKind::Wild - } - ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); - self.tcx.sess.span_err(span, &msg); - PatternKind::Wild - }, - ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { - match cv.val { - ConstVal::Value(val) => { - let discr = const_discr( - self.tcx, self.param_env, instance, val, cv.ty - ).unwrap(); - let variant_index = adt_def - .discriminants(self.tcx) - .position(|var| var.val == discr) - .unwrap(); - PatternKind::Variant { - adt_def, - substs, - variant_index, - subpatterns: adt_def - .variants[variant_index] - .fields - .iter() - .enumerate() - .map(|(i, _)| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, - Some(variant_index), field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), - } - }).collect(), - } - }, - _ => return Pattern { - span, - ty: cv.ty, - kind: Box::new(PatternKind::Constant { - value: cv, - }), - } - } - }, - ty::TyAdt(adt_def, _) => { - let struct_var = adt_def.non_enum_variant(); - PatternKind::Leaf { - subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), - } - }).collect() - } - } - ty::TyTuple(fields, _) => { - PatternKind::Leaf { - subpatterns: (0..fields.len()).map(|i| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), - } - }).collect() - } - } - ty::TyArray(_, n) => { - PatternKind::Array { - prefix: (0..n.val.unwrap_u64()).map(|i| { - let i = i as usize; - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - self.const_to_pat(instance, val, id, span) - }).collect(), - slice: None, - suffix: Vec::new(), - } - } - _ => { - PatternKind::Constant { - value: cv, - } - }, - }; - - Pattern { - span, - ty: cv.ty, - kind: Box::new(kind), - } - } -} - -pub trait PatternFoldable<'tcx> : Sized { - fn fold_with>(&self, folder: &mut F) -> Self { - self.super_fold_with(folder) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self; -} - -pub trait PatternFolder<'tcx> : Sized { - fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> { - pattern.super_fold_with(self) - } - - fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> { - kind.super_fold_with(self) - } -} - - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - box content - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { - fn super_fold_with>(&self, folder: &mut F) -> Self{ - self.as_ref().map(|t| t.fold_with(folder)) - } -} - -macro_rules! CloneImpls { - (<$lt_tcx:tt> $($ty:ty),+) => { - $( - impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { - fn super_fold_with>(&self, _: &mut F) -> Self { - Clone::clone(self) - } - } - )+ - } -} - -CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, - Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, - &'tcx Substs<'tcx>, &'tcx Kind<'tcx> -} - -impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - FieldPattern { - field: self.field.fold_with(folder), - pattern: self.pattern.fold_with(folder) - } - } -} - -impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> { - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_pattern(self) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self { - Pattern { - ty: self.ty.fold_with(folder), - span: self.span.fold_with(folder), - kind: self.kind.fold_with(folder) - } - } -} - -impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_pattern_kind(self) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - PatternKind::Wild => PatternKind::Wild, - PatternKind::Binding { - mutability, - name, - mode, - var, - ty, - ref subpattern, - } => PatternKind::Binding { - mutability: mutability.fold_with(folder), - name: name.fold_with(folder), - mode: mode.fold_with(folder), - var: var.fold_with(folder), - ty: ty.fold_with(folder), - subpattern: subpattern.fold_with(folder), - }, - PatternKind::Variant { - adt_def, - substs, - variant_index, - ref subpatterns, - } => PatternKind::Variant { - adt_def: adt_def.fold_with(folder), - substs: substs.fold_with(folder), - variant_index: variant_index.fold_with(folder), - subpatterns: subpatterns.fold_with(folder) - }, - PatternKind::Leaf { - ref subpatterns, - } => PatternKind::Leaf { - subpatterns: subpatterns.fold_with(folder), - }, - PatternKind::Deref { - ref subpattern, - } => PatternKind::Deref { - subpattern: subpattern.fold_with(folder), - }, - PatternKind::Constant { - value - } => PatternKind::Constant { - value: value.fold_with(folder) - }, - PatternKind::Range { - lo, - hi, - end, - } => PatternKind::Range { - lo: lo.fold_with(folder), - hi: hi.fold_with(folder), - end, - }, - PatternKind::Slice { - ref prefix, - ref slice, - ref suffix, - } => PatternKind::Slice { - prefix: prefix.fold_with(folder), - slice: slice.fold_with(folder), - suffix: suffix.fold_with(folder) - }, - PatternKind::Array { - ref prefix, - ref slice, - ref suffix - } => PatternKind::Array { - prefix: prefix.fold_with(folder), - slice: slice.fold_with(folder), - suffix: suffix.fold_with(folder) - }, - } - } -} - -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { - use rustc_const_math::ConstFloat; - trace!("compare_const_vals: {:?}, {:?}", a, b); - use rustc::mir::interpret::{Value, PrimVal}; - match (a, b) { - (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), - &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { - match ty.sty { - ty::TyFloat(ty) => { - let l = ConstFloat { - bits: a, - ty, - }; - let r = ConstFloat { - bits: b, - ty, - }; - // FIXME(oli-obk): report cmp errors? - l.try_cmp(r).ok() - }, - ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), - _ => Some(a.cmp(&b)), - } - }, - _ if a == b => Some(Ordering::Equal), - _ => None, - } -} - -fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - neg: bool) - -> Result, ()> { - use syntax::ast::*; - - use rustc::mir::interpret::*; - let lit = match *lit { - LitKind::Str(ref s, _) => { - let s = s.as_str(); - let id = tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - ) - }, - LitKind::ByteStr(ref data) => { - let id = tcx.allocate_cached(data); - let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) - }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), - LitKind::Int(n, _) => { - enum Int { - Signed(IntTy), - Unsigned(UintTy), - } - let ty = match ty.sty { - ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty), - ty::TyInt(other) => Int::Signed(other), - ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty), - ty::TyUint(other) => Int::Unsigned(other), - _ => bug!(), - }; - let n = match ty { - // FIXME(oli-obk): are these casts correct? - Int::Signed(IntTy::I8) if neg => - (n as i128 as i8).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I16) if neg => - (n as i128 as i16).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I32) if neg => - (n as i128 as i32).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I64) if neg => - (n as i128 as i64).overflowing_neg().0 as i128 as u128, - Int::Signed(IntTy::I128) if neg => - (n as i128).overflowing_neg().0 as u128, - Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, - Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, - Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, - Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, - Int::Signed(IntTy::I128) => n, - Int::Unsigned(UintTy::U8) => n as u8 as u128, - Int::Unsigned(UintTy::U16) => n as u16 as u128, - Int::Unsigned(UintTy::U32) => n as u32 as u128, - Int::Unsigned(UintTy::U64) => n as u64 as u128, - Int::Unsigned(UintTy::U128) => n, - _ => bug!(), - }; - Value::ByVal(PrimVal::Bytes(n)) - }, - LitKind::Float(n, fty) => { - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::FloatUnsuffixed(n) => { - let fty = match ty.sty { - ty::TyFloat(fty) => fty, - _ => bug!() - }; - let n = n.as_str(); - let mut f = parse_float(&n, fty)?; - if neg { - f = -f; - } - let bits = f.bits; - Value::ByVal(PrimVal::Bytes(bits)) - } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), - }; - Ok(ConstVal::Value(lit)) -} - -fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) - -> Result { - ConstFloat::from_str(num, fty).map_err(|_| ()) -} diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index d7bef752cb339..badc472a735c4 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -374,6 +374,7 @@ pub fn const_val_field<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, + span: Span, variant: Option, field: mir::Field, val: Value, @@ -385,7 +386,7 @@ pub fn const_val_field<'a, 'tcx>( ty, })), Err(err) => Err(ConstEvalErr { - span: tcx.def_span(instance.def_id()), + span, kind: err.into(), }), } @@ -455,7 +456,6 @@ pub fn const_eval_provider<'a, 'tcx>( trace!("const eval: {:?}", key); let cid = key.value; let def_id = cid.instance.def.def_id(); - let span = tcx.def_span(def_id); if tcx.is_foreign_item(def_id) { let id = tcx.interpret_interner.get_cached(def_id); @@ -479,6 +479,7 @@ pub fn const_eval_provider<'a, 'tcx>( if let Some(id) = tcx.hir.as_local_node_id(def_id) { let tables = tcx.typeck_tables_of(def_id); + let span = tcx.def_span(def_id); // Do match-check before building MIR if tcx.check_match(def_id).is_err() { @@ -511,6 +512,7 @@ pub fn const_eval_provider<'a, 'tcx>( if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); } + let span = ecx.frame().span; ConstEvalErr { kind: err.into(), span, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 565c5df8878f4..40687357ed6f0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1633,9 +1633,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }; err.span_label(span, e.to_string()); let mut last_span = None; - for &Frame { instance, span, .. } in self.stack().iter().rev() { + // skip 1 because the last frame is just the environment of the constant + for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() { // make sure we don't emit frames that are duplicates of the previous if explicit_span == Some(span) { + last_span = Some(span); continue; } if let Some(last) = last_span { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 6aa8b7e5449fd..8018073883fcc 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -203,6 +203,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx.tcx(), ty::ParamEnv::empty(traits::Reveal::All), self.instance, + constant.span, None, mir::Field::new(field as usize), c, diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr index 0e26db7ac0858..3211e840427f8 100644 --- a/src/test/ui/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -1,26 +1,14 @@ -error[E0080]: constant evaluation error - --> $DIR/conditional_array_execution.rs:13:19 - | -13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 - | ^^^^^ attempt to subtract with overflow - | -note: inside call to FOO - --> $DIR/conditional_array_execution.rs:13:1 - | -13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0080]: constant evaluation error --> $DIR/conditional_array_execution.rs:16:20 | 16 | println!("{}", FOO); //~ E0080 | ^^^ attempt to subtract with overflow + +error[E0080]: constant evaluation error + --> $DIR/conditional_array_execution.rs:13:19 | -note: inside call to main - --> $DIR/conditional_array_execution.rs:16:20 - | -16 | println!("{}", FOO); //~ E0080 - | ^^^ +13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 + | ^^^^^ attempt to subtract with overflow error: aborting due to 2 previous errors diff --git a/src/test/ui/const-eval/index_out_of_bound.stderr b/src/test/ui/const-eval/index_out_of_bound.stderr index 53cc8d361ff95..e7ac15a7eefb5 100644 --- a/src/test/ui/const-eval/index_out_of_bound.stderr +++ b/src/test/ui/const-eval/index_out_of_bound.stderr @@ -3,12 +3,6 @@ error[E0080]: constant evaluation error | 11 | static FOO: i32 = [][0]; | ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 - | -note: inside call to FOO - --> $DIR/index_out_of_bound.rs:11:1 - | -11 | static FOO: i32 = [][0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constant evaluation error --> $DIR/index_out_of_bound.rs:11:1 diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 9ba9c43462c53..8c72910218c2b 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -3,48 +3,24 @@ error[E0080]: constant evaluation error | 20 | println!("{} {}", X, Y); | ^ attempt to subtract with overflow - | -note: inside call to main - --> $DIR/issue-43197.rs:20:23 - | -20 | println!("{} {}", X, Y); - | ^ error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:20:26 | 20 | println!("{} {}", X, Y); | ^ attempt to subtract with overflow - | -note: inside call to main - --> $DIR/issue-43197.rs:20:26 - | -20 | println!("{} {}", X, Y); - | ^ error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:19:24 | 19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error | ^^^ attempt to subtract with overflow - | -note: inside call to main::Y - --> $DIR/issue-43197.rs:19:5 - | -19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:18:20 | 18 | const X: u32 = 0-1; //~ ERROR constant evaluation error | ^^^ attempt to subtract with overflow - | -note: inside call to main::X - --> $DIR/issue-43197.rs:18:5 - | -18 | const X: u32 = 0-1; //~ ERROR constant evaluation error - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 5409ff545fe43..bbe7fb6cf0b93 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -3,12 +3,6 @@ error[E0080]: constant evaluation error | 17 | const LEN: usize = ONE - TWO; | ^^^^^^^^^ attempt to subtract with overflow - | -note: inside call to LEN - --> $DIR/const-len-underflow-separate-spans.rs:17:1 - | -17 | const LEN: usize = ONE - TWO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: constant evaluation error --> $DIR/const-len-underflow-separate-spans.rs:21:17 diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index e0a403cd1f11f..b13b9409b20bd 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,8 +1,14 @@ error[E0080]: constant evaluation error - --> $DIR/infinite-recursion-const-fn.rs:16:18 + --> $DIR/infinite-recursion-const-fn.rs:14:25 + | +14 | const fn a() -> usize { b() } + | ^^^ reached the configured maximum number of stack frames + | +note: for constant expression here + --> $DIR/infinite-recursion-const-fn.rs:16:1 | 16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error - | ^^^ reached the configured maximum number of stack frames + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From ec4be3ab861e955e97e0bee23fb1ace84cdd2170 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 20:46:42 +0100 Subject: [PATCH 083/115] Stabilize const_indexing feature --- .../src/language-features/const-indexing.md | 19 ------------------- src/libsyntax/feature_gate.rs | 5 ++--- 2 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/const-indexing.md diff --git a/src/doc/unstable-book/src/language-features/const-indexing.md b/src/doc/unstable-book/src/language-features/const-indexing.md deleted file mode 100644 index 42d46ce15f676..0000000000000 --- a/src/doc/unstable-book/src/language-features/const-indexing.md +++ /dev/null @@ -1,19 +0,0 @@ -# `const_indexing` - -The tracking issue for this feature is: [#29947] - -[#29947]: https://github.com/rust-lang/rust/issues/29947 - ------------------------- - -The `const_indexing` feature allows the constant evaluation of index operations -on constant arrays and repeat expressions. - -## Examples - -```rust -#![feature(const_indexing)] - -const ARR: [usize; 5] = [1, 2, 3, 4, 5]; -const ARR2: [usize; ARR[1]] = [42, 99]; -``` \ No newline at end of file diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874a8..ea4ac0add12db 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -210,9 +210,6 @@ declare_features! ( // Allows the definition of `const fn` functions. (active, const_fn, "1.2.0", Some(24111)), - // Allows indexing into constant arrays. - (active, const_indexing, "1.4.0", Some(29947)), - // Allows using #[prelude_import] on glob `use` items. // // rustc internal @@ -480,6 +477,8 @@ declare_features! ( (accepted, augmented_assignments, "1.8.0", Some(28235)), // allow empty structs and enum variants with braces (accepted, braced_empty_structs, "1.8.0", Some(29720)), + // Allows indexing into constant arrays. + (accepted, const_indexing, "1.24.0", Some(29947)), (accepted, default_type_params, "1.0.0", None), (accepted, globs, "1.0.0", None), (accepted, if_let, "1.0.0", None), From 766f97b87097fbe152e9ce6183a106af968d0dbf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 29 Jan 2018 20:47:09 +0100 Subject: [PATCH 084/115] Update tests --- src/librustc_mir/transform/const_prop.rs | 7 +++-- src/test/compile-fail/E0080.rs | 1 + src/test/compile-fail/array_const_index-0.rs | 1 + src/test/compile-fail/array_const_index-1.rs | 1 + src/test/compile-fail/const-err-early.rs | 11 +++++++- src/test/compile-fail/const-err-multi.rs | 5 ++++ src/test/compile-fail/const-err.rs | 1 + src/test/compile-fail/const-eval-overflow2.rs | 28 +++++++++---------- .../compile-fail/const-eval-overflow2b.rs | 28 +++++++++---------- .../compile-fail/const-eval-overflow2c.rs | 28 +++++++++---------- src/test/compile-fail/const-slice-oob.rs | 1 + .../compile-fail/lint-exceeding-bitshifts.rs | 1 - .../compile-fail/lint-exceeding-bitshifts2.rs | 6 ++-- src/test/compile-fail/lint-type-overflow2.rs | 1 - src/test/ui/infinite-recursion-const-fn.rs | 4 +-- .../ui/infinite-recursion-const-fn.stderr | 4 +-- 16 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e0d8744f7c400..039aecdb0b3c1 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -198,7 +198,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right); - let left = self.eval_operand(left)?; let right = self.eval_operand(right)?; let def_id = if self.tcx.is_closure(self.source.def_id) { self.tcx.closure_base_def_id(self.source.def_id) @@ -218,8 +217,8 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; if op == BinOp::Shr || op == BinOp::Shl { let param_env = self.tcx.param_env(self.source.def_id); - let bits = (self.tcx, param_env).layout_of(left.1).unwrap().size.bits(); - if r.to_bytes().ok()? >= bits as u128 { + let bits = (self.tcx, param_env).layout_of(place_ty).unwrap().size.bits(); + if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) { let scope_info = match self.mir.visibility_scope_info { ClearCrossCrate::Set(ref data) => data, ClearCrossCrate::Clear => return None, @@ -230,8 +229,10 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { node_id, span, "bitshift exceeds the type's number of bits"); + return None; } } + let left = self.eval_operand(left)?; let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); match ecx.binary_op(op, l, left.1, r, right.1) { diff --git a/src/test/compile-fail/E0080.rs b/src/test/compile-fail/E0080.rs index c8e425711284e..cca63f23b7776 100644 --- a/src/test/compile-fail/E0080.rs +++ b/src/test/compile-fail/E0080.rs @@ -10,6 +10,7 @@ enum Enum { X = (1 << 500), //~ ERROR E0080 + //~| ERROR bitshift exceeds //~| shift left with overflow Y = (1 / 0) //~ ERROR E0080 //~| const_err diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index 501c66e75cded..35e7a42256251 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -11,6 +11,7 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; //~^ ERROR constant evaluation error +//~| ERROR E0080 //~| index out of bounds: the len is 0 but the index is 1 fn main() { diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index d3b43e83bfe52..db4cfa4268919 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -11,6 +11,7 @@ const A: [i32; 0] = []; const B: i32 = A[1]; //~^ ERROR constant evaluation error +//~| ERROR E0080 //~| index out of bounds: the len is 0 but the index is 1 fn main() { diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 4a146d8de3cde..3182ffa73b08d 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -8,18 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_indexing)] #![deny(const_err)] pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 //~| ERROR const_err //~| ERROR const_err +//~| ERROR E0080 pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 +//~| ERROR E0080 pub const C: u8 = 200u8 * 4; //~ ERROR E0080 +//~| ERROR E0080 pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080 +//~| ERROR E0080 pub const E: u8 = [5u8][1]; //~^ ERROR E0080 +//~| ERROR E0080 fn main() { + let _a = A; + let _b = B; + let _c = C; + let _d = D; + let _e = E; let _e = [6u8][1]; } diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index eb24a698419eb..1e3150a74d985 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -14,12 +14,17 @@ pub const A: i8 = -std::i8::MIN; //~^ ERROR E0080 //~| ERROR const_err //~| ERROR const_err +//~| ERROR E0080 pub const B: i8 = A; //~^ ERROR E0080 +//~| ERROR E0080 pub const C: u8 = A as u8; //~^ ERROR E0080 +//~| ERROR E0080 pub const D: i8 = 50 - A; //~^ ERROR E0080 +//~| ERROR E0080 fn main() { + let _ = (A, B, C, D); } diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index 8bd759b6d3735..5f55cc82e6d83 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -24,6 +24,7 @@ fn black_box(_: T) { const FOO: u8 = [5u8][1]; //~^ ERROR constant evaluation error //~| index out of bounds: the len is 1 but the index is 1 +//~| ERROR E0080 fn main() { black_box((FOO, FOO)); diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index 61a653589fff9..aa735cc045364 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - ( - i8::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + i8::MIN - 1, ); const VALS_I16: (i16,) = - ( - i16::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + i16::MIN - 1, ); const VALS_I32: (i32,) = - ( - i32::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + i32::MIN - 1, ); const VALS_I64: (i64,) = - ( - i64::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + i64::MIN - 1, ); const VALS_U8: (u8,) = - ( - u8::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + u8::MIN - 1, ); const VALS_U16: (u16,) = ( - u16::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + u16::MIN - 1, ); const VALS_U32: (u32,) = ( - u32::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + u32::MIN - 1, ); const VALS_U64: (u64,) = - ( - u64::MIN - 1, //~^ ERROR constant evaluation error //~| attempt to subtract with overflow + ( + u64::MIN - 1, ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index b2e84486101bc..01c3ea1ff425f 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - ( - i8::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + i8::MAX + 1, ); const VALS_I16: (i16,) = - ( - i16::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + i16::MAX + 1, ); const VALS_I32: (i32,) = - ( - i32::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + i32::MAX + 1, ); const VALS_I64: (i64,) = - ( - i64::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + i64::MAX + 1, ); const VALS_U8: (u8,) = - ( - u8::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + u8::MAX + 1, ); const VALS_U16: (u16,) = ( - u16::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + u16::MAX + 1, ); const VALS_U32: (u32,) = ( - u32::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + u32::MAX + 1, ); const VALS_U64: (u64,) = - ( - u64::MAX + 1, //~^ ERROR constant evaluation error //~| attempt to add with overflow + ( + u64::MAX + 1, ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index c4a8beaf0f057..dd7c151d85f69 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - ( - i8::MIN * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + i8::MIN * 2, ); const VALS_I16: (i16,) = - ( - i16::MIN * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + i16::MIN * 2, ); const VALS_I32: (i32,) = - ( - i32::MIN * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + i32::MIN * 2, ); const VALS_I64: (i64,) = - ( - i64::MIN * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + i64::MIN * 2, ); const VALS_U8: (u8,) = - ( - u8::MAX * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + u8::MAX * 2, ); const VALS_U16: (u16,) = ( - u16::MAX * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + u16::MAX * 2, ); const VALS_U32: (u32,) = ( - u32::MAX * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + u32::MAX * 2, ); const VALS_U64: (u64,) = - ( - u64::MAX * 2, //~^ ERROR constant evaluation error //~| attempt to multiply with overflow + ( + u64::MAX * 2, ); fn main() { diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index 179ea9e853f3a..cb884313f3373 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -13,6 +13,7 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; //~^ ERROR constant evaluation error [E0080] +//~| ERROR constant evaluation error [E0080] //~| index out of bounds: the len is 3 but the index is 5 fn main() { diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 2634157c80671..34b43c5badb51 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -11,7 +11,6 @@ #![deny(exceeding_bitshifts)] #![allow(unused_variables)] #![allow(dead_code, const_err)] -#![feature(const_indexing)] fn main() { let n = 1u8 << 7; diff --git a/src/test/compile-fail/lint-exceeding-bitshifts2.rs b/src/test/compile-fail/lint-exceeding-bitshifts2.rs index 0eab143fa49e0..a8027034fbee8 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts2.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts2.rs @@ -14,7 +14,7 @@ fn main() { let n = 1u8 << (4+3); - let n = 1u8 << (4+4); //~ ERROR: const_err + let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds let n = 1i64 >> [63][0]; let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation @@ -22,6 +22,6 @@ fn main() { const BITS: usize = 32; #[cfg(target_pointer_width = "64")] const BITS: usize = 64; - let n = 1_isize << BITS; //~ ERROR: const_err - let n = 1_usize << BITS; //~ ERROR: const_err + let n = 1_isize << BITS; //~ ERROR: bitshift exceeds + let n = 1_usize << BITS; //~ ERROR: bitshift exceeds } diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index 9178d8d2f6ed2..f7cf8a68d5684 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -17,7 +17,6 @@ #[rustc_error] fn main() { //~ ERROR: compilation successful let x2: i8 = --128; //~ warn: literal out of range for i8 - //~^ WARN constant evaluation error let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs index 05e40abdc0f2f..f98074bc554bb 100644 --- a/src/test/ui/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -11,8 +11,8 @@ //https://github.com/rust-lang/rust/issues/31364 #![feature(const_fn)] -const fn a() -> usize { b() } +const fn a() -> usize { b() } //~ ERROR constant evaluation error const fn b() -> usize { a() } -const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error +const ARR: [i32; a()] = [5; 6]; fn main(){} diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index b13b9409b20bd..67d8083103715 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,13 +1,13 @@ error[E0080]: constant evaluation error --> $DIR/infinite-recursion-const-fn.rs:14:25 | -14 | const fn a() -> usize { b() } +14 | const fn a() -> usize { b() } //~ ERROR constant evaluation error | ^^^ reached the configured maximum number of stack frames | note: for constant expression here --> $DIR/infinite-recursion-const-fn.rs:16:1 | -16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error +16 | const ARR: [i32; a()] = [5; 6]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From 5a6cab1d9d8647a4e588f3ca4ba3e339dfd91cb7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 09:40:13 +0100 Subject: [PATCH 085/115] Rebase fallout --- src/librustc_mir/hair/pattern/_match.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index e5acbc369ad7d..2549c93735408 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { match b { Value::ByVal(PrimVal::Ptr(ptr)) => { let is_array_ptr = ty - .builtin_deref(true, ty::NoPreference) + .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) .map_or(false, |t| t == tcx.types.u8); assert!(is_array_ptr); @@ -560,7 +560,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( } } => { let is_array_ptr = ty - .builtin_deref(true, ty::NoPreference) + .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) .map_or(false, |t| t == cx.tcx.types.u8); if is_array_ptr { @@ -949,7 +949,7 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, Value::ByVal(PrimVal::Ptr(ptr)) ), ty }) => { let is_array_ptr = ty - .builtin_deref(true, ty::NoPreference) + .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) .map_or(false, |t| t == tcx.types.u8); assert!(is_array_ptr); @@ -1089,7 +1089,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( Slice(..) => match value.val { ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { let is_array_ptr = value.ty - .builtin_deref(true, ty::NoPreference) + .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) .map_or(false, |t| t == cx.tcx.types.u8); assert!(is_array_ptr); From 50fdf2f340509ab321c4896e12eeb0a1d2ee9c76 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 09:40:26 +0100 Subject: [PATCH 086/115] Remove unused error E0020 --- src/librustc/diagnostics.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 8bd89b834d6b6..ab24faafae364 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -14,19 +14,6 @@ // Each message should start and end with a new line, and be wrapped to 80 characters. // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. register_long_diagnostics! { -E0020: r##" -This error indicates that an attempt was made to divide by zero (or take the -remainder of a zero divisor) in a static or constant expression. Erroneous -code example: - -```compile_fail -#[deny(const_err)] - -const X: i32 = 42 / 0; -// error: attempt to divide by zero in a constant expression -``` -"##, - E0038: r##" Trait objects like `Box` can only be constructed when certain requirements are satisfied by the trait in question. From 68373d5a922fa2f3f3f8a837aa266aa9b6004ce5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 09:40:46 +0100 Subject: [PATCH 087/115] Figure out const propgatable locals in a single pass --- src/librustc_mir/transform/const_prop.rs | 58 ++++++++++++------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 039aecdb0b3c1..51ac8b2c61a20 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -55,6 +55,7 @@ struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, places: IndexVec>>, + can_const_prop: IndexVec, } impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { @@ -67,6 +68,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { mir, tcx, source, + can_const_prop: CanConstProp::check(mir), places: IndexVec::from_elem(None, &mir.local_decls), } } @@ -271,33 +273,34 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } struct CanConstProp { - local: Local, - can_const_prop: bool, + can_const_prop: IndexVec, // false at the beginning, once set, there are not allowed to be any more assignments - found_assignment: bool, + found_assignment: IndexVec, } impl CanConstProp { /// returns true if `local` can be propagated - fn check<'tcx>(local: Local, mir: &Mir<'tcx>) -> bool { + fn check<'tcx>(mir: &Mir<'tcx>) -> IndexVec { let mut cpv = CanConstProp { - local, - can_const_prop: true, - found_assignment: false, + can_const_prop: IndexVec::from_elem(true, &mir.local_decls), + found_assignment: IndexVec::from_elem(false, &mir.local_decls), }; + for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { + *val = mir.local_kind(local) == LocalKind::Temp; + } cpv.visit_mir(mir); cpv.can_const_prop } +} - fn is_our_local(&mut self, mut place: &Place) -> bool { - while let Place::Projection(ref proj) = place { - place = &proj.base; - } - if let Place::Local(local) = *place { - local == self.local - } else { - false - } +fn place_to_local(mut place: &Place) -> Option { + while let Place::Projection(ref proj) = place { + place = &proj.base; + } + if let Place::Local(local) = *place { + Some(local) + } else { + None } } @@ -312,21 +315,21 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { match statement.kind { StatementKind::SetDiscriminant { ref place, .. } | StatementKind::Assign(ref place, _) => { - if self.is_our_local(place) { - if self.found_assignment { - self.can_const_prop = false; + if let Some(local) = place_to_local(place) { + if self.found_assignment[local] { + self.can_const_prop[local] = false; } else { - self.found_assignment = true + self.found_assignment[local] = true } } }, StatementKind::InlineAsm { ref outputs, .. } => { for place in outputs { - if self.is_our_local(place) { - if self.found_assignment { - self.can_const_prop = false; + if let Some(local) = place_to_local(place) { + if self.found_assignment[local] { + self.can_const_prop[local] = false; } else { - self.found_assignment = true + self.found_assignment[local] = true } return; } @@ -338,8 +341,8 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); if let Rvalue::Ref(_, _, ref place) = *rvalue { - if self.is_our_local(place) { - self.can_const_prop = false; + if let Some(local) = place_to_local(place) { + self.can_const_prop[local] = false; } } } @@ -369,8 +372,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { .to_ty(self.tcx); if let Some(value) = self.const_prop(rval, place_ty, statement.source_info) { if let Place::Local(local) = *place { - if self.mir.local_kind(local) == LocalKind::Temp - && CanConstProp::check(local, self.mir) { + if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); assert!(self.places[local].is_none()); self.places[local] = Some(value); From 506b272f3e6c7535d58aa2ff6c80c339b8b982a5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 09:52:01 +0100 Subject: [PATCH 088/115] Rebase fallout --- src/librustc_trans/mir/operand.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index a66528858e14a..75df349de41ee 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -12,6 +12,7 @@ use llvm::ValueRef; use rustc::middle::const_val::ConstEvalErr; use rustc::mir; use rustc::mir::interpret::Value as MiriValue; +use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; From b2e83ce3a98c35dbff39d06beccee6f30584394b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 11:18:37 +0100 Subject: [PATCH 089/115] Move the resource limits to the session in preparation for attributes configuring them --- src/librustc/session/mod.rs | 10 ++++++++ src/librustc_mir/interpret/const_eval.rs | 9 +++---- src/librustc_mir/interpret/eval_context.rs | 28 ++++------------------ src/librustc_mir/interpret/memory.rs | 4 ++-- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/step.rs | 2 +- 6 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index f4a00a43d8d92..ad3ba6d46625b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -100,6 +100,13 @@ pub struct Session { /// The maximum length of types during monomorphization. pub type_length_limit: Cell, + /// The maximum number of stackframes allowed in const eval + pub const_eval_stack_frame_limit: Cell, + /// The maximum number miri steps per constant + pub const_eval_step_limit: Cell, + /// The maximum number of virtual bytes per constant + pub const_eval_memory_limit: Cell, + /// The metadata::creader module may inject an allocator/panic_runtime /// dependency if it didn't already find one, and this tracks what was /// injected. @@ -1007,6 +1014,9 @@ pub fn build_session_(sopts: config::Options, features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), + const_eval_stack_frame_limit: Cell::new(100), + const_eval_step_limit: Cell::new(1_000_000), + const_eval_memory_limit: Cell::new(100 * 1024 * 1024), // 100 MB next_node_id: Cell::new(NodeId::new(1)), injected_allocator: Cell::new(None), allocator_kind: Cell::new(None), diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index badc472a735c4..4161b32604fd8 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -24,8 +24,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { debug!("mk_borrowck_eval_cx: {:?}", instance); let param_env = tcx.param_env(instance.def_id()); - let limits = super::ResourceLimits::default(); - let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( instance, @@ -43,8 +42,7 @@ pub fn mk_eval_cx<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> { debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); - let limits = super::ResourceLimits::default(); - let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); let mir = ecx.load_mir(instance.def)?; // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( @@ -95,8 +93,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { debug!("eval_body: {:?}, {:?}", cid, param_env); - let limits = super::ResourceLimits::default(); - let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); let res = (|| { let mut mir = match mir { Some(mir) => mir, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 40687357ed6f0..d9c07cf5cdd87 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -43,7 +43,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// The maximum number of operations that may be executed. /// This prevents infinite loops and huge computations from freezing up const eval. /// Remove once halting problem is solved. - pub(crate) steps_remaining: u64, + pub(crate) steps_remaining: usize, } /// A stack frame. @@ -102,23 +102,6 @@ pub enum StackPopCleanup { None, } -#[derive(Copy, Clone, Debug)] -pub struct ResourceLimits { - pub memory_size: u64, - pub step_limit: u64, - pub stack_limit: usize, -} - -impl Default for ResourceLimits { - fn default() -> Self { - ResourceLimits { - memory_size: 100 * 1024 * 1024, // 100 MB - step_limit: 1_000_000, - stack_limit: 100, - } - } -} - #[derive(Copy, Clone, Debug)] pub struct TyAndPacked<'tcx> { pub ty: Ty<'tcx>, @@ -200,7 +183,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn new( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - limits: ResourceLimits, machine: M, memory_data: M::MemoryData, ) -> Self { @@ -208,10 +190,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M machine, tcx, param_env, - memory: Memory::new(tcx, limits.memory_size, memory_data), + memory: Memory::new(tcx, memory_data), stack: Vec::new(), - stack_limit: limits.stack_limit, - steps_remaining: limits.step_limit, + stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), + steps_remaining: tcx.sess.const_eval_step_limit.get(), } } @@ -559,7 +541,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } Aggregate(ref kind, ref operands) => { - self.inc_step_counter_and_check_limit(operands.len() as u64)?; + self.inc_step_counter_and_check_limit(operands.len())?; let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 711bd3dd57e93..7252308c17070 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -55,14 +55,14 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { } impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, max_memory: u64, data: M::MemoryData) -> Self { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { Memory { data, alloc_kind: HashMap::new(), alloc_map: HashMap::new(), uninitialized_statics: HashMap::new(), tcx, - memory_size: max_memory, + memory_size: tcx.sess.const_eval_memory_limit.get(), memory_usage: 0, cur_frame: usize::max_value(), } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index f23ba90fd4c3f..8e0158569a867 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -11,7 +11,7 @@ mod step; mod terminator; mod traits; -pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup, +pub use self::eval_context::{EvalContext, Frame, StackPopCleanup, TyAndPacked, ValTy}; pub use self::place::{Place, PlaceExtra}; diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 21e81ff668ea5..94fe3d1c67b8f 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -8,7 +8,7 @@ use rustc::mir::interpret::EvalResult; use super::{EvalContext, Machine}; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { + pub fn inc_step_counter_and_check_limit(&mut self, n: usize) -> EvalResult<'tcx> { self.steps_remaining = self.steps_remaining.saturating_sub(n); if self.steps_remaining > 0 { Ok(()) From d4f07144ebdc33d3bcb9d02b11cc0a494ec5bdaa Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 13:57:13 +0100 Subject: [PATCH 090/115] Simplify const prop checks through PlaceContext --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc_mir/transform/const_prop.rs | 104 +++++++++++------------ 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 48db9cebf38b0..68eb0355b89b9 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -171,7 +171,7 @@ pub struct Allocation { /// The alignment of the allocation to detect unaligned reads. pub align: Align, /// Whether the allocation (of a static) should be put into mutable memory when translating - /// + /// /// Only happens for `static mut` or `static` with interior mutability pub runtime_mutability: Mutability, } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 51ac8b2c61a20..f461fb736c5ac 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -15,8 +15,8 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp}; -use rustc::mir::visit::Visitor; +use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, BorrowKind}; +use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; @@ -64,11 +64,16 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, ) -> OptimizationFinder<'b, 'a, 'tcx> { + let can_const_prop = CanConstProp::check( + mir, + tcx, + tcx.param_env(source.def_id), + ); OptimizationFinder { mir, tcx, source, - can_const_prop: CanConstProp::check(mir), + can_const_prop, places: IndexVec::from_elem(None, &mir.local_decls), } } @@ -272,78 +277,71 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) } -struct CanConstProp { +struct CanConstProp<'b, 'a, 'tcx:'a+'b> { can_const_prop: IndexVec, // false at the beginning, once set, there are not allowed to be any more assignments found_assignment: IndexVec, + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, } -impl CanConstProp { +impl<'b, 'a, 'tcx:'b> CanConstProp<'b, 'a, 'tcx> { /// returns true if `local` can be propagated - fn check<'tcx>(mir: &Mir<'tcx>) -> IndexVec { + fn check( + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> IndexVec { let mut cpv = CanConstProp { can_const_prop: IndexVec::from_elem(true, &mir.local_decls), found_assignment: IndexVec::from_elem(false, &mir.local_decls), + mir, + tcx, + param_env, }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { - *val = mir.local_kind(local) == LocalKind::Temp; + *val = mir.local_kind(local) != LocalKind::Arg; } cpv.visit_mir(mir); cpv.can_const_prop } } -fn place_to_local(mut place: &Place) -> Option { - while let Place::Projection(ref proj) = place { - place = &proj.base; - } - if let Place::Local(local) = *place { - Some(local) - } else { - None - } -} - -impl<'tcx> Visitor<'tcx> for CanConstProp { - fn visit_statement( +impl<'a, 'b, 'tcx> Visitor<'tcx> for CanConstProp<'a, 'b, 'tcx> { + fn visit_local( &mut self, - block: BasicBlock, - statement: &Statement<'tcx>, - location: Location, + &local: &Local, + context: PlaceContext<'tcx>, + _: Location, ) { - self.super_statement(block, statement, location); - match statement.kind { - StatementKind::SetDiscriminant { ref place, .. } | - StatementKind::Assign(ref place, _) => { - if let Some(local) = place_to_local(place) { - if self.found_assignment[local] { - self.can_const_prop[local] = false; - } else { - self.found_assignment[local] = true - } - } + use rustc::mir::visit::PlaceContext::*; + match context { + // Constants must have at most one write + // FIXME(oli-obk): we could be more powerful here, if the multiple writes + // only occur in independent execution paths + Store => if self.found_assignment[local] { + self.can_const_prop[local] = false; + } else { + self.found_assignment[local] = true }, - StatementKind::InlineAsm { ref outputs, .. } => { - for place in outputs { - if let Some(local) = place_to_local(place) { - if self.found_assignment[local] { - self.can_const_prop[local] = false; - } else { - self.found_assignment[local] = true - } - return; - } + // Reading constants is allowed an arbitrary number of times + Copy | Move | + StorageDead | StorageLive | + Validate | + Inspect => {}, + Borrow { kind: BorrowKind::Shared, .. } => { + // cannot const prop immutable borrows of types with interior mutability + let has_interior_mutability = self + .mir + .local_decls[local] + .ty + .is_freeze(self.tcx, self.param_env, self.mir.span); + if has_interior_mutability { + self.can_const_prop[local] = false; } } - _ => {} - } - } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_rvalue(rvalue, location); - if let Rvalue::Ref(_, _, ref place) = *rvalue { - if let Some(local) = place_to_local(place) { - self.can_const_prop[local] = false; - } + _ => self.can_const_prop[local] = false, } } } From 33afeaee542597146440cdbc9c7a2ed69de09943 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 14:12:16 +0100 Subject: [PATCH 091/115] Rename OptimizationFinder and don't propagate any borrows --- src/librustc_mir/transform/const_prop.rs | 50 ++++++------------------ 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f461fb736c5ac..45cbdc7d0c1ee 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -15,7 +15,7 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, BorrowKind}; +use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; @@ -40,7 +40,7 @@ impl MirPass for ConstProp { // constants, instead of just checking for const-folding succeeding. // That would require an uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = OptimizationFinder::new(mir, tcx, source); + let mut optimization_finder = ConstPropagator::new(mir, tcx, source); optimization_finder.visit_mir(mir); trace!("ConstProp done for {:?}", source.def_id); @@ -50,7 +50,7 @@ impl MirPass for ConstProp { type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); /// Finds optimization opportunities on the MIR. -struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { +struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, @@ -58,22 +58,17 @@ struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { can_const_prop: IndexVec, } -impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { +impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn new( mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, - ) -> OptimizationFinder<'b, 'a, 'tcx> { - let can_const_prop = CanConstProp::check( - mir, - tcx, - tcx.param_env(source.def_id), - ); - OptimizationFinder { + ) -> ConstPropagator<'b, 'a, 'tcx> { + ConstPropagator { mir, tcx, source, - can_const_prop, + can_const_prop: CanConstProp::check(mir), places: IndexVec::from_elem(None, &mir.local_decls), } } @@ -277,28 +272,18 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) } -struct CanConstProp<'b, 'a, 'tcx:'a+'b> { +struct CanConstProp { can_const_prop: IndexVec, // false at the beginning, once set, there are not allowed to be any more assignments found_assignment: IndexVec, - mir: &'b Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, } -impl<'b, 'a, 'tcx:'b> CanConstProp<'b, 'a, 'tcx> { +impl CanConstProp { /// returns true if `local` can be propagated - fn check( - mir: &'b Mir<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> IndexVec { + fn check(mir: &Mir) -> IndexVec { let mut cpv = CanConstProp { can_const_prop: IndexVec::from_elem(true, &mir.local_decls), found_assignment: IndexVec::from_elem(false, &mir.local_decls), - mir, - tcx, - param_env, }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { *val = mir.local_kind(local) != LocalKind::Arg; @@ -308,7 +293,7 @@ impl<'b, 'a, 'tcx:'b> CanConstProp<'b, 'a, 'tcx> { } } -impl<'a, 'b, 'tcx> Visitor<'tcx> for CanConstProp<'a, 'b, 'tcx> { +impl<'tcx> Visitor<'tcx> for CanConstProp { fn visit_local( &mut self, &local: &Local, @@ -330,23 +315,12 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for CanConstProp<'a, 'b, 'tcx> { StorageDead | StorageLive | Validate | Inspect => {}, - Borrow { kind: BorrowKind::Shared, .. } => { - // cannot const prop immutable borrows of types with interior mutability - let has_interior_mutability = self - .mir - .local_decls[local] - .ty - .is_freeze(self.tcx, self.param_env, self.mir.span); - if has_interior_mutability { - self.can_const_prop[local] = false; - } - } _ => self.can_const_prop[local] = false, } } } -impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { +impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { fn visit_constant( &mut self, constant: &Constant<'tcx>, From 0ecc40a65fac0f090f75b127961e09c60c4de1cf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 14:28:45 +0100 Subject: [PATCH 092/115] Simplify const propagator by removing unused code paths --- src/librustc_mir/transform/const_prop.rs | 123 ++++++++++------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 45cbdc7d0c1ee..fc2a149cfe940 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -359,81 +359,62 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { &mut self, block: BasicBlock, kind: &TerminatorKind<'tcx>, - _location: Location, + location: Location, ) { - match kind { - TerminatorKind::SwitchInt { discr: value, .. } | - TerminatorKind::Yield { value, .. } | - TerminatorKind::Assert { cond: value, .. } => { - match value { - Operand::Constant(box Constant { - literal: Literal::Value { - value: &ty::Const { - val: ConstVal::Value(_), - .. - }, - }, - .. - }) => return, - _ => {}, - } - if let Some(value) = self.eval_operand(value) { - if let TerminatorKind::Assert { expected, msg, .. } = kind { - if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 { - let span = self.mir[block] - .terminator - .as_ref() - .unwrap() - .source_info - .span; - let node_id = self - .tcx - .hir - .as_local_node_id(self.source.def_id) - .expect("some part of a failing const eval must be local"); - let mut lint = self.tcx.struct_span_lint_node( - ::rustc::lint::builtin::CONST_ERR, - node_id, + self.super_terminator_kind(block, kind, location); + if let TerminatorKind::Assert { expected, msg, cond, .. } = kind { + if let Some(value) = self.eval_operand(cond) { + if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 { + let span = self.mir[block] + .terminator + .as_ref() + .unwrap() + .source_info + .span; + let node_id = self + .tcx + .hir + .as_local_node_id(self.source.def_id) + .expect("some part of a failing const eval must be local"); + let mut lint = self.tcx.struct_span_lint_node( + ::rustc::lint::builtin::CONST_ERR, + node_id, + span, + "constant evaluation error", + ); + use rustc::mir::AssertMessage::*; + match msg { + GeneratorResumedAfterReturn => + lint.span_label(span, "generator resumed after completion"), + GeneratorResumedAfterPanic => + lint.span_label(span, "generator resumed after panicking"), + Math(ref err) => lint.span_label(span, err.description()), + BoundsCheck { ref len, ref index } => { + let len = self.eval_operand(len).expect("len must be const"); + let len = match len.0 { + Value::ByVal(PrimVal::Bytes(n)) => n, + _ => bug!("const len not primitive: {:?}", len), + }; + let index = self + .eval_operand(index) + .expect("index must be const"); + let index = match index.0 { + Value::ByVal(PrimVal::Bytes(n)) => n, + _ => bug!("const index not primitive: {:?}", index), + }; + lint.span_label( span, - "constant evaluation error", - ); - use rustc::mir::AssertMessage::*; - match msg { - GeneratorResumedAfterReturn => - lint.span_label(span, "generator resumed after completion"), - GeneratorResumedAfterPanic => - lint.span_label(span, "generator resumed after panicking"), - Math(ref err) => lint.span_label(span, err.description()), - BoundsCheck { ref len, ref index } => { - let len = self.eval_operand(len).expect("len must be const"); - let len = match len.0 { - Value::ByVal(PrimVal::Bytes(n)) => n, - _ => bug!("const len not primitive: {:?}", len), - }; - let index = self - .eval_operand(index) - .expect("index must be const"); - let index = match index.0 { - Value::ByVal(PrimVal::Bytes(n)) => n, - _ => bug!("const index not primitive: {:?}", index), - }; - lint.span_label( - span, - format!( - "index out of bounds: \ - the len is {} but the index is {}", - len, - index, - ), - ) - }, - }.emit(); - } - } + format!( + "index out of bounds: \ + the len is {} but the index is {}", + len, + index, + ), + ) + }, + }.emit(); } } - // FIXME: do this optimization for function calls - _ => {}, } } } From f6f956278bfa402ce39405d18fcc712d0729fbf0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 14:32:47 +0100 Subject: [PATCH 093/115] Update tests --- src/test/compile-fail/const-eval-overflow2.rs | 8 ++++++++ src/test/compile-fail/const-eval-overflow2b.rs | 8 ++++++++ src/test/compile-fail/const-eval-overflow2c.rs | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index aa735cc045364..ef1cdb2814fc7 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -26,6 +26,7 @@ const VALS_I8: (i8,) = //~| attempt to subtract with overflow ( i8::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = @@ -33,6 +34,7 @@ const VALS_I16: (i16,) = //~| attempt to subtract with overflow ( i16::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = @@ -40,6 +42,7 @@ const VALS_I32: (i32,) = //~| attempt to subtract with overflow ( i32::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = @@ -47,6 +50,7 @@ const VALS_I64: (i64,) = //~| attempt to subtract with overflow ( i64::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = @@ -54,18 +58,21 @@ const VALS_U8: (u8,) = //~| attempt to subtract with overflow ( u8::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error //~| attempt to subtract with overflow u16::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error //~| attempt to subtract with overflow u32::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = @@ -73,6 +80,7 @@ const VALS_U64: (u64,) = //~| attempt to subtract with overflow ( u64::MIN - 1, + //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index 01c3ea1ff425f..347ba7603e2f3 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -26,6 +26,7 @@ const VALS_I8: (i8,) = //~| attempt to add with overflow ( i8::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = @@ -33,6 +34,7 @@ const VALS_I16: (i16,) = //~| attempt to add with overflow ( i16::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = @@ -40,6 +42,7 @@ const VALS_I32: (i32,) = //~| attempt to add with overflow ( i32::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = @@ -47,6 +50,7 @@ const VALS_I64: (i64,) = //~| attempt to add with overflow ( i64::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = @@ -54,18 +58,21 @@ const VALS_U8: (u8,) = //~| attempt to add with overflow ( u8::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error //~| attempt to add with overflow u16::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error //~| attempt to add with overflow u32::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = @@ -73,6 +80,7 @@ const VALS_U64: (u64,) = //~| attempt to add with overflow ( u64::MAX + 1, + //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index dd7c151d85f69..5ebbab1b6499d 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -26,6 +26,7 @@ const VALS_I8: (i8,) = //~| attempt to multiply with overflow ( i8::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = @@ -33,6 +34,7 @@ const VALS_I16: (i16,) = //~| attempt to multiply with overflow ( i16::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = @@ -40,6 +42,7 @@ const VALS_I32: (i32,) = //~| attempt to multiply with overflow ( i32::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = @@ -47,6 +50,7 @@ const VALS_I64: (i64,) = //~| attempt to multiply with overflow ( i64::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = @@ -54,18 +58,21 @@ const VALS_U8: (u8,) = //~| attempt to multiply with overflow ( u8::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error //~| attempt to multiply with overflow u16::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error //~| attempt to multiply with overflow u32::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = @@ -73,6 +80,7 @@ const VALS_U64: (u64,) = //~| attempt to multiply with overflow ( u64::MAX * 2, + //~^ ERROR constant evaluation error ); fn main() { From f84a249e9f324df6f48abf6f6a0d3bda452a558d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 16:38:14 +0100 Subject: [PATCH 094/115] Can only const prop temporaries Variables might error in branches that are not reachable due to the variable value. --- src/librustc_mir/transform/const_prop.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fc2a149cfe940..09c72c4bf9387 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -286,7 +286,12 @@ impl CanConstProp { found_assignment: IndexVec::from_elem(false, &mir.local_decls), }; for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { - *val = mir.local_kind(local) != LocalKind::Arg; + // cannot use args at all + // cannot use locals because if x < y { y - x } else { x - y } would + // lint for x != y + // FIXME(oli-obk): lint variables until they are used in a condition + // FIXME(oli-obk): lint if return value is constant + *val = mir.local_kind(local) == LocalKind::Temp; } cpv.visit_mir(mir); cpv.can_const_prop From 1196106f5e67dfc9a67bddec91e029d16138334e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 16:46:37 +0100 Subject: [PATCH 095/115] Add regression test for const prop --- .../no_lint_for_statically_known_error.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/ui/const-eval/no_lint_for_statically_known_error.rs diff --git a/src/test/ui/const-eval/no_lint_for_statically_known_error.rs b/src/test/ui/const-eval/no_lint_for_statically_known_error.rs new file mode 100644 index 0000000000000..968a7de469107 --- /dev/null +++ b/src/test/ui/const-eval/no_lint_for_statically_known_error.rs @@ -0,0 +1,28 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +// if `X` were used instead of `x`, `X - 10` would result in a lint. +// This file should never produce a lint, no matter how the const +// propagator is improved. + +#![deny(warnings)] + +const X: u32 = 5; + +fn main() { + let x = X; + if x > 10 { + println!("{}", x - 10); + } else { + println!("{}", 10 - x); + } +} From 787b639e4c66771f423b05e9778b517669818f5f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 09:31:24 +0100 Subject: [PATCH 096/115] Compute the ParamEnv only once and use it to call tcx.const_eval --- src/librustc_mir/interpret/const_eval.rs | 18 +++++++------ src/librustc_mir/transform/const_prop.rs | 34 +++++++++++++++++------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 4161b32604fd8..ec2f8693ae01a 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -61,7 +61,7 @@ pub fn eval_body_with_mir<'a, 'mir, 'tcx>( mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); + let (res, ecx, _) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -76,7 +76,7 @@ pub fn eval_body<'a, 'tcx>( cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env); + let (res, ecx, _) = eval_body_and_ecx(tcx, cid, None, param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -91,9 +91,12 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { +) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, Span) { debug!("eval_body: {:?}, {:?}", cid, param_env); let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); + // we start out with the best span we have + // and try improving it down the road when more information is available + let mut span = tcx.def_span(cid.instance.def_id()); let res = (|| { let mut mir = match mir { Some(mir) => mir, @@ -102,6 +105,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } + span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); let alloc = match alloc { @@ -120,8 +124,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if tcx.is_static(cid.instance.def_id()).is_some() { tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); } - let span = tcx.def_span(cid.instance.def_id()); - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, span); + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); let mutability = tcx.is_static(cid.instance.def_id()); let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { Mutability::Mutable @@ -152,7 +155,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( }; Ok((value, ptr, layout.ty)) })(); - (res, ecx) + (res, ecx, span) } pub struct CompileTimeEvaluator; @@ -499,7 +502,7 @@ pub fn const_eval_provider<'a, 'tcx>( } }; - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); + let (res, ecx, span) = eval_body_and_ecx(tcx, cid, None, key.param_env); res.map(|(miri_value, _, miri_ty)| { tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), @@ -509,7 +512,6 @@ pub fn const_eval_provider<'a, 'tcx>( if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); } - let span = ecx.frame().span; ConstEvalErr { kind: err.into(), span, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 09c72c4bf9387..d3ab494139a50 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -21,11 +21,12 @@ use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; +use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, unary_op, ValTy}; use transform::{MirPass, MirSource}; use syntax::codemap::Span; use rustc::ty::subst::Substs; use rustc_data_structures::indexed_vec::IndexVec; +use rustc::ty::ParamEnv; pub struct ConstProp; @@ -56,6 +57,7 @@ struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { source: MirSource, places: IndexVec>>, can_const_prop: IndexVec, + param_env: ParamEnv<'tcx>, } impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { @@ -64,24 +66,40 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, ) -> ConstPropagator<'b, 'a, 'tcx> { + let param_env = tcx.param_env(source.def_id); ConstPropagator { mir, tcx, source, + param_env, can_const_prop: CanConstProp::check(mir), places: IndexVec::from_elem(None, &mir.local_decls), } } + fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option> { + let value = match self.tcx.const_eval(self.param_env.and(cid)) { + Ok(val) => val, + // FIXME: report some errors + Err(_) => return None, + }; + let val = match value.val { + ConstVal::Value(v) => v, + _ => bug!("eval produced: {:?}", value), + }; + let val = (val, value.ty, span); + trace!("evaluated {:?} to {:?}", cid, val); + Some(val) + } + fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { match c.literal { Literal::Value { value } => match value.val { ConstVal::Value(v) => Some((v, value.ty, c.span)), ConstVal::Unevaluated(did, substs) => { - let param_env = self.tcx.param_env(self.source.def_id); let instance = Instance::resolve( self.tcx, - param_env, + self.param_env, did, substs, )?; @@ -89,10 +107,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { instance, promoted: None, }; - let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; - let val = (value, ty, c.span); - trace!("evaluated {:?} to {:?}", c, val); - Some(val) + self.const_eval(cid, c.span) }, }, // evaluate the promoted and replace the constant with the evaluated result @@ -108,8 +123,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { instance, promoted: Some(index), }; - let param_env = self.tcx.param_env(self.source.def_id); - let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; + // cannot use `const_eval` here, because that would require having the MIR + // for the current function available, but we're producing said MIR right now + let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); Some(val) From 927249c98dc888d9c174b8ab5befad2b3069c655 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 09:57:25 +0100 Subject: [PATCH 097/115] Report all errors other than those about insufficient type information --- src/librustc_mir/transform/const_prop.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index d3ab494139a50..9dee1e1633e02 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -80,8 +80,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option> { let value = match self.tcx.const_eval(self.param_env.and(cid)) { Ok(val) => val, - // FIXME: report some errors - Err(_) => return None, + Err(err) => { + err.report(self.tcx, span, "const prop"); + return None; + }, }; let val = match value.val { ConstVal::Value(v) => v, From cbea51c120b0ea4ccbf2306c27df77ccaa86167c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 10:20:30 +0100 Subject: [PATCH 098/115] Update tests --- src/librustc_mir/transform/const_prop.rs | 2 +- src/test/compile-fail/const-err-multi.rs | 3 +++ src/test/compile-fail/const-err.rs | 1 + src/test/compile-fail/const-eval-overflow2.rs | 16 +++++++-------- .../compile-fail/const-eval-overflow2b.rs | 16 +++++++-------- .../compile-fail/const-eval-overflow2c.rs | 16 +++++++-------- .../conditional_array_execution.stderr | 10 ++++++++-- src/test/ui/const-eval/issue-43197.stderr | 20 +++++++++++++++---- .../const-len-underflow-separate-spans.stderr | 10 ++++++++-- src/test/ui/infinite-recursion-const-fn.rs | 4 ++-- .../ui/infinite-recursion-const-fn.stderr | 12 +++-------- 11 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 9dee1e1633e02..e0203953fb2a4 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -81,7 +81,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { let value = match self.tcx.const_eval(self.param_env.and(cid)) { Ok(val) => val, Err(err) => { - err.report(self.tcx, span, "const prop"); + err.report(self.tcx, span, "constant propagated"); return None; }, }; diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 1e3150a74d985..5dd8651005df8 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -14,6 +14,9 @@ pub const A: i8 = -std::i8::MIN; //~^ ERROR E0080 //~| ERROR const_err //~| ERROR const_err +//~| ERROR constant evaluation error +//~| ERROR constant evaluation error +//~| ERROR constant evaluation error //~| ERROR E0080 pub const B: i8 = A; //~^ ERROR E0080 diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index 5f55cc82e6d83..b0cf639cd762f 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -23,6 +23,7 @@ fn black_box(_: T) { // Make sure that the two uses get two errors. const FOO: u8 = [5u8][1]; //~^ ERROR constant evaluation error +//~| ERROR constant evaluation error //~| index out of bounds: the len is 1 but the index is 1 //~| ERROR E0080 diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index ef1cdb2814fc7..d715847e03fe3 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -23,64 +23,64 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( i8::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( i16::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( i32::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( i64::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( u8::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow u16::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow u32::MIN - 1, - //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to subtract with overflow ( u64::MIN - 1, - //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index 347ba7603e2f3..f6463900eeb53 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -23,64 +23,64 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( i8::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( i16::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( i32::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( i64::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( u8::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow u16::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow u32::MAX + 1, - //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to add with overflow ( u64::MAX + 1, - //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index 5ebbab1b6499d..8665b9d97a84d 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -23,64 +23,64 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( i8::MIN * 2, - //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( i16::MIN * 2, - //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( i32::MIN * 2, - //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( i64::MIN * 2, - //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( u8::MAX * 2, - //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow u16::MAX * 2, - //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow u32::MAX * 2, - //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = //~^ ERROR constant evaluation error + //~| ERROR constant evaluation error //~| attempt to multiply with overflow ( u64::MAX * 2, - //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr index 3211e840427f8..835761d433a75 100644 --- a/src/test/ui/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -5,10 +5,16 @@ error[E0080]: constant evaluation error | ^^^ attempt to subtract with overflow error[E0080]: constant evaluation error - --> $DIR/conditional_array_execution.rs:13:19 + --> $DIR/conditional_array_execution.rs:13:1 | 13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 - | ^^^^^ attempt to subtract with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + | +note: for constant propagated here + --> $DIR/conditional_array_execution.rs:16:20 + | +16 | println!("{}", FOO); //~ E0080 + | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 8c72910218c2b..7c123842a4ce7 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -11,16 +11,28 @@ error[E0080]: constant evaluation error | ^ attempt to subtract with overflow error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:19:24 + --> $DIR/issue-43197.rs:19:5 | 19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - | ^^^ attempt to subtract with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + | +note: for constant propagated here + --> $DIR/issue-43197.rs:20:26 + | +20 | println!("{} {}", X, Y); + | ^ error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:18:20 + --> $DIR/issue-43197.rs:18:5 | 18 | const X: u32 = 0-1; //~ ERROR constant evaluation error - | ^^^ attempt to subtract with overflow + | ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + | +note: for constant propagated here + --> $DIR/issue-43197.rs:20:23 + | +20 | println!("{} {}", X, Y); + | ^ error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index bbe7fb6cf0b93..7b8d5d66735d0 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -1,8 +1,14 @@ error[E0080]: constant evaluation error - --> $DIR/const-len-underflow-separate-spans.rs:17:20 + --> $DIR/const-len-underflow-separate-spans.rs:17:1 | 17 | const LEN: usize = ONE - TWO; - | ^^^^^^^^^ attempt to subtract with overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + | +note: for constant propagated here + --> $DIR/const-len-underflow-separate-spans.rs:21:17 + | +21 | let a: [i8; LEN] = unimplemented!(); + | ^^^ error[E0080]: constant evaluation error --> $DIR/const-len-underflow-separate-spans.rs:21:17 diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs index f98074bc554bb..05e40abdc0f2f 100644 --- a/src/test/ui/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -11,8 +11,8 @@ //https://github.com/rust-lang/rust/issues/31364 #![feature(const_fn)] -const fn a() -> usize { b() } //~ ERROR constant evaluation error +const fn a() -> usize { b() } const fn b() -> usize { a() } -const ARR: [i32; a()] = [5; 6]; +const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error fn main(){} diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index 67d8083103715..e0a403cd1f11f 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,14 +1,8 @@ error[E0080]: constant evaluation error - --> $DIR/infinite-recursion-const-fn.rs:14:25 + --> $DIR/infinite-recursion-const-fn.rs:16:18 | -14 | const fn a() -> usize { b() } //~ ERROR constant evaluation error - | ^^^ reached the configured maximum number of stack frames - | -note: for constant expression here - --> $DIR/infinite-recursion-const-fn.rs:16:1 - | -16 | const ARR: [i32; a()] = [5; 6]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error + | ^^^ reached the configured maximum number of stack frames error: aborting due to previous error From e720af24e76a82e07df96ef9bc3a6bc8d141aeb0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 10:39:30 +0100 Subject: [PATCH 099/115] Add stack traces to miri errors --- src/librustc/ich/impls_ty.rs | 14 ++++++++--- src/librustc/middle/const_val.rs | 34 ++++++++++++++++---------- src/librustc/mir/interpret/error.rs | 9 +++---- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/fulfill.rs | 2 +- src/librustc/ty/structural_impls.rs | 10 ++++---- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 4e6db5549a0bd..7e566132e1478 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -419,6 +419,11 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> { kind }); +impl_stable_hash_for!(struct ::middle::const_val::FrameInfo { + span, + location +}); + impl<'a, 'gcx> HashStable> for ::middle::const_val::ErrKind<'gcx> { fn hash_stable(&self, @@ -447,7 +452,10 @@ for ::middle::const_val::ErrKind<'gcx> { LayoutError(ref layout_error) => { layout_error.hash_stable(hcx, hasher); } - Miri(ref err) => err.hash_stable(hcx, hasher), + Miri(ref err, ref trace) => { + err.hash_stable(hcx, hasher); + trace.hash_stable(hcx, hasher); + }, } } } @@ -468,9 +476,9 @@ for ::mir::interpret::EvalError<'gcx> { hasher: &mut StableHasher) { use mir::interpret::EvalErrorKind::*; - mem::discriminant(&*self.kind).hash_stable(hcx, hasher); + mem::discriminant(&self.kind).hash_stable(hcx, hasher); - match *self.kind { + match self.kind { DanglingPointerDeref | DoubleFree | InvalidMemoryAccess | diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index c987ed0ea5d3f..d6d23c5cad8ad 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -19,6 +19,7 @@ use graphviz::IntoCow; use syntax_pos::Span; use std::borrow::Cow; +use std::rc::Rc; pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; @@ -51,7 +52,7 @@ impl<'tcx> ConstVal<'tcx> { #[derive(Clone, Debug)] pub struct ConstEvalErr<'tcx> { pub span: Span, - pub kind: ErrKind<'tcx>, + pub kind: Rc>, } #[derive(Clone, Debug)] @@ -66,13 +67,13 @@ pub enum ErrKind<'tcx> { TypeckError, CheckMatchError, - Miri(::mir::interpret::EvalError<'tcx>), + Miri(::mir::interpret::EvalError<'tcx>, Vec), } -impl<'tcx> From<::mir::interpret::EvalError<'tcx>> for ErrKind<'tcx> { - fn from(err: ::mir::interpret::EvalError<'tcx>) -> ErrKind<'tcx> { - ErrKind::Miri(err) - } +#[derive(Clone, Debug)] +pub struct FrameInfo { + pub span: Span, + pub location: String, } impl<'tcx> From for ErrKind<'tcx> { @@ -85,21 +86,23 @@ impl<'tcx> From for ErrKind<'tcx> { } #[derive(Clone, Debug)] -pub enum ConstEvalErrDescription<'a> { +pub enum ConstEvalErrDescription<'a, 'tcx: 'a> { Simple(Cow<'a, str>), + Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]), } -impl<'a> ConstEvalErrDescription<'a> { +impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> { /// Return a one-line description of the error, for lints and such pub fn into_oneline(self) -> Cow<'a, str> { match self { ConstEvalErrDescription::Simple(simple) => simple, + ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(), } } } impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { - pub fn description(&self) -> ConstEvalErrDescription { + pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> { use self::ErrKind::*; use self::ConstEvalErrDescription::*; @@ -110,7 +113,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { }) } - match self.kind { + match *self.kind { NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => simple!("unimplemented constant expression: {}", what), @@ -124,8 +127,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { TypeckError => simple!("type-checking failed"), CheckMatchError => simple!("match-checking failed"), - // FIXME: report a full backtrace - Miri(ref err) => simple!("{}", err), + Miri(ref err, ref trace) => Backtrace(err, trace), } } @@ -150,6 +152,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { ConstEvalErrDescription::Simple(message) => { diag.span_label(self.span, message); } + ConstEvalErrDescription::Backtrace(miri, frames) => { + diag.span_label(self.span, format!("{}", miri)); + for frame in frames { + diag.span_label(frame.span, format!("inside call to {}", frame.location)); + } + } } if !primary_span.contains(self.span) { @@ -163,7 +171,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { primary_span: Span, primary_kind: &str) { - match self.kind { + match *self.kind { ErrKind::TypeckError | ErrKind::CheckMatchError => return, _ => {} } diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 3e8aeaff57e62..90d10df151530 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -1,6 +1,5 @@ use std::error::Error; use std::{fmt, env}; -use std::rc::Rc; use mir; use ty::{FnSig, Ty, layout}; @@ -15,7 +14,7 @@ use backtrace::Backtrace; #[derive(Debug, Clone)] pub struct EvalError<'tcx> { - pub kind: Rc>, + pub kind: EvalErrorKind<'tcx>, pub backtrace: Option, } @@ -26,7 +25,7 @@ impl<'tcx> From> for EvalError<'tcx> { _ => None }; EvalError { - kind: Rc::new(kind), + kind, backtrace, } } @@ -132,7 +131,7 @@ pub type EvalResult<'tcx, T = ()> = Result>; impl<'tcx> Error for EvalError<'tcx> { fn description(&self) -> &str { use self::EvalErrorKind::*; - match *self.kind { + match self.kind { MachineError(ref inner) => inner, FunctionPointerTyMismatch(..) => "tried to call a function through a function pointer of a different type", @@ -253,7 +252,7 @@ impl<'tcx> Error for EvalError<'tcx> { impl<'tcx> fmt::Display for EvalError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::EvalErrorKind::*; - match *self.kind { + match self.kind { PointerOutOfBounds { ptr, access, allocation_size } => { write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", if access { "memory access" } else { "pointer computed" }, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 31442256401c5..7b627f014c829 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -761,7 +761,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ConstEvalFailure(ref err) => { - if let ::middle::const_val::ErrKind::TypeckError = err.kind { + if let ::middle::const_val::ErrKind::TypeckError = *err.kind { return; } err.struct_error(self.tcx, span, "constant expression") diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 680c6f4d55d77..c64fa759e4e32 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -547,7 +547,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } else { Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { span: obligation.cause.span, - kind: ErrKind::UnimplementedConstVal("could not resolve"), + kind: ErrKind::UnimplementedConstVal("could not resolve").into(), }))) } }, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 333028f91437e..a992774842d2f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -599,10 +599,10 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { type Lifted = ConstEvalErr<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.kind).map(|kind| { + tcx.lift(&*self.kind).map(|kind| { ConstEvalErr { span: self.span, - kind, + kind: Rc::new(kind), } }) } @@ -612,7 +612,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { type Lifted = interpret::EvalError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { use ::mir::interpret::EvalErrorKind::*; - let kind = match *self.kind { + let kind = match self.kind { MachineError(ref err) => MachineError(err.clone()), FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch( tcx.lift(&a)?, @@ -712,7 +712,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { TypeckError => TypeckError, }; Some(interpret::EvalError { - kind: Rc::new(kind), + kind: kind, backtrace: self.backtrace.clone(), }) } @@ -735,7 +735,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { TypeckError => TypeckError, CheckMatchError => CheckMatchError, - Miri(ref e) => return tcx.lift(e).map(Miri), + Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())), }) } } From 85e3f42aa5da53c4d6c74af50480eb8a671cf47c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 15:06:45 +0100 Subject: [PATCH 100/115] Const eval error refactoring --- src/librustc/ich/impls_ty.rs | 1 + src/librustc/middle/const_val.rs | 7 ++ src/librustc/mir/interpret/error.rs | 5 + src/librustc/ty/structural_impls.rs | 1 + src/librustc_mir/interpret/const_eval.rs | 92 +++++++++---------- src/librustc_mir/interpret/eval_context.rs | 87 +++++++++++------- .../conditional_array_execution.stderr | 2 +- src/test/ui/const-eval/issue-43197.stderr | 4 +- src/test/ui/const-fn-error.stderr | 5 +- .../const-len-underflow-separate-spans.stderr | 2 +- .../ui/infinite-recursion-const-fn.stderr | 59 +++++++++++- 11 files changed, 175 insertions(+), 90 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7e566132e1478..b557a6994bd6f 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -510,6 +510,7 @@ for ::mir::interpret::EvalError<'gcx> { TypeckError | DerefFunctionPointer | ExecuteMemory | + ReferencedConstant | OverflowingMath => {} MachineError(ref err) => err.hash_stable(hcx, hasher), FunctionPointerTyMismatch(a, b) => { diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index d6d23c5cad8ad..151cc9b1ce2ab 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -173,6 +173,13 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { { match *self.kind { ErrKind::TypeckError | ErrKind::CheckMatchError => return, + ErrKind::Miri(ref miri, _) => { + match miri.kind { + ::mir::interpret::EvalErrorKind::TypeckError | + ::mir::interpret::EvalErrorKind::Layout(_) => return, + _ => {}, + } + } _ => {} } self.struct_error(tcx, primary_span, primary_kind).emit(); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 90d10df151530..bb27628fa9c73 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -124,6 +124,9 @@ pub enum EvalErrorKind<'tcx> { UnimplementedTraitSelection, /// Abort in case type errors are reached TypeckError, + /// Cannot compute this constant because it depends on another one + /// which already produced an error + ReferencedConstant, } pub type EvalResult<'tcx, T = ()> = Result>; @@ -245,6 +248,8 @@ impl<'tcx> Error for EvalError<'tcx> { "there were unresolved type arguments during trait selection", TypeckError => "encountered constants with type errors, stopping evaluation", + ReferencedConstant => + "referenced constant has errors", } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index a992774842d2f..fbb0d2da635f5 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -710,6 +710,7 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { PathNotFound(ref v) => PathNotFound(v.clone()), UnimplementedTraitSelection => UnimplementedTraitSelection, TypeckError => TypeckError, + ReferencedConstant => ReferencedConstant, }; Some(interpret::EvalError { kind: kind, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index ec2f8693ae01a..0b7e5987c1b74 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,7 +1,6 @@ use rustc::hir; use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError}; -use rustc::traits; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; use rustc::ty::layout::{self, LayoutOf}; @@ -15,6 +14,7 @@ use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; use std::fmt; use std::error::Error; +use std::rc::Rc; pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -236,7 +236,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(err) => { - if let EvalErrorKind::NoMirFor(ref path) = *err.kind { + if let EvalErrorKind::NoMirFor(ref path) = err.kind { return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -333,15 +333,8 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - let param_env = ty::ParamEnv::empty(traits::Reveal::All); // ensure the static is computed - if let Err(err) = ecx.tcx.const_eval(param_env.and(cid)) { - match err.kind { - ErrKind::Miri(miri) => return Err(miri), - ErrKind::TypeckError => return err!(TypeckError), - other => bug!("const eval returned {:?}", other), - } - }; + ecx.const_eval(cid)?; Ok(ecx .tcx .interpret_interner @@ -377,52 +370,47 @@ pub fn const_val_field<'a, 'tcx>( span: Span, variant: Option, field: mir::Field, - val: Value, + value: Value, ty: Ty<'tcx>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { - match const_val_field_inner(tcx, param_env, instance, variant, field, val, ty) { + trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); + let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); + let result = (|| { + let (mut field, ty) = match value { + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), + Value::ByRef(ptr, align) => { + let place = Place::Ptr { + ptr, + align, + extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), + }; + let layout = ecx.layout_of(ty)?; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + (Value::ByRef(ptr, align), layout.ty) + } + }; + if let Value::ByRef(ptr, align) = field { + if let Some(val) = ecx.try_read_value(ptr, align, ty)? { + field = val; + } + } + Ok((field, ty)) + })(); + match result { Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { val: ConstVal::Value(field), ty, })), - Err(err) => Err(ConstEvalErr { - span, - kind: err.into(), - }), - } -} - -fn const_val_field_inner<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - instance: ty::Instance<'tcx>, - variant: Option, - field: mir::Field, - value: Value, - ty: Ty<'tcx>, -) -> EvalResult<'tcx, (Value, Ty<'tcx>)> { - trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); - let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); - let (mut field, ty) = match value { - Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), - Value::ByRef(ptr, align) => { - let place = Place::Ptr { - ptr, - align, - extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), - }; - let layout = ecx.layout_of(ty)?; - let (place, layout) = ecx.place_field(place, field, layout)?; - let (ptr, align) = place.to_ptr_align(); - (Value::ByRef(ptr, align), layout.ty) - } - }; - if let Value::ByRef(ptr, align) = field { - if let Some(val) = ecx.try_read_value(ptr, align, ty)? { - field = val; - } + Err(err) => { + let trace = ecx.generate_stacktrace(None); + let err = ErrKind::Miri(err, trace); + Err(ConstEvalErr { + kind: err.into(), + span, + }) + }, } - Ok((field, ty)) } pub fn const_discr<'a, 'tcx>( @@ -484,7 +472,7 @@ pub fn const_eval_provider<'a, 'tcx>( // Do match-check before building MIR if tcx.check_match(def_id).is_err() { return Err(ConstEvalErr { - kind: CheckMatchError, + kind: Rc::new(CheckMatchError), span, }); } @@ -496,7 +484,7 @@ pub fn const_eval_provider<'a, 'tcx>( // Do not continue into miri if typeck errors occurred; it will fail horribly if tables.tainted_by_errors { return Err(ConstEvalErr { - kind: TypeckError, + kind: Rc::new(TypeckError), span, }); } @@ -512,6 +500,8 @@ pub fn const_eval_provider<'a, 'tcx>( if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); } + let trace = ecx.generate_stacktrace(None); + let err = ErrKind::Miri(err, trace); ConstEvalErr { kind: err.into(), span, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index d9c07cf5cdd87..e6d28e679c83b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -10,6 +10,7 @@ use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs, Kind}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; +use rustc::middle::const_val::FrameInfo; use syntax::codemap::{self, DUMMY_SP, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ @@ -930,17 +931,28 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M return Ok(Value::ByRef(ptr.into(), layout.align)) } } - let cv = match self.tcx.const_eval(self.param_env.and(gid)) { - Ok(val) => val, - Err(err) => match err.kind { - ErrKind::Miri(miri) => return Err(miri), - ErrKind::TypeckError => return err!(TypeckError), - other => bug!("const eval returned {:?}", other), - }, - }; + let cv = self.const_eval(gid)?; self.const_to_value(&cv.val, ty) } + pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> { + let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() { + use rustc::traits; + ty::ParamEnv::empty(traits::Reveal::All) + } else { + self.param_env + }; + self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind { + ErrKind::Miri(ref err, _) => match err.kind { + EvalErrorKind::TypeckError | + EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(), + _ => EvalErrorKind::ReferencedConstant.into(), + }, + ErrKind::TypeckError => EvalErrorKind::TypeckError.into(), + ref other => bug!("const eval returned {:?}", other), + }) + } + pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> { let new_place = match place { Place::Local { frame, local } => { @@ -1492,7 +1504,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M match self.stack[frame].get_local(local) { Err(err) => { - if let EvalErrorKind::DeadLocal = *err.kind { + if let EvalErrorKind::DeadLocal = err.kind { write!(msg, " is dead").unwrap(); } else { panic!("Failed to access local: {:?}", err); @@ -1554,9 +1566,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } + pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec { + let mut last_span = None; + let mut frames = Vec::new(); + // skip 1 because the last frame is just the environment of the constant + for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() { + // make sure we don't emit frames that are duplicates of the previous + if explicit_span == Some(span) { + last_span = Some(span); + continue; + } + if let Some(last) = last_span { + if last == span { + continue; + } + } else { + last_span = Some(span); + } + let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr { + "closure".to_owned() + } else { + instance.to_string() + }; + frames.push(FrameInfo { span, location }); + } + frames + } + pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { - if let EvalErrorKind::TypeckError = *e.kind { - return; + match e.kind { + EvalErrorKind::Layout(_) | + EvalErrorKind::TypeckError => return, + _ => {}, } if let Some(ref mut backtrace) = e.backtrace { let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); @@ -1614,28 +1655,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) }; err.span_label(span, e.to_string()); - let mut last_span = None; - // skip 1 because the last frame is just the environment of the constant - for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() { - // make sure we don't emit frames that are duplicates of the previous - if explicit_span == Some(span) { - last_span = Some(span); - continue; - } - if let Some(last) = last_span { - if last == span { - continue; - } - } else { - last_span = Some(span); - } - if self.tcx.def_key(instance.def_id()).disambiguated_data.data == - DefPathData::ClosureExpr - { - err.span_note(span, "inside call to closure"); - continue; - } - err.span_note(span, &format!("inside call to {}", instance)); + for FrameInfo { span, location } in self.generate_stacktrace(explicit_span) { + err.span_note(span, &format!("inside call to {}", location)); } err.emit(); } else { diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr index 835761d433a75..7345188deeeb8 100644 --- a/src/test/ui/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/conditional_array_execution.rs:16:20 | 16 | println!("{}", FOO); //~ E0080 - | ^^^ attempt to subtract with overflow + | ^^^ referenced constant has errors error[E0080]: constant evaluation error --> $DIR/conditional_array_execution.rs:13:1 diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 7c123842a4ce7..7010ec592c17c 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -2,13 +2,13 @@ error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:20:23 | 20 | println!("{} {}", X, Y); - | ^ attempt to subtract with overflow + | ^ referenced constant has errors error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:20:26 | 20 | println!("{} {}", X, Y); - | ^ attempt to subtract with overflow + | ^ referenced constant has errors error[E0080]: constant evaluation error --> $DIR/issue-43197.rs:19:5 diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index 02a8920727e67..322f183c8f4da 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -20,7 +20,10 @@ error[E0080]: constant evaluation error --> $DIR/const-fn-error.rs:28:19 | 28 | let a : [i32; f(X)]; - | ^^^^ calling non-const fn `>::into_iter` + | ^^^^ + | | + | calling non-const fn `>::into_iter` + | inside call to f error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 7b8d5d66735d0..5cad64205390f 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -14,7 +14,7 @@ error[E0080]: constant evaluation error --> $DIR/const-len-underflow-separate-spans.rs:21:17 | 21 | let a: [i8; LEN] = unimplemented!(); - | ^^^ attempt to subtract with overflow + | ^^^ referenced constant has errors error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index e0a403cd1f11f..11438a847a0c7 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,8 +1,65 @@ error[E0080]: constant evaluation error --> $DIR/infinite-recursion-const-fn.rs:16:18 | +14 | const fn a() -> usize { b() } + | --- inside call to b +15 | const fn b() -> usize { a() } + | --- + | | + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a + | inside call to a 16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error - | ^^^ reached the configured maximum number of stack frames + | ^^^ + | | + | reached the configured maximum number of stack frames + | inside call to a error: aborting due to previous error From 6203db21b9087c7692e6da1f1235a18536c89670 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 31 Jan 2018 15:45:59 +0100 Subject: [PATCH 101/115] Tidy fix --- src/librustc/traits/fulfill.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index c64fa759e4e32..5a1cfdc5616ec 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -547,7 +547,8 @@ fn process_predicate<'a, 'gcx, 'tcx>( } else { Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { span: obligation.cause.span, - kind: ErrKind::UnimplementedConstVal("could not resolve").into(), + kind: ErrKind::UnimplementedConstVal("could not resolve") + .into(), }))) } }, From a2a3357b041c29b162194e31653dc62d90af27db Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 09:51:36 +0100 Subject: [PATCH 102/115] Rebase fallout --- src/librustc_mir/hair/pattern/mod.rs | 1 + src/librustc_mir/interpret/const_eval.rs | 2 +- src/librustc_mir/transform/const_prop.rs | 6 ++---- src/librustc_typeck/check/mod.rs | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 4723cf0f2a0f8..7995e99ea6fd5 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -41,6 +41,7 @@ pub enum PatternError { StaticInPattern(Span), FloatBug, NonConstPath(Span), + AssociatedConstInPattern(Span), } #[derive(Copy, Clone, Debug)] diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 0b7e5987c1b74..495dc30514576 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -457,7 +457,7 @@ pub fn const_eval_provider<'a, 'tcx>( }, }; let ty = tcx.type_of(def_id); - let layout = (tcx, key.param_env).layout_of(ty).unwrap(); + let layout = tcx.layout_of(key.param_env.and(ty)).unwrap(); let ptr = MemoryPointer::new(id, 0); return Ok(tcx.mk_const(ty::Const { val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)), diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e0203953fb2a4..b43227c9f1a22 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -17,7 +17,6 @@ use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp}; use rustc::mir::visit::{Visitor, PlaceContext}; -use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; @@ -237,7 +236,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; if op == BinOp::Shr || op == BinOp::Shl { let param_env = self.tcx.param_env(self.source.def_id); - let bits = (self.tcx, param_env).layout_of(place_ty).unwrap().size.bits(); + let bits = self.tcx.layout_of(param_env.and(place_ty)).unwrap().size.bits(); if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) { let scope_info = match self.mir.visibility_scope_info { ClearCrossCrate::Set(ref data) => data, @@ -286,8 +285,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: ty::Ty<'tcx>) -> Option { - use rustc::ty::layout::LayoutOf; - (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) + tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) } struct CanConstProp { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0197988f56669..e20fcb63d257d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -101,7 +101,6 @@ use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::TypeFoldable; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt, Discr}; -use rustc::ty::layout::LayoutOf; use errors::{DiagnosticBuilder, DiagnosticId}; use require_c_abi_if_variadic; From f014cf7951f2e7533ceae034463e106c03994d5e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 09:52:08 +0100 Subject: [PATCH 103/115] Reduce code duplication --- src/librustc_mir/hair/pattern/mod.rs | 99 +++++++++------------------- 1 file changed, 32 insertions(+), 67 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 7995e99ea6fd5..95bf1aeb27d3a 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -41,7 +41,6 @@ pub enum PatternError { StaticInPattern(Span), FloatBug, NonConstPath(Span), - AssociatedConstInPattern(Span), } #[derive(Copy, Clone, Debug)] @@ -774,6 +773,26 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { span: Span, ) -> Pattern<'tcx> { debug!("const_to_pat: cv={:#?}", cv); + let adt_subpattern = |i, variant_opt| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => const_val_field( + self.tcx, self.param_env, instance, span, + variant_opt, field, miri, cv.ty, + ).unwrap(), + _ => bug!("{:#?} is not a valid adt", cv), + }; + self.const_to_pat(instance, val, id, span) + }; + let adt_subpatterns = |n, variant_opt| { + (0..n).map(|i| { + let field = Field::new(i); + FieldPattern { + field, + pattern: adt_subpattern(i, variant_opt), + } + }).collect::>() + }; let kind = match cv.ty.sty { ty::TyFloat(_) => { let id = self.tcx.hir.hir_to_node_id(id); @@ -810,91 +829,37 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { .discriminants(self.tcx) .position(|var| var.val == discr) .unwrap(); + let subpatterns = adt_subpatterns( + adt_def.variants[variant_index].fields.len(), + Some(variant_index), + ); PatternKind::Variant { adt_def, substs, variant_index, - subpatterns: adt_def - .variants[variant_index] - .fields - .iter() - .enumerate() - .map(|(i, _)| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, span, - Some(variant_index), field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), - } - }).collect(), + subpatterns, } }, - _ => return Pattern { - span, - ty: cv.ty, - kind: Box::new(PatternKind::Constant { - value: cv, - }), + ConstVal::Unevaluated(..) => + span_bug!(span, "{:#?} is not a valid enum constant", cv), } - } }, ty::TyAdt(adt_def, _) => { let struct_var = adt_def.non_enum_variant(); PatternKind::Leaf { - subpatterns: struct_var.fields.iter().enumerate().map(|(i, _)| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, span, - None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), + subpatterns: adt_subpatterns(struct_var.fields.len(), None), } - }).collect() } - } ty::TyTuple(fields, _) => { PatternKind::Leaf { - subpatterns: (0..fields.len()).map(|i| { - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, span, - None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - FieldPattern { - field, - pattern: self.const_to_pat(instance, val, id, span), - } - }).collect() + subpatterns: adt_subpatterns(fields.len(), None), } } ty::TyArray(_, n) => { PatternKind::Array { - prefix: (0..n.val.unwrap_u64()).map(|i| { - let i = i as usize; - let field = Field::new(i); - let val = match cv.val { - ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, span, - None, field, miri, cv.ty, - ).unwrap(), - _ => bug!("{:#?} is not a valid tuple", cv), - }; - self.const_to_pat(instance, val, id, span) - }).collect(), + prefix: (0..n.val.unwrap_u64()) + .map(|i| adt_subpattern(i as usize, None)) + .collect(), slice: None, suffix: Vec::new(), } From c600322048c8f51b59679509fc7774119f247fe4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 09:52:28 +0100 Subject: [PATCH 104/115] Rebase fallout --- src/librustc_mir/hair/pattern/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 95bf1aeb27d3a..9a2ecdc412676 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -41,6 +41,7 @@ pub enum PatternError { StaticInPattern(Span), FloatBug, NonConstPath(Span), + AssociatedConstInPattern(Span), } #[derive(Copy, Clone, Debug)] From ba7cfd781de6dfd07663ea419ec4a229c015b721 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 09:52:56 +0100 Subject: [PATCH 105/115] Add some documentation to pattern/const conversions --- src/librustc_mir/hair/pattern/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 9a2ecdc412676..6ff728afe1cc7 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -666,6 +666,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } + /// Takes a HIR Path. If the path is a constant, evaluates it and feeds + /// it to `const_to_pat`. Any other path (like enum variants without fields) + /// is converted to the corresponding pattern via `lower_variant_or_leaf` fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, @@ -721,6 +724,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } + /// Converts literals, paths and negation of literals to patterns. + /// The special case for negation exists to allow things like -128i8 + /// which would overflow if we tried to evaluate 128i8 and then negate + /// afterwards. fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { match expr.node { hir::ExprLit(ref lit) => { @@ -766,6 +773,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } + /// Converts an evaluated constant to a pattern (if possible). + /// This means aggregate values (like structs and enums) are converted + /// to a pattern that matches the value (as if you'd compare via eq). fn const_to_pat( &self, instance: ty::Instance<'tcx>, @@ -843,14 +853,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }, ConstVal::Unevaluated(..) => span_bug!(span, "{:#?} is not a valid enum constant", cv), - } + } }, ty::TyAdt(adt_def, _) => { let struct_var = adt_def.non_enum_variant(); PatternKind::Leaf { subpatterns: adt_subpatterns(struct_var.fields.len(), None), - } } + } ty::TyTuple(fields, _) => { PatternKind::Leaf { subpatterns: adt_subpatterns(fields.len(), None), From a19143dbc44042b601e8f0e174261a804032a72c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 10:24:53 +0100 Subject: [PATCH 106/115] Remove dead code --- src/librustc_mir/hair/pattern/_match.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 2549c93735408..a7d96312b7525 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -905,7 +905,6 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], - Single => vec![ty], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], @@ -914,9 +913,6 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs[0].as_type().unwrap()] } else { - if let ConstantValue(_) = *ctor { - return vec![]; - } adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); @@ -1025,7 +1021,6 @@ fn constructor_covered_by_range(ctor: &Constructor, (end == RangeEnd::Excluded && to == Ordering::Equal); Ok(some_or_ok!(cmp_from(&from.val)) && end) } - Variant(_) | Single => Ok(true), _ => bug!(), } From 5cdb7764d156063214f916fb8ac46f3b5238c477 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 10:25:08 +0100 Subject: [PATCH 107/115] Add regression test --- src/test/ui/const-eval/issue-47971.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/ui/const-eval/issue-47971.rs diff --git a/src/test/ui/const-eval/issue-47971.rs b/src/test/ui/const-eval/issue-47971.rs new file mode 100644 index 0000000000000..4a2f0a7f38cda --- /dev/null +++ b/src/test/ui/const-eval/issue-47971.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +#![feature(const_fn)] + +struct S(pub &'static u32, pub u32); + +const fn g(ss: &S) -> &u32 { &ss.1 } + +static T: S = S(g(&T), 0); + +fn main () { } From 6811829db3b7a4a162e6cbc352ea1f74ac59fa52 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 10:25:53 +0100 Subject: [PATCH 108/115] Fix ui tests after rebase --- .../ui/lint/unused_parens_json_suggestion.stderr | 3 +++ src/test/ui/lint/use_suggestion_json.stderr | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 37eb9a98f74df..d849520b14019 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -24,6 +24,7 @@ ], "label": null, "suggested_replacement": null, + "suggestion_approximate": null, "expansion": null } ], @@ -51,6 +52,7 @@ ], "label": null, "suggested_replacement": null, + "suggestion_approximate": null, "expansion": null } ], @@ -80,6 +82,7 @@ ], "label": null, "suggested_replacement": "1 / (2 + 3)", + "suggestion_approximate": null, "expansion": null } ], diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 86c2ad4c0e7a4..6efffa4751108 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -89,6 +89,7 @@ mod foo { ], "label": "not found in this scope", "suggested_replacement": null, + "suggestion_approximate": null, "expansion": null } ], @@ -118,6 +119,7 @@ mod foo { "suggested_replacement": "use std::collections::binary_heap::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -140,6 +142,7 @@ mod foo { "suggested_replacement": "use std::collections::btree_map::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -162,6 +165,7 @@ mod foo { "suggested_replacement": "use std::collections::btree_set::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -184,6 +188,7 @@ mod foo { "suggested_replacement": "use std::collections::hash_map::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -206,6 +211,7 @@ mod foo { "suggested_replacement": "use std::collections::hash_set::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -228,6 +234,7 @@ mod foo { "suggested_replacement": "use std::collections::linked_list::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -250,6 +257,7 @@ mod foo { "suggested_replacement": "use std::collections::vec_deque::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -272,6 +280,7 @@ mod foo { "suggested_replacement": "use std::option::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -294,6 +303,7 @@ mod foo { "suggested_replacement": "use std::path::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -316,6 +326,7 @@ mod foo { "suggested_replacement": "use std::result::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -338,6 +349,7 @@ mod foo { "suggested_replacement": "use std::slice::Iter; ", + "suggestion_approximate": null, "expansion": null }, { @@ -360,6 +372,7 @@ mod foo { "suggested_replacement": "use std::sync::mpsc::Iter; ", + "suggestion_approximate": null, "expansion": null } ], From d9277b92deec01d196a5e09de6599a758f24c208 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 10:51:54 +0100 Subject: [PATCH 109/115] Stage 2 doesn't see suggestion_approximate --- .../ui/lint/unused_parens_json_suggestion.stderr | 3 --- src/test/ui/lint/use_suggestion_json.stderr | 13 ------------- 2 files changed, 16 deletions(-) diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index d849520b14019..37eb9a98f74df 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -24,7 +24,6 @@ ], "label": null, "suggested_replacement": null, - "suggestion_approximate": null, "expansion": null } ], @@ -52,7 +51,6 @@ ], "label": null, "suggested_replacement": null, - "suggestion_approximate": null, "expansion": null } ], @@ -82,7 +80,6 @@ ], "label": null, "suggested_replacement": "1 / (2 + 3)", - "suggestion_approximate": null, "expansion": null } ], diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 6efffa4751108..86c2ad4c0e7a4 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -89,7 +89,6 @@ mod foo { ], "label": "not found in this scope", "suggested_replacement": null, - "suggestion_approximate": null, "expansion": null } ], @@ -119,7 +118,6 @@ mod foo { "suggested_replacement": "use std::collections::binary_heap::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -142,7 +140,6 @@ mod foo { "suggested_replacement": "use std::collections::btree_map::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -165,7 +162,6 @@ mod foo { "suggested_replacement": "use std::collections::btree_set::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -188,7 +184,6 @@ mod foo { "suggested_replacement": "use std::collections::hash_map::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -211,7 +206,6 @@ mod foo { "suggested_replacement": "use std::collections::hash_set::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -234,7 +228,6 @@ mod foo { "suggested_replacement": "use std::collections::linked_list::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -257,7 +250,6 @@ mod foo { "suggested_replacement": "use std::collections::vec_deque::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -280,7 +272,6 @@ mod foo { "suggested_replacement": "use std::option::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -303,7 +294,6 @@ mod foo { "suggested_replacement": "use std::path::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -326,7 +316,6 @@ mod foo { "suggested_replacement": "use std::result::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -349,7 +338,6 @@ mod foo { "suggested_replacement": "use std::slice::Iter; ", - "suggestion_approximate": null, "expansion": null }, { @@ -372,7 +360,6 @@ mod foo { "suggested_replacement": "use std::sync::mpsc::Iter; ", - "suggestion_approximate": null, "expansion": null } ], From 12255d66c0fc27851b2b56bebb78023018397b3a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 14:04:35 +0100 Subject: [PATCH 110/115] Unregress error spans in constant errors --- src/librustc/middle/const_val.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 2 +- src/librustc_mir/interpret/const_eval.rs | 15 +-- src/librustc_mir/interpret/eval_context.rs | 17 ++- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_trans/mir/constant.rs | 1 - src/test/ui/const-eval-overflow-2.stderr | 4 +- src/test/ui/const-eval-overflow-4.stderr | 2 +- .../conditional_array_execution.stderr | 10 +- src/test/ui/const-eval/index_out_of_bound.rs | 1 - .../ui/const-eval/index_out_of_bound.stderr | 8 +- src/test/ui/const-eval/issue-43197.stderr | 20 +-- src/test/ui/const-fn-error.rs | 2 +- src/test/ui/const-fn-error.stderr | 18 ++- .../const-len-underflow-separate-spans.stderr | 10 +- src/test/ui/infinite-recursion-const-fn.rs | 4 +- .../ui/infinite-recursion-const-fn.stderr | 120 +++++++++--------- 17 files changed, 112 insertions(+), 126 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 151cc9b1ce2ab..8c3dfd0bce752 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -155,7 +155,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { ConstEvalErrDescription::Backtrace(miri, frames) => { diag.span_label(self.span, format!("{}", miri)); for frame in frames { - diag.span_label(frame.span, format!("inside call to {}", frame.location)); + diag.span_label(frame.span, format!("inside call to `{}`", frame.location)); } } } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6ff728afe1cc7..61f468a3c857f 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -788,7 +788,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let field = Field::new(i); let val = match cv.val { ConstVal::Value(miri) => const_val_field( - self.tcx, self.param_env, instance, span, + self.tcx, self.param_env, instance, variant_opt, field, miri, cv.ty, ).unwrap(), _ => bug!("{:#?} is not a valid adt", cv), diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 495dc30514576..b864e64fa742f 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -61,7 +61,7 @@ pub fn eval_body_with_mir<'a, 'mir, 'tcx>( mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx, _) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); + let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -76,7 +76,7 @@ pub fn eval_body<'a, 'tcx>( cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx, _) = eval_body_and_ecx(tcx, cid, None, param_env); + let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -91,7 +91,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, Span) { +) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { debug!("eval_body: {:?}, {:?}", cid, param_env); let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); // we start out with the best span we have @@ -155,7 +155,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( }; Ok((value, ptr, layout.ty)) })(); - (res, ecx, span) + (res, ecx) } pub struct CompileTimeEvaluator; @@ -367,7 +367,6 @@ pub fn const_val_field<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, - span: Span, variant: Option, field: mir::Field, value: Value, @@ -403,7 +402,7 @@ pub fn const_val_field<'a, 'tcx>( ty, })), Err(err) => { - let trace = ecx.generate_stacktrace(None); + let (trace, span) = ecx.generate_stacktrace(None); let err = ErrKind::Miri(err, trace); Err(ConstEvalErr { kind: err.into(), @@ -490,7 +489,7 @@ pub fn const_eval_provider<'a, 'tcx>( } }; - let (res, ecx, span) = eval_body_and_ecx(tcx, cid, None, key.param_env); + let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); res.map(|(miri_value, _, miri_ty)| { tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), @@ -500,7 +499,7 @@ pub fn const_eval_provider<'a, 'tcx>( if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); } - let trace = ecx.generate_stacktrace(None); + let (trace, span) = ecx.generate_stacktrace(None); let err = ErrKind::Miri(err, trace); ConstEvalErr { kind: err.into(), diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6d28e679c83b..e4f816f93c458 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1566,7 +1566,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } - pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec { + pub fn generate_stacktrace(&self, explicit_span: Option) -> (Vec, Span) { let mut last_span = None; let mut frames = Vec::new(); // skip 1 because the last frame is just the environment of the constant @@ -1590,7 +1590,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }; frames.push(FrameInfo { span, location }); } - frames + let frame = self.frame(); + let bb = &frame.mir.basic_blocks()[frame.block]; + let span = if let Some(stmt) = bb.statements.get(frame.stmt) { + stmt.source_info.span + } else { + bb.terminator().source_info.span + }; + trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); + (frames, span) } pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { @@ -1654,9 +1662,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M "constant evaluation error", ) }; + let (frames, span) = self.generate_stacktrace(explicit_span); err.span_label(span, e.to_string()); - for FrameInfo { span, location } in self.generate_stacktrace(explicit_span) { - err.span_note(span, &format!("inside call to {}", location)); + for FrameInfo { span, location } in frames { + err.span_note(span, &format!("inside call to `{}`", location)); } err.emit(); } else { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index b43227c9f1a22..de17872e96ff2 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -80,7 +80,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { let value = match self.tcx.const_eval(self.param_env.and(cid)) { Ok(val) => val, Err(err) => { - err.report(self.tcx, span, "constant propagated"); + err.report(self.tcx, err.span, "constant propagated"); return None; }, }; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8018073883fcc..6aa8b7e5449fd 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -203,7 +203,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx.tcx(), ty::ParamEnv::empty(traits::Reveal::All), self.instance, - constant.span, None, mir::Field::new(field as usize), c, diff --git a/src/test/ui/const-eval-overflow-2.stderr b/src/test/ui/const-eval-overflow-2.stderr index bf72b9960c6df..28324069f54c3 100644 --- a/src/test/ui/const-eval-overflow-2.stderr +++ b/src/test/ui/const-eval-overflow-2.stderr @@ -1,8 +1,8 @@ error[E0080]: constant evaluation error - --> $DIR/const-eval-overflow-2.rs:21:1 + --> $DIR/const-eval-overflow-2.rs:21:25 | 21 | const NEG_NEG_128: i8 = -NEG_128; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to negate with overflow + | ^^^^^^^^ attempt to negate with overflow | note: for pattern here --> $DIR/const-eval-overflow-2.rs:26:9 diff --git a/src/test/ui/const-eval-overflow-4.stderr b/src/test/ui/const-eval-overflow-4.stderr index 1ccac3cd01ee5..d35b9c6c571b4 100644 --- a/src/test/ui/const-eval-overflow-4.stderr +++ b/src/test/ui/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: constant evaluation error --> $DIR/const-eval-overflow-4.rs:23:13 | 23 | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow + | ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow error: aborting due to previous error diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr index 7345188deeeb8..197accdacb8d6 100644 --- a/src/test/ui/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -5,16 +5,10 @@ error[E0080]: constant evaluation error | ^^^ referenced constant has errors error[E0080]: constant evaluation error - --> $DIR/conditional_array_execution.rs:13:1 + --> $DIR/conditional_array_execution.rs:13:19 | 13 | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~ E0080 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow - | -note: for constant propagated here - --> $DIR/conditional_array_execution.rs:16:20 - | -16 | println!("{}", FOO); //~ E0080 - | ^^^ + | ^^^^^ attempt to subtract with overflow error: aborting due to 2 previous errors diff --git a/src/test/ui/const-eval/index_out_of_bound.rs b/src/test/ui/const-eval/index_out_of_bound.rs index 632804f2fd366..e7ffbe81b9ae7 100644 --- a/src/test/ui/const-eval/index_out_of_bound.rs +++ b/src/test/ui/const-eval/index_out_of_bound.rs @@ -10,6 +10,5 @@ static FOO: i32 = [][0]; //~^ ERROR E0080 -//~| ERROR E0080 fn main() {} diff --git a/src/test/ui/const-eval/index_out_of_bound.stderr b/src/test/ui/const-eval/index_out_of_bound.stderr index e7ac15a7eefb5..504c6ea9f1db3 100644 --- a/src/test/ui/const-eval/index_out_of_bound.stderr +++ b/src/test/ui/const-eval/index_out_of_bound.stderr @@ -4,11 +4,5 @@ error[E0080]: constant evaluation error 11 | static FOO: i32 = [][0]; | ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 -error[E0080]: constant evaluation error - --> $DIR/index_out_of_bound.rs:11:1 - | -11 | static FOO: i32 = [][0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24 - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 7010ec592c17c..ceaea9568d627 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -11,28 +11,16 @@ error[E0080]: constant evaluation error | ^ referenced constant has errors error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:19:5 + --> $DIR/issue-43197.rs:19:24 | 19 | const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow - | -note: for constant propagated here - --> $DIR/issue-43197.rs:20:26 - | -20 | println!("{} {}", X, Y); - | ^ + | ^^^ attempt to subtract with overflow error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:18:5 + --> $DIR/issue-43197.rs:18:20 | 18 | const X: u32 = 0-1; //~ ERROR constant evaluation error - | ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow - | -note: for constant propagated here - --> $DIR/issue-43197.rs:20:23 - | -20 | println!("{} {}", X, Y); - | ^ + | ^^^ attempt to subtract with overflow error: aborting due to 4 previous errors diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs index dc1526a7079d4..9e09f66776c9b 100644 --- a/src/test/ui/const-fn-error.rs +++ b/src/test/ui/const-fn-error.rs @@ -18,6 +18,7 @@ const fn f(x: usize) -> usize { for i in 0..x { //~^ ERROR E0015 //~| ERROR E0019 + //~| ERROR E0080 sum += i; } sum @@ -26,5 +27,4 @@ const fn f(x: usize) -> usize { #[allow(unused_variables)] fn main() { let a : [i32; f(X)]; - //~^ ERROR E0080 } diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index 322f183c8f4da..883cd41f90517 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -17,13 +17,19 @@ error[E0019]: constant function contains unimplemented expression type | ^^^^ error[E0080]: constant evaluation error - --> $DIR/const-fn-error.rs:28:19 + --> $DIR/const-fn-error.rs:18:14 + | +18 | for i in 0..x { + | ^^^^ calling non-const fn `>::into_iter` +... +29 | let a : [i32; f(X)]; + | ---- inside call to `f` + | +note: for constant expression here + --> $DIR/const-fn-error.rs:29:13 | -28 | let a : [i32; f(X)]; - | ^^^^ - | | - | calling non-const fn `>::into_iter` - | inside call to f +29 | let a : [i32; f(X)]; + | ^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.stderr b/src/test/ui/const-len-underflow-separate-spans.stderr index 5cad64205390f..34a20ecb0c01b 100644 --- a/src/test/ui/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/const-len-underflow-separate-spans.stderr @@ -1,14 +1,8 @@ error[E0080]: constant evaluation error - --> $DIR/const-len-underflow-separate-spans.rs:17:1 + --> $DIR/const-len-underflow-separate-spans.rs:17:20 | 17 | const LEN: usize = ONE - TWO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow - | -note: for constant propagated here - --> $DIR/const-len-underflow-separate-spans.rs:21:17 - | -21 | let a: [i8; LEN] = unimplemented!(); - | ^^^ + | ^^^^^^^^^ attempt to subtract with overflow error[E0080]: constant evaluation error --> $DIR/const-len-underflow-separate-spans.rs:21:17 diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs index 05e40abdc0f2f..51de304405a0a 100644 --- a/src/test/ui/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -12,7 +12,7 @@ #![feature(const_fn)] const fn a() -> usize { b() } -const fn b() -> usize { a() } -const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error +const fn b() -> usize { a() } //~ ERROR constant evaluation error +const ARR: [i32; a()] = [5; 6]; fn main(){} diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index 11438a847a0c7..68fb2cf1da5e5 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,65 +1,69 @@ error[E0080]: constant evaluation error - --> $DIR/infinite-recursion-const-fn.rs:16:18 + --> $DIR/infinite-recursion-const-fn.rs:15:25 | 14 | const fn a() -> usize { b() } - | --- inside call to b -15 | const fn b() -> usize { a() } - | --- + | --- inside call to `b` +15 | const fn b() -> usize { a() } //~ ERROR constant evaluation error + | ^^^ | | - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a - | inside call to a -16 | const ARR: [i32; a()] = [5; 6]; //~ ERROR constant evaluation error - | ^^^ - | | - | reached the configured maximum number of stack frames - | inside call to a + | reached the configured maximum number of stack frames + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` + | inside call to `a` +16 | const ARR: [i32; a()] = [5; 6]; + | --- inside call to `a` + | +note: for constant expression here + --> $DIR/infinite-recursion-const-fn.rs:16:1 + | +16 | const ARR: [i32; a()] = [5; 6]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error From d2aad4e20369817954036b3cc77ce61f38e5c3a0 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 14:04:42 +0100 Subject: [PATCH 111/115] Typo --- src/librustc_passes/rvalue_promotion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 0c47a00a07281..e961cf20c4c93 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -296,7 +296,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node // References to a static that are themselves within a static // are inherently promotable with the exception - // of "#[thread_loca]" statics, which may not + // of "#[thread_local]" statics, which may not // outlive the current function Def::Static(did, _) => { From b3b60716b383558043306db12427be6e9b51deaf Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 14:05:06 +0100 Subject: [PATCH 112/115] Add a test for transmuting via unions in constants --- src/test/ui/const-eval/const_transmute.rs | 62 +++++++++++++++++++ src/test/ui/const-eval/const_transmute.stderr | 0 2 files changed, 62 insertions(+) create mode 100644 src/test/ui/const-eval/const_transmute.rs create mode 100644 src/test/ui/const-eval/const_transmute.stderr diff --git a/src/test/ui/const-eval/const_transmute.rs b/src/test/ui/const-eval/const_transmute.rs new file mode 100644 index 0000000000000..a64a1d212abf3 --- /dev/null +++ b/src/test/ui/const-eval/const_transmute.rs @@ -0,0 +1,62 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully +// run-pass + +union Transmute { + t: T, + u: U, +} + +trait Bar { + fn bar(&self) -> u32; +} + +struct Foo { + foo: u32, + bar: bool, +} + +impl Bar for Foo { + fn bar(&self) -> u32 { + self.foo + } +} + +impl Drop for Foo { + fn drop(&mut self) { + assert!(!self.bar); + self.bar = true; + println!("dropping Foo"); + } +} + +#[derive(Copy, Clone)] +struct Fat<'a>(&'a Foo, &'static VTable); + +struct VTable { + drop: Option fn(&'a mut Foo)>, + size: usize, + align: usize, + bar: for<'a> fn(&'a Foo) -> u32, +} + +const FOO: &Bar = &Foo { foo: 128, bar: false }; +const G: Fat = unsafe { Transmute { t: FOO }.u }; +const F: Option fn(&'a mut Foo)> = G.1.drop; +const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar; + +fn main() { + let mut foo = Foo { foo: 99, bar: false }; + (F.unwrap())(&mut foo); + std::mem::forget(foo); // already ran the drop impl + assert_eq!(H(&Foo { foo: 42, bar: false }), 42); +} diff --git a/src/test/ui/const-eval/const_transmute.stderr b/src/test/ui/const-eval/const_transmute.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d From cfd11fb28532f386b1e9ea4ba7a221736d2aeee1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 14:15:36 +0100 Subject: [PATCH 113/115] Update compile-fail tests --- src/test/compile-fail/array_const_index-0.rs | 1 - src/test/compile-fail/array_const_index-1.rs | 1 - src/test/compile-fail/const-err-early.rs | 5 --- src/test/compile-fail/const-err-multi.rs | 7 ---- src/test/compile-fail/const-err.rs | 2 -- src/test/compile-fail/const-eval-overflow2.rs | 32 +++++-------------- .../compile-fail/const-eval-overflow2b.rs | 32 +++++-------------- .../compile-fail/const-eval-overflow2c.rs | 32 +++++-------------- src/test/compile-fail/const-slice-oob.rs | 1 - 9 files changed, 24 insertions(+), 89 deletions(-) diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index 35e7a42256251..501c66e75cded 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -11,7 +11,6 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; //~^ ERROR constant evaluation error -//~| ERROR E0080 //~| index out of bounds: the len is 0 but the index is 1 fn main() { diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index db4cfa4268919..d3b43e83bfe52 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -11,7 +11,6 @@ const A: [i32; 0] = []; const B: i32 = A[1]; //~^ ERROR constant evaluation error -//~| ERROR E0080 //~| index out of bounds: the len is 0 but the index is 1 fn main() { diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 3182ffa73b08d..53077d74ce50d 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -13,16 +13,11 @@ pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 //~| ERROR const_err //~| ERROR const_err -//~| ERROR E0080 pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 -//~| ERROR E0080 pub const C: u8 = 200u8 * 4; //~ ERROR E0080 -//~| ERROR E0080 pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080 -//~| ERROR E0080 pub const E: u8 = [5u8][1]; //~^ ERROR E0080 -//~| ERROR E0080 fn main() { let _a = A; diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 5dd8651005df8..d72097848feaa 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -14,19 +14,12 @@ pub const A: i8 = -std::i8::MIN; //~^ ERROR E0080 //~| ERROR const_err //~| ERROR const_err -//~| ERROR constant evaluation error -//~| ERROR constant evaluation error -//~| ERROR constant evaluation error -//~| ERROR E0080 pub const B: i8 = A; //~^ ERROR E0080 -//~| ERROR E0080 pub const C: u8 = A as u8; //~^ ERROR E0080 -//~| ERROR E0080 pub const D: i8 = 50 - A; //~^ ERROR E0080 -//~| ERROR E0080 fn main() { let _ = (A, B, C, D); diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index b0cf639cd762f..8bd759b6d3735 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -23,9 +23,7 @@ fn black_box(_: T) { // Make sure that the two uses get two errors. const FOO: u8 = [5u8][1]; //~^ ERROR constant evaluation error -//~| ERROR constant evaluation error //~| index out of bounds: the len is 1 but the index is 1 -//~| ERROR E0080 fn main() { black_box((FOO, FOO)); diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index d715847e03fe3..25787b7bb4b92 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -22,65 +22,49 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( i8::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( i16::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( i32::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( i64::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( u8::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow u16::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow u32::MIN - 1, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to subtract with overflow ( u64::MIN - 1, + //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index f6463900eeb53..d8332757b642b 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -22,65 +22,49 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( i8::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( i16::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( i32::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( i64::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( u8::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow u16::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow u32::MAX + 1, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to add with overflow ( u64::MAX + 1, + //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index 8665b9d97a84d..2a8e4dc2c34fe 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -22,65 +22,49 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( i8::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I16: (i16,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( i16::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I32: (i32,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( i32::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_I64: (i64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( i64::MIN * 2, + //~^ ERROR constant evaluation error ); const VALS_U8: (u8,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( u8::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U16: (u16,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow u16::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U32: (u32,) = ( - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow u32::MAX * 2, + //~^ ERROR constant evaluation error ); const VALS_U64: (u64,) = - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error - //~| attempt to multiply with overflow ( u64::MAX * 2, + //~^ ERROR constant evaluation error ); fn main() { diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index cb884313f3373..179ea9e853f3a 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -13,7 +13,6 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; //~^ ERROR constant evaluation error [E0080] -//~| ERROR constant evaluation error [E0080] //~| index out of bounds: the len is 3 but the index is 5 fn main() { From 253ac3f255d8e0cc3b2a7c26987aa8192600afd9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 15:35:43 +0100 Subject: [PATCH 114/115] Report a best guess span if no stack is available anymore --- src/librustc_mir/interpret/const_eval.rs | 7 ++++--- src/librustc_mir/interpret/eval_context.rs | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index b864e64fa742f..d3802b4fb3056 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -24,7 +24,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { debug!("mk_borrowck_eval_cx: {:?}", instance); let param_env = tcx.param_env(instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( instance, @@ -42,7 +42,8 @@ pub fn mk_eval_cx<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> { debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); + let span = tcx.def_span(instance.def_id()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); let mir = ecx.load_mir(instance.def)?; // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( @@ -93,10 +94,10 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { debug!("eval_body: {:?}, {:?}", cid, param_env); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); // we start out with the best span we have // and try improving it down the road when more information is available let mut span = tcx.def_span(cid.instance.def_id()); + let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), mir.map(|mir| mir.span).unwrap_or(span)); let res = (|| { let mut mir = match mir { Some(mir) => mir, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e4f816f93c458..74cad7cdb513c 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -45,6 +45,11 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// This prevents infinite loops and huge computations from freezing up const eval. /// Remove once halting problem is solved. pub(crate) steps_remaining: usize, + + /// The span that is used if no more stack frames are available + /// + /// This happens after successful evaluation when the result is inspected + root_span: codemap::Span, } /// A stack frame. @@ -186,6 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M param_env: ty::ParamEnv<'tcx>, machine: M, memory_data: M::MemoryData, + root_span: codemap::Span, ) -> Self { EvalContext { machine, @@ -195,6 +201,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), steps_remaining: tcx.sess.const_eval_step_limit.get(), + root_span, } } @@ -1590,12 +1597,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }; frames.push(FrameInfo { span, location }); } - let frame = self.frame(); - let bb = &frame.mir.basic_blocks()[frame.block]; - let span = if let Some(stmt) = bb.statements.get(frame.stmt) { - stmt.source_info.span + let span = if let Some(frame) = self.stack().last() { + let bb = &frame.mir.basic_blocks()[frame.block]; + if let Some(stmt) = bb.statements.get(frame.stmt) { + stmt.source_info.span + } else { + bb.terminator().source_info.span + } } else { - bb.terminator().source_info.span + self.root_span }; trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); (frames, span) From c14d33a67eae71097a9cc3fc714b415988f0628d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 18:33:59 +0100 Subject: [PATCH 115/115] Report tcx errors with the span of the currently evaluating statement --- src/librustc_mir/interpret/const_eval.rs | 9 +-- src/librustc_mir/interpret/eval_context.rs | 64 ++++++------------- src/librustc_mir/interpret/memory.rs | 7 +- src/librustc_mir/interpret/place.rs | 4 +- src/librustc_mir/interpret/step.rs | 4 ++ src/librustc_mir/interpret/terminator/mod.rs | 11 ++-- src/librustc_mir/interpret/traits.rs | 5 +- src/test/ui/infinite-recursion-const-fn.rs | 4 +- .../ui/infinite-recursion-const-fn.stderr | 10 +-- 9 files changed, 48 insertions(+), 70 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index d3802b4fb3056..ec5d254694c72 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -24,7 +24,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { debug!("mk_borrowck_eval_cx: {:?}", instance); let param_env = tcx.param_env(instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( instance, @@ -43,7 +43,7 @@ pub fn mk_eval_cx<'a, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> { debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); let span = tcx.def_span(instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); let mir = ecx.load_mir(instance.def)?; // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( @@ -96,8 +96,9 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( debug!("eval_body: {:?}, {:?}", cid, param_env); // we start out with the best span we have // and try improving it down the road when more information is available - let mut span = tcx.def_span(cid.instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), mir.map(|mir| mir.span).unwrap_or(span)); + let span = tcx.def_span(cid.instance.def_id()); + let mut span = mir.map(|mir| mir.span).unwrap_or(span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); let res = (|| { let mut mir = match mir { Some(mir) => mir, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 74cad7cdb513c..ec12c499a8fa4 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -5,13 +5,13 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc::mir; -use rustc::traits::Reveal; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; -use rustc::ty::subst::{Subst, Substs, Kind}; +use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::TyCtxtAt; use rustc_data_structures::indexed_vec::Idx; use rustc::middle::const_val::FrameInfo; -use syntax::codemap::{self, DUMMY_SP, Span}; +use syntax::codemap::{self, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, @@ -27,7 +27,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { pub machine: M, /// The results of the type checker, from rustc. - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>, /// Bounds in scope for polymorphic evaluations. pub param_env: ty::ParamEnv<'tcx>, @@ -45,11 +45,6 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// This prevents infinite loops and huge computations from freezing up const eval. /// Remove once halting problem is solved. pub(crate) steps_remaining: usize, - - /// The span that is used if no more stack frames are available - /// - /// This happens after successful evaluation when the result is inspected - root_span: codemap::Span, } /// A stack frame. @@ -154,7 +149,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.tcx + *self.tcx } } @@ -162,7 +157,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> { - self.tcx + *self.tcx } } @@ -187,11 +182,10 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf> impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn new( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, machine: M, memory_data: M::MemoryData, - root_span: codemap::Span, ) -> Self { EvalContext { machine, @@ -201,7 +195,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), steps_remaining: tcx.sess.const_eval_step_limit.get(), - root_span, } } @@ -255,7 +248,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> { let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); ty::Instance::resolve( - self.tcx, + *self.tcx, self.param_env, def_id, substs, @@ -263,7 +256,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, self.param_env, DUMMY_SP) + ty.is_sized(*self.tcx, self.param_env, self.tcx.span) } pub fn load_mir( @@ -290,7 +283,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M // miri doesn't care about lifetimes, and will choke on some crazy ones // let's simply get rid of them let without_lifetimes = self.tcx.erase_regions(&ty); - let substituted = without_lifetimes.subst(self.tcx, substs); + let substituted = without_lifetimes.subst(*self.tcx, substs); let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted); substituted } @@ -721,7 +714,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ty::TyClosure(def_id, substs) => { let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); let instance = ty::Instance::resolve_closure( - self.tcx, + *self.tcx, def_id, substs, ty::ClosureKind::FnOnce, @@ -744,8 +737,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let place = self.eval_place(place)?; let discr_val = self.read_discriminant_value(place, ty)?; if let ty::TyAdt(adt_def, _) = ty.sty { - trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::>()); - if adt_def.discriminants(self.tcx).all(|v| { + trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::>()); + if adt_def.discriminants(*self.tcx).all(|v| { discr_val != v.val }) { @@ -793,7 +786,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> { use rustc::mir::Operand::*; - let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs()); + let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs()); match *op { // FIXME: do some more logic on `move` to invalidate the old location Copy(ref place) | @@ -901,7 +894,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } layout::Variants::Tagged { .. } => { let discr_val = dest_ty.ty_adt_def().unwrap() - .discriminant_for_variant(self.tcx, variant_index) + .discriminant_for_variant(*self.tcx, variant_index) .val; let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; @@ -1408,7 +1401,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } (_, &ty::TyDynamic(ref data, _)) => { let trait_ref = data.principal().unwrap().with_self_ty( - self.tcx, + *self.tcx, src_pointee_ty, ); let trait_ref = self.tcx.erase_regions(&trait_ref); @@ -1597,18 +1590,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }; frames.push(FrameInfo { span, location }); } - let span = if let Some(frame) = self.stack().last() { - let bb = &frame.mir.basic_blocks()[frame.block]; - if let Some(stmt) = bb.statements.get(frame.stmt) { - stmt.source_info.span - } else { - bb.terminator().source_info.span - } - } else { - self.root_span - }; trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); - (frames, span) + (frames, self.tcx.span) } pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { @@ -1656,7 +1639,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }); trace!("reporting const eval failure at {:?}", span); let mut err = if as_err { - ::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error") + ::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error") } else { let node_id = self .stack() @@ -1718,14 +1701,3 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> { return Ok(old); } } - -// TODO(solson): Upstream these methods into rustc::ty::layout. - -pub fn resolve_drop_in_place<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[Kind::from(ty)]); - ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap() -} diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 7252308c17070..6efa80505ae01 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -2,7 +2,8 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::{ptr, io}; -use rustc::ty::{Instance, TyCtxt}; +use rustc::ty::Instance; +use rustc::ty::maps::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; @@ -51,11 +52,11 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// The current stack frame. Used to check accesses against locks. pub cur_frame: usize, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>, } impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { + pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { Memory { data, alloc_kind: HashMap::new(), diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4ca68068728d7..d27de3ef6bfc4 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { extra: PlaceExtra::None, } } else { - let instance = ty::Instance::mono(self.tcx, static_.def_id); + let instance = ty::Instance::mono(*self.tcx, static_.def_id); let cid = GlobalId { instance, promoted: None @@ -445,7 +445,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { self.monomorphize( - place.ty(self.mir(), self.tcx).to_ty(self.tcx), + place.ty(self.mir(), *self.tcx).to_ty(*self.tcx), self.substs(), ) } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 94fe3d1c67b8f..54fd364d3f820 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -51,6 +51,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { // Some statements (e.g. box) push new stack frames. We have to record the stack frame number // *before* executing the statement. let frame_idx = self.cur_frame(); + self.tcx.span = stmt.source_info.span; + self.memory.tcx.span = stmt.source_info.span; match stmt.kind { Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, @@ -99,6 +101,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { trace!("{:?}", terminator.kind); + self.tcx.span = terminator.source_info.span; + self.memory.tcx.span = terminator.source_info.span; self.eval_terminator(terminator)?; if !self.stack.is_empty() { trace!("// {:?}", self.frame().block); diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 783755ea553ce..1e51d4ecbb851 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -5,8 +5,7 @@ use syntax::codemap::Span; use syntax::abi::Abi; use rustc::mir::interpret::{EvalResult, PrimVal, Value}; -use super::{EvalContext, eval_context, - Place, Machine, ValTy}; +use super::{EvalContext, Place, Machine, ValTy}; use rustc_data_structures::indexed_vec::Idx; use interpret::memory::HasMemory; @@ -72,10 +71,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { ty::TyFnPtr(sig) => { let fn_ptr = self.value_to_primval(func)?.to_ptr()?; let instance = self.memory.get_fn(fn_ptr)?; - let instance_ty = instance.ty(self.tcx); + let instance_ty = instance.ty(*self.tcx); match instance_ty.sty { ty::TyFnDef(..) => { - let real_sig = instance_ty.fn_sig(self.tcx); + let real_sig = instance_ty.fn_sig(*self.tcx); let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig); if !self.check_sig_compat(sig, real_sig)? { @@ -88,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } ty::TyFnDef(def_id, substs) => ( self.resolve(def_id, substs)?, - func.ty.fn_sig(self.tcx), + func.ty.fn_sig(*self.tcx), ), _ => { let msg = format!("can't handle callee of type {:?}", func.ty); @@ -117,7 +116,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let ty = self.tcx.trans_apply_param_substs(self.substs(), &ty); trace!("TerminatorKind::drop: {:?}, type {}", location, ty); - let instance = eval_context::resolve_drop_in_place(self.tcx, ty); + let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty); self.drop_place( place, instance, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 03b215fa0b8ea..c67cf1c84bf0b 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -3,8 +3,7 @@ use rustc::ty::layout::{Size, Align, LayoutOf}; use syntax::ast::Mutability; use rustc::mir::interpret::{PrimVal, Value, MemoryPointer, EvalResult}; -use super::{EvalContext, eval_context, - Machine}; +use super::{EvalContext, Machine}; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -34,7 +33,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { None, )?; - let drop = eval_context::resolve_drop_in_place(self.tcx, ty); + let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty); let drop = self.memory.create_fn_alloc(drop); self.memory.write_ptr_sized_unsigned(vtable, ptr_align, PrimVal::Ptr(drop))?; diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs index 51de304405a0a..f98074bc554bb 100644 --- a/src/test/ui/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -11,8 +11,8 @@ //https://github.com/rust-lang/rust/issues/31364 #![feature(const_fn)] -const fn a() -> usize { b() } -const fn b() -> usize { a() } //~ ERROR constant evaluation error +const fn a() -> usize { b() } //~ ERROR constant evaluation error +const fn b() -> usize { a() } const ARR: [i32; a()] = [5; 6]; fn main(){} diff --git a/src/test/ui/infinite-recursion-const-fn.stderr b/src/test/ui/infinite-recursion-const-fn.stderr index 68fb2cf1da5e5..bd447710f3328 100644 --- a/src/test/ui/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite-recursion-const-fn.stderr @@ -1,12 +1,14 @@ error[E0080]: constant evaluation error - --> $DIR/infinite-recursion-const-fn.rs:15:25 + --> $DIR/infinite-recursion-const-fn.rs:14:25 | -14 | const fn a() -> usize { b() } - | --- inside call to `b` -15 | const fn b() -> usize { a() } //~ ERROR constant evaluation error +14 | const fn a() -> usize { b() } //~ ERROR constant evaluation error | ^^^ | | | reached the configured maximum number of stack frames + | inside call to `b` +15 | const fn b() -> usize { a() } + | --- + | | | inside call to `a` | inside call to `a` | inside call to `a`