1
Fork 0

Stop using the const_eval query for initializers of statics

As a side effect, we now represent most promoteds as `ConstValue::Scalar` again. This is useful because all implict promoteds are just references anyway and most explicit promoteds are numeric arguments to `asm!` or SIMD instructions.
This commit is contained in:
Oliver Scherer 2020-07-31 13:27:54 +02:00
parent 083f1d7a37
commit 2d7ac728e4
17 changed files with 53 additions and 108 deletions

View file

@ -182,7 +182,7 @@ pub(super) fn op_to_const<'tcx>(
}
}
fn validate_and_turn_into_const<'tcx>(
fn turn_into_const<'tcx>(
tcx: TyCtxt<'tcx>,
constant: RawConst<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@ -191,30 +191,21 @@ fn validate_and_turn_into_const<'tcx>(
let def_id = cid.instance.def.def_id();
let is_static = tcx.is_static(def_id);
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
let val = (|| {
let mplace = ecx.raw_const_to_mplace(constant)?;
// Turn this into a proper constant.
// Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
// whether they become immediates.
if is_static || cid.promoted.is_some() {
let ptr = mplace.ptr.assert_ptr();
Ok(ConstValue::ByRef {
alloc: ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(),
offset: ptr.offset,
})
} else {
Ok(op_to_const(&ecx, mplace.into()))
}
})();
// FIXME: Can this ever be an error and not be a compiler bug or can we just ICE here?
val.map_err(|error| {
let mplace = ecx.raw_const_to_mplace(constant).map_err(|error| {
// FIXME: Can the above ever error and not be a compiler bug or can we just ICE here?
let err = ConstEvalErr::new(&ecx, error, None);
err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
diag.note(note_on_undefined_behavior_error());
diag.emit();
})
})
})?;
assert!(
!is_static || cid.promoted.is_some(),
"the const eval query should not be used for statics, use `const_eval_raw` instead"
);
// Turn this into a proper constant.
Ok(op_to_const(&ecx, mplace.into()))
}
pub fn const_eval_validated_provider<'tcx>(
@ -248,7 +239,7 @@ pub fn const_eval_validated_provider<'tcx>(
});
}
tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key))
tcx.const_eval_raw(key).and_then(|val| turn_into_const(tcx, val, key))
}
pub fn const_eval_raw_provider<'tcx>(

View file

@ -914,13 +914,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
self.param_env
};
// We use `const_eval_raw` here, and get an unvalidated result. That is okay:
// Our result will later be validated anyway, and there seems no good reason
// to have to fail early here. This is also more consistent with
// `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles.
// FIXME: We can hit delay_span_bug if this is an invalid const, interning finds
// that problem, but we never run validation to show an error. Can we ensure
// this does not happen?
let val = self.tcx.const_eval_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
}

View file

@ -554,11 +554,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::ConstKind::Unevaluated(def, substs, promoted) => {
let instance = self.resolve(def.did, substs)?;
// We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
// The reason we use `const_eval_raw` everywhere else is to prevent cycles during
// validation, because validation automatically reads through any references, thus
// potentially requiring the current static to be evaluated again. This is not a
// problem here, because we are building an operand which means an actual read is
// happening.
// The reason we use `const_eval` here is that there can never be a `ty::ConstKind`
// that directly mentions the initializer of a static. Statics are always encoded
// as constants with vaule `&STATIC`.
return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?);
}
ty::ConstKind::Infer(..)

View file

@ -364,8 +364,10 @@ fn collect_items_rec<'tcx>(
recursion_depth_reset = None;
if let Ok(val) = tcx.const_eval_poly(def_id) {
collect_const_value(tcx, val, &mut neighbors);
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
for &((), id) in alloc.relocations().values() {
collect_miri(tcx, id, &mut neighbors);
}
}
}
MonoItem::Fn(instance) => {

View file

@ -631,14 +631,11 @@ pub fn write_allocations<'tcx>(
None => write!(w, " (deallocated)")?,
Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?,
Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
match tcx.const_eval_poly(did) {
Ok(ConstValue::ByRef { alloc, .. }) => {
match tcx.eval_static_initializer(did) {
Ok(alloc) => {
write!(w, " (static: {}, ", tcx.def_path_str(did))?;
write_allocation_track_relocs(w, alloc)?;
}
Ok(_) => {
span_bug!(tcx.def_span(did), " static item without `ByRef` initializer")
}
Err(_) => write!(
w,
" (static: {}, error during initializer evaluation)",