Add a query to convert from ConstValue to Allocation

This commit is contained in:
John Kåre Alsaker 2018-05-03 18:29:14 +02:00
parent fdd9787777
commit 0aa92acda7
10 changed files with 110 additions and 21 deletions

View File

@ -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),

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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 |

View File

@ -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>>,

View File

@ -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()
})
},
},
}

View File

@ -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,

View File

@ -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;
}

View File

@ -1373,6 +1373,7 @@ mod temp_stable_hash_impls {
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
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<u8>) {
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())
}