From 918b6d763319863fb53c5b7bceebc14ad5fb4024 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 16 Jan 2018 09:24:38 +0100 Subject: [PATCH] Produce instead of pointers --- src/libcore/cmp.rs | 4 +- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/middle/const_val.rs | 39 +- src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/mem_categorization.rs | 3 +- src/librustc/mir/interpret/value.rs | 10 + src/librustc/mir/mod.rs | 80 ++++- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 14 +- src/librustc/ty/context.rs | 39 +- src/librustc/ty/error.rs | 11 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/maps/config.rs | 1 + src/librustc/ty/maps/keys.rs | 1 + src/librustc/ty/maps/on_disk_cache.rs | 9 +- src/librustc/ty/mod.rs | 28 ++ src/librustc/ty/relate.rs | 9 + src/librustc/ty/structural_impls.rs | 55 +++ src/librustc/ty/util.rs | 2 + src/librustc/util/ppaux.rs | 4 + src/librustc_const_eval/_match.rs | 180 ++++++++-- src/librustc_const_eval/eval.rs | 180 +++++----- src/librustc_const_eval/pattern.rs | 337 +++++++++++------- src/librustc_data_structures/stable_hasher.rs | 8 + src/librustc_lint/types.rs | 11 + src/librustc_metadata/decoder.rs | 38 +- src/librustc_metadata/encoder.rs | 14 +- .../borrow_check/nll/type_check/mod.rs | 47 ++- src/librustc_mir/build/expr/as_rvalue.rs | 21 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 69 +++- src/librustc_mir/build/misc.rs | 19 +- src/librustc_mir/hair/cx/expr.rs | 46 ++- src/librustc_mir/hair/cx/mod.rs | 178 ++++++++- src/librustc_mir/interpret/const_eval.rs | 153 ++++++-- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/operator.rs | 5 + src/librustc_mir/interpret/place.rs | 43 ++- src/librustc_mir/interpret/terminator/mod.rs | 4 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_mir/shim.rs | 29 +- src/librustc_mir/transform/generator.rs | 9 +- src/librustc_mir/transform/inline.rs | 7 + src/librustc_mir/transform/qualify_consts.rs | 2 +- .../transform/simplify_branches.rs | 4 +- src/librustc_mir/util/elaborate_drops.rs | 15 +- src/librustc_passes/consts.rs | 23 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/analyze.rs | 19 +- src/librustc_trans/mir/block.rs | 9 +- src/librustc_trans/mir/constant.rs | 110 ++++-- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/op.rs | 8 +- src/librustc_typeck/collect.rs | 16 +- src/librustc_typeck/lib.rs | 1 + src/test/mir-opt/end_region_2.rs | 2 +- src/test/mir-opt/end_region_3.rs | 2 +- src/test/mir-opt/end_region_9.rs | 2 +- src/test/mir-opt/end_region_cyclic.rs | 2 +- src/test/mir-opt/issue-38669.rs | 2 +- src/test/mir-opt/match_false_edges.rs | 10 +- src/test/mir-opt/nll/region-liveness-basic.rs | 2 +- src/test/mir-opt/simplify_if.rs | 2 +- src/test/ui/const-eval-overflow-2.rs | 3 +- src/test/ui/const-eval-overflow-4.rs | 3 +- src/test/ui/const-eval/issue-43197.rs | 2 - src/test/ui/const-expr-addr-operator.rs | 3 +- src/test/ui/const-fn-error.rs | 13 +- src/test/ui/const-fn-error.stderr | 14 + .../ui/const-len-underflow-separate-spans.rs | 3 +- .../ui/const-pattern-not-const-evaluable.rs | 4 +- src/test/ui/feature-gate-const-indexing.rs | 3 +- src/test/ui/issue-38875/issue_38875.rs | 1 + src/test/ui/union/union-const-eval.rs | 9 +- 80 files changed, 1497 insertions(+), 533 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b98470449827..6602643dc510 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,6 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` +#[cfg_attr(not(stage0), lang = "ord")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -596,7 +597,8 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[lang = "ord"] +#[cfg_attr(stage0, lang = "ord")] +#[cfg_attr(not(stage0), lang = "partial_ord")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ed46296389da..15e1d38be695 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,6 +63,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; +use mir; use ich::Fingerprint; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 589890947cd5..cf322010e05c 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use rustc_const_math::*; -use mir::interpret::Value; +use mir::interpret::{Value, PrimVal}; use graphviz::IntoCow; use errors::DiagnosticBuilder; @@ -39,7 +39,7 @@ pub enum ConstVal<'tcx> { Function(DefId, &'tcx Substs<'tcx>), Aggregate(ConstAggregate<'tcx>), Unevaluated(DefId, &'tcx Substs<'tcx>), - /// A miri value, currently only produced if old ctfe fails, but miri succeeds + /// A miri value, currently only produced if --miri is enabled Value(Value), } @@ -71,12 +71,37 @@ impl<'tcx> Decodable for ConstAggregate<'tcx> { } impl<'tcx> ConstVal<'tcx> { - pub fn to_const_int(&self) -> Option { + pub fn to_u128(&self) -> Option { match *self { - ConstVal::Integral(i) => Some(i), - ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)), - ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)), - _ => None + ConstVal::Integral(i) => i.to_u128(), + ConstVal::Bool(b) => Some(b as u128), + ConstVal::Char(ch) => Some(ch as u32 as u128), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + Some(b) + }, + _ => None, + } + } + pub fn unwrap_u64(&self) -> u64 { + match self.to_u128() { + Some(val) => { + assert_eq!(val as u64 as u128, val); + val as u64 + }, + None => bug!("expected constant u64, got {:#?}", self), + } + } + pub fn unwrap_usize<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> ConstUsize { + match *self { + ConstVal::Integral(ConstInt::Usize(i)) => i, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u64 as u128, b); + match ConstUsize::new(b as u64, tcx.sess.target.usize_ty) { + Ok(val) => val, + Err(e) => bug!("{:#?} is not a usize {:?}", self, e), + } + }, + _ => bug!("expected constant u64, got {:#?}", self), } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 447ce46ee5c5..3b37031cf461 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -280,6 +280,7 @@ language_item_table! { GeneratorTraitLangItem, "generator", gen_trait; EqTraitLangItem, "eq", eq_trait; + PartialOrdTraitLangItem, "partial_ord", partial_ord_trait; OrdTraitLangItem, "ord", ord_trait; // A number of panic-related lang items. The `panic` item corresponds to diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c532427cc9b4..1c60ae36cd33 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -913,8 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if - len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, + ty::TyArray(_, len) if len.val.to_u128() == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 8d67856c0df8..c00956c0a857 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,7 @@ #![allow(unknown_lints)] use ty::layout::{Align, HasDataLayout}; +use ty; use super::{EvalResult, MemoryPointer, PointerArithmetic}; use syntax::ast::FloatTy; @@ -36,6 +37,15 @@ pub enum Value { ByValPair(PrimVal, PrimVal), } +impl<'tcx> ty::TypeFoldable<'tcx> for Value { + fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. /// This type clears up a few APIs where having a `PrimVal` argument for something that is /// potentially an integer pointer or a pointer to an allocation was unclear. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4c1b8cb79ed1..d35cbd0027fb 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -15,7 +15,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use middle::region; -use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; +use rustc_const_math::{ConstUsize, ConstMathErr}; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; @@ -25,9 +25,11 @@ use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; use mir::visit::MirVisitable; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::TypeAndMut; use util::ppaux; use std::slice; use hir::{self, InlineAsm}; @@ -707,7 +709,7 @@ pub enum TerminatorKind<'tcx> { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [ConstInt]>, + values: Cow<'tcx, [u128]>, /// Possible branch sites. The last element of this vector is used /// for the otherwise branch, so targets.len() == values.len() + 1 @@ -858,7 +860,7 @@ impl<'tcx> Terminator<'tcx> { impl<'tcx> TerminatorKind<'tcx> { pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)]; + static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, @@ -1144,12 +1146,16 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, .. } => { + SwitchInt { ref values, switch_ty, .. } => { values.iter() - .map(|const_val| { - let mut buf = String::new(); - fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap(); - buf.into() + .map(|&u| { + let mut s = String::new(); + print_miri_value( + Value::ByVal(PrimVal::Bytes(u)), + switch_ty, + &mut s, + ).unwrap(); + s.into() }) .chain(iter::once(String::from("otherwise").into())) .collect() @@ -1533,7 +1539,12 @@ impl<'tcx> Operand<'tcx> { ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + }, ty }) }, @@ -1853,7 +1864,7 @@ impl<'tcx> Debug for Literal<'tcx> { match *self { Value { value } => { write!(fmt, "const ")?; - fmt_const_val(fmt, &value.val) + fmt_const_val(fmt, value) } Promoted { index } => { write!(fmt, "{:?}", index) @@ -1863,9 +1874,9 @@ impl<'tcx> Debug for Literal<'tcx> { } /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { +fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { use middle::const_val::ConstVal::*; - match *const_val { + match const_val.val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), Str(s) => write!(fmt, "{:?}", s), @@ -1882,7 +1893,41 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => write!(fmt, "{:?}", val), + Value(val) => print_miri_value(val, const_val.ty, fmt), + } +} + +fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { + use ty::TypeVariants::*; + use rustc_const_math::ConstFloat; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) => + write!(f, "{}", ConstFloat { bits, ty: fty }), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) => + write!(f, "{}", item_path_str(did)), + (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut { + ty: &ty::TyS { sty: TyStr, .. }, .. + })) => { + ty::tls::with(|tcx| { + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + write!(f, "{:?}", s) + }) + }, + _ => write!(f, "{:?}:{}", value, ty), } } @@ -2468,6 +2513,15 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> } } +impl<'tcx> TypeFoldable<'tcx> for Field { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with>(&self, _: &mut V) -> bool { + false + } +} + impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { Constant { diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index bbfb9c89b3fc..067c1742040b 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 0b6f1275bdb4..54d3ed38d653 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -243,12 +243,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_int(&mut self, - const_int: &ConstInt, - _: Location) { - self.super_const_int(const_int); - } - fn visit_const_usize(&mut self, const_usize: & $($mutability)* ConstUsize, _: Location) { @@ -426,13 +420,10 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { ref $($mutability)* discr, ref $($mutability)* switch_ty, - ref values, + values: _, ref targets } => { self.visit_operand(discr, source_location); self.visit_ty(switch_ty, TyContext::Location(source_location)); - for value in &values[..] { - self.visit_const_int(value, source_location); - } for &target in targets { self.visit_branch(block, target); } @@ -798,9 +789,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_int(&mut self, _const_int: &ConstInt) { - } - fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 520da34c40ac..17926eeec002 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -30,7 +30,8 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{Mir, interpret}; +use mir::{self, Mir, interpret}; +use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; @@ -1267,6 +1268,36 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_lang_items(LOCAL_CRATE) } + pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> { + let items = self.lang_items(); + let def_id = Some(def_id); + if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } + else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } + else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } + else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } + else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } + else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } + else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } + else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } + else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } + else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } + else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } + else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } + else { None } + } + pub fn stability(self) -> Lrc> { self.stability_index(LOCAL_CRATE) } @@ -2068,7 +2099,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(n)), + val: if self.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.as_u64().into()))) + } else { + ConstVal::Integral(ConstInt::Usize(n)) + }, ty: self.types.usize }))) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index be89aeebdea7..07920c58271c 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use mir::interpret::{Value, PrimVal}; use std::fmt; use syntax::abi; @@ -186,10 +187,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { - format!("array of {} elements", n) - } else { - "array".to_string() + match n.val { + ConstVal::Integral(ConstInt::Usize(n)) => + format!("array of {} elements", n), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))) => + format!("array of {} elements", n), + _ => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 93e4cd9adf88..bfaa661b2432 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_const_int().and_then(|i| i.to_u64()) { + match len.val.to_u128() { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1aa7f671ad39..35d8fb2a67ac 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -952,7 +952,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { enum StructKind { /// A tuple, closure, or univariant which cannot be coerced to unsized. AlwaysSized, - /// A univariant, the last field of which may be coerced to unsized. + /// A univariant, the last field of which fn compute_uncachedmay be coerced to unsized. MaybeUnsized, /// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag). Prefixed(Size, Align), @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.to_const_int().unwrap().to_u64().unwrap(); + let count = count.val.unwrap_u64(); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index d880b022e2f1..ef1c8a8d4fa4 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -13,6 +13,7 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::maps::queries; use ty::subst::Substs; +use mir; use std::hash::Hash; use syntax_pos::symbol::InternedString; diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b7b64c9761a8..3dd482ad1640 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -14,6 +14,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; +use mir; use std::fmt::Debug; use std::hash::Hash; diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index b18837ff35aa..77e022fe7300 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -15,7 +15,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; -use mir; +use mir::{self, interpret}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -542,6 +542,13 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + unimplemented!() + } +} + impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let tag: u8 = Decodable::decode(self)?; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be27e3d51529..1577e78d81e2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -26,6 +26,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; +use mir::interpret::{Value, PrimVal}; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits; @@ -1838,6 +1839,19 @@ impl<'a, 'gcx, 'tcx> AdtDef { Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { discr = v; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + discr = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), @@ -1879,6 +1893,20 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value = v; break; } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + trace!("discriminants: {} ({:?})", b, repr_type); + use syntax::attr::IntType; + explicit_value = match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }; + break; + } err => { if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b9927c7eeb2f..bac78508993a 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -20,6 +20,7 @@ use ty::subst::{UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeVisitor, TypeFolder}; use ty::error::{ExpectedFound, TypeError}; +use mir::interpret::{Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -483,6 +484,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { match x.val { ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), ConstVal::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(Reveal::UserFacing); @@ -492,6 +494,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { return Ok(x.to_u64().unwrap()); } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + assert_eq!(b as u64 as u128, b); + return Ok(b as u64); + } _ => {} } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 54db2d4f06be..80250949b0b4 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -890,6 +890,61 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use ty::InstanceDef::*; + Self { + substs: self.substs.fold_with(folder), + def: match self.def { + Item(did) => Item(did.fold_with(folder)), + Intrinsic(did) => Intrinsic(did.fold_with(folder)), + FnPtrShim(did, ty) => FnPtrShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + Virtual(did, i) => Virtual( + did.fold_with(folder), + i, + ), + ClosureOnceShim { call_once } => ClosureOnceShim { + call_once: call_once.fold_with(folder), + }, + DropGlue(did, ty) => DropGlue( + did.fold_with(folder), + ty.fold_with(folder), + ), + CloneShim(did, ty) => CloneShim( + did.fold_with(folder), + ty.fold_with(folder), + ), + }, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use ty::InstanceDef::*; + self.substs.visit_with(visitor) || + match self.def { + Item(did) => did.visit_with(visitor), + Intrinsic(did) => did.visit_with(visitor), + FnPtrShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + Virtual(did, _) => did.visit_with(visitor), + ClosureOnceShim { call_once } => call_once.visit_with(visitor), + DropGlue(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + CloneShim(did, ty) => { + did.visit_with(visitor) || + ty.visit_with(visitor) + }, + } + } +} + impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 785035ee5f4f..6ad2901ce3a1 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -24,6 +24,7 @@ use ty::maps::TyCtxtAt; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; +use mir::interpret::{Value, PrimVal}; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -765,6 +766,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> self.hash_discriminant_u8(&n.val); match n.val { ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), _ => bug!("arrays should not have {:?} as length", n) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index a2620da4c10c..63d1f1468251 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,6 +21,7 @@ use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, Ty use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use util::nodemap::FxHashSet; +use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -1168,6 +1169,9 @@ define_print! { ConstVal::Integral(ConstInt::Usize(sz)) => { write!(f, "{}", sz)?; } + ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { + write!(f, "{}", sz)?; + } ConstVal::Unevaluated(_def_id, substs) => { write!(f, "", &substs[..])?; } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 8e3b99f2dbfe..9e9eb4a81d03 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -28,6 +28,7 @@ use rustc::hir::RangeEnd; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::mir::Field; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::common::ErrorReported; use syntax_pos::{Span, DUMMY_SP}; @@ -195,6 +196,41 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } })).collect() } + box PatternKind::Constant { + value: &ty::Const { val: ConstVal::Value(b), ty } + } => { + match b { + Value::ByVal(PrimVal::Ptr(ptr)) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + assert_eq!(ptr.offset, 0); + // FIXME: check length + alloc.bytes.iter().map(|b| { + &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: tcx.mk_const(ty::Const { + val: ConstVal::Value(Value::ByVal( + PrimVal::Bytes(*b as u128), + )), + ty: tcx.types.u8 + }) + } + }) + }).collect() + }, + _ => bug!("not a byte str: {:?}", b), + } + } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) } }).clone() @@ -422,13 +458,17 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::TyBool => { [true, false].iter().map(|&b| { ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Bool(b), + val: if cx.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))) + } else { + ConstVal::Bool(b) + }, ty: cx.tcx.types.bool })) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + ty::TyArray(ref sub_ty, len) if len.val.to_u128().is_some() => { + let len = len.val.unwrap_u64(); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -461,7 +501,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, } fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( - _cx: &mut MatchCheckCtxt<'a, 'tcx>, + cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64 where I: Iterator> { @@ -538,6 +578,25 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); } + PatternKind::Constant { + value: &ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), + ty, + } + } => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + if is_array_ptr { + let alloc = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } + } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); @@ -581,7 +640,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { let &Matrix(ref rows) = matrix; - debug!("is_useful({:?}, {:?})", matrix, v); + debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. @@ -626,10 +685,10 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) }; - debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); + debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:?}", constructors); + debug!("is_useful - expanding constructors: {:#?}", constructors); constructors.into_iter().map(|c| is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) ).find(|result| result.is_useful()).unwrap_or(NotUseful) @@ -639,9 +698,9 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let used_ctors: Vec = rows.iter().flat_map(|row| { pat_constructors(cx, row[0], pcx).unwrap_or(vec![]) }).collect(); - debug!("used_ctors = {:?}", used_ctors); + debug!("used_ctors = {:#?}", used_ctors); let all_ctors = all_constructors(cx, pcx); - debug!("all_ctors = {:?}", all_ctors); + debug!("all_ctors = {:#?}", all_ctors); let missing_ctors: Vec = all_ctors.iter().filter(|c| { !used_ctors.contains(*c) }).cloned().collect(); @@ -669,7 +728,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}", + debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", missing_ctors, is_privately_empty, is_declared_nonexhaustive); // For privately empty and non-exhaustive enums, we work as if there were an "extra" @@ -769,7 +828,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( lty: Ty<'tcx>, witness: WitnessPreference) -> Usefulness<'tcx> { - debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty); + debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty); let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| { Pattern { @@ -821,7 +880,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { ty::TyArray(_, length) => Some(vec![ - Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) + Slice(length.val.unwrap_u64()) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -842,7 +901,7 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { - debug!("constructor_arity({:?}, {:?})", ctor, ty); + debug!("constructor_arity({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TySlice(..) | ty::TyArray(..) => match *ctor { @@ -866,12 +925,13 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor, ty: Ty<'tcx>) -> Vec> { - debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); + debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], + Single => vec![ty], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], @@ -880,6 +940,9 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, // Use T as the sub pattern type of Box. vec![substs.type_at(0)] } else { + if let ConstantValue(_) = *ctor { + return vec![]; + } adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); @@ -901,14 +964,30 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, +fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, ctor: &Constructor, prefix: &[Pattern], slice: &Option, suffix: &[Pattern]) -> Result { - let data = match *ctor { + let data: &[u8] = match *ctor { ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, + ConstantValue(&ty::Const { val: ConstVal::Value( + Value::ByVal(PrimVal::Ptr(ptr)) + ), ty }) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .as_ref() + } _ => bug!() }; @@ -928,6 +1007,12 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, return Ok(false); } }, + ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); + } + } _ => span_bug!(pat.span, "bad const u8 {:?}", value) }, _ => {} @@ -937,32 +1022,43 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(tcx: TyCtxt, span: Span, - ctor: &Constructor, +fn constructor_covered_by_range(ctor: &Constructor, from: &ConstVal, to: &ConstVal, - end: RangeEnd) + end: RangeEnd, + ty: Ty) -> Result { - let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); + trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); + let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + .map(|res| res != Ordering::Less); + let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + macro_rules! some_or_ok { + ($e:expr) => { + match $e { + Some(to) => to, + None => return Ok(false), // not char or int + } + }; + } match *ctor { ConstantValue(value) => { - let to = cmp_to(&value.val)?; + let to = some_or_ok!(cmp_to(&value.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&value.val)? && end) + Ok(some_or_ok!(cmp_from(&value.val)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = cmp_to(&to.val)?; + let to = some_or_ok!(cmp_to(&to.val)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(cmp_from(&from.val)? && end) + Ok(some_or_ok!(cmp_from(&from.val)) && end) } + Variant(_) | Single => Ok(true), _ => bug!(), } @@ -979,7 +1075,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( result[subpat.field.index()] = &subpat.pattern; } - debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, wild_patterns, result); + debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result); result } @@ -994,7 +1090,7 @@ fn patterns_for_variant<'p, 'a: 'p, 'tcx: 'a>( fn specialize<'p, 'a: 'p, 'tcx: 'a>( cx: &mut MatchCheckCtxt<'a, 'tcx>, r: &[&'p Pattern<'tcx>], - constructor: &Constructor, + constructor: &Constructor<'tcx>, wild_patterns: &[&'p Pattern<'tcx>]) -> Option>> { @@ -1031,12 +1127,32 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( None } } + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + let is_array_ptr = value.ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == cx.tcx.types.u8); + assert!(is_array_ptr); + let data_len = cx.tcx + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .unwrap() + .bytes + .len(); + if wild_patterns.len() == data_len { + Some(cx.lower_byte_str_pattern(pat)) + } else { + None + } + } _ => span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) }, _ => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included + constructor, &value.val, &value.val, RangeEnd::Included, + value.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1048,7 +1164,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() + constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -1092,7 +1208,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } } }; - debug!("specialize({:?}, {:?}) = {:?}", r[0], wild_patterns, head); + debug!("specialize({:#?}, {:#?}) = {:#?}", r[0], wild_patterns, head); head.map(|mut head| { head.extend_from_slice(&r[1 ..]); diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 2a571fa82643..58fe40d12be8 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -26,7 +26,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use rustc::hir::{self, Expr}; -use syntax_pos::Span; use std::cmp::Ordering; @@ -104,60 +103,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, hir::ExprUnary(hir::UnNeg, ref inner) => { // unary neg literals already got their sign during creation if let hir::ExprLit(ref lit) = inner.node { - use syntax::ast::*; - use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128; - const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128; - const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; - const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; - const I128_OVERFLOW: u128 = i128::min_value() as u128; - let negated = match (&lit.node, &ty.sty) { - (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | - (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - Some(I8(i8::min_value())) - }, - (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | - (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - Some(I16(i16::min_value())) - }, - (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | - (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - Some(I32(i32::min_value())) - }, - (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | - (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - Some(I64(i64::min_value())) - }, - (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | - (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { - Some(I128(i128::min_value())) - }, - (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) | - (&LitKind::Int(n, Signed(IntTy::Isize)), _) => { - match tcx.sess.target.isize_ty { - IntTy::I16 => if n == I16_OVERFLOW { - Some(Isize(Is16(i16::min_value()))) - } else { - None - }, - IntTy::I32 => if n == I32_OVERFLOW { - Some(Isize(Is32(i32::min_value()))) - } else { - None - }, - IntTy::I64 => if n == I64_OVERFLOW { - Some(Isize(Is64(i64::min_value()))) - } else { - None - }, - _ => span_bug!(e.span, "typeck error") - } - }, - _ => None + return match lit_to_const(&lit.node, tcx, ty, true) { + Ok(val) => Ok(mk_const(val)), + Err(err) => signal!(e, err), }; - if let Some(i) = negated { - return Ok(mk_const(Integral(i))); - } } mk_const(match cx.eval(inner)?.val { Float(f) => Float(-f), @@ -377,7 +326,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }; callee_cx.eval(&body.value)? }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) { + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty, false) { Ok(val) => mk_const(val), Err(err) => signal!(e, err), }, @@ -438,7 +387,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } hir::ExprRepeat(ref elem, _) => { let n = match ty.sty { - ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(), + ty::TyArray(_, n) => n.val.unwrap_u64(), _ => span_bug!(e.span, "typeck error") }; mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) @@ -447,7 +396,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { fields[index.node] } else { - signal!(base, ExpectedConstTuple); + span_bug!(base.span, "{:#?}", cx.eval(base)?.val); + //signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { @@ -557,7 +507,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { ty::TyArray(ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); if ty == tcx.types.u8 && n == b.data.len() as u64 { Ok(val) } else { @@ -583,13 +533,66 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, +pub fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut ty: Ty<'tcx>) + mut ty: Ty<'tcx>, + neg: bool) -> Result, ErrKind<'tcx>> { use syntax::ast::*; use syntax::ast::LitIntType::*; + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty)?; + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Ok(ConstVal::Value(lit)); + } + if let ty::TyAdt(adt, _) = ty.sty { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(tcx) @@ -604,26 +607,38 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, match (&ty.sty, hint) { (&ty::TyInt(ity), _) | (_, Signed(ity)) => { - Ok(Integral(ConstInt::new_signed_truncating(n as i128, + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, ity, tcx.sess.target.isize_ty))) } (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { - Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, + Ok(Integral(ConstInt::new_unsigned_truncating(n, uty, tcx.sess.target.usize_ty))) } _ => bug!() } } LitKind::Float(n, fty) => { - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::FloatUnsuffixed(n) => { let fty = match ty.sty { ty::TyFloat(fty) => fty, _ => bug!() }; - parse_float(&n.as_str(), fty).map(Float) + let mut f = parse_float(&n.as_str(), fty)?; + if neg { + f = -f; + } + Ok(Float(f)) } LitKind::Bool(b) => Ok(Bool(b)), LitKind::Char(c) => Ok(Char(c)), @@ -638,36 +653,31 @@ fn parse_float<'tcx>(num: &str, fty: ast::FloatTy) }) } -pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) - -> Result -{ - let result = match (a, b) { +pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option { + trace!("compare_const_vals: {:?}, {:?}", a, b); + use rustc::mir::interpret::{Value, PrimVal}; + match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), - (&Float(a), &Float(b)) => a.try_cmp(b).ok(), - (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), - (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), - (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)), (&Char(a), &Char(b)) => Some(a.cmp(&b)), + (&Value(Value::ByVal(PrimVal::Bytes(a))), + &Value(Value::ByVal(PrimVal::Bytes(b)))) => { + Some(if ty.is_signed() { + (a as i128).cmp(&(b as i128)) + } else { + a.cmp(&b) + }) + }, + _ if a == b => Some(Ordering::Equal), _ => None, - }; - - match result { - Some(result) => Ok(result), - None => { - // FIXME: can this ever be reached? - tcx.sess.delay_span_bug(span, - &format!("type mismatch comparing {:?} and {:?}", a, b)); - Err(ErrorReported) - } } } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn compare_lit_exprs(&self, - span: Span, a: &'tcx Expr, - b: &'tcx Expr) -> Result { + b: &'tcx Expr) -> Result, ErrorReported> { let tcx = self.tcx; + let ty = self.tables.expr_ty(a); let a = match self.eval(a) { Ok(a) => a, Err(e) => { @@ -682,6 +692,6 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { return Err(ErrorReported); } }; - compare_const_vals(tcx, span, &a.val, &b.val) + Ok(compare_const_vals(&a.val, &b.val, ty)) } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a09e2f2edd59..a2daf22c3b45 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -10,8 +10,9 @@ use eval; -use rustc::middle::const_val::{ConstEvalErr, ConstVal}; +use rustc::middle::const_val::{ConstEvalErr, ConstVal, ConstAggregate}; use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -110,22 +111,35 @@ pub enum PatternKind<'tcx> { }, } -fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { - match *value { +fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { + match value.val { ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Integral(ref i) => write!(f, "{}", i), ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Value(v) => print_miri_value(v, value.ty, f), ConstVal::Variant(_) | ConstVal::Function(..) | ConstVal::Aggregate(_) | - ConstVal::Value(_) | ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } +fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result { + use rustc::ty::TypeVariants::*; + match (value, &ty.sty) { + (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), + (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), + (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n), + (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128), + (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => + write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), + _ => bug!("{:?}: {} not printable in a pattern", value, ty), + } +} + impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -233,15 +247,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - print_const_val(&value.val, f) + print_const_val(value, f) } PatternKind::Range { lo, hi, end } => { - print_const_val(&lo.val, f)?; + print_const_val(lo, f)?; match end { RangeEnd::Included => write!(f, "...")?, RangeEnd::Excluded => write!(f, "..")?, } - print_const_val(&hi.val, f) + print_const_val(hi, f) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -362,7 +376,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } PatKind::Path(ref qpath) => { - return self.lower_path(qpath, pat.hir_id, pat.id, pat.span); + return self.lower_path(qpath, pat.hir_id, pat.span); } PatKind::Ref(ref subpattern, _) | @@ -581,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -632,7 +646,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn lower_path(&mut self, qpath: &hir::QPath, id: hir::HirId, - pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); @@ -644,29 +657,23 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { - Some((def_id, substs)) => { - // Enter the inlined constant's tables&substs temporarily. - let old_tables = self.tables; - let old_substs = self.substs; - self.tables = self.tcx.typeck_tables_of(def_id); - self.substs = substs; - let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) - } else { - self.tcx.extern_const_body(def_id).body - }; - let pat = self.lower_const_expr(&body.value, pat_id, span); - self.tables = old_tables; - self.substs = old_substs; - return pat; - } - None => { - self.errors.push(if is_associated_const { - PatternError::AssociatedConstInPattern(span) - } else { - PatternError::StaticInPattern(span) - }); + match self.tcx.at(span).const_eval(self.param_env.and((def_id, substs))) { + Ok(value) => { + if self.tcx.sess.opts.debugging_opts.miri { + if let ConstVal::Value(_) = value.val {} else { + panic!("const eval produced non-miri value: {:#?}", value); + } + } + let instance = ty::Instance::resolve( + self.tcx, + self.param_env, + def_id, + substs, + ).unwrap(); + return self.const_to_pat(instance, value, span) + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(e)); PatternKind::Wild } } @@ -682,6 +689,52 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { + if self.tcx.sess.opts.debugging_opts.miri { + return match expr.node { + hir::ExprLit(ref lit) => { + let ty = self.tables.expr_ty(expr); + match ::eval::lit_to_const(&lit.node, self.tcx, ty, false) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + }, + hir::ExprPath(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::ExprUnary(hir::UnNeg, ref expr) => { + let ty = self.tables.expr_ty(expr); + let lit = match expr.node { + hir::ExprLit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + match ::eval::lit_to_const(&lit.node, self.tcx, ty, true) { + Ok(value) => PatternKind::Constant { + value: self.tcx.mk_const(ty::Const { + ty, + val: value, + }), + }, + Err(e) => { + self.errors.push(PatternError::ConstEval(ConstEvalErr { + span: lit.span, + kind: e, + })); + PatternKind::Wild + }, + } + } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + } + } let const_cx = eval::ConstContext::new(self.tcx, self.param_env.and(self.substs), self.tables); @@ -701,118 +754,156 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_const_expr(&mut self, - expr: &'tcx hir::Expr, - pat_id: ast::NodeId, - span: Span) - -> Pattern<'tcx> { - let pat_ty = self.tables.expr_ty(expr); - debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); - match pat_ty.sty { + fn const_to_pat( + &self, + instance: ty::Instance<'tcx>, + cv: &'tcx ty::Const<'tcx>, + span: Span, + ) -> Pattern<'tcx> { + debug!("const_to_pat: cv={:#?}", cv); + let kind = match cv.ty.sty { ty::TyFloat(_) => { self.tcx.sess.span_err(span, "floating point constants cannot be used in patterns"); + PatternKind::Wild } ty::TyAdt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); + PatternKind::Wild } - ty::TyAdt(adt_def, _) => { - if !self.tcx.has_attr(adt_def.did, "structural_match") { - let msg = format!("to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - self.tcx.item_path_str(adt_def.did), - self.tcx.item_path_str(adt_def.did)); - self.tcx.sess.span_err(span, &msg); + ty::TyAdt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + let msg = format!("to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + self.tcx.item_path_str(adt_def.did), + self.tcx.item_path_str(adt_def.did)); + self.tcx.sess.span_err(span, &msg); + PatternKind::Wild + }, + ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { + match cv.val { + ConstVal::Value(val) => { + let discr = self.tcx.const_discr(self.param_env.and(( + instance, val, cv.ty + ))).unwrap(); + let variant_index = adt_def + .discriminants(self.tcx) + .position(|var| var.to_u128_unchecked() == discr) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: adt_def + .variants[variant_index] + .fields + .iter() + .enumerate() + .map(|(i, _)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect(), + } + }, + ConstVal::Variant(var_did) => { + let variant_index = adt_def + .variants + .iter() + .position(|var| var.did == var_did) + .unwrap(); + PatternKind::Variant { + adt_def, + substs, + variant_index, + subpatterns: Vec::new(), + } + } + _ => return Pattern { + span, + ty: cv.ty, + kind: Box::new(PatternKind::Constant { + value: cv, + }), + } } - } - _ => { } - } - let kind = match expr.node { - hir::ExprTup(ref exprs) => { + }, + ty::TyAdt(adt_def, _) => { + let struct_var = adt_def.struct_variant(); PatternKind::Leaf { - subpatterns: exprs.iter().enumerate().map(|(i, expr)| { + subpatterns: struct_var.fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Struct(consts)) => { + consts.iter().find(|&&(name, _)| name == f.name).unwrap().1 + }, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) + field, + pattern: self.const_to_pat(instance, val, span), } }).collect() } } - - hir::ExprCall(ref callee, ref args) => { - let qpath = match callee.node { - hir::ExprPath(ref qpath) => qpath, - _ => bug!() - }; - let ty = self.tables.node_id_to_type(callee.hir_id); - let def = self.tables.qpath_def(qpath, callee.hir_id); - match def { - Def::Fn(..) | Def::Method(..) => self.lower_lit(expr), - _ => { - let subpatterns = args.iter().enumerate().map(|(i, expr)| { - FieldPattern { - field: Field::new(i), - pattern: self.lower_const_expr(expr, pat_id, span) - } - }).collect(); - self.lower_variant_or_leaf(def, ty, subpatterns) - } + ty::TyTuple(fields, _) => { + PatternKind::Leaf { + subpatterns: (0..fields.len()).map(|i| { + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Tuple(consts)) => consts[i], + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - - hir::ExprStruct(ref qpath, ref fields, None) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - expr.span, - "struct expr without ADT type"); - } - }; - let variant_def = adt_def.variant_of_def(def); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.name.node); - let index = index.unwrap_or_else(|| { - span_bug!( - expr.span, - "no field with name {:?}", - field.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.lower_const_expr(&field.expr, pat_id, span), - } - }) - .collect(); - - self.lower_variant_or_leaf(def, pat_ty, subpatterns) - } - - hir::ExprArray(ref exprs) => { - let pats = exprs.iter() - .map(|expr| self.lower_const_expr(expr, pat_id, span)) - .collect(); - PatternKind::Array { - prefix: pats, - slice: None, - suffix: vec![] + ty::TyArray(_, n) => { + PatternKind::Leaf { + subpatterns: (0..n.val.unwrap_u64()).map(|i| { + let i = i as usize; + let field = Field::new(i); + let val = match cv.val { + ConstVal::Aggregate(ConstAggregate::Array(consts)) => consts[i], + ConstVal::Aggregate(ConstAggregate::Repeat(cv, _)) => cv, + ConstVal::Value(miri) => self.tcx.const_val_field( + self.param_env.and((instance, field, miri, cv.ty)), + ).unwrap(), + _ => bug!("{:#?} is not a valid tuple", cv), + }; + FieldPattern { + field, + pattern: self.const_to_pat(instance, val, span), + } + }).collect() } } - - hir::ExprPath(ref qpath) => { - return self.lower_path(qpath, expr.hir_id, pat_id, span); - } - - _ => self.lower_lit(expr) + _ => { + PatternKind::Constant { + value: cv, + } + }, }; Pattern { span, - ty: pat_ty, + ty: cv.ty, kind: Box::new(kind), } } diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index d82b712b5b14..70733bc6aeda 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -259,6 +259,14 @@ impl HashStable for f64 { } } +impl HashStable for ::std::cmp::Ordering { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (*self as i8).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for (T1,) { fn hash_stable(&self, ctx: &mut CTX, diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1c4bd0ff4c2e..f400ce42a904 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -16,6 +16,7 @@ use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; +use rustc::mir::interpret::{Value, PrimVal}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -122,6 +123,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { .map(|i| i >= bits) .unwrap_or(true) } + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + ty, + }) => { + if ty.is_signed() { + (b as i128) < 0 + } else { + b >= bits as u128 + } + } _ => false, } }; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3c3c489d0ff7..1663cab0a592 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -276,38 +276,54 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { const MAX1: usize = usize::max_value() - 1; - let mut interpret_interner = self.tcx.unwrap().interpret_interner.borrow_mut(); + let tcx = self.tcx; + let interpret_interner = || tcx.unwrap().interpret_interner.borrow_mut(); let pos = self.position(); - match self.read_usize()? { + match usize::decode(self)? { ::std::usize::MAX => { + let id = interpret_interner().reserve(); + let alloc_id = interpret::AllocId(id); + trace!("creating alloc id {:?} at {}", alloc_id, pos); + // insert early to allow recursive allocs + self.interpret_alloc_cache.insert(pos, alloc_id); + let allocation = interpret::Allocation::decode(self)?; - let id = interpret_interner.reserve(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); let allocation = self.tcx.unwrap().intern_const_alloc(allocation); - interpret_interner.intern_at_reserved(id, allocation); - let id = interpret::AllocId(id); - self.interpret_alloc_cache.insert(pos, id); + interpret_interner().intern_at_reserved(id, allocation); let num = usize::decode(self)?; let ptr = interpret::Pointer { primval: interpret::PrimVal::Ptr(interpret::MemoryPointer { - alloc_id: id, + alloc_id, offset: 0, }), }; for _ in 0..num { let glob = interpret::GlobalId::decode(self)?; - interpret_interner.cache(glob, ptr); + interpret_interner().cache(glob, ptr); } - Ok(id) + Ok(alloc_id) }, MAX1 => { + trace!("creating fn alloc id at {}", pos); let instance = ty::Instance::decode(self)?; - let id = interpret::AllocId(interpret_interner.create_fn_alloc(instance)); + trace!("decoded fn alloc instance: {:?}", instance); + let id = interpret::AllocId(interpret_interner().create_fn_alloc(instance)); + trace!("created fn alloc id: {:?}", id); self.interpret_alloc_cache.insert(pos, id); Ok(id) }, - shorthand => Ok(self.interpret_alloc_cache[&shorthand]), + shorthand => { + trace!("loading shorthand {}", shorthand); + if let Some(&alloc_id) = self.interpret_alloc_cache.get(&shorthand) { + return Ok(alloc_id); + } + trace!("shorthand {} not cached, loading entire allocation", shorthand); + // need to load allocation + self.with_position(shorthand, |this| interpret::AllocId::decode(this)) + }, } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 928bf0a56ae5..1e1baba2bac5 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -189,12 +189,18 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + trace!("encoding {:?} at {}", alloc_id, self.position()); if let Some(shorthand) = self.interpret_alloc_shorthands.get(alloc_id).cloned() { - return self.emit_usize(shorthand); + trace!("encoding {:?} as shorthand to {}", alloc_id, shorthand); + return shorthand.encode(self); } let start = self.position(); + // cache the allocation shorthand now, because the allocation itself might recursively + // point to itself. + self.interpret_alloc_shorthands.insert(*alloc_id, start); let interpret_interner = self.tcx.interpret_interner.borrow(); if let Some(alloc) = interpret_interner.get_alloc(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); usize::max_value().encode(self)?; alloc.encode(self)?; let globals = interpret_interner.get_globals(interpret::Pointer { @@ -208,16 +214,12 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx glob.encode(self)?; } } else if let Some(fn_instance) = interpret_interner.get_fn(alloc_id.0) { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); (usize::max_value() - 1).encode(self)?; fn_instance.encode(self)?; } else { bug!("alloc id without corresponding allocation: {}", alloc_id.0); } - let len = self.position() - start * 7; - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - assert!(len >= 64 || (start as u64) < (1 << len)); - self.interpret_alloc_shorthands.insert(*alloc_id, start); Ok(()) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index bbf4357e5b0f..5955d0ca59ad 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -26,6 +26,7 @@ use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use std::fmt; @@ -258,7 +259,24 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - if let ConstVal::Function(def_id, ..) = value.val { + let did = match value.val { + ConstVal::Function(def_id, ..) => Some(def_id), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + self.tcx() + .interpret_interner + .borrow() + .get_fn(p.alloc_id.0) + .map(|instance| instance.def_id()) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match value.ty.sty { + ty::TyFnDef(ty_def_id, _) => Some(ty_def_id), + _ => None, + } + }, + _ => None, + }; + if let Some(def_id) = did { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -436,7 +454,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ProjectionElem::Subslice { from, to } => PlaceTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) @@ -1019,13 +1037,32 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { Literal::Value { value: &ty::Const { - val: ConstVal::Function(def_id, _), - .. + val, + ty, }, .. }, .. - }) => Some(def_id) == self.tcx().lang_items().box_free_fn(), + }) => match val { + ConstVal::Function(def_id, _) => { + Some(def_id) == self.tcx().lang_items().box_free_fn() + }, + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let inst = self.tcx().interpret_interner.borrow().get_fn(p.alloc_id.0); + inst.map_or(false, |inst| { + Some(inst.def_id()) == self.tcx().lang_items().box_free_fn() + }) + }, + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => { + match ty.sty { + ty::TyFnDef(ty_def_id, _) => { + Some(ty_def_id) == self.tcx().lang_items().box_free_fn() + } + _ => false, + } + } + _ => false, + } _ => false, } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d3cc95275905..b5b8f8d7e78b 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty}; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use syntax::ast; use syntax_pos::Span; @@ -203,7 +204,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: this.hir.tcx().types.u32, literal: Literal::Value { value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(0)), + val: if this.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(ConstInt::U32(0)) + }, ty: this.hir.tcx().types.u32 }), }, @@ -401,7 +406,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.to_u128_unchecked()))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -439,7 +448,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes( + val.to_u128_unchecked() + ))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 58ce572ae8d8..229e33dcd786 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -354,7 +354,7 @@ enum TestKind<'tcx> { // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec<&'tcx ty::Const<'tcx>>, + options: Vec, indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index bdcbfc0bdd85..fafdee5b1e1b 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -24,6 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::ty::util::IntTypeExt; use rustc::mir::*; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::hir::RangeEnd; use syntax_pos::Span; use std::cmp::Ordering; @@ -112,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_place: &Place<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec<&'tcx ty::Const<'tcx>>, + options: &mut Vec, indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { @@ -128,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { indices.entry(value) .or_insert_with(|| { - options.push(value); + options.push(value.val.to_u128().expect("switching on int")); options.len() - 1 }); true @@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { target_blocks.place_back() <- if variants.contains(idx) { - values.push(discr); + values.push(discr.to_u128_unchecked()); *(targets.place_back() <- self.cfg.start_new_block()) } else { if otherwise_block.is_none() { @@ -266,9 +267,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - let ret = match options[0].val { - ConstVal::Bool(true) => vec![true_bb, false_bb], - ConstVal::Bool(false) => vec![false_bb, true_bb], + let ret = match options[0] { + 1 => vec![true_bb, false_bb], + 0 => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()), @@ -282,13 +283,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .chain(Some(otherwise)) .collect(); - let values: Vec<_> = options.iter().map(|v| - v.val.to_const_int().expect("switching on integral") - ).collect(); (targets.clone(), TerminatorKind::SwitchInt { discr: Operand::Copy(place.clone()), switch_ty, - values: From::from(values), + values: options.clone().into(), targets, }) }; @@ -300,14 +298,49 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let tcx = self.hir.tcx(); let mut val = Operand::Copy(place.clone()); + let bytes = match value.val { + ConstVal::ByteStr(bytes) => Some(bytes.data), + ConstVal::Value(Value::ByVal(PrimVal::Ptr(p))) => { + let is_array_ptr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == self.hir.tcx().types.u8); + if is_array_ptr { + self.hir + .tcx() + .interpret_interner + .borrow() + .get_alloc(p.alloc_id.0) + .map(|alloc| &alloc.bytes[..]) + } else { + None + } + }, + _ => None, + }; // If we're using b"..." as a pattern, we need to insert an // unsizing coercion, as the byte string has the type &[u8; N]. // // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val { - let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64); + let expect = if let Some(bytes) = bytes { + let tcx = self.hir.tcx(); + + // Unsize the place to &[u8], too, if necessary. + if let ty::TyRef(region, mt) = ty.sty { + if let ty::TyArray(_, _) = mt.ty.sty { + ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8)); + let val_slice = self.temp(ty, test.span); + self.cfg.push_assign(block, source_info, &val_slice, + Rvalue::Cast(CastKind::Unsize, val, ty)); + val = Operand::Move(val_slice); + } + } + + assert!(ty.is_slice()); + + let array_ty = tcx.mk_array(tcx.types.u8, bytes.len() as u64); let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value @@ -324,11 +357,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq. let fail = self.cfg.start_new_block(); - let ty = expect.ty(&self.local_decls, tcx); - if let ty::TyRef(_, mt) = ty.sty { - assert!(ty.is_slice()); + let str_or_bytestr = ty + .builtin_deref(true, ty::NoPreference) + .and_then(|tam| match tam.ty.sty { + ty::TyStr => Some(tam.ty), + ty::TySlice(inner) if inner == self.hir.tcx().types.u8 => Some(tam.ty), + _ => None, + }); + if let Some(ty) = str_or_bytestr { let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); - let ty = mt.ty; let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]); let bool_ty = self.hir.bool_ty(); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a3350cb1671d..efb367201189 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -16,6 +16,7 @@ use build::Builder; use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax::ast; @@ -62,7 +63,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyChar => { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Char('\0'), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Char('\0') + }, ty }) } @@ -83,7 +88,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } @@ -104,7 +113,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Literal::Value { value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Integral(val), + val: if self.hir.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Integral(val) + }, ty }) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 00ab2e459952..198e55358e7e 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,7 +10,6 @@ use hair::*; use rustc_data_structures::indexed_vec::Idx; -use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; @@ -18,6 +17,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; use rustc::hir::def_id::LocalDefId; @@ -100,7 +100,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Deref { arg: expr.to_ref() } } Adjust::Deref(Some(deref)) => { - let call = deref.method_call(cx.tcx, expr.ty); + let call = deref.method_call(cx.tcx(), expr.ty); expr = Expr { temp_lifetime, @@ -314,7 +314,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, + hir::ExprLit(ref lit) => ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + }, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tables().is_method_call(expr) { @@ -400,9 +402,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, if cx.tables().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) } else { - // FIXME runtime-overflow - if let hir::ExprLit(_) = arg.node { - ExprKind::Literal { literal: cx.const_eval_literal(expr) } + if let hir::ExprLit(ref lit) = arg.node { + ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + } } else { ExprKind::Unary { op: UnOp::Neg, @@ -509,8 +512,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, - Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), + Ok(cv) => cv.val.unwrap_usize(cx.tcx), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; @@ -634,8 +636,8 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + value: cx.tcx().mk_const(ty::Const { + val: const_fn(cx.tcx, def_id, substs), ty }), }, @@ -675,6 +677,28 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) } } +fn const_fn<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, +) -> ConstVal<'tcx> { + if tcx.sess.opts.debugging_opts.miri { + /* + let inst = ty::Instance::new(def_id, substs); + let ptr = tcx + .interpret_interner + .borrow_mut() + .create_fn_alloc(inst); + let ptr = MemoryPointer::new(AllocId(ptr), 0); + ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) + */ + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, substs) + } +} + fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, def: Def) @@ -688,7 +712,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, substs), + val: const_fn(cx.tcx.global_tcx(), def_id, substs), ty: cx.tables().node_id_to_type(expr.hir_id) }), }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 44c413561175..7ebed0bbddbf 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -17,7 +17,6 @@ use hair::*; use rustc::middle::const_val::{ConstEvalErr, ConstVal}; -use rustc_const_eval::ConstContext; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -32,6 +31,7 @@ use syntax::symbol::Symbol; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::{Value, PrimVal}; #[derive(Clone)] pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -119,7 +119,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { Ok(val) => { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(val)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))) + } else { + ConstVal::Integral(ConstInt::Usize(val)) + }, ty: self.tcx.types.usize }) } @@ -139,7 +143,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn true_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(true), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))) + } else { + ConstVal::Bool(true) + }, ty: self.tcx.types.bool }) } @@ -148,20 +156,161 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Bool(false), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))) + } else { + ConstVal::Bool(false) + }, ty: self.tcx.types.bool }) } } - pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { + pub fn const_eval_literal( + &mut self, + lit: &'tcx ast::LitKind, + ty: Ty<'tcx>, + sp: Span, + neg: bool, + ) -> Literal<'tcx> { let tcx = self.tcx.global_tcx(); - let const_cx = ConstContext::new(tcx, - self.param_env.and(self.identity_substs), - self.tables()); - match const_cx.eval(tcx.hir.expect_expr(e.id)) { - Ok(value) => Literal::Value { value }, - Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") + + let mut repr_ty = ty; + if let ty::TyAdt(adt, _) = ty.sty { + if adt.is_enum() { + repr_ty = adt.repr.discr_type().to_ty(tcx) + } + } + + let parse_float = |num: &str, fty| -> ConstFloat { + ConstFloat::from_str(num, fty).unwrap_or_else(|_| { + // FIXME(#31407) this is only necessary because float parsing is buggy + tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); + }) + }; + + if tcx.sess.opts.debugging_opts.miri { + use rustc::mir::interpret::*; + let lit = match *lit { + LitKind::Str(ref s, _) => { + let s = s.as_str(); + let id = self.tcx.allocate_cached(s.as_bytes()); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByValPair( + PrimVal::Ptr(ptr), + PrimVal::from_u128(s.len() as u128), + ) + }, + LitKind::ByteStr(ref data) => { + let id = self.tcx.allocate_cached(data); + let ptr = MemoryPointer::new(AllocId(id), 0); + Value::ByVal(PrimVal::Ptr(ptr)) + }, + LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Int(n, _) if neg => { + let n = n as i128; + let n = n.overflowing_neg().0; + Value::ByVal(PrimVal::Bytes(n as u128)) + }, + LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)), + LitKind::Float(n, fty) => { + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let n = n.as_str(); + let mut f = parse_float(&n, fty); + if neg { + f = -f; + } + let bits = f.bits; + Value::ByVal(PrimVal::Bytes(bits)) + } + LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + }; + return Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: Value(lit), + ty, + }), + }; + } + + use syntax::ast::*; + use syntax::ast::LitIntType::*; + use rustc::middle::const_val::ConstVal::*; + use rustc_const_math::ConstInt::*; + use rustc::ty::util::IntTypeExt; + use rustc::middle::const_val::ByteArray; + use rustc_const_math::ConstFloat; + + let lit = match *lit { + LitKind::Str(ref s, _) => Ok(Str(s.as_str())), + LitKind::ByteStr(ref data) => { + let data: &'tcx [u8] = data; + Ok(ByteStr(ByteArray { data })) + }, + LitKind::Byte(n) => Ok(Integral(U8(n))), + LitKind::Int(n, hint) => { + match (&repr_ty.sty, hint) { + (&ty::TyInt(ity), _) | + (_, Signed(ity)) => { + let mut n = n as i128; + if neg { + n = n.overflowing_neg().0; + } + Ok(Integral(ConstInt::new_signed_truncating(n, + ity, tcx.sess.target.isize_ty))) + } + (&ty::TyUint(uty), _) | + (_, Unsigned(uty)) => { + Ok(Integral(ConstInt::new_unsigned_truncating(n, + uty, tcx.sess.target.usize_ty))) + } + _ => bug!() + } + } + LitKind::Float(n, fty) => { + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::FloatUnsuffixed(n) => { + let fty = match ty.sty { + ty::TyFloat(fty) => fty, + _ => bug!() + }; + let mut f = parse_float(&n.as_str(), fty); + if neg { + f = -f; + } + Ok(ConstVal::Float(f)) + } + LitKind::Bool(b) => Ok(Bool(b)), + LitKind::Char(c) => Ok(Char(c)), + }; + + match lit { + Ok(value) => Literal::Value { value: self.tcx.mk_const(ty::Const { + val: value, + ty, + }) }, + Err(kind) => self.fatal_const_eval_err(&ConstEvalErr { + span: sp, + kind, + }, sp, "expression") } } @@ -203,7 +352,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { return (method_ty, Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Function(item.def_id, substs), + val: if self.tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(item.def_id, substs) + }, ty: method_ty }), }); diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index bc555368f0f5..ec8215fb64c3 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -13,14 +13,13 @@ use syntax::ast::Mutability; use syntax::codemap::Span; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; -use super::{Place, EvalContext, StackPopCleanup, ValTy}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, HasMemory}; use rustc_const_math::ConstInt; use std::fmt; use std::error::Error; - pub fn mk_eval_cx<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, @@ -45,7 +44,7 @@ pub fn eval_body<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", instance, param_env); let limits = super::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); @@ -82,7 +81,13 @@ pub fn eval_body<'a, 'tcx>( while ecx.step()? {} } let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); - Ok((MemoryPointer::new(alloc, 0).into(), instance_ty)) + let align = ecx.layout_of(instance_ty)?.align; + let ptr = MemoryPointer::new(alloc, 0).into(); + let value = match ecx.try_read_value(ptr, align, instance_ty)? { + Some(val) => val, + _ => Value::ByRef(ptr, align), + }; + Ok((value, ptr, instance_ty)) } pub fn eval_body_as_integer<'a, 'tcx>( @@ -90,11 +95,9 @@ pub fn eval_body_as_integer<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, instance: Instance<'tcx>, ) -> EvalResult<'tcx, ConstInt> { - let ptr_ty = eval_body(tcx, instance, param_env); - let (ptr, ty) = ptr_ty?; - let ecx = mk_eval_cx(tcx, instance, param_env)?; - let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { - Some(Value::ByVal(prim)) => prim.to_bytes()?, + let (value, _, ty) = eval_body(tcx, instance, param_env)?; + let prim = match value { + Value::ByVal(prim) => prim.to_bytes()?, _ => return err!(TypeNotPrimitive(ty)), }; use syntax::ast::{IntTy, UintTy}; @@ -133,7 +136,7 @@ pub struct CompileTimeEvaluator; impl<'tcx> Into> for ConstEvalError { fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() + EvalErrorKind::MachineError(self.to_string()).into() } } @@ -193,7 +196,6 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { let mir = match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -302,6 +304,70 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { } } +pub fn const_val_field<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::middle::const_val::EvalResult<'tcx> { + trace!("const_val_field: {:#?}", key); + match const_val_field_inner(tcx, key) { + Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(field), + ty, + })), + Err(err) => Err(ConstEvalErr { + span: tcx.def_span(key.value.0.def_id()), + kind: err.into(), + }), + } +} + +fn const_val_field_inner<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, mir::Field, Value, Ty<'tcx>)>, +) -> ::rustc::mir::interpret::EvalResult<'tcx, (Value, Ty<'tcx>)> { + trace!("const_val_field: {:#?}", key); + let (instance, field, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (mut field, ty) = match value { + Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, field, ty)?.expect("const_val_field on non-field"), + Value::ByRef(ptr, align) => { + let place = Place::from_primval_ptr(ptr, align); + let layout = ecx.layout_of(ty)?; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + (Value::ByRef(ptr, align), layout.ty) + } + }; + if let Value::ByRef(ptr, align) = field { + if let Some(val) = ecx.try_read_value(ptr, align, ty)? { + field = val; + } + } + Ok((field, ty)) +} + +pub fn const_discr<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, Value, Ty<'tcx>)>, +) -> EvalResult<'tcx, u128> { + trace!("const_discr: {:#?}", key); + let (instance, value, ty) = key.value; + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let (ptr, align) = match value { + Value::ByValPair(..) | Value::ByVal(_) => { + let layout = ecx.layout_of(ty)?; + use super::MemoryKind; + let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr: Pointer = ptr.into(); + ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; + (ptr, layout.align) + }, + Value::ByRef(ptr, align) => (ptr, align), + }; + let place = Place::from_primval_ptr(ptr, align); + ecx.read_discriminant_value(place, ty) +} + pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, @@ -340,35 +406,48 @@ pub fn const_eval_provider<'a, 'tcx>( return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) } + + let instance = ty::Instance::new(def_id, substs); + if tcx.sess.opts.debugging_opts.miri { + return match ::interpret::eval_body(tcx, instance, key.param_env) { + Ok((miri_value, _, miri_ty)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(miri_value), + ty: miri_ty, + })), + Err(err) => { + Err(ConstEvalErr { span: body.value.span, kind: err.into() }) + } + }; + } + trace!("running old const eval"); let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); trace!("old const eval produced {:?}", old_result); - if tcx.sess.opts.debugging_opts.miri { - let instance = ty::Instance::new(def_id, substs); - trace!("const eval instance: {:?}, {:?}", instance, key.param_env); - let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); - match (miri_result, old_result) { - (Err(err), Ok(ok)) => { - trace!("miri failed, ctfe returned {:?}", ok); - tcx.sess.span_warn( - tcx.def_span(key.value.0), - "miri failed to eval, while ctfe succeeded", - ); - let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let () = unwrap_miri(&ecx, Err(err)); - Ok(ok) - }, - (_, Err(err)) => Err(err), - (Ok((miri_val, miri_ty)), Ok(ctfe)) => { - let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let layout = ecx.layout_of(miri_ty).unwrap(); - let miri_place = Place::from_primval_ptr(miri_val, layout.align); - check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); - Ok(ctfe) - } + trace!("const eval instance: {:?}, {:?}", instance, key.param_env); + let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); + match (miri_result, old_result) { + (Err(err), Ok(ok)) => { + trace!("miri failed, ctfe returned {:?}", ok); + tcx.sess.span_warn( + tcx.def_span(key.value.0), + "miri failed to eval, while ctfe succeeded", + ); + let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let () = unwrap_miri(&ecx, Err(err)); + Ok(ok) + }, + (Ok((value, _, ty)), Err(_)) => Ok(tcx.mk_const(ty::Const { + val: ConstVal::Value(value), + ty, + })), + (Err(_), Err(err)) => Err(err), + (Ok((_, miri_ptr, miri_ty)), Ok(ctfe)) => { + let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); + let layout = ecx.layout_of(miri_ty).unwrap(); + let miri_place = Place::from_primval_ptr(miri_ptr, layout.align); + check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); + Ok(ctfe) } - } else { - old_result } } @@ -451,7 +530,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( } }, TyArray(elem_ty, n) => { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e9e8ccd03b10..f37fb3072b58 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), + ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -1386,7 +1386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = self.into_ptr(src)?; // u64 cast is from usize to u64, which is always good let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), + value: ptr.to_value_with_len(length.val.unwrap_u64() ), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index fee62c8a82e2..a6ebdd45968f 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,6 +18,6 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; -pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider}; +pub use self::const_eval::{eval_body_as_integer, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, const_discr}; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 6ab1aec38b86..b20540b00cea 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -248,10 +248,15 @@ pub fn unary_op<'tcx>( (Not, I64) => !(bytes as i64) as u128, (Not, I128) => !(bytes as i128) as u128, + (Neg, I8) if bytes == i8::min_value() as u128 => return err!(OverflowingMath), (Neg, I8) => -(bytes as i8) as u128, + (Neg, I16) if bytes == i16::min_value() as u128 => return err!(OverflowingMath), (Neg, I16) => -(bytes as i16) as u128, + (Neg, I32) if bytes == i32::min_value() as u128 => return err!(OverflowingMath), (Neg, I32) => -(bytes as i32) as u128, + (Neg, I64) if bytes == i64::min_value() as u128 => return err!(OverflowingMath), (Neg, I64) => -(bytes as i64) as u128, + (Neg, I128) if bytes == i128::min_value() as u128 => return err!(OverflowingMath), (Neg, I128) => -(bytes as i128) as u128, (Neg, F32) => (-bytes_to_f32(bytes)).bits, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 701b7a07ac98..c5e4eeab8670 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -71,7 +71,7 @@ impl<'tcx> Place { pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), + ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), ty::TySlice(elem) => { match self { @@ -115,6 +115,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } + pub fn read_field( + &self, + base: Value, + field: mir::Field, + base_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> { + let base_layout = self.layout_of(base_ty)?; + let field_index = field.index(); + let field = base_layout.field(self, field_index)?; + let offset = base_layout.fields.offset(field_index); + match base { + // the field covers the entire type + Value::ByValPair(..) | + Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))), + // split fat pointers, 2 element tuples, ... + Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { + let val = [a, b][field_index]; + Ok(Some((Value::ByVal(val), field.ty))) + }, + _ => Ok(None), + } + } + fn try_read_place_projection( &mut self, proj: &mir::PlaceProjection<'tcx>, @@ -126,23 +149,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let base_ty = self.place_ty(&proj.base); match proj.elem { - Field(field, _) => { - let base_layout = self.layout_of(base_ty)?; - let field_index = field.index(); - let field = base_layout.field(&self, field_index)?; - let offset = base_layout.fields.offset(field_index); - match base { - // the field covers the entire type - Value::ByValPair(..) | - Value::ByVal(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some(base)), - // split fat pointers, 2 element tuples, ... - Value::ByValPair(a, b) if base_layout.fields.count() == 2 => { - let val = [a, b][field_index]; - Ok(Some(Value::ByVal(val))) - }, - _ => Ok(None), - } - }, + Field(field, _) => Ok(self.read_field(base, field, base_ty)?.map(|(f, _)| f)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 606bda51edb1..c18cf6d9f96b 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -45,8 +45,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Branch to the `otherwise` case by default, if no match is found. let mut target_block = targets[targets.len() - 1]; - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); + for (index, &const_int) in values.iter().enumerate() { + let prim = PrimVal::Bytes(const_int); if discr_prim.to_bytes()? == prim.to_bytes()? { target_block = targets[index]; break; diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 38b8ffc6b9c8..1f7f1237ba78 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -314,7 +314,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.push('['); self.push_type_name(inner_type, output); write!(output, "; {}", - len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap(); + len.val.unwrap_u64()).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index e6ebdd3d6c16..11dded1d3f07 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; use rustc_const_math::{ConstInt, ConstUsize}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +304,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), ty::TyArray(ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len = len.val.unwrap_u64(); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -443,7 +444,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ty: func_ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(self.def_id, substs), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(self.def_id, substs) + }, ty: func_ty }), }, @@ -501,13 +507,20 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { } fn make_usize(&self, value: u64) -> Box> { - let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap(); box Constant { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::Usize(value)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))) + } else { + let value = ConstUsize::new( + value, + self.tcx.sess.target.usize_ty, + ).unwrap(); + ConstVal::Integral(ConstInt::Usize(value)) + }, ty: self.tcx.types.usize, }) } @@ -739,8 +752,12 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty, literal: Literal::Value { value: tcx.mk_const(ty::Const { - val: ConstVal::Function(def_id, - Substs::identity_for_item(tcx, def_id)), + val: if tcx.sess.opts.debugging_opts.miri { + // ZST function type + ConstVal::Value(Value::ByVal(PrimVal::Undef)) + } else { + ConstVal::Function(def_id, Substs::identity_for_item(tcx, def_id)) + }, ty }), }, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 04ebaa031fe5..ec3edb1e0680 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -80,6 +80,7 @@ use transform::simplify; use transform::no_landing_pads::no_landing_pads; use dataflow::{do_dataflow, DebugFormatted, state_for_location}; use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; +use rustc::mir::interpret::{Value, PrimVal}; pub struct StateTransform; @@ -181,7 +182,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { ty: self.tcx.types.u32, literal: Literal::Value { value: self.tcx.mk_const(ty::Const { - val: ConstVal::Integral(ConstInt::U32(state_disc)), + val: if self.tcx.sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))) + } else { + ConstVal::Integral(ConstInt::U32(state_disc)) + }, ty: self.tcx.types.u32 }), }, @@ -534,7 +539,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let switch = TerminatorKind::SwitchInt { discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)), switch_ty: tcx.types.u32, - values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::>()), + values: Cow::from(cases.iter().map(|&(i, _)| i.into()).collect::>()), targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), }; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 64c702b99cdb..b8a0e0f89073 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -207,6 +207,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } + // Do not inline {u,i}128 lang items, trans const eval depends + // on detecting calls to these lang items and intercepting them + if tcx.is_binop_lang_item(callsite.callee).is_some() { + debug!(" not inlining 128bit integer lang item"); + return false; + } + let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee); let hinted = match trans_fn_attrs.inline { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 8f5831270d6e..88618122e4f1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { _ => false } } else if let ty::TyArray(_, len) = ty.sty { - len.val.to_const_int().unwrap().to_u64().unwrap() == 0 && + len.val.unwrap_u64() == 0 && self.mode == Mode::Fn } else { false diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 41089f567bd7..ca7f573b58a4 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -40,10 +40,10 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(ref constint) = value.val.to_const_int() { + if let Some(constint) = value.val.to_u128() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (v, t) in values.iter().zip(targets.iter()) { + for (&v, t) in values.iter().zip(targets.iter()) { if v == constint { ret = TerminatorKind::Goto { target: *t }; break; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e2feb0ed3905..77ef2c20117f 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,13 +11,14 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::{ConstInt, ConstVal}; +use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use util::patch::MirPatch; +use rustc::mir::interpret::{Value, PrimVal}; use std::{iter, u32}; @@ -425,7 +426,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> variant_path, &adt.variants[variant_index], substs); - values.push(discr); + values.push(discr.to_u128().unwrap()); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original // drop ladder, because this breaks the @@ -480,7 +481,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn adt_switch_block(&mut self, adt: &'tcx ty::AdtDef, blocks: Vec, - values: &[ConstInt], + values: &[u128], succ: BasicBlock, unwind: Unwind) -> BasicBlock { @@ -803,7 +804,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_const_int().and_then(|v| v.to_u64())), + ety, size.val.to_u128().map(|i| i as u64)), ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -949,7 +950,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty: self.tcx().types.usize, literal: Literal::Value { value: self.tcx().mk_const(ty::Const { - val: ConstVal::Integral(self.tcx().const_usize(val)), + val: if self.tcx().sess.opts.debugging_opts.miri { + ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))) + } else { + ConstVal::Integral(self.tcx().const_usize(val)) + }, ty: self.tcx().types.usize }) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b93b759fdf86..8153c3c8493f 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -129,6 +129,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } fn check_const_eval(&self, expr: &'gcx hir::Expr) { + if self.tcx.sess.opts.debugging_opts.miri { + return; + } if let Err(err) = self.const_cx().eval(expr) { match err.kind { UnimplementedConstVal(_) => {} @@ -220,23 +223,24 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(lit); } PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) => {} - Ok(Ordering::Equal) | - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) => {} + Ok(Some(Ordering::Equal)) | + Ok(Some(Ordering::Greater)) => { span_err!(self.tcx.sess, start.span, E0579, "lower range bound must be less than upper"); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } PatKind::Range(ref start, ref end, RangeEnd::Included) => { - match self.const_cx().compare_lit_exprs(p.span, start, end) { - Ok(Ordering::Less) | - Ok(Ordering::Equal) => {} - Ok(Ordering::Greater) => { + match self.const_cx().compare_lit_exprs(start, end) { + Ok(Some(Ordering::Less)) | + Ok(Some(Ordering::Equal)) => {} + Ok(Some(Ordering::Greater)) => { let mut err = struct_span_err!( self.tcx.sess, start.span, @@ -252,6 +256,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } err.emit(); } + Ok(None) => bug!("ranges must be char or int"), Err(ErrorReported) => {} } } @@ -308,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.promotable = false; } - if self.in_fn && self.promotable { + if self.in_fn && self.promotable && !self.tcx.sess.opts.debugging_opts.miri { match self.const_cx().eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 3708f6f6ec4f..314b8c59df5a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -195,7 +195,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, len.val.unwrap_u64()) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2c430d03c968..0fe425fb7ea1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -276,7 +276,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.to_const_int().unwrap().to_u64().unwrap() as c_longlong + len.val.unwrap_u64() as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6490d109f293..a88eb9ae3547 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap())); + output.push_str(&format!("; {}", len.val.unwrap_u64())); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index f683703ce6d5..c88e39d7824c 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::mir::traversal; +use rustc::mir::interpret::{Value, PrimVal}; use rustc::ty; use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; @@ -109,15 +110,26 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { - match *kind { + let check = match *kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(box mir::Constant { literal: Literal::Value { - value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. + value: &ty::Const { val, ty }, .. }, .. }), ref args, .. - } if Some(def_id) == self.fx.cx.tcx.lang_items().box_free_fn() => { + } => match val { + ConstVal::Function(def_id, _) => Some((def_id, args)), + ConstVal::Value(Value::ByVal(PrimVal::Undef)) => match ty.sty { + ty::TyFnDef(did, _) => Some((did, args)), + _ => None, + }, + _ => None, + } + _ => None, + }; + if let Some((def_id, args)) = check { + if Some(def_id) == self.cx.ccx.tcx().lang_items().box_free_fn() { // box_free(x) shares with `drop x` the property that it // is not guaranteed to be statically dominated by the // definition of x, so x must always be in an alloca. @@ -125,7 +137,6 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { self.visit_place(place, PlaceContext::Drop, location); } } - _ => {} } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index bb2a7840faee..239300c1ecf4 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::traits; @@ -196,17 +196,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if switch_ty == bx.tcx().types.bool { let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [ConstInt::U8(0)] = values[..] { + if let [0] = values[..] { bx.cond_br(discr.immediate(), llfalse, lltrue); } else { + assert_eq!(&values[..], &[1]); bx.cond_br(discr.immediate(), lltrue, llfalse); } } else { let (otherwise, targets) = targets.split_last().unwrap(); let switch = bx.switch(discr.immediate(), llblock(self, *otherwise), values.len()); - for (value, target) in values.iter().zip(targets) { - let val = Const::from_constint(bx.cx, value); + for (&value, target) in values.iter().zip(targets) { + let val = Const::from_bytes(bx.cx, value, switch_ty); let llbb = llblock(self, *target); bx.add_case(switch, val.llval, llbb) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c853230b15ab..5bd5f19a57c6 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::traits; use rustc::mir; +use rustc::mir::interpret::{Value as MiriValue, PrimVal}; use rustc::mir::tcx::PlaceTy; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -38,6 +39,7 @@ use value::Value; use syntax_pos::Span; use syntax::ast; +use syntax::symbol::Symbol; use std::fmt; use std::ptr; @@ -81,12 +83,46 @@ impl<'a, 'tcx> Const<'tcx> { Const { llval: llval, ty: ty } } + pub fn from_bytes(ccx: &CrateContext<'a, 'tcx>, b: u128, ty: Ty<'tcx>) -> Const<'tcx> { + let llval = match ty.sty { + ty::TyInt(ast::IntTy::I128) | + ty::TyUint(ast::UintTy::U128) => C_uint_big(Type::i128(ccx), b), + ty::TyInt(i) => C_int(Type::int_from_ty(ccx, i), b as i128 as i64), + ty::TyUint(u) => C_uint(Type::uint_from_ty(ccx, u), b as u64), + ty::TyBool => { + assert!(b <= 1); + C_bool(ccx, b == 1) + }, + ty::TyChar => { + assert_eq!(b as u32 as u128, b); + let c = b as u32; + assert!(::std::char::from_u32(c).is_some()); + C_uint(Type::char(ccx), c as u64) + }, + ty::TyFloat(fty) => { + let llty = ccx.layout_of(ty).llvm_type(ccx); + let bits = match fty { + ast::FloatTy::F32 => C_u32(ccx, b as u32), + ast::FloatTy::F64 => C_u64(ccx, b as u64), + }; + consts::bitcast(bits, llty) + }, + ty::TyAdt(adt, _) if adt.is_enum() => { + use rustc::ty::util::IntTypeExt; + Const::from_bytes(ccx, b, adt.repr.discr_type().to_ty(ccx.tcx())).llval + }, + _ => bug!("from_bytes({}, {})", b, ty), + }; + Const { llval, ty } + } + /// Translate ConstVal into a LLVM constant value. pub fn from_constval(cx: &CodegenCx<'a, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>) -> Const<'tcx> { let llty = cx.layout_of(ty).llvm_type(cx); + trace!("from_constval: {:#?}: {}", cv, ty); let val = match *cv { ConstVal::Float(v) => { let bits = match v.ty { @@ -108,7 +144,41 @@ impl<'a, 'tcx> Const<'tcx> { ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Value(_) => unimplemented!(), + ConstVal::Value(MiriValue::ByRef(..)) => unimplemented!("{:#?}:{}", cv, ty), + ConstVal::Value(MiriValue::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) => { + match ty.sty { + ty::TyRef(_, ref tam) => match tam.ty.sty { + ty::TyStr => {}, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + }, + _ => unimplemented!("non-str fat pointer: {:?}: {:?}", ptr, ty), + } + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + C_str_slice(ccx, Symbol::intern(s).as_str()) + }, + ConstVal::Value(MiriValue::ByValPair(..)) => unimplemented!(), + ConstVal::Value(MiriValue::ByVal(PrimVal::Bytes(b))) => + return Const::from_bytes(ccx, b, ty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Undef)) => C_undef(llty), + ConstVal::Value(MiriValue::ByVal(PrimVal::Ptr(ptr))) => { + let alloc = ccx + .tcx() + .interpret_interner + .borrow() + .get_alloc(ptr.alloc_id.0) + .expect("miri alloc not found"); + let data = &alloc.bytes[(ptr.offset as usize)..]; + consts::addr_of(ccx, C_bytes(ccx, data), ccx.align_of(ty), "byte_str") + } }; assert!(!ty.has_erasable_regions()); @@ -239,7 +309,7 @@ impl<'tcx> ConstPlace<'tcx> { pub fn len<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef { match self.ty.sty { ty::TyArray(_, n) => { - C_usize(cx, n.val.to_const_int().unwrap().to_u64().unwrap()) + C_usize(cx, n.val.unwrap_u64()) } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); @@ -316,7 +386,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let tcx = self.cx.tcx; let mut bb = mir::START_BLOCK; - // Make sure to evaluate all statemenets to + // Make sure to evaluate all statements to // report as many errors as we possibly can. let mut failure = Ok(()); @@ -392,6 +462,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "calling {:?} (of type {}) in constant", func, fn_ty) }; + trace!("trans const fn call {:?}, {:?}, {:#?}", func, fn_ty, args); let mut arg_vals = IndexVec::with_capacity(args.len()); for arg in args { @@ -419,7 +490,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } _ => span_bug!(span, "{:?} in constant", terminator.kind) } - } else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) { + } else if let Some((op, is_checked)) = tcx.is_binop_lang_item(def_id) { (||{ assert_eq!(arg_vals.len(), 2); let rhs = arg_vals.pop().unwrap()?; @@ -470,37 +541,6 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } - fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> { - let tcx = self.cx.tcx; - let items = tcx.lang_items(); - let def_id = Some(def_id); - if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) } - else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) } - else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) } - else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) } - else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) } - else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) } - else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) } - else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) } - else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) } - else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) } - else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) } - else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) } - else { None } - } - fn store(&mut self, dest: &mir::Place<'tcx>, value: Result, ConstEvalErr<'tcx>>, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 34ac44cec025..b0cb7de824eb 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + let n = n.val.unwrap_u64(); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a261c12bcdd9..eb02c05fd395 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let size = size.val.unwrap_u64(); let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0f59973eab25..26b964933102 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4029,9 +4029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_const_int().and_then(|count| { - count.to_u64().map(|count| count <= 1) - }).unwrap_or(false); + let zero_or_one = count.val.to_u128().map_or(false, |count| count <= 1); if !zero_or_one { // For [foo, ..n] where n > 1, `foo` must have // Copy type: diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 12791107ebb4..47a229cbd3b5 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -447,10 +447,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::BiBitOr => ("bitor", lang.bitor_trait()), hir::BiShl => ("shl", lang.shl_trait()), hir::BiShr => ("shr", lang.shr_trait()), - hir::BiLt => ("lt", lang.ord_trait()), - hir::BiLe => ("le", lang.ord_trait()), - hir::BiGe => ("ge", lang.ord_trait()), - hir::BiGt => ("gt", lang.ord_trait()), + hir::BiLt => ("lt", lang.partial_ord_trait()), + hir::BiLe => ("le", lang.partial_ord_trait()), + hir::BiGe => ("ge", lang.partial_ord_trait()), + hir::BiGt => ("gt", lang.partial_ord_trait()), hir::BiEq => ("eq", lang.eq_trait()), hir::BiNe => ("ne", lang.eq_trait()), hir::BiAnd | hir::BiOr => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1a7d8bb56780..5ed35e8203ce 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -37,8 +37,8 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; -use rustc::util::nodemap::FxHashSet; -use util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::mir::interpret::{Value, PrimVal}; use rustc_const_math::ConstInt; @@ -534,6 +534,18 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match result { Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), + Ok(&ty::Const { + val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), + .. + }) => { + use syntax::attr::IntType; + Some(match repr_type { + IntType::SignedInt(int_type) => ConstInt::new_signed( + b as i128, int_type, tcx.sess.target.isize_ty).unwrap(), + IntType::UnsignedInt(uint_type) => ConstInt::new_unsigned( + b, uint_type, tcx.sess.target.usize_ty).unwrap(), + }) + } _ => None } } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d9bd96b0d769..40385cabf566 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,6 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(i128_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index d6084d5a6da9..3fb5621c8ae3 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -49,7 +49,7 @@ fn main() { // _3 = &'23_1rs _2; // StorageLive(_5); // _5 = _2; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 46548f1cce97..070bde8e3c3e 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -51,7 +51,7 @@ fn main() { // _3 = &'26_1rs _1; // StorageLive(_5); // _5 = _1; -// switchInt(move _5) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _5) -> [false: bb5, otherwise: bb4]; // } // bb3: { // ... diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index 0f1d714cc6fd..6d9a27eeeb45 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -72,7 +72,7 @@ fn main() { // bb4: { // StorageLive(_7); // _7 = _1; -// switchInt(move _7) -> [0u8: bb6, otherwise: bb5]; +// switchInt(move _7) -> [false: bb6, otherwise: bb5]; // } // bb5: { // _0 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 2a82e2675b67..83425a72f459 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -103,7 +103,7 @@ fn query() -> bool { true } // _11 = const query() -> [return: bb6, unwind: bb3]; // } // bb6: { -// switchInt(move _11) -> [0u8: bb8, otherwise: bb7]; +// switchInt(move _11) -> [false: bb8, otherwise: bb7]; // } // bb7: { // _0 = (); diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 3151c0643079..a9eea26f4664 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -36,7 +36,7 @@ fn main() { // bb3: { // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [0u8: bb5, otherwise: bb4]; +// switchInt(move _4) -> [false: bb5, otherwise: bb4]; // } // bb4: { // _0 = (); diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index ba1b54d59f69..596bb4e115df 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -93,7 +93,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -157,7 +157,7 @@ fn main() { // _7 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { // end of guard -// switchInt(move _7) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _7) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb6, imaginary: bb5]; @@ -219,7 +219,7 @@ fn main() { // _9 = const guard() -> [return: bb10, unwind: bb1]; // } // bb10: { //end of guard -// switchInt(move _9) -> [0u8: bb11, otherwise: bb2]; +// switchInt(move _9) -> [false: bb11, otherwise: bb2]; // } // bb11: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb5]; @@ -239,8 +239,8 @@ fn main() { // _11 = const guard2(move _12) -> [return: bb14, unwind: bb1]; // } // bb14: { // end of guard2 -// StorageDead(_12); -// switchInt(move _11) -> [0u8: bb15, otherwise: bb3]; +// StorageDead(_11); +// switchInt(move _11) -> [false: bb15, otherwise: bb3]; // } // bb15: { // to pre_binding4 // falseEdges -> [real: bb7, imaginary: bb7]; diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index e9834305550c..19d733d4f6b6 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -41,7 +41,7 @@ fn main() { // | Live variables on entry to bb2[0]: [_1, _3] // _2 = &'_#2r _1[_3]; // | Live variables on entry to bb2[1]: [_2] -// switchInt(const true) -> [0u8: bb4, otherwise: bb3]; +// switchInt(const true) -> [false: bb4, otherwise: bb3]; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index 35786643648e..52d5892e6560 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,7 +17,7 @@ fn main() { // END RUST SOURCE // START rustc.main.SimplifyBranches-initial.before.mir // bb0: { -// switchInt(const false) -> [0u8: bb3, otherwise: bb2]; +// switchInt(const false) -> [false: bb3, otherwise: bb2]; // } // END rustc.main.SimplifyBranches-initial.before.mir // START rustc.main.SimplifyBranches-initial.after.mir diff --git a/src/test/ui/const-eval-overflow-2.rs b/src/test/ui/const-eval-overflow-2.rs index 6b7f631ff4c8..885edb55ed86 100644 --- a/src/test/ui/const-eval-overflow-2.rs +++ b/src/test/ui/const-eval-overflow-2.rs @@ -19,8 +19,7 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error -//~| attempt to negate with overflow +//~^ ERROR E0080 fn main() { match -128i8 { diff --git a/src/test/ui/const-eval-overflow-4.rs b/src/test/ui/const-eval-overflow-4.rs index 4423fdec33a8..a1b90f623cda 100644 --- a/src/test/ui/const-eval-overflow-4.rs +++ b/src/test/ui/const-eval-overflow-4.rs @@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR constant evaluation error - //~| WARNING constant evaluation error + //~^ ERROR E0080 = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index 85ab2a005216..86c5e873df86 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -16,8 +16,6 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0-1; //~ ERROR constant evaluation error - //~^ WARN constant evaluation error const Y: u32 = foo(0-1); //~ ERROR constant evaluation error - //~^ WARN constant evaluation error println!("{} {}", X, Y); } diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs index 24d4457f01d7..bfd6a4090649 100644 --- a/src/test/ui/const-expr-addr-operator.rs +++ b/src/test/ui/const-expr-addr-operator.rs @@ -9,10 +9,11 @@ // except according to those terms. // Encountered while testing #44614. +// must-compile-successfully pub fn main() { // Constant of generic type (int) - const X: &'static u32 = &22; //~ ERROR constant evaluation error + const X: &'static u32 = &22; assert_eq!(0, match &22 { X => 0, _ => 1, diff --git a/src/test/ui/const-fn-error.rs b/src/test/ui/const-fn-error.rs index ac1c2fe5432d..dc1526a7079d 100644 --- a/src/test/ui/const-fn-error.rs +++ b/src/test/ui/const-fn-error.rs @@ -13,17 +13,18 @@ const X : usize = 2; const fn f(x: usize) -> usize { - let mut sum = 0; //~ ERROR blocks in constant functions are limited - for i in 0..x { //~ ERROR calls in constant functions - //~| ERROR constant function contains unimplemented + let mut sum = 0; + //~^ ERROR E0016 + for i in 0..x { + //~^ ERROR E0015 + //~| ERROR E0019 sum += i; } - sum //~ ERROR E0080 - //~| non-constant path in constant + sum } #[allow(unused_variables)] fn main() { let a : [i32; f(X)]; - //~^ WARNING constant evaluation error: non-constant path + //~^ ERROR E0080 } diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index e738a5e4ff30..26c238992ab6 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -1,3 +1,4 @@ +<<<<<<< HEAD warning: constant evaluation error: non-constant path in constant expression --> $DIR/const-fn-error.rs:27:19 | @@ -10,6 +11,12 @@ error[E0016]: blocks in constant functions are limited to items and tail express --> $DIR/const-fn-error.rs:16:19 | LL | let mut sum = 0; //~ ERROR blocks in constant functions are limited +======= +error[E0016]: blocks in constant functions are limited to items and tail expressions + --> $DIR/const-fn-error.rs:16:19 + | +16 | let mut sum = 0; +>>>>>>> Produce instead of pointers | ^ error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors @@ -25,6 +32,7 @@ LL | for i in 0..x { //~ ERROR calls in constant functions | ^^^^ error[E0080]: constant evaluation error +<<<<<<< HEAD --> $DIR/const-fn-error.rs:21:5 | LL | sum //~ ERROR E0080 @@ -35,6 +43,12 @@ note: for constant expression here | LL | let a : [i32; f(X)]; | ^^^^^^^^^^^ +======= + --> $DIR/const-fn-error.rs:28:19 + | +28 | let a : [i32; f(X)]; + | ^^^^ miri failed: machine error: Cannot evaluate within constants: "calling non-const fn `>::into_iter`" +>>>>>>> Produce instead of pointers error: aborting due to 4 previous errors diff --git a/src/test/ui/const-len-underflow-separate-spans.rs b/src/test/ui/const-len-underflow-separate-spans.rs index 823cc988947c..7582d0efa812 100644 --- a/src/test/ui/const-len-underflow-separate-spans.rs +++ b/src/test/ui/const-len-underflow-separate-spans.rs @@ -15,9 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR constant evaluation error [E0080] -//~| WARN attempt to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); +//~^ ERROR E0080 } diff --git a/src/test/ui/const-pattern-not-const-evaluable.rs b/src/test/ui/const-pattern-not-const-evaluable.rs index 263c0bdc64c6..09b24d1ffa20 100644 --- a/src/test/ui/const-pattern-not-const-evaluable.rs +++ b/src/test/ui/const-pattern-not-const-evaluable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + #![feature(const_fn)] #[derive(PartialEq, Eq)] @@ -20,8 +22,6 @@ use Cake::*; struct Pair(A, B); const BOO: Pair = Pair(Marmor, BlackForest); -//~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { diff --git a/src/test/ui/feature-gate-const-indexing.rs b/src/test/ui/feature-gate-const-indexing.rs index 0d61878cd807..eb5f746774cf 100644 --- a/src/test/ui/feature-gate-const-indexing.rs +++ b/src/test/ui/feature-gate-const-indexing.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully fn main() { const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47]; const IDX: usize = 3; const VAL: i32 = ARR[IDX]; - const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; //~ ERROR constant evaluation error + const BLUB: [i32; (ARR[0] - 41) as usize] = [5]; } diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs index 42e3c05a38c7..24cd20a84a9f 100644 --- a/src/test/ui/issue-38875/issue_38875.rs +++ b/src/test/ui/issue-38875/issue_38875.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:issue_38875_b.rs +// must-compile-successfully extern crate issue_38875_b; diff --git a/src/test/ui/union/union-const-eval.rs b/src/test/ui/union/union-const-eval.rs index a4c969ba20c4..aeafb45e6a55 100644 --- a/src/test/ui/union/union-const-eval.rs +++ b/src/test/ui/union/union-const-eval.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + union U { a: usize, b: usize, @@ -16,9 +18,6 @@ union U { const C: U = U { a: 10 }; fn main() { - unsafe { - let a: [u8; C.a]; // OK - let b: [u8; C.b]; //~ ERROR constant evaluation error - //~| WARNING constant evaluation error - } + let a: [u8; unsafe { C.a }]; + let b: [u8; unsafe { C.b }]; }