From 28572d2c1fae5ab4c6bcade0c1a9fa485da0ec61 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:28:27 +0100 Subject: [PATCH] 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 | 72 -- 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 | 34 +- src/librustc_mir/hair/cx/mod.rs | 172 +---- 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 | 113 +-- 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 - 53 files changed, 630 insertions(+), 2067 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 4d802491c96..08a42e61ea0 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -338,53 +338,10 @@ fn hash_stable(&self, 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 b68b7dc6c06..a951265d458 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -20,6 +20,12 @@ use session::config::Epoch; use syntax::codemap::Span; +declare_lint! { + pub EXCEEDING_BITSHIFTS, + Deny, + "shift exceeds the type's number of bits" +} + declare_lint! { pub CONST_ERR, Warn, @@ -263,6 +269,12 @@ Epoch::Epoch2018 } +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)] @@ -271,6 +283,8 @@ 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 cf322010e05..dd99305809c 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -18,9 +18,7 @@ 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 @@ #[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 @@ pub fn unwrap_u64(&self) -> u64 { } 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 d35cbd0027f..d8994351418 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -33,7 +33,6 @@ 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}; @@ -1539,12 +1538,8 @@ pub fn function_handle<'a>( 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 }) }, @@ -1877,21 +1872,6 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 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), } @@ -1918,7 +1898,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 17926eeec00..ebd78467c3b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -54,7 +54,7 @@ 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 rustc_data_structures::sync::Lrc; use std::any::Any; @@ -909,7 +909,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. @@ -959,20 +959,17 @@ pub fn get_cached( 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, @@ -2099,11 +2096,7 @@ pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'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 07920c58271..5dc78d84da8 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -19,8 +19,6 @@ use errors::DiagnosticBuilder; use syntax_pos::Span; -use rustc_const_math::ConstInt; - use hir; #[derive(Clone, Copy, Debug)] @@ -188,8 +186,6 @@ pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { 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 60bf4afc2fc..f067789771c 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 @@ fn add_region(&mut self, r: ty::Region) { 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 1577e78d81e..8c955bf340e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1836,9 +1836,6 @@ pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) 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))), .. @@ -1889,10 +1886,6 @@ pub fn discriminant_for_variant(&self, 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 bac78508993..2cbe9da88b5 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -483,7 +483,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. @@ -491,9 +490,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 80250949b0b..ad66cbd9eab 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -13,7 +13,7 @@ //! hand, though we've recently added some macros (e.g., //! `BraceStructLiftImpl!`) to help with the tedium. -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; @@ -1410,54 +1410,7 @@ fn super_visit_with>(&self, visitor: &mut V) -> bool { 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)) } @@ -1466,25 +1419,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) 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 6ad2901ce3a..6ae0d520e54 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -765,7 +765,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { 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 4ef7706c45e..722fdfe773a 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 443e0e857a7..49ae79ae9c9 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; @@ -217,29 +217,7 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'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 63d1f146825..5e2792ee641 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -27,7 +27,6 @@ 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; @@ -1166,9 +1165,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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 54457eacbf2..943de121118 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1088,6 +1088,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 62ac898337c..831d4fc755f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -682,78 +682,6 @@ fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { } } -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::Paren(..) | - 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 79f3ff9f19f..e941f2e4e1c 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -43,7 +43,6 @@ extern crate syntax_pos; use rustc::lint; -use rustc::middle; use rustc::session; use rustc::util; @@ -107,7 +106,6 @@ macro_rules! add_lint_group { UnusedParens, UnusedImportBraces, AnonymousParameters, - IllegalFloatLiteralPattern, UnusedDocComment, ); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 926aa2a7241..be7f1152ea4 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -14,9 +14,6 @@ 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}; @@ -43,12 +40,6 @@ "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, @@ -70,8 +61,7 @@ pub fn new() -> TypeLimits { impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { lint_array!(UNUSED_COMPARISONS, - OVERFLOWING_LITERALS, - EXCEEDING_BITSHIFTS) + OVERFLOWING_LITERALS) } } @@ -90,59 +80,6 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { 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 { @@ -301,28 +238,6 @@ fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { } } - 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 1663cab0a59..77c3eed9e44 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -281,8 +281,7 @@ fn specialized_decode(&mut self) -> Result { 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 @@ fn specialized_decode(&mut self) -> Result { 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 @@ fn specialized_decode(&mut self) -> Result { 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 1e1baba2bac..f5631f5fab9 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -199,26 +199,21 @@ fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Se // 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 5955d0ca59a..182ed529619 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 @@ fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) { // 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)) => { @@ -1044,11 +1043,8 @@ fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { }, .. }) => 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 b5b8f8d7e78..ca6e7c2c415 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -204,11 +204,7 @@ fn expr_as_rvalue(&mut self, 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 @@ fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'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 @@ fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'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 fafdee5b1e1..30c70ac30a7 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -299,7 +299,6 @@ pub fn perform_test(&mut self, 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 @@ pub fn perform_test(&mut self, .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 efb36720118..78c7004ef60 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 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'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 9ebbc111628..2057b0a5b4f 100644 --- a/src/librustc_mir/const_eval/_match.rs +++ b/src/librustc_mir/const_eval/_match.rs @@ -15,8 +15,6 @@ 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 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt 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 @@ fn lower_byte_str_pattern<'p>(&mut self, pat: &'p Pattern<'tcx>) -> Vec<&'p Patt 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 00000000000..70435c16ff7 --- /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 58fe40d12be..370b8681ba6 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.features().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 27356c2b082..f47dc61c27c 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -14,5 +14,6 @@ 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 48822c506ae..48438e7dbfd 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::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 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'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 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'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 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { }) .collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) + self.lower_variant_or_leaf(def, pat.span, ty, subpatterns) } }; @@ -610,6 +618,7 @@ fn slice_or_array_pattern( fn lower_variant_or_leaf( &mut self, def: Def, + span: Span, ty: Ty<'tcx>, subpatterns: Vec>) -> PatternKind<'tcx> @@ -640,7 +649,13 @@ fn lower_variant_or_leaf( PatternKind::Leaf { subpatterns: subpatterns } } - _ => bug!() + _ => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span, + kind: ErrKind::NonConstPath, + })); + PatternKind::Wild + } } } @@ -660,18 +675,13 @@ fn lower_path(&mut self, 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 @@ fn lower_path(&mut self, } } } - _ => self.lower_variant_or_leaf(def, ty, vec![]), + _ => self.lower_variant_or_leaf(def, span, ty, vec![]), }; Pattern { @@ -690,68 +700,51 @@ fn lower_path(&mut self, } 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 @@ 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(_) => { - 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 @@ fn const_to_pat( 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 @@ fn const_to_pat( 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 @@ fn const_to_pat( }; FieldPattern { field, - pattern: self.const_to_pat(instance, val, span), + pattern: self.const_to_pat(instance, val, id, span), } }).collect() } @@ -862,7 +849,6 @@ fn const_to_pat( 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 @@ fn const_to_pat( }; 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 d71298fb1a6..f2533276645 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -325,6 +325,24 @@ struct X { 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 198e55358e7..e65f8f3f683 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -637,7 +637,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 }), }, @@ -677,28 +677,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) @@ -706,13 +684,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 7ebed0bbddb..6fda4703d1c 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -25,7 +25,7 @@ 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; @@ -119,11 +119,7 @@ pub fn usize_literal(&mut self, value: u64) -> Literal<'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 @@ pub fn unit_ty(&mut self) -> Ty<'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 @@ pub fn true_literal(&mut self) -> Literal<'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 @@ pub fn const_eval_literal( ) -> 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 @@ pub fn const_eval_literal( }) }; - 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 @@ pub fn trait_method(&mut self, 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 3a9149b44bb..6929bccaa95 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -5,17 +5,13 @@ 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 f37fb3072b5..63939f7e038 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -241,39 +241,16 @@ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { } 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 a6ebdd45968..ba894a1728a 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ 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 c5e4eeab867..4a2b4547cb0 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -118,10 +118,14 @@ pub fn try_read_place( 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 @@ fn try_read_place_projection( }; 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 11dded1d3f0..ae790971ec8 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -16,7 +16,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_const_math::ConstUsize; use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -444,12 +444,8 @@ fn make_clone_call( 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 @@ fn make_usize(&self, value: u64) -> Box> { 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, }) @@ -752,12 +746,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 9eca343cb5e..2e8dd623d74 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -19,6 +19,7 @@ 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 @@ fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'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 ec3edb1e068..0ff73569433 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -68,7 +68,6 @@ use rustc::ty::subst::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 @@ fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'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 ca7f573b58a..e39f5412355 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 @@ fn run_pass<'a, 'tcx>(&self, }, 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 77ef2c20117..2ad1580f75d 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -950,11 +950,7 @@ fn constant_usize(&self, val: u16) -> Operand<'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(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 420e8c4aad2..013bc07d8e9 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::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 rustc_data_structures::sync::Lrc; 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 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) { 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,54 +178,6 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) { 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)) => { - let mut err = struct_span_err!( - self.tcx.sess, - start.span, - E0030, - "lower range bound must be less than or equal to upper" - ); - err.span_label(start.span, "lower bound larger than upper bound"); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note("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."); - } - err.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, _) => { @@ -313,30 +226,6 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) { 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 184fab778c6..7a54fc72d53 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -31,23 +31,6 @@ ``` "##, */ -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. @@ -228,24 +211,6 @@ fn foo() {} "##, -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 c88e39d7824..da10fcffb4c 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -119,7 +119,6 @@ fn visit_terminator_kind(&mut self, }), 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 5bd5f19a57c..66173cfef92 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 @@ pub fn new(llval: ValueRef, ty: Ty<'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 @@ pub fn from_constval(cx: &CodegenCx<'a, '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 @@ pub fn from_constval(cx: &CodegenCx<'a, '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 @@ pub fn from_constval(cx: &CodegenCx<'a, '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 5ed35e8203c..595ae463ab0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -533,7 +533,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 e3548d74071..74121e3a420 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 aa075023064..f01fd1fd8f1 100644 --- a/src/test/compile-fail/issue-39559-2.rs +++ b/src/test/compile-fail/issue-39559-2.rs @@ -22,7 +22,9 @@ fn dim() -> usize { 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 191b867e7a8..823ece2bdca 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 3e51550d1fa..e94d1ff7793 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 55934997583..f7cf8a68d56 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 679be9ce219..fd888b659f1 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 720e15991c0..dc220bd1cc9 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 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 @@ 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 -- 2.44.0