Add a query to convert from ConstValue to Allocation
This commit is contained in:
parent
fdd9787777
commit
0aa92acda7
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 |
|
||||
|
@ -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>>,
|
||||
|
@ -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()
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user