From fdd9787777dac5db6bd555df08038e3c191999e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 26 Apr 2018 09:18:19 +0200 Subject: [PATCH 1/2] Introduce ConstValue and use it instead of miri's Value for constant values --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/ich/impls_ty.rs | 24 +++ src/librustc/middle/const_val.rs | 24 +-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/mir/interpret/mod.rs | 62 +++++- src/librustc/mir/interpret/value.rs | 64 +++++- src/librustc/mir/mod.rs | 21 +- src/librustc/mir/tcx.rs | 2 +- src/librustc/ty/codec.rs | 19 ++ src/librustc/ty/context.rs | 9 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/maps/config.rs | 2 +- src/librustc/ty/maps/mod.rs | 2 +- src/librustc/ty/mod.rs | 42 ++-- src/librustc/ty/relate.rs | 19 +- src/librustc/ty/sty.rs | 153 ++++++++++++++ src/librustc/ty/util.rs | 4 +- src/librustc/util/ppaux.rs | 10 +- .../borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 21 +- src/librustc_mir/build/matches/test.rs | 5 +- src/librustc_mir/build/misc.rs | 7 +- src/librustc_mir/hair/cx/expr.rs | 37 ++-- src/librustc_mir/hair/cx/mod.rs | 45 ++--- src/librustc_mir/hair/pattern/_match.rs | 186 +++++++++--------- src/librustc_mir/hair/pattern/mod.rs | 137 ++++++------- src/librustc_mir/interpret/const_eval.rs | 128 ++++++++---- src/librustc_mir/interpret/eval_context.rs | 171 ++++++++-------- src/librustc_mir/interpret/memory.rs | 69 ++----- src/librustc_mir/interpret/mod.rs | 1 + src/librustc_mir/interpret/place.rs | 16 +- src/librustc_mir/monomorphize/collector.rs | 23 +-- src/librustc_mir/monomorphize/item.rs | 3 +- src/librustc_mir/shim.rs | 21 +- src/librustc_mir/transform/const_prop.rs | 128 +++++++----- src/librustc_mir/transform/elaborate_drops.rs | 7 +- src/librustc_mir/transform/generator.rs | 15 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- .../transform/simplify_branches.rs | 17 +- .../transform/uniform_array_move_out.rs | 8 +- src/librustc_mir/util/elaborate_drops.rs | 13 +- src/librustc_mir/util/pretty.rs | 2 +- src/librustc_trans/base.rs | 18 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/mir/constant.rs | 106 ++++++---- src/librustc_trans/mir/operand.rs | 32 ++- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_typeck/astconv.rs | 6 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 9 +- src/test/codegen/link_section.rs | 8 +- 55 files changed, 985 insertions(+), 737 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e4f432e7caf49..54dda320e1fca 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,7 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, ConstValue}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d0d0ab093c87f..1036eae9b856b 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -384,6 +384,30 @@ for ::middle::const_val::ConstVal<'gcx> { } } +impl<'a, 'gcx> HashStable> +for ::mir::interpret::ConstValue<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use mir::interpret::ConstValue::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ByVal(val) => { + val.hash_stable(hcx, hasher); + } + ByValPair(a, b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + ByRef(alloc) => { + alloc.hash_stable(hcx, hasher); + } + } + } +} + impl_stable_hash_for!(enum mir::interpret::Value { ByVal(v), ByValPair(a, b), diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 0ecab50dda229..3a76f75d01833 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::ConstValue; use errors::DiagnosticBuilder; use graphviz::IntoCow; @@ -25,27 +25,7 @@ pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { Unevaluated(DefId, &'tcx Substs<'tcx>), - Value(Value), -} - -impl<'tcx> ConstVal<'tcx> { - pub fn to_raw_bits(&self) -> Option { - match *self { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - Some(b) - }, - _ => None, - } - } - pub fn unwrap_u64(&self) -> u64 { - match self.to_raw_bits() { - Some(val) => { - assert_eq!(val as u64 as u128, val); - val as u64 - }, - None => bug!("expected constant u64, got {:#?}", self), - } - } + Value(ConstValue<'tcx>), } #[derive(Clone, Debug)] diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3875770a5ff5c..a4c38333da19e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -945,7 +945,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_raw_bits() == Some(0) => true, + ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 546c7a920d538..afdd1c167c6dc 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -10,7 +10,7 @@ mod value; pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; -pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; +pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue}; use std::collections::BTreeMap; use std::fmt; @@ -20,8 +20,10 @@ use ty::{self, TyCtxt}; use ty::layout::{self, Align, HasDataLayout}; use middle::region; use std::iter; +use std::io; use syntax::ast::Mutability; use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; +use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lock { @@ -235,7 +237,7 @@ impl fmt::Display for AllocId { } } -#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer @@ -254,17 +256,69 @@ pub struct Allocation { } impl Allocation { - pub fn from_bytes(slice: &[u8]) -> Self { + pub fn from_bytes(slice: &[u8], align: Align) -> Self { let mut undef_mask = UndefMask::new(0); undef_mask.grow(slice.len() as u64, true); Self { bytes: slice.to_owned(), relocations: BTreeMap::new(), undef_mask, - align: Align::from_bytes(1, 1).unwrap(), + align, runtime_mutability: Mutability::Immutable, } } + + pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self { + Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap()) + } + + pub fn undef(size: u64, align: Align) -> Self { + assert_eq!(size as usize as u64, size); + Allocation { + bytes: vec![0; size as usize], + relocations: BTreeMap::new(), + undef_mask: UndefMask::new(size), + align, + runtime_mutability: Mutability::Immutable, + } + } +} + +impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {} + +//////////////////////////////////////////////////////////////////////////////// +// Methods to access integers in the target endianness +//////////////////////////////////////////////////////////////////////////////// + +pub fn write_target_uint( + endianness: layout::Endian, + mut target: &mut [u8], + data: u128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_uint128::(data, len), + layout::Endian::Big => target.write_uint128::(data, len), + } +} + +pub fn write_target_int( + endianness: layout::Endian, + mut target: &mut [u8], + data: i128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_int128::(data, len), + layout::Endian::Big => target.write_int128::(data, len), + } +} + +pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { + layout::Endian::Little => source.read_uint128::(source.len()), + layout::Endian::Big => source.read_uint128::(source.len()), + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7289d74bfbb1b..2cd4bf9d18ca5 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -3,7 +3,69 @@ use ty::layout::{Align, HasDataLayout}; use ty; -use super::{EvalResult, MemoryPointer, PointerArithmetic}; +use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation}; + +/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which +/// matches Value's optimizations for easy conversions between these two types +#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +pub enum ConstValue<'tcx> { + // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef + ByVal(PrimVal), + // Used only for types with layout::abi::ScalarPair + ByValPair(PrimVal, PrimVal), + // Used only for the remaining cases + ByRef(&'tcx Allocation), +} + +impl<'tcx> ConstValue<'tcx> { + #[inline] + pub fn from_byval_value(val: Value) -> Self { + match val { + Value::ByRef(..) => bug!(), + Value::ByValPair(a, b) => ConstValue::ByValPair(a, b), + Value::ByVal(val) => ConstValue::ByVal(val), + } + } + + #[inline] + pub fn to_byval_value(&self) -> Option { + match *self { + ConstValue::ByRef(..) => None, + ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)), + ConstValue::ByVal(val) => Some(Value::ByVal(val)), + } + } + + #[inline] + pub fn from_primval(val: PrimVal) -> Self { + ConstValue::ByVal(val) + } + + #[inline] + pub fn to_primval(&self) -> Option { + match *self { + ConstValue::ByRef(..) => None, + ConstValue::ByValPair(..) => None, + ConstValue::ByVal(val) => Some(val), + } + } + + #[inline] + pub fn to_bits(&self) -> Option { + match self.to_primval() { + Some(PrimVal::Bytes(val)) => Some(val), + _ => None, + } + } + + #[inline] + pub fn to_ptr(&self) -> Option { + match self.to_primval() { + Some(PrimVal::Ptr(ptr)) => Some(ptr), + _ => None, + } + } +} /// A `Value` represents a single self-contained Rust value. /// diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 11e25322f0072..eb12444bcb4c9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -13,7 +13,6 @@ //! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html use graphviz::IntoCow; -use middle::const_val::ConstVal; use middle::region; use rustc_data_structures::sync::{Lrc}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -1549,11 +1548,7 @@ impl<'tcx> Operand<'tcx> { span, ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }) + value: ty::Const::zero_sized(tcx, ty), }, }) } @@ -1881,11 +1876,17 @@ 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: &ty::Const) -> fmt::Result { - use middle::const_val::ConstVal::*; +pub fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { + use middle::const_val::ConstVal; match const_val.val { - Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => print_miri_value(val, const_val.ty, fmt), + ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val), + ConstVal::Value(val) => { + if let Some(value) = val.to_byval_value() { + print_miri_value(value, const_val.ty, fmt) + } else { + write!(fmt, "{:?}:{}", val, const_val.ty) + } + }, } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6a9ff39c5f56b..67dfad50f4435 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.unwrap_u64(); + let size = size.unwrap_usize(tcx); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 4e15f0711a5aa..d911f32ed3f1f 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -24,6 +24,7 @@ use std::hash::Hash; use std::intrinsics; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; +use mir::interpret::Allocation; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) } +#[inline] +pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx Allocation, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) +} + #[macro_export] macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { @@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder { decode_const(self) } } + + impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation> + for $DecoderName<$($typaram),*> { + fn specialized_decode( + &mut self + ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> { + decode_allocation(self) + } + } } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 36eb091cb6e5b..06e08a0e263cc 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -26,14 +26,12 @@ use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; -use middle::const_val::ConstVal; use middle::cstore::{CrateStore, LinkMeta}; use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; -use mir::interpret::{Value, PrimVal}; use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use ty::Instance; @@ -1132,7 +1130,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return alloc_id; } // create an allocation that just contains these bytes - let alloc = interpret::Allocation::from_bytes(bytes); + let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); let alloc = self.intern_const_alloc(alloc); // the next unique id @@ -2375,10 +2373,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))), - ty: self.types.usize - }))) + self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n))) } pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index cfde35de93c3b..7dfdc592647db 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -182,7 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - match n.val.to_raw_bits() { + match n.assert_usize(tcx) { Some(n) => format!("array of {} elements", n), None => "array".to_string(), } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 17a3d0011eddf..19e5406cd0d0a 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_raw_bits() { + match len.assert_usize(tcx) { // 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 0688dcabe5585..9cbee14399079 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.unwrap_u64(); + let count = count.unwrap_usize(tcx); 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 57c8c4f34e70e..ca594faf5cd3b 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -11,7 +11,7 @@ use dep_graph::SerializedDepNodeIndex; use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, ConstValue}; use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index d89846a75ef51..80402f87650c6 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -28,7 +28,7 @@ use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; use middle::const_val::EvalResult; use mir::mono::{CodegenUnit, Stats}; use mir; -use mir::interpret::{GlobalId}; +use mir::interpret::{GlobalId, Allocation, ConstValue}; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::{self, Vtable}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7076112e3715a..eede7bd2ea619 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -22,12 +22,11 @@ use hir::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; use infer::canonical::{Canonical, Canonicalize}; -use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits::{self, Reveal}; @@ -1933,27 +1932,23 @@ impl<'a, 'gcx, 'tcx> AdtDef { promoted: None }; match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - ty, - }) => { - trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { - val: b, - ty, - }) - }, - Ok(&ty::Const { - val: ConstVal::Value(other), - .. - }) => { - info!("invalid enum discriminant: {:#?}", other); - ::middle::const_val::struct_error( - tcx, - tcx.def_span(expr_did), - "constant evaluation of enum discriminant resulted in non-integer", - ).emit(); - None + Ok(val) => { + // FIXME: Find the right type and use it instead of `val.ty` here + if let Some(b) = val.assert_bits(val.ty) { + trace!("discriminants: {} ({:?})", b, repr_type); + Some(Discr { + val: b, + ty: val.ty, + }) + } else { + info!("invalid enum discriminant: {:#?}", val); + ::middle::const_val::struct_error( + tcx, + tcx.def_span(expr_did), + "constant evaluation of enum discriminant resulted in non-integer", + ).emit(); + None + } } Err(err) => { err.report(tcx, tcx.def_span(expr_did), "enum discriminant"); @@ -1964,7 +1959,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } None } - _ => span_bug!(tcx.def_span(expr_did), "const eval "), } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 109dfebf154de..4a33f1a1f54d2 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -18,7 +18,7 @@ use middle::const_val::ConstVal; use ty::subst::{Kind, UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use util::common::ErrorReported; use std::rc::Rc; use std::iter; @@ -469,8 +469,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, assert_eq!(sz_a.ty, tcx.types.usize); assert_eq!(sz_b.ty, tcx.types.usize); let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { + if let Some(s) = x.assert_usize(tcx) { + return Ok(s); + } match x.val { - 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(); @@ -487,15 +489,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, instance, promoted: None }; - match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - .. - }) => { - assert_eq!(b as u64 as u128, b); - return Ok(b as u64); - } - _ => {} + if let Some(s) = tcx.const_eval(param_env.and(cid)) + .ok() + .map(|c| c.unwrap_usize(tcx)) { + return Ok(s) } } }, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7518f008fb316..f0a7ce5497166 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,6 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; use util::captures::Captures; +use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue}; use std::iter; use std::cmp::Ordering; @@ -1730,4 +1731,156 @@ pub struct Const<'tcx> { pub val: ConstVal<'tcx>, } +impl<'tcx> Const<'tcx> { + pub fn unevaluated( + tcx: TyCtxt<'_, '_, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val: ConstVal::Unevaluated(def_id, substs), + ty, + }) + } + + #[inline] + pub fn from_const_val( + tcx: TyCtxt<'_, '_, 'tcx>, + val: ConstVal<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val, + ty, + }) + } + + #[inline] + pub fn from_const_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_val(tcx, ConstVal::Value(val), ty) + } + + #[inline] + pub fn from_alloc( + tcx: TyCtxt<'_, '_, 'tcx>, + alloc: &'tcx Allocation, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty) + } + + #[inline] + pub fn from_byval_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: Value, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty) + } + + #[inline] + pub fn from_primval( + tcx: TyCtxt<'_, '_, 'tcx>, + val: PrimVal, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_primval(val), ty) + } + + #[inline] + pub fn from_bits( + tcx: TyCtxt<'_, '_, 'tcx>, + val: u128, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_primval(tcx, PrimVal::Bytes(val), ty) + } + + #[inline] + pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + Self::from_primval(tcx, PrimVal::Undef, ty) + } + + #[inline] + pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { + Self::from_bits(tcx, v as u128, tcx.types.bool) + } + + #[inline] + pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self { + Self::from_bits(tcx, n as u128, tcx.types.usize) + } + + #[inline] + pub fn to_bits(&self, ty: Ty<'_>) -> Option { + if self.ty != ty { + return None; + } + match self.val { + ConstVal::Value(val) => val.to_bits(), + _ => None, + } + } + + #[inline] + pub fn to_ptr(&self) -> Option { + match self.val { + ConstVal::Value(val) => val.to_ptr(), + _ => None, + } + } + + #[inline] + pub fn to_primval(&self) -> Option { + match self.val { + ConstVal::Value(val) => val.to_primval(), + _ => None, + } + } + + #[inline] + pub fn assert_bits(&self, ty: Ty<'_>) -> Option { + assert_eq!(self.ty, ty); + match self.val { + ConstVal::Value(val) => val.to_bits(), + _ => None, + } + } + + #[inline] + pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx.types.bool).and_then(|v| match v { + 0 => Some(false), + 1 => Some(true), + _ => None, + }) + } + + #[inline] + pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx.types.usize).map(|v| v as u64) + } + + #[inline] + pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 { + match self.assert_bits(ty) { + Some(val) => val, + None => bug!("expected bits of {}, got {:#?}", ty, self), + } + } + + #[inline] + pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 { + match self.assert_usize(tcx) { + Some(val) => val, + None => bug!("expected constant usize, got {:#?}", self), + } + } +} + impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 80dc3b2b452ce..76803f4503129 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -25,7 +25,6 @@ use ty::TypeVariants::*; use ty::layout::{Integer, IntegerExt}; use util::common::ErrorReported; use middle::lang_items; -use mir::interpret::{Value, PrimVal}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; @@ -659,9 +658,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyArray(_, n) => { self.hash_discriminant_u8(&n.val); match n.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), + ConstVal::Value(alloc) => self.hash(alloc), ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), - _ => bug!("arrays should not have {:?} as length", n) } } TyRawPtr(m) => self.hash(m.mutbl), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4fb1017035168..a6eb468e33836 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -21,7 +21,6 @@ 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; @@ -1183,15 +1182,12 @@ define_print! { TyArray(ty, sz) => { print!(f, cx, write("["), print(ty), write("; "))?; match sz.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { - write!(f, "{}", sz)?; - } + ConstVal::Value(..) => ty::tls::with(|tcx| { + write!(f, "{}", sz.unwrap_usize(tcx)) + })?, ConstVal::Unevaluated(_def_id, _substs) => { write!(f, "_")?; } - _ => { - write!(f, "{:?}", sz)?; - } } write!(f, "]") } 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 42a1745addff7..1014299c708dd 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -425,7 +425,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.unwrap_u64(); + let size = size.unwrap_usize(tcx); 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) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 648746b6e9047..20e11abca9fa0 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -16,11 +16,10 @@ use rustc_data_structures::indexed_vec::Idx; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use hair::*; -use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::ty::{self, Ty, UpvarSubsts}; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind}; +use rustc::mir::interpret::EvalErrorKind; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -200,10 +199,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: expr_span, ty: this.hir.tcx().types.u32, literal: Literal::Value { - value: this.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: this.hir.tcx().types.u32 - }), + value: ty::Const::from_bits( + this.hir.tcx(), + 0, + this.hir.tcx().types.u32), }, })); box AggregateKind::Generator(closure_id, substs, movability) @@ -378,10 +377,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bits = self.hir.integer_bit_width(ty); let n = (!0u128) >> (128 - bits); let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), n, ty) }; self.literal_operand(span, ty, literal) @@ -393,10 +389,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bits = self.hir.integer_bit_width(ty); let n = 1 << (bits - 1); let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), n, ty) }; self.literal_operand(span, ty, literal) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index d6ddfea1f19fb..913cb94483555 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -122,12 +122,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match *match_pair.pattern.kind { PatternKind::Constant { value } => { - // if the places match, the type should match - assert_eq!(match_pair.pattern.ty, switch_ty); - indices.entry(value) .or_insert_with(|| { - options.push(value.val.to_raw_bits().expect("switching on int")); + options.push(value.unwrap_bits(switch_ty)); options.len() - 1 }); true diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 6e10c2307c8e6..6501dd00fe817 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -13,9 +13,7 @@ use build::Builder; -use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::mir::*; use syntax_pos::{Span, DUMMY_SP}; @@ -64,10 +62,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } let literal = Literal::Value { - value: self.hir.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty - }) + value: ty::Const::from_bits(self.hir.tcx(), 0, ty) }; self.literal_operand(span, ty, literal) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 76605a7aa0484..e3ff67703bd4e 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -14,8 +14,7 @@ use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; -use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::mir::interpret::GlobalId; use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; @@ -522,7 +521,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, promoted: None }; let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) { - Ok(cv) => cv.val.unwrap_u64(), + Ok(cv) => cv.unwrap_usize(cx.tcx), Err(e) => { e.report(cx.tcx, cx.tcx.def_span(def_id), "array length"); 0 @@ -635,22 +634,17 @@ fn make_mirror_unadjusted<'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, - ty, - }), + value: val, }, }, }.to_ref(); - let offset = mk_const( - ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))), - ); + let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty)); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ConstVal::Unevaluated(did, substs)); + let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty)); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -707,10 +701,7 @@ 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::Value(Value::ByVal(PrimVal::Undef)), - ty - }), + value: ty::Const::zero_sized(cx.tcx(), ty), }, }, } @@ -764,20 +755,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: cx.tables().node_id_to_type(expr.hir_id) - }), + value: ty::Const::zero_sized( + cx.tcx, + cx.tables().node_id_to_type(expr.hir_id)), }, }, Def::Const(def_id) | Def::AssociatedConst(def_id) => ExprKind::Literal { literal: Literal::Value { - value: cx.tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(def_id, substs), - ty: cx.tables().node_id_to_type(expr.hir_id) - }), + value: ty::Const::unevaluated( + cx.tcx, + def_id, + substs, + 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 5890ea5c9d0c6..4765a82d85b6c 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,6 @@ use hair::*; -use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; @@ -31,7 +30,6 @@ use syntax::attr; use syntax::symbol::Symbol; use rustc::hir; use rustc_data_structures::sync::Lrc; -use rustc::mir::interpret::{Value, PrimVal}; use hair::pattern::parse_float; #[derive(Clone)] @@ -117,10 +115,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> { Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))), - ty: self.tcx.types.usize - }) + value: ty::Const::from_usize(self.tcx, value), } } @@ -134,19 +129,13 @@ 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::Value(Value::ByVal(PrimVal::Bytes(1))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, true), } } pub fn false_literal(&mut self) -> Literal<'tcx> { Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, false), } } @@ -162,6 +151,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { layout::Integer::from_attr(self.tcx, ty).size().bits() } + // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const pub fn const_eval_literal( &mut self, lit: &'tcx ast::LitKind, @@ -171,7 +161,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ) -> Literal<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); - let parse_float = |num, fty| -> Value { + let parse_float = |num, fty| -> ConstValue<'tcx> { parse_float(num, fty, neg).unwrap_or_else(|_| { // FIXME(#31407) this is only necessary because float parsing is buggy self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)"); @@ -193,7 +183,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let s = s.as_str(); let id = self.tcx.allocate_cached(s.as_bytes()); let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( + ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), ) @@ -201,16 +191,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { LitKind::ByteStr(ref data) => { let id = self.tcx.allocate_cached(data); let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) + ConstValue::ByVal(PrimVal::Ptr(ptr)) }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), LitKind::Int(n, _) if neg => { let n = n as i128; let n = n.overflowing_neg().0; let n = clamp(n as u128); - Value::ByVal(PrimVal::Bytes(n)) + ConstValue::ByVal(PrimVal::Bytes(n)) }, - LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))), + LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))), LitKind::Float(n, fty) => { parse_float(n, fty) } @@ -221,14 +211,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { }; parse_float(n, fty) } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)), }; Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(lit), - ty, - }), + value: ty::Const::from_const_value(self.tcx, lit, ty) } } @@ -258,11 +245,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Value { - value: self.tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: method_ty - }), + value: ty::Const::zero_sized(self.tcx, method_ty) }); } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 1245f506955c1..f930d47dc0bd3 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -25,7 +25,6 @@ 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}; @@ -180,37 +179,34 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { self.byte_array_map.entry(pat).or_insert_with(|| { match pat.kind { box PatternKind::Constant { - value: &ty::Const { val: ConstVal::Value(b), ty } + value: const_val } => { - match b { - Value::ByVal(PrimVal::Ptr(ptr)) => { - let is_array_ptr = ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == tcx.types.u8); - assert!(is_array_ptr); - let alloc = tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .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), + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + let alloc = tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .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: ty::Const::from_bits( + tcx, + *b as u128, + tcx.types.u8) + } + }) + }).collect() + } else { + bug!("not a byte str: {:?}", const_val) } } _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) @@ -439,14 +435,11 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match pcx.ty.sty { ty::TyBool => { [true, false].iter().map(|&b| { - ConstantValue(cx.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))), - ty: cx.tcx.types.bool - })) + ConstantValue(ty::Const::from_bool(cx.tcx, b)) }).collect() } - ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => { - let len = len.val.unwrap_u64(); + ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => { + let len = len.unwrap_usize(cx.tcx); if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { @@ -554,21 +547,23 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( for row in patterns { match *row.kind { PatternKind::Constant { - value: &ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))), - ty, + value: const_val @ &ty::Const { + val: ConstVal::Value(..), + .. } } => { - let is_array_ptr = ty - .builtin_deref(true) - .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 - .get_alloc(ptr.alloc_id) - .unwrap(); - max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .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 + .get_alloc(ptr.alloc_id) + .unwrap(); + max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64); + } } } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { @@ -836,7 +831,7 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. /// /// Returns None in case of a catch-all, which can't be specialized. -fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, +fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt, pat: &Pattern<'tcx>, pcx: PatternContext) -> Option>> @@ -854,7 +849,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.unwrap_u64()) + Slice(length.unwrap_usize(cx.tcx)) ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, @@ -934,27 +929,31 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, - ctor: &Constructor, - prefix: &[Pattern], - slice: &Option, - suffix: &[Pattern]) - -> Result { +fn slice_pat_covered_by_constructor<'tcx>( + tcx: TyCtxt<'_, 'tcx, '_>, + _span: Span, + ctor: &Constructor, + prefix: &[Pattern<'tcx>], + slice: &Option>, + suffix: &[Pattern<'tcx>] +) -> Result { let data: &[u8] = match *ctor { - ConstantValue(&ty::Const { val: ConstVal::Value( - Value::ByVal(PrimVal::Ptr(ptr)) - ), ty }) => { - let is_array_ptr = ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == tcx.types.u8); - assert!(is_array_ptr); - tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .unwrap() - .bytes - .as_ref() + ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => { + if let Some(ptr) = const_val.to_ptr() { + let is_array_ptr = const_val.ty + .builtin_deref(true) + .and_then(|t| t.ty.builtin_index()) + .map_or(false, |t| t == tcx.types.u8); + assert!(is_array_ptr); + tcx + .interpret_interner + .get_alloc(ptr.alloc_id) + .unwrap() + .bytes + .as_ref() + } else { + bug!() + } } _ => bug!() }; @@ -969,15 +968,13 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, data[data.len()-suffix.len()..].iter().zip(suffix)) { match pat.kind { - box PatternKind::Constant { value } => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - assert_eq!(b as u8 as u128, b); - if b as u8 != *ch { - return Ok(false); - } + box PatternKind::Constant { value } => { + let b = value.unwrap_bits(pat.ty); + assert_eq!(b as u8 as u128, b); + if b as u8 != *ch { + return Ok(false); } - _ => span_bug!(pat.span, "bad const u8 {:?}", value) - }, + } _ => {} } } @@ -987,8 +984,8 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, fn constructor_covered_by_range<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - ctor: &Constructor, - from: &ConstVal, to: &ConstVal, + ctor: &Constructor<'tcx>, + from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>, end: RangeEnd, ty: Ty<'tcx>, ) -> Result { @@ -1006,22 +1003,22 @@ fn constructor_covered_by_range<'a, 'tcx>( } match *ctor { ConstantValue(value) => { - let to = some_or_ok!(cmp_to(&value.val)); + let to = some_or_ok!(cmp_to(value)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&value.val)) && end) + Ok(some_or_ok!(cmp_from(value)) && end) }, ConstantRange(from, to, RangeEnd::Included) => { - let to = some_or_ok!(cmp_to(&to.val)); + let to = some_or_ok!(cmp_to(to)); let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&from.val)) && end) + Ok(some_or_ok!(cmp_from(from)) && end) }, ConstantRange(from, to, RangeEnd::Excluded) => { - let to = some_or_ok!(cmp_to(&to.val)); + let to = some_or_ok!(cmp_to(to)); let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(some_or_ok!(cmp_from(&from.val)) && end) + Ok(some_or_ok!(cmp_from(from)) && end) } Single => Ok(true), _ => bug!(), @@ -1083,8 +1080,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Constant { value } => { match *constructor { - Slice(..) => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => { + Slice(..) => { + if let Some(ptr) = value.to_ptr() { let is_array_ptr = value.ty .builtin_deref(true) .and_then(|t| t.ty.builtin_index()) @@ -1101,14 +1098,15 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } else { None } - } - _ => span_bug!(pat.span, + } else { + span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor) + } }, _ => { match constructor_covered_by_range( cx.tcx, - constructor, &value.val, &value.val, RangeEnd::Included, + constructor, value, value, RangeEnd::Included, value.ty, ) { Ok(true) => Some(vec![]), @@ -1122,7 +1120,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( cx.tcx, - constructor, &lo.val, &hi.val, end.clone(), lo.ty, + constructor, lo, hi, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), Ok(false) => None, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 2585447fa0a04..749e574ff7ad4 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -19,8 +19,8 @@ pub(crate) use self::check_match::check_match; use interpret::{const_val_field, const_variant_index, self}; use rustc::middle::const_val::ConstVal; -use rustc::mir::{Field, BorrowKind, Mutability}; -use rustc::mir::interpret::{GlobalId, Value, PrimVal}; +use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; @@ -124,24 +124,11 @@ pub enum PatternKind<'tcx> { fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result { match value.val { - ConstVal::Value(v) => print_miri_value(v, value.ty, f), + ConstVal::Value(..) => fmt_const_val(f, 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 { @@ -372,7 +359,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; - match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) { + match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) { (RangeEnd::Excluded, Ordering::Less) => PatternKind::Range { lo, hi, end }, (RangeEnd::Excluded, _) => { @@ -616,7 +603,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - let len = len.val.unwrap_u64(); + let len = len.unwrap_usize(self.tcx); assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -740,8 +727,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tables.local_id_root.expect("literal outside any scope"), self.substs, ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, Err(()) => { self.errors.push(PatternError::FloatBug); @@ -762,8 +748,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tables.local_id_root.expect("literal outside any scope"), self.substs, ); - let cv = self.tcx.mk_const(ty::Const { val, ty }); - *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind + *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind }, Err(()) => { self.errors.push(PatternError::FloatBug); @@ -866,7 +851,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } ty::TyArray(_, n) => { PatternKind::Array { - prefix: (0..n.val.unwrap_u64()) + prefix: (0..n.unwrap_usize(self.tcx)) .map(|i| adt_subpattern(i as usize, None)) .collect(), slice: None, @@ -1049,45 +1034,48 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { pub fn compare_const_vals<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - a: &ConstVal, - b: &ConstVal, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, ty: Ty<'tcx>, ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); - use rustc::mir::interpret::{Value, PrimVal}; - match (a, b) { - (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))), - &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => { - use ::rustc_apfloat::Float; - match ty.sty { - ty::TyFloat(ast::FloatTy::F32) => { - let l = ::rustc_apfloat::ieee::Single::from_bits(a); - let r = ::rustc_apfloat::ieee::Single::from_bits(b); - l.partial_cmp(&r) - }, - ty::TyFloat(ast::FloatTy::F64) => { - let l = ::rustc_apfloat::ieee::Double::from_bits(a); - let r = ::rustc_apfloat::ieee::Double::from_bits(b); - l.partial_cmp(&r) - }, - ty::TyInt(_) => { - let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); - let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); - Some((a as i128).cmp(&(b as i128))) - }, - _ => Some(a.cmp(&b)), - } - }, - _ if a == b => Some(Ordering::Equal), - _ => None, + // FIXME: This should use assert_bits(ty) instead of use_bits + // but triggers possibly bugs due to mismatching of arrays and slices + if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) { + use ::rustc_apfloat::Float; + match ty.sty { + ty::TyFloat(ast::FloatTy::F32) => { + let l = ::rustc_apfloat::ieee::Single::from_bits(a); + let r = ::rustc_apfloat::ieee::Single::from_bits(b); + l.partial_cmp(&r) + }, + ty::TyFloat(ast::FloatTy::F64) => { + let l = ::rustc_apfloat::ieee::Double::from_bits(a); + let r = ::rustc_apfloat::ieee::Double::from_bits(b); + l.partial_cmp(&r) + }, + ty::TyInt(_) => { + let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); + let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); + Some((a as i128).cmp(&(b as i128))) + }, + _ => Some(a.cmp(&b)), + } + } else { + if a == b { + Some(Ordering::Equal) + } else { + None + } } } +// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, neg: bool) - -> Result, ()> { + -> Result<&'tcx ty::Const<'tcx>, ()> { use syntax::ast::*; use rustc::mir::interpret::*; @@ -1096,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, let s = s.as_str(); let id = tcx.allocate_cached(s.as_bytes()); let ptr = MemoryPointer::new(id, 0); - Value::ByValPair( + ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), ) @@ -1104,9 +1092,9 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, LitKind::ByteStr(ref data) => { let id = tcx.allocate_cached(data); let ptr = MemoryPointer::new(id, 0); - Value::ByVal(PrimVal::Ptr(ptr)) + ConstValue::ByVal(PrimVal::Ptr(ptr)) }, - LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)), + LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), LitKind::Int(n, _) => { enum Int { Signed(IntTy), @@ -1119,31 +1107,28 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, ty::TyUint(other) => Int::Unsigned(other), _ => bug!(), }; + // This converts from LitKind::Int (which is sign extended) to + // PrimVal::Bytes (which is zero extended) let n = match ty { // FIXME(oli-obk): are these casts correct? Int::Signed(IntTy::I8) if neg => - (n as i128 as i8).overflowing_neg().0 as i128 as u128, + (n as i8).overflowing_neg().0 as u8 as u128, Int::Signed(IntTy::I16) if neg => - (n as i128 as i16).overflowing_neg().0 as i128 as u128, + (n as i16).overflowing_neg().0 as u16 as u128, Int::Signed(IntTy::I32) if neg => - (n as i128 as i32).overflowing_neg().0 as i128 as u128, + (n as i32).overflowing_neg().0 as u32 as u128, Int::Signed(IntTy::I64) if neg => - (n as i128 as i64).overflowing_neg().0 as i128 as u128, + (n as i64).overflowing_neg().0 as u64 as u128, Int::Signed(IntTy::I128) if neg => (n as i128).overflowing_neg().0 as u128, - Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128, - Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128, - Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128, - Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128, - Int::Signed(IntTy::I128) => n, - Int::Unsigned(UintTy::U8) => n as u8 as u128, - Int::Unsigned(UintTy::U16) => n as u16 as u128, - Int::Unsigned(UintTy::U32) => n as u32 as u128, - Int::Unsigned(UintTy::U64) => n as u64 as u128, - Int::Unsigned(UintTy::U128) => n, + Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128, + Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128, + Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128, + Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128, + Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n, _ => bug!(), }; - Value::ByVal(PrimVal::Bytes(n)) + ConstValue::ByVal(PrimVal::Bytes(n)) }, LitKind::Float(n, fty) => { parse_float(n, fty, neg)? @@ -1155,17 +1140,17 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }; parse_float(n, fty, neg)? } - LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)), - LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)), + LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)), + LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)), }; - Ok(ConstVal::Value(lit)) + Ok(ty::Const::from_const_value(tcx, lit, ty)) } -pub fn parse_float( +pub fn parse_float<'tcx>( num: Symbol, fty: ast::FloatTy, neg: bool, -) -> Result { +) -> Result, ()> { let num = num.as_str(); use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::Float; @@ -1192,5 +1177,5 @@ pub fn parse_float( } }; - Ok(Value::ByVal(PrimVal::Bytes(bits))) + Ok(ConstValue::ByVal(PrimVal::Bytes(bits))) } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index dff9fa271aba5..b8bb58b9ed24c 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -1,5 +1,5 @@ use rustc::hir; -use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind}; +use rustc::middle::const_val::{ConstEvalErr, ErrKind}; use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError}; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; @@ -9,7 +9,10 @@ use rustc::ty::subst::Subst; use syntax::ast::Mutability; use syntax::codemap::Span; -use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId}; +use rustc::mir::interpret::{ + EvalResult, EvalError, EvalErrorKind, GlobalId, + Value, Pointer, PrimVal, AllocId, Allocation, ConstValue, +}; use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; use std::fmt; @@ -57,19 +60,21 @@ pub fn mk_eval_cx<'a, 'tcx>( } pub fn eval_promoted<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, cid: GlobalId<'tcx>, mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); - match res { - Ok(val) => Some(val), - Err(mut err) => { - ecx.report(&mut err, false, None); - None + ecx.with_fresh_body(|ecx| { + let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env); + match res { + Ok(val) => Some(val), + Err(mut err) => { + ecx.report(&mut err, false, None); + None + } } - } + }) } pub fn eval_body<'a, 'tcx>( @@ -87,19 +92,76 @@ pub fn eval_body<'a, 'tcx>( } } +pub fn value_to_const_value<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + val: Value, + ty: Ty<'tcx>, +) -> &'tcx ty::Const<'tcx> { + let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); + + if layout.is_zst() { + return ty::Const::from_const_value( + tcx, + ConstValue::ByVal(PrimVal::Undef), + ty); + } + + let val = match layout.abi { + layout::Abi::Scalar(..) => { + if let Value::ByVal(val) = val { + ConstValue::ByVal(val) + } else { + bug!("expected ByVal value, got {:?}", val); + } + } + layout::Abi::ScalarPair(..) => { + if let Value::ByValPair(a, b) = val { + ConstValue::ByValPair(a, b) + } else { + bug!("expected ByValPair value, got {:?}", val); + } + } + _ => { + if let Value::ByRef(ptr, align) = val { + let ptr = ptr.primval.to_ptr().unwrap(); + assert_eq!(ptr.offset, 0); + let alloc = tcx.interpret_interner + .get_alloc(ptr.alloc_id) + .expect("miri allocation never successfully created"); + assert_eq!(align, alloc.align); + ConstValue::ByRef(alloc) + } else { + bug!("expected ByRef value, got {:?}", val); + } + }, + }; + ty::Const::from_const_value(tcx, val, ty) +} + fn eval_body_and_ecx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, ) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { - debug!("eval_body: {:?}, {:?}", cid, param_env); + debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env); // we start out with the best span we have // and try improving it down the road when more information is available let span = tcx.def_span(cid.instance.def_id()); - let mut span = mir.map(|mir| mir.span).unwrap_or(span); + let span = mir.map(|mir| mir.span).unwrap_or(span); let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); - let res = (|| { + let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env); + (r, ecx) +} + +fn eval_body_using_ecx<'a, 'mir, 'tcx>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, + cid: GlobalId<'tcx>, + mir: Option<&'mir mir::Mir<'tcx>>, + param_env: ty::ParamEnv<'tcx>, +) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { + debug!("eval_body: {:?}, {:?}", cid, param_env); + let tcx = ecx.tcx.tcx; let mut mir = match mir { Some(mir) => mir, None => ecx.load_mir(cid.instance.def)?, @@ -107,7 +169,6 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } - span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( @@ -139,14 +200,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( let ptr = ptr.into(); // always try to read the value and report errors let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { - // if it's a constant (so it needs no address, directly compute its value) - Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val, + Some(val) => val, // point at the allocation _ => Value::ByRef(ptr, layout.align), }; Ok((value, ptr, layout.ty)) - })(); - (res, ecx) } pub struct CompileTimeEvaluator; @@ -357,14 +415,16 @@ pub fn const_val_field<'a, 'tcx>( instance: ty::Instance<'tcx>, variant: Option, field: mir::Field, - value: Value, + value: ConstValue<'tcx>, ty: Ty<'tcx>, ) -> ::rustc::middle::const_val::EvalResult<'tcx> { trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let result = (|| { + let value = ecx.const_value_to_value(value, ty)?; let (mut field, ty) = match value { - Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), + Value::ByValPair(..) | Value::ByVal(_) => + ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), Value::ByRef(ptr, align) => { let place = Place::Ptr { ptr, @@ -385,10 +445,7 @@ pub fn const_val_field<'a, 'tcx>( Ok((field, ty)) })(); match result { - Ok((field, ty)) => Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(field), - ty, - })), + Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)), Err(err) => { let (trace, span) = ecx.generate_stacktrace(None); let err = ErrKind::Miri(err, trace); @@ -404,11 +461,12 @@ pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, - value: Value, + val: ConstValue<'tcx>, ty: Ty<'tcx>, ) -> EvalResult<'tcx, usize> { - trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty); + trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); + let value = ecx.const_value_to_value(val, ty)?; let (ptr, align) = match value { Value::ByValPair(..) | Value::ByVal(_) => { let layout = ecx.layout_of(ty)?; @@ -432,17 +490,6 @@ pub fn const_eval_provider<'a, 'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); - if tcx.is_foreign_item(def_id) { - let id = tcx.interpret_interner.cache_static(def_id); - let ty = tcx.type_of(def_id); - let layout = tcx.layout_of(key.param_env.and(ty)).unwrap(); - let ptr = MemoryPointer::new(id, 0); - return Ok(tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)), - ty, - })) - } - if let Some(id) = tcx.hir.as_local_node_id(def_id) { let tables = tcx.typeck_tables_of(def_id); let span = tcx.def_span(def_id); @@ -469,11 +516,8 @@ pub fn const_eval_provider<'a, 'tcx>( }; let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.map(|(miri_value, _, miri_ty)| { - tcx.mk_const(ty::Const { - val: ConstVal::Value(miri_value), - ty: miri_ty, - }) + res.map(|(val, _, miri_ty)| { + value_to_const_value(tcx, val, miri_ty) }).map_err(|mut err| { if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3d670acf98cb2..03137619edaf4 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -15,7 +15,7 @@ use syntax::codemap::{self, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, - EvalError, EvalResult, EvalErrorKind, MemoryPointer, + EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue, }; use std::mem; @@ -116,15 +116,6 @@ pub struct ValTy<'tcx> { pub ty: Ty<'tcx>, } -impl<'tcx> ValTy<'tcx> { - pub fn from(val: &ty::Const<'tcx>) -> Option { - match val.val { - ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }), - ConstVal::Unevaluated { .. } => None, - } - } -} - impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { type Target = Value; fn deref(&self) -> &Value { @@ -183,6 +174,8 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf } } +const MAX_TERMINATORS: usize = 1_000_000; + impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn new( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, @@ -197,10 +190,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M memory: Memory::new(tcx, memory_data), stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit, - terminators_remaining: 1_000_000, + terminators_remaining: MAX_TERMINATORS, } } + pub(crate) fn with_fresh_body R, R>(&mut self, f: F) -> R { + let stack = mem::replace(&mut self.stack, Vec::new()); + let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS); + let r = f(self); + self.stack = stack; + self.terminators_remaining = terminators_remaining; + r + } + pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> { let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "cannot alloc memory for unsized type"); @@ -235,7 +237,27 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M )) } - pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub fn const_value_to_value( + &mut self, + val: ConstValue<'tcx>, + _ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Value> { + match val { + ConstValue::ByRef(alloc) => { + // FIXME: Allocate new AllocId for all constants inside + let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?; + Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align)) + }, + ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)), + ConstValue::ByVal(val) => Ok(Value::ByVal(val)), + } + } + + pub(super) fn const_to_value( + &mut self, + const_val: &ConstVal<'tcx>, + ty: Ty<'tcx> + ) -> EvalResult<'tcx, Value> { match *const_val { ConstVal::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; @@ -244,7 +266,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M promoted: None, }, ty) } - ConstVal::Value(val) => Ok(val), + ConstVal::Value(val) => self.const_value_to_value(val, ty) } } @@ -568,7 +590,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Repeat(ref operand, _) => { let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()), + ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)), _ => { bug!( "tried to assign array-repeat to non-array type {:?}", @@ -592,7 +614,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M // FIXME(CTFE): don't allow computing the length of arrays in const eval let src = self.eval_place(place)?; let ty = self.place_ty(place); - let (_, len) = src.elem_ty_and_len(ty); + let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx); self.write_primval( dest, PrimVal::from_u128(len as u128), @@ -822,8 +844,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Literal::Value { ref value } => self.const_to_value(&value.val, ty)?, Literal::Promoted { index } => { + let instance = self.frame().instance; self.read_global_as_value(GlobalId { - instance: self.frame().instance, + instance, promoted: Some(index), }, ty)? } @@ -997,7 +1020,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } - pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { if self.tcx.is_static(gid.instance.def_id()).is_some() { let alloc_id = self .tcx @@ -1341,92 +1364,84 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } - pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - use syntax::ast::FloatTy; - - let layout = self.layout_of(ty)?; - self.memory.check_align(ptr, ptr_align)?; - - if layout.size.bytes() == 0 { - return Ok(Some(Value::ByVal(PrimVal::Undef))); - } - - let ptr = ptr.to_ptr()?; - let val = match ty.sty { + pub fn validate_ptr_target( + &self, + ptr: MemoryPointer, + ptr_align: Align, + ty: Ty<'tcx> + ) -> EvalResult<'tcx> { + match ty.sty { ty::TyBool => { let val = self.memory.read_primval(ptr, ptr_align, 1)?; - let val = match val { - PrimVal::Bytes(0) => false, - PrimVal::Bytes(1) => true, + match val { + PrimVal::Bytes(0) | PrimVal::Bytes(1) => (), // TODO: This seems a little overeager, should reading at bool type already be insta-UB? _ => return err!(InvalidBool), - }; - PrimVal::from_bool(val) + } } ty::TyChar => { let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32; match ::std::char::from_u32(c) { - Some(ch) => PrimVal::from_char(ch), + Some(..) => (), None => return err!(InvalidChar(c as u128)), } } - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Isize => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, ptr_align, size)? - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Usize => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, ptr_align, size)? - } - - ty::TyFloat(FloatTy::F32) => { - PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?) - } - ty::TyFloat(FloatTy::F64) => { - PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?) - } - - ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?, + ty::TyFnPtr(_) => { + self.memory.read_ptr_sized(ptr, ptr_align)?; + }, ty::TyRef(_, rty, _) | ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => { - return self.read_ptr(ptr, ptr_align, rty).map(Some) + self.read_ptr(ptr, ptr_align, rty)?; } ty::TyAdt(def, _) => { if def.is_box() { - return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some); + self.read_ptr(ptr, ptr_align, ty.boxed_ty())?; + return Ok(()); } if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi { let size = scalar.value.size(self).bytes(); - self.memory.read_primval(ptr, ptr_align, size)? - } else { - return Ok(None); + self.memory.read_primval(ptr, ptr_align, size)?; } } - _ => return Ok(None), - }; + _ => (), + } + Ok(()) + } + + pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { + let layout = self.layout_of(ty)?; + self.memory.check_align(ptr, ptr_align)?; - Ok(Some(Value::ByVal(val))) + if layout.size.bytes() == 0 { + return Ok(Some(Value::ByVal(PrimVal::Undef))); + } + + let ptr = ptr.to_ptr()?; + + // Not the right place to do this + //self.validate_ptr_target(ptr, ptr_align, ty)?; + + match layout.abi { + layout::Abi::Scalar(..) => { + let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?; + Ok(Some(Value::ByVal(primval))) + } + layout::Abi::ScalarPair(ref a, ref b) => { + let (a, b) = (&a.value, &b.value); + let (a_size, b_size) = (a.size(self), b.size(self)); + let a_ptr = ptr; + let b_offset = a_size.abi_align(b.align(self)); + let b_ptr = ptr.offset(b_offset.bytes(), self)?.into(); + let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?; + let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?; + Ok(Some(Value::ByValPair(a_val, b_val))) + } + _ => Ok(None), + } } pub fn frame(&self) -> &Frame<'mir, 'tcx> { @@ -1466,7 +1481,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, '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.unwrap_u64() ), + value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)), ty: dest_ty, }; self.write_value(valty, dest) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 7f8205b8327fa..18cd75ae0bbf4 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,6 +1,5 @@ -use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; -use std::collections::{btree_map, BTreeMap, VecDeque}; -use std::{ptr, io}; +use std::collections::{btree_map, VecDeque}; +use std::ptr; use rustc::ty::Instance; use rustc::ty::maps::TyCtxtAt; @@ -8,8 +7,9 @@ use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; -use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer, +use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer, EvalResult, PrimVal, EvalErrorKind}; +pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint}; use super::{EvalContext, Machine}; @@ -79,20 +79,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } /// kind is `None` for statics - pub fn allocate( + pub fn allocate_value( &mut self, - size: u64, - align: Align, + alloc: Allocation, kind: Option>, - ) -> EvalResult<'tcx, MemoryPointer> { - assert_eq!(size as usize as u64, size); - let alloc = Allocation { - bytes: vec![0; size as usize], - relocations: BTreeMap::new(), - undef_mask: UndefMask::new(size), - align, - runtime_mutability: Mutability::Immutable, - }; + ) -> EvalResult<'tcx, AllocId> { let id = self.tcx.interpret_interner.reserve(); M::add_lock(self, id); match kind { @@ -105,6 +96,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.uninitialized_statics.insert(id, alloc); }, } + Ok(id) + } + + /// kind is `None` for statics + pub fn allocate( + &mut self, + size: u64, + align: Align, + kind: Option>, + ) -> EvalResult<'tcx, MemoryPointer> { + let id = self.allocate_value(Allocation::undef(size, align), kind)?; Ok(MemoryPointer::new(id, 0)) } @@ -873,41 +875,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } } -//////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianness -//////////////////////////////////////////////////////////////////////////////// - -pub fn write_target_uint( - endianness: layout::Endian, - mut target: &mut [u8], - data: u128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianness { - layout::Endian::Little => target.write_uint128::(data, len), - layout::Endian::Big => target.write_uint128::(data, len), - } -} - -pub fn write_target_int( - endianness: layout::Endian, - mut target: &mut [u8], - data: i128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianness { - layout::Endian::Little => target.write_int128::(data, len), - layout::Endian::Big => target.write_int128::(data, len), - } -} - -pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { - match endianness { - layout::Endian::Little => source.read_uint128::(source.len()), - layout::Endian::Big => source.read_uint128::(source.len()), - } -} - //////////////////////////////////////////////////////////////////////////////// // Unaligned accesses //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 1eb131810bdf3..7f9e67a62ccc4 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -26,6 +26,7 @@ pub use self::const_eval::{ const_eval_provider, const_val_field, const_variant_index, + value_to_const_value, }; pub use self::machine::Machine; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index b5a06286e4eed..883b17b8584fb 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; @@ -69,9 +69,13 @@ impl<'tcx> Place { self.to_ptr_align().0.to_ptr() } - pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { + pub(super) fn elem_ty_and_len( + self, + ty: Ty<'tcx>, + tcx: TyCtxt<'_, 'tcx, '_> + ) -> (Ty<'tcx>, u64) { match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64), + ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)), ty::TySlice(elem) => { match self { @@ -320,7 +324,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, len) = base.elem_ty_and_len(outer_ty); + let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!( n < len, @@ -396,7 +400,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!(n >= min_length as u64); @@ -415,7 +419,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let base = self.force_allocation(base)?; let (base_ptr, align) = base.to_ptr_align(); - let (elem_ty, n) = base.elem_ty_and_len(base_ty); + let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); let elem_size = self.layout_of(elem_ty)?.size.bytes(); assert!(u64::from(from) <= n - u64::from(to)); let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e051b848c011f..e690e8ee88066 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -194,7 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer}; +use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt}; @@ -203,7 +203,7 @@ use rustc::session::config; use rustc::mir::{self, Location, Promoted}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::MonoItem; -use rustc::mir::interpret::GlobalId; +use rustc::mir::interpret::{PrimVal, GlobalId}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -1237,22 +1237,17 @@ fn collect_const<'a, 'tcx>( }; match val { ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"), - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { + ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => { collect_miri(tcx, a.alloc_id, output); collect_miri(tcx, b.alloc_id, output); } - ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) | - ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) | - ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => + ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) | + ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) | + ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) => collect_miri(tcx, ptr.alloc_id, output), - ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => { - // by ref should only collect the inner allocation, not the value itself - let alloc = tcx - .interpret_interner - .get_alloc(ptr.alloc_id) - .expect("ByRef to extern static is not allowed"); - for &inner in alloc.relocations.values() { - collect_miri(tcx, inner, output); + ConstVal::Value(ConstValue::ByRef(alloc)) => { + for &id in alloc.relocations.values() { + collect_miri(tcx, id, output); } } _ => {}, diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 176ed8c5bca74..a569ad00d0c65 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -313,8 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::TyArray(inner_type, len) => { output.push('['); self.push_type_name(inner_type, output); - write!(output, "; {}", - len.val.unwrap_u64()).unwrap(); + write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 699a5b17435bd..5b2f3a8b8aac7 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -11,12 +11,10 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer; -use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::maps::Providers; -use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -303,7 +301,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.unwrap_u64(); + let len = len.unwrap_usize(tcx); builder.array_shim(dest, src, ty, len) } ty::TyClosure(def_id, substs) => { @@ -442,11 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty: func_ty - }), + value: ty::Const::zero_sized(self.tcx, func_ty) }, }); @@ -506,10 +500,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))), - ty: self.tcx.types.usize, - }) + value: ty::Const::from_usize(self.tcx, value), } } } @@ -738,11 +729,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }), + value: ty::Const::zero_sized(tcx, ty) }, }), vec![rcvr]) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e1db216b6bbbc..6b0217c8f7cbc 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -19,15 +19,17 @@ use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionE use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; -use rustc::mir::interpret::{Value, PrimVal, GlobalId}; +use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult}; +use interpret::EvalContext; +use interpret::CompileTimeEvaluator; use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy}; use transform::{MirPass, MirSource}; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use rustc::ty::subst::Substs; use rustc_data_structures::indexed_vec::IndexVec; use rustc::ty::ParamEnv; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, + LayoutOf, TyLayout, LayoutError, LayoutCx, HasTyCtxt, TargetDataLayout, HasDataLayout, }; @@ -64,6 +66,7 @@ type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); /// Finds optimization opportunities on the MIR. struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { + ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>, mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, @@ -102,7 +105,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { source: MirSource, ) -> ConstPropagator<'b, 'a, 'tcx> { let param_env = tcx.param_env(source.def_id); + let substs = Substs::identity_for_item(tcx, source.def_id); + let instance = Instance::new(source.def_id, substs); + let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap(); ConstPropagator { + ecx, mir, tcx, source, @@ -112,7 +119,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } } - fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option> { + fn use_ecx( + &mut self, + span: Span, + f: F + ) -> Option + where + F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, + { + self.ecx.tcx.span = span; + let r = match f(self) { + Ok(val) => Some(val), + Err(mut err) => { + self.ecx.report(&mut err, false, Some(span)); + None + }, + }; + self.ecx.tcx.span = DUMMY_SP; + r + } + + fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option> { let value = match self.tcx.const_eval(self.param_env.and(cid)) { Ok(val) => val, Err(err) => { @@ -121,7 +148,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { }, }; let val = match value.val { - ConstVal::Value(v) => v, + ConstVal::Value(v) => { + self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))? + }, _ => bug!("eval produced: {:?}", value), }; let val = (val, value.ty, span); @@ -132,7 +161,12 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { match c.literal { Literal::Value { value } => match value.val { - ConstVal::Value(v) => Some((v, value.ty, c.span)), + ConstVal::Value(v) => { + let v = self.use_ecx(c.span, |this| { + this.ecx.const_value_to_value(v, value.ty) + })?; + Some((v, value.ty, c.span)) + }, ConstVal::Unevaluated(did, substs) => { let instance = Instance::resolve( self.tcx, @@ -162,7 +196,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { }; // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now - let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?; + let span = self.mir.span; + let (value, _, ty) = self.use_ecx(span, |this| { + Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)) + })??; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); Some(val) @@ -185,7 +222,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { use rustc_data_structures::indexed_vec::Idx; let field_index = field.index(); let val = [a, b][field_index]; - let field = base_layout.field(&*self, field_index).ok()?; + let cx = LayoutCx { + tcx: self.tcx, + param_env: self.param_env, + }; + let field = base_layout.field(cx, field_index).ok()?; trace!("projection resulted in: {:?}", val); Some((Value::ByVal(val), field.ty, span)) }, @@ -258,19 +299,13 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { // FIXME: can't handle code with generics return None; } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); let val = self.eval_operand(arg)?; - let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?; - match ecx.unary_op(op, prim, val.1) { - Ok(val) => Some((Value::ByVal(val), place_ty, span)), - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } + let prim = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }) + })?; + let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?; + Some((Value::ByVal(val), place_ty, span)) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -287,11 +322,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { // FIXME: can't handle code with generics return None; } - let substs = Substs::identity_for_item(self.tcx, self.source.def_id); - let instance = Instance::new(self.source.def_id, substs); - let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + let r = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }) + })?; if op == BinOp::Shr || op == BinOp::Shl { let param_env = self.tcx.param_env(self.source.def_id); let left_ty = left.ty(self.mir, self.tcx); @@ -316,31 +350,31 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } } let left = self.eval_operand(left)?; - let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; + let l = self.use_ecx(span, |this| { + this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }) + })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); - match ecx.binary_op(op, l, left.1, r, right.1) { - Ok((val, overflow)) => { - let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { - Value::ByValPair( - val, - PrimVal::from_bool(overflow), - ) - } else { - if overflow { - use rustc::mir::interpret::EvalErrorKind; - let mut err = EvalErrorKind::Overflow(op).into(); - ecx.report(&mut err, false, Some(span)); - return None; - } - Value::ByVal(val) - }; - Some((val, place_ty, span)) - }, - Err(mut err) => { - ecx.report(&mut err, false, Some(span)); - None - }, - } + let (val, overflow) = self.use_ecx(span, |this| { + this.ecx.binary_op(op, l, left.1, r, right.1) + })?; + let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { + Value::ByValPair( + val, + PrimVal::from_bool(overflow), + ) + } else { + if overflow { + use rustc::mir::interpret::EvalErrorKind; + let mut err = EvalErrorKind::Overflow(op).into(); + self.use_ecx(span, |this| { + this.ecx.report(&mut err, false, Some(span)); + Ok(()) + }); + return None; + } + Value::ByVal(val) + }; + Some((val, place_ty, span)) }, } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5397d18cdd720..0666209d4f13a 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -17,8 +17,6 @@ use dataflow::MoveDataParamEnv; use dataflow::{self, do_dataflow, DebugFormatted}; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; -use rustc::middle::const_val::ConstVal; -use rustc::mir::interpret::{Value, PrimVal}; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; @@ -533,10 +531,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))), - ty: self.tcx.types.bool - }) + value: ty::Const::from_bool(self.tcx, val) } }))) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c4e700cdd1f41..5da40d04b3373 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -61,7 +61,6 @@ use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor}; use rustc::ty::{self, TyCtxt, AdtDef, Ty}; @@ -79,7 +78,6 @@ 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; @@ -180,10 +178,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { span: source_info.span, ty: self.tcx.types.u32, literal: Literal::Value { - value: self.tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))), - ty: self.tcx.types.u32 - }), + value: ty::Const::from_bits( + self.tcx, + state_disc.into(), + self.tcx.types.u32), }, }); Statement { @@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, literal: Literal::Value { - value: tcx.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))), - ty: tcx.types.bool - }), + value: ty::Const::from_bool(tcx, false), }, }), expected: true, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4762c6aaa27cc..28ab3d6a8574f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } Operand::Constant(ref constant) => { if let Literal::Value { - value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty } + value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. } } = constant.literal { // Don't peek inside trait associated constants. if self.tcx.trait_of_item(def_id).is_some() { @@ -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.unwrap_u64() == 0 && + len.unwrap_usize(self.tcx) == 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 9dd48952208a9..72bee040c06a9 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -10,10 +10,8 @@ //! A pass that simplifies branches when their condition is known. -use rustc::ty::{self, TyCtxt}; -use rustc::middle::const_val::ConstVal; +use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc::mir::interpret::{Value, PrimVal}; use transform::{MirPass, MirSource}; use std::borrow::Cow; @@ -32,7 +30,7 @@ impl MirPass for SimplifyBranches { } fn run_pass<'a, 'tcx>(&self, - _tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { for block in mir.basic_blocks_mut() { @@ -40,8 +38,8 @@ impl MirPass for SimplifyBranches { terminator.kind = match terminator.kind { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. - }), ref values, ref targets, .. } => { - if let Some(constint) = value.val.to_raw_bits() { + }), switch_ty, ref values, ref targets, .. } => { + if let Some(constint) = value.assert_bits(switch_ty) { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; for (&v, t) in values.iter().zip(targets.iter()) { @@ -57,12 +55,9 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(box Constant { literal: Literal::Value { - value: &ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))), - .. } + value }, .. - }), expected, .. } if (cond == 1) == expected => { - assert!(cond <= 1); + }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => { TerminatorKind::Goto { target: target } }, TerminatorKind::FalseEdges { real_target, .. } => { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 9cc3ffb30638f..5019c74742a2b 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -81,9 +81,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { } else { let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); if let ty::TyArray(item_ty, const_size) = place_ty.sty { - if let Some(size) = const_size.val.to_raw_bits() { - assert!(size <= (u32::max_value() as u128), - "unform array move out doesn't supported + if let Some(size) = const_size.assert_usize(self.tcx) { + assert!(size <= u32::max_value() as u64, + "uniform array move out doesn't supported for array bigger then u32"); self.uniform(location, dst_place, proj, item_ty, size as u32); } @@ -203,7 +203,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_size = opt_src_place.and_then(|src_place| { let src_ty = src_place.ty(mir, tcx).to_ty(tcx); if let ty::TyArray(_, ref size_o) = src_ty.sty { - size_o.val.to_raw_bits().map(|n| n as u64) + size_o.assert_usize(tcx) } else { None } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index a641cf3d93ecf..9fc04dc7d2491 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -11,7 +11,6 @@ use std::fmt; use rustc::hir; use rustc::mir::*; -use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; @@ -19,7 +18,6 @@ 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}; @@ -809,8 +807,10 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let succ = self.succ; self.complete_drop(Some(DropFlagMode::Deep), succ, unwind) } - ty::TyArray(ety, size) => self.open_drop_for_array( - ety, size.val.to_raw_bits().map(|i| i as u64)), + ty::TyArray(ety, size) => { + let size = size.assert_usize(self.tcx()); + self.open_drop_for_array(ety, size) + }, ty::TySlice(ety) => self.open_drop_for_array(ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty) @@ -961,10 +961,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, literal: Literal::Value { - value: self.tcx().mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))), - ty: self.tcx().types.usize - }) + value: ty::Const::from_usize(self.tcx(), val.into()) } }) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 71012ca6d5f79..9d74ad0830f0c 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -402,7 +402,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); - let ty::Const { ty, val } = constant; + let ty::Const { ty, val, .. } = constant; self.push(&format!("ty::Const")); self.push(&format!("+ ty: {:?}", ty)); self.push(&format!("+ val: {:?}", val)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 33dc9b3b7ab90..54177c5d5a2cc 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -199,7 +199,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.unwrap_u64()) + C_usize(cx, len.unwrap_usize(cx.tcx)) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker @@ -1372,8 +1372,7 @@ mod temp_stable_hash_impls { } fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { - use rustc::mir::interpret::{GlobalId, Value, PrimVal}; - use rustc::middle::const_val::ConstVal; + use rustc::mir::interpret::GlobalId; info!("loading wasm section {:?}", id); @@ -1392,18 +1391,7 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { let param_env = ty::ParamEnv::reveal_all(); let val = tcx.const_eval(param_env.and(cid)).unwrap(); - let val = match val.val { - ConstVal::Value(val) => val, - ConstVal::Unevaluated(..) => bug!("should be evaluated"), - }; - let val = match val { - Value::ByRef(ptr, _align) => ptr.into_inner_primval(), - ref v => bug!("should be ByRef, was {:?}", v), - }; - let mem = match val { - PrimVal::Ptr(mem) => mem, - ref v => bug!("should be Ptr, was {:?}", v), - }; + let mem = val.to_ptr().expect("should be pointer"); assert_eq!(mem.offset, 0); let alloc = tcx .interpret_interner diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ae23b523cbfae..4e77c0df65ef4 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -277,7 +277,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.unwrap_u64() as c_longlong + len.unwrap_usize(cx.tcx) as c_longlong } _ => -1 }; diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 565a9bedef0f5..05a74db3a6ca9 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.unwrap_u64())); + output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 6e07b8e73ef22..a10b7c9c9f10f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -14,7 +14,7 @@ use rustc_mir::interpret::{read_target_uint, const_val_field}; use rustc::hir::def_id::DefId; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue}; +use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue}; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; use builder::Builder; @@ -56,7 +56,7 @@ pub fn primval_to_llvm(cx: &CodegenCx, consts::get_static(cx, def_id) } else if let Some(alloc) = cx.tcx.interpret_interner .get_alloc(ptr.alloc_id) { - let init = global_initializer(cx, alloc); + let init = const_alloc_to_llvm(cx, alloc); if alloc.runtime_mutability == Mutability::Mutable { consts::addr_of_mut(cx, init, alloc.align, "byte_str") } else { @@ -81,7 +81,50 @@ pub fn primval_to_llvm(cx: &CodegenCx, } } -pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { +fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { + let layout = cx.layout_of(ty); + + if layout.is_zst() { + return C_undef(layout.immediate_llvm_type(cx)); + } + + match val { + ConstValue::ByVal(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) + }; + primval_to_llvm( + cx, + x, + scalar, + layout.immediate_llvm_type(cx), + ) + }, + ConstValue::ByValPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) + }; + let a_llval = primval_to_llvm( + cx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(cx, 0), + ); + let b_llval = primval_to_llvm( + cx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(cx, 1), + ); + C_struct(cx, &[a_llval, b_llval], false) + }, + ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), + } +} + +pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); let layout = cx.data_layout(); let pointer_size = layout.pointer_size.bytes() as usize; @@ -96,7 +139,7 @@ pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let ptr_offset = read_target_uint( layout.endian, &alloc.bytes[offset..(offset + pointer_size)], - ).expect("global_initializer: could not read relocation pointer") as u64; + ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(primval_to_llvm( cx, PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), @@ -128,25 +171,19 @@ pub fn trans_static_initializer<'a, 'tcx>( let param_env = ty::ParamEnv::reveal_all(); let static_ = cx.tcx.const_eval(param_env.and(cid))?; - let ptr = match static_.val { - ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr, + let val = match static_.val { + ConstVal::Value(val) => val, _ => bug!("static const eval returned {:#?}", static_), }; - - let alloc = cx - .tcx - .interpret_interner - .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id) - .expect("miri allocation never successfully created"); - Ok(global_initializer(cx, alloc)) + Ok(const_value_to_llvm(cx, val, static_.ty)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - fn const_to_miri_value( + fn const_to_const_value( &mut self, bx: &Builder<'a, 'tcx>, constant: &'tcx ty::Const<'tcx>, - ) -> Result> { + ) -> Result, ConstEvalErr<'tcx>> { match constant.val { ConstVal::Unevaluated(def_id, ref substs) => { let tcx = bx.tcx(); @@ -157,17 +194,17 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { promoted: None, }; let c = tcx.const_eval(param_env.and(cid))?; - self.const_to_miri_value(bx, c) + self.const_to_const_value(bx, c) }, - ConstVal::Value(miri_val) => Ok(miri_val), + ConstVal::Value(val) => Ok(val), } } - pub fn mir_constant_to_miri_value( + pub fn mir_constant_to_const_value( &mut self, bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, - ) -> Result> { + ) -> Result, ConstEvalErr<'tcx>> { match constant.literal { mir::Literal::Promoted { index } => { let param_env = ty::ParamEnv::reveal_all(); @@ -180,7 +217,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Literal::Value { value } => { Ok(self.monomorphize(&value)) } - }.and_then(|c| self.const_to_miri_value(bx, c)) + }.and_then(|c| self.const_to_const_value(bx, c)) } /// process constant containing SIMD shuffle indices @@ -189,11 +226,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, constant: &mir::Constant<'tcx>, ) -> (ValueRef, Ty<'tcx>) { - self.mir_constant_to_miri_value(bx, constant) + self.mir_constant_to_const_value(bx, constant) .and_then(|c| { let field_ty = constant.ty.builtin_index().unwrap(); let fields = match constant.ty.sty { - ty::TyArray(_, n) => n.val.unwrap_u64(), + ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()), ref other => bug!("invalid simd shuffle type: {}", other), }; let values: Result, _> = (0..fields).map(|field| { @@ -206,19 +243,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { c, constant.ty, )?; - match field.val { - ConstVal::Value(MiriValue::ByVal(prim)) => { - let layout = bx.cx.layout_of(field_ty); - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - Ok(primval_to_llvm( - bx.cx, prim, scalar, - layout.immediate_llvm_type(bx.cx), - )) - }, - other => bug!("simd shuffle field {:?}, {}", other, constant.ty), + if let Some(prim) = field.to_primval() { + let layout = bx.cx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(primval_to_llvm( + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), + )) + } else { + bug!("simd shuffle field {:?}", field) } }).collect(); let llval = C_struct(bx.cx, &values?, false); diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 656ab95a28cf3..432ac44e0a566 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -11,7 +11,7 @@ use llvm::ValueRef; use rustc::middle::const_val::ConstEvalErr; use rustc::mir; -use rustc::mir::interpret::Value as MiriValue; +use rustc::mir::interpret::ConstValue; use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; @@ -22,12 +22,13 @@ use builder::Builder; use value::Value; use type_of::LayoutLlvmExt; use type_::Type; +use consts; use std::fmt; use std::ptr; use super::{FunctionCx, LocalRef}; -use super::constant::{primval_to_llvm}; +use super::constant::{primval_to_llvm, const_alloc_to_llvm}; use super::place::PlaceRef; /// The representation of a Rust value. The enum variant is in fact @@ -94,7 +95,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { } pub fn from_const(bx: &Builder<'a, 'tcx>, - miri_val: MiriValue, + val: ConstValue<'tcx>, ty: ty::Ty<'tcx>) -> Result, ConstEvalErr<'tcx>> { let layout = bx.cx.layout_of(ty); @@ -103,8 +104,8 @@ impl<'a, 'tcx> OperandRef<'tcx> { return Ok(OperandRef::new_zst(bx.cx, layout)); } - let val = match miri_val { - MiriValue::ByVal(x) => { + let val = match val { + ConstValue::ByVal(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) @@ -117,7 +118,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { ); OperandValue::Immediate(llval) }, - MiriValue::ByValPair(a, b) => { + ConstValue::ByValPair(a, b) => { let (a_scalar, b_scalar) = match layout.abi { layout::Abi::ScalarPair(ref a, ref b) => (a, b), _ => bug!("from_const: invalid ByValPair layout: {:#?}", layout) @@ -136,18 +137,11 @@ impl<'a, 'tcx> OperandRef<'tcx> { ); OperandValue::Pair(a_llval, b_llval) }, - MiriValue::ByRef(ptr, align) => { - let scalar = layout::Scalar { - value: layout::Primitive::Pointer, - valid_range: 0..=!0 - }; - let ptr = primval_to_llvm( - bx.cx, - ptr.into_inner_primval(), - &scalar, - layout.llvm_type(bx.cx).ptr_to(), - ); - return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx)); + ConstValue::ByRef(alloc) => { + let init = const_alloc_to_llvm(bx.cx, alloc); + let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); + return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx)); }, }; @@ -396,7 +390,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Operand::Constant(ref constant) => { let ty = self.monomorphize(&constant.ty); - self.mir_constant_to_miri_value(bx, constant) + self.mir_constant_to_const_value(bx, constant) .and_then(|c| OperandRef::from_const(bx, c, ty)) .unwrap_or_else(|err| { match constant.literal { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 0cd823391b9b6..3b4477564502c 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -516,7 +516,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.unwrap_u64(); + let n = n.unwrap_usize(bx.cx.tcx); return common::C_usize(bx.cx, n); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 93dbba6e873a9..d307ef30044e1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,6 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc::middle::const_val::ConstVal; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1087,10 +1086,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyArray(ref ty, length) => { let length_def_id = tcx.hir.body_owner_def_id(length); let substs = Substs::identity_for_item(tcx, length_def_id); - let length = tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(length_def_id, substs), - ty: tcx.types.usize - }); + let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize); let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c7585c827ce11..2547952d1043c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -375,7 +375,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.unwrap_u64(); + let size = size.unwrap_usize(tcx); 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 ef14fa9a12248..7b859635f60df 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4018,7 +4018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Ok(count) = count { - let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1); + let zero_or_one = count.assert_usize(tcx).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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 007938e86ed9d..3ffdd5595a2d5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2644,10 +2644,7 @@ impl Clean for hir::Ty { promoted: None }; let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| { - cx.tcx.mk_const(ty::Const { - val: ConstVal::Unevaluated(def_id, substs), - ty: cx.tcx.types.usize - }) + ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize) }); let n = print_const(cx, n); Array(box ty.clean(cx), n) @@ -3828,9 +3825,9 @@ fn print_const(cx: &DocContext, n: &ty::Const) -> String { inline::print_inlined_const(cx, def_id) } }, - ConstVal::Value(val) => { + ConstVal::Value(..) => { let mut s = String::new(); - ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap(); + ::rustc::mir::fmt_const_val(&mut s, n).unwrap(); // array lengths are obviously usize if s.ends_with("usize") { let n = s.len() - "usize".len(); diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 415ee6eb7eab8..1879002e7f3d7 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,17 +12,11 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" +// CHECK: @VAR1 = constant i32 1, section ".test_one" #[no_mangle] #[link_section = ".test_one"] -#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; -#[no_mangle] -#[link_section = ".test_one"] -#[cfg(target_endian = "big")] -pub static VAR1: u32 = 0x01000000; - pub enum E { A(u32), B(f32) From 0aa92acda7cb14c0040dcd346e5f015b6f36c352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 3 May 2018 18:29:14 +0200 Subject: [PATCH 2/2] Add a query to convert from ConstValue to Allocation --- src/librustc/dep_graph/dep_node.rs | 11 +++--- src/librustc/ty/maps/config.rs | 6 +++ src/librustc/ty/maps/keys.rs | 9 +++++ src/librustc/ty/maps/mod.rs | 11 ++++++ src/librustc/ty/maps/plumbing.rs | 1 + src/librustc_mir/interpret/const_eval.rs | 28 ++++++++++++- src/librustc_mir/interpret/memory.rs | 50 ++++++++++++++++++++---- src/librustc_mir/interpret/mod.rs | 1 + src/librustc_mir/lib.rs | 1 + src/librustc_trans/base.rs | 13 +++--- 10 files changed, 110 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 54dda320e1fca..4847a7f4ddbec 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -621,13 +621,14 @@ define_dep_nodes!( <'tcx> [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - // This query is not expected to have inputs -- as a result, it's - // not a good candidate for "replay" because it's essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just this - // query). Making it anonymous avoids hashing the result, which + // These queries are not expected to have inputs -- as a result, they + // are not good candidates for "replay" because they are essentially + // pure functions of their input (and hence the expectation is that + // no caller would be green **apart** from just these + // queries). Making them anonymous avoids hashing the result, which // may save a bit of time. [anon] EraseRegionsTy { ty: Ty<'tcx> }, + [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> }, [input] Freevars(DefId), [input] MaybeUnusedTraitImport(DefId), diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index ca594faf5cd3b..4e104692d859b 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -137,6 +137,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> { + fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String { + format!("converting value `{:?}` ({}) to an allocation", val, ty) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> { fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String { format!("erasing regions from `{:?}`", ty) diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index da29f23589e85..3510a1b7a028f 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -145,6 +145,15 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ } } +impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for Ty<'tcx> { fn map_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 80402f87650c6..6e419627dd8b5 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -228,6 +228,11 @@ define_maps! { <'tcx> [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalResult<'tcx>, + /// Converts a constant value to an constant allocation + [] fn const_value_to_allocation: const_value_to_allocation( + (ConstValue<'tcx>, Ty<'tcx>) + ) -> &'tcx Allocation, + [] fn check_match: CheckMatch(DefId) -> Result<(), ErrorReported>, @@ -478,6 +483,12 @@ fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::EraseRegionsTy { ty } } +fn const_value_to_allocation<'tcx>( + (val, ty): (ConstValue<'tcx>, Ty<'tcx>) +) -> DepConstructor<'tcx> { + DepConstructor::ConstValueToAllocation { val, ty } +} + fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { DepConstructor::TypeParamPredicates { item_id, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 37950463f7444..65dcb7311d336 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -956,6 +956,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::FulfillObligation | DepKind::VtableMethods | DepKind::EraseRegionsTy | + DepKind::ConstValueToAllocation | DepKind::NormalizeProjectionTy | DepKind::NormalizeTyAfterErasingRegions | DepKind::DropckOutlives | diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index b8bb58b9ed24c..6bf965aaf4463 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -8,12 +8,13 @@ use rustc::ty::subst::Subst; use syntax::ast::Mutability; use syntax::codemap::Span; +use syntax::codemap::DUMMY_SP; use rustc::mir::interpret::{ EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, AllocId, Allocation, ConstValue, }; -use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind}; use std::fmt; use std::error::Error; @@ -470,7 +471,6 @@ pub fn const_variant_index<'a, 'tcx>( 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)?; @@ -482,6 +482,30 @@ pub fn const_variant_index<'a, 'tcx>( ecx.read_discriminant_as_variant_index(place, ty) } +pub fn const_value_to_allocation_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + (val, ty): (ConstValue<'tcx>, Ty<'tcx>), +) -> &'tcx Allocation { + match val { + ConstValue::ByRef(alloc) => return alloc, + _ => () + } + let result = || -> EvalResult<'tcx, &'tcx Allocation> { + let mut ecx = EvalContext::new( + tcx.at(DUMMY_SP), + ty::ParamEnv::reveal_all(), + CompileTimeEvaluator, + ()); + let value = ecx.const_value_to_value(val, ty)?; + let layout = ecx.layout_of(ty)?; + let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?; + let alloc = ecx.memory.get(ptr.alloc_id)?; + Ok(tcx.intern_const_alloc(alloc.clone())) + }; + result().expect("unable to convert ConstVal to Allocation") +} + pub fn const_eval_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 18cd75ae0bbf4..ba1c05deef1b4 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,14 +1,17 @@ use std::collections::{btree_map, VecDeque}; use std::ptr; +use rustc::hir::def_id::DefId; use rustc::ty::Instance; +use rustc::ty::ParamEnv; use rustc::ty::maps::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; +use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer, - EvalResult, PrimVal, EvalErrorKind}; + EvalResult, PrimVal, EvalErrorKind, GlobalId}; pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint}; use super::{EvalContext, Machine}; @@ -274,6 +277,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// Allocation accessors impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { + fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> { + let instance = Instance::mono(self.tcx.tcx, def_id); + let gid = GlobalId { + instance, + promoted: None, + }; + self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| { + match *err.kind { + ErrKind::Miri(ref err, _) => match err.kind { + EvalErrorKind::TypeckError | + EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(), + _ => EvalErrorKind::ReferencedConstant.into(), + }, + ErrKind::TypeckError => EvalErrorKind::TypeckError.into(), + ref other => bug!("const eval returned {:?}", other), + } + }).map(|val| { + let const_val = match val.val { + ConstVal::Value(val) => val, + ConstVal::Unevaluated(..) => bug!("should be evaluated"), + }; + self.tcx.const_value_to_allocation((const_val, val.ty)) + }) + } + pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { // normal alloc? match self.alloc_map.get(&id) { @@ -283,13 +311,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Some(alloc) => Ok(alloc), None => { // static alloc? - self.tcx.interpret_interner.get_alloc(id) - // no alloc? produce an error - .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() { - EvalErrorKind::DerefFunctionPointer.into() - } else { - EvalErrorKind::DanglingPointerDeref.into() - }) + if let Some(a) = self.tcx.interpret_interner.get_alloc(id) { + return Ok(a); + } + // static variable? + if let Some(did) = self.tcx.interpret_interner.get_static(id) { + return self.const_eval_static(did); + } + // otherwise return an error + Err(if self.tcx.interpret_interner.get_fn(id).is_some() { + EvalErrorKind::DerefFunctionPointer.into() + } else { + EvalErrorKind::DanglingPointerDeref.into() + }) }, }, } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 7f9e67a62ccc4..d39bae5e8dbba 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -23,6 +23,7 @@ pub use self::const_eval::{ mk_borrowck_eval_cx, eval_body, CompileTimeEvaluator, + const_value_to_allocation_provider, const_eval_provider, const_val_field, const_variant_index, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 2545ba3a94af1..fbc0facbc4967 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -85,6 +85,7 @@ pub fn provide(providers: &mut Providers) { shim::provide(providers); transform::provide(providers); providers.const_eval = interpret::const_eval_provider; + providers.const_value_to_allocation = interpret::const_value_to_allocation_provider; providers.check_match = hair::pattern::check_match; } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 54177c5d5a2cc..0dd1adbff86e0 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1373,6 +1373,7 @@ mod temp_stable_hash_impls { fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { use rustc::mir::interpret::GlobalId; + use rustc::middle::const_val::ConstVal; info!("loading wasm section {:?}", id); @@ -1391,11 +1392,11 @@ fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { let param_env = ty::ParamEnv::reveal_all(); let val = tcx.const_eval(param_env.and(cid)).unwrap(); - let mem = val.to_ptr().expect("should be pointer"); - assert_eq!(mem.offset, 0); - let alloc = tcx - .interpret_interner - .get_alloc(mem.alloc_id) - .expect("miri allocation never successfully created"); + let const_val = match val.val { + ConstVal::Value(val) => val, + ConstVal::Unevaluated(..) => bug!("should be evaluated"), + }; + + let alloc = tcx.const_value_to_allocation((const_val, val.ty)); (section.to_string(), alloc.bytes.clone()) }