InterpCx
store TypingEnv
instead of a ParamEnv
This commit is contained in:
parent
b9dea31ea9
commit
7a90e84f4d
36 changed files with 167 additions and 192 deletions
|
@ -7,7 +7,6 @@ use rustc_middle::bug;
|
|||
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
|
||||
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -31,7 +30,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||
cid: GlobalId<'tcx>,
|
||||
body: &'tcx mir::Body<'tcx>,
|
||||
) -> InterpResult<'tcx, R> {
|
||||
trace!(?ecx.param_env);
|
||||
trace!(?ecx.typing_env);
|
||||
let tcx = *ecx.tcx;
|
||||
assert!(
|
||||
cid.promoted.is_some()
|
||||
|
@ -126,14 +125,14 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||
pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
root_span: Span,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
can_access_mut_global: CanAccessMutGlobal,
|
||||
) -> CompileTimeInterpCx<'tcx> {
|
||||
debug!("mk_eval_cx: {:?}", param_env);
|
||||
debug!("mk_eval_cx: {:?}", typing_env);
|
||||
InterpCx::new(
|
||||
tcx,
|
||||
root_span,
|
||||
param_env,
|
||||
typing_env,
|
||||
CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No),
|
||||
)
|
||||
}
|
||||
|
@ -142,11 +141,11 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
|
|||
/// Returns both the context and an `OpTy` that represents the constant.
|
||||
pub fn mk_eval_cx_for_const_val<'tcx>(
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
val: mir::ConstValue<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
|
||||
let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No);
|
||||
let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No);
|
||||
// FIXME: is it a problem to discard the error here?
|
||||
let op = ecx.const_val_to_op(val, ty, None).discard_err()?;
|
||||
Some((ecx, op))
|
||||
|
@ -221,7 +220,7 @@ pub(super) fn op_to_const<'tcx>(
|
|||
let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
|
||||
debug_assert!(
|
||||
matches!(
|
||||
ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
|
||||
ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env).kind(),
|
||||
ty::Str | ty::Slice(..),
|
||||
),
|
||||
"`ConstValue::Slice` is for slice-tailed types only, but got {}",
|
||||
|
@ -245,7 +244,7 @@ pub(super) fn op_to_const<'tcx>(
|
|||
pub(crate) fn turn_into_const_value<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
constant: ConstAlloc<'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
|
||||
) -> ConstValue<'tcx> {
|
||||
let cid = key.value;
|
||||
let def_id = cid.instance.def.def_id();
|
||||
|
@ -254,7 +253,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
|
|||
let ecx = mk_eval_cx_to_read_const_val(
|
||||
tcx,
|
||||
tcx.def_span(key.value.instance.def_id()),
|
||||
key.param_env,
|
||||
key.typing_env,
|
||||
CanAccessMutGlobal::from(is_static),
|
||||
);
|
||||
|
||||
|
@ -274,23 +273,16 @@ pub(crate) fn turn_into_const_value<'tcx>(
|
|||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub fn eval_to_const_value_raw_provider<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
|
||||
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
|
||||
// Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
|
||||
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
|
||||
// types that are not specified in the opaque type.
|
||||
assert_eq!(key.param_env.reveal(), Reveal::All);
|
||||
let typing_env =
|
||||
ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: key.param_env };
|
||||
|
||||
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
|
||||
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
|
||||
if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def {
|
||||
let ty = key.value.instance.ty(tcx, typing_env);
|
||||
let ty = key.value.instance.ty(tcx, key.typing_env);
|
||||
let ty::FnDef(_, args) = ty.kind() else {
|
||||
bug!("intrinsic with type {:?}", ty);
|
||||
};
|
||||
return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err(
|
||||
return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err(
|
||||
|error| {
|
||||
let span = tcx.def_span(def_id);
|
||||
|
||||
|
@ -317,7 +309,7 @@ pub fn eval_static_initializer_provider<'tcx>(
|
|||
|
||||
let instance = ty::Instance::mono(tcx, def_id.to_def_id());
|
||||
let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
|
||||
eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all())
|
||||
eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized())
|
||||
}
|
||||
|
||||
pub trait InterpretationResult<'tcx> {
|
||||
|
@ -342,16 +334,14 @@ impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
|
|||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
|
||||
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
|
||||
// This shouldn't be used for statics, since statics are conceptually places,
|
||||
// not values -- so what we do here could break pointer identity.
|
||||
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
|
||||
// Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
|
||||
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
|
||||
// types that are not specified in the opaque type.
|
||||
|
||||
assert_eq!(key.param_env.reveal(), Reveal::All);
|
||||
// Const eval always happens in PostAnalysis mode . See the comment in
|
||||
// `InterpCx::new` for more details.
|
||||
debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
|
||||
if cfg!(debug_assertions) {
|
||||
// Make sure we format the instance even if we do not print it.
|
||||
// This serves as a regression test against an ICE on printing.
|
||||
|
@ -362,13 +352,13 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||
trace!("const eval: {:?} ({})", key, instance);
|
||||
}
|
||||
|
||||
eval_in_interpreter(tcx, key.value, key.param_env)
|
||||
eval_in_interpreter(tcx, key.value, key.typing_env)
|
||||
}
|
||||
|
||||
fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> Result<R, ErrorHandled> {
|
||||
let def = cid.instance.def.def_id();
|
||||
let is_static = tcx.is_static(def);
|
||||
|
@ -376,7 +366,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
|
|||
let mut ecx = InterpCx::new(
|
||||
tcx,
|
||||
tcx.def_span(def),
|
||||
param_env,
|
||||
typing_env,
|
||||
// Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
|
||||
// they do not have to behave "as if" they were evaluated at runtime.
|
||||
// For consts however we want to ensure they behave "as if" they were evaluated at runtime,
|
||||
|
|
|
@ -667,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
.is_some_and(|p| !p.immutable())
|
||||
{
|
||||
// That next check is expensive, that's why we have all the guards above.
|
||||
let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env());
|
||||
let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env);
|
||||
let place = ecx.ref_to_mplace(val)?;
|
||||
let new_place = if is_immutable {
|
||||
place.map_provenance(CtfeProvenance::as_immutable)
|
||||
|
|
|
@ -38,8 +38,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
|
|||
val: mir::ConstValue<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<mir::DestructuredConstant<'tcx>> {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?;
|
||||
let typing_env = ty::TypingEnv::fully_monomorphized();
|
||||
let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?;
|
||||
|
||||
// We go to `usize` as we cannot allocate anything bigger anyway.
|
||||
let (field_count, variant, down) = match ty.kind() {
|
||||
|
@ -76,10 +76,12 @@ pub fn tag_for_variant_provider<'tcx>(
|
|||
) -> Option<ty::ScalarInt> {
|
||||
assert!(ty.is_enum());
|
||||
|
||||
// FIXME: This uses an empty `TypingEnv` even though
|
||||
// it may be used by a generic CTFE.
|
||||
let ecx = InterpCx::new(
|
||||
tcx,
|
||||
ty.default_span(tcx),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
crate::const_eval::DummyMachine,
|
||||
);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ use rustc_abi::{BackendRepr, VariantIdx};
|
|||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::solve::Reveal;
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
@ -229,16 +228,19 @@ fn create_valtree_place<'tcx>(
|
|||
/// Evaluates a constant and turns it into a type-level constant value.
|
||||
pub(crate) fn eval_to_valtree<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
) -> EvalToValTreeResult<'tcx> {
|
||||
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
|
||||
// Const eval always happens in PostAnalysis mode . See the comment in
|
||||
// `InterpCx::new` for more details.
|
||||
debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
|
||||
let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
|
||||
|
||||
// FIXME Need to provide a span to `eval_to_valtree`
|
||||
let ecx = mk_eval_cx_to_read_const_val(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
param_env,
|
||||
typing_env,
|
||||
// It is absolutely crucial for soundness that
|
||||
// we do not read from mutable memory.
|
||||
CanAccessMutGlobal::No,
|
||||
|
@ -273,7 +275,8 @@ pub(crate) fn eval_to_valtree<'tcx>(
|
|||
#[instrument(skip(tcx), level = "debug", ret)]
|
||||
pub fn valtree_to_const_value<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
valtree: ty::ValTree<'tcx>,
|
||||
) -> mir::ConstValue<'tcx> {
|
||||
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
|
||||
|
@ -282,10 +285,6 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
// the `ValTree` and using `place_projection` and `place_field` to
|
||||
// create inner `MPlace`s which are filled recursively.
|
||||
// FIXME Does this need an example?
|
||||
let (param_env, ty) = param_env_ty.into_parts();
|
||||
debug_assert_eq!(param_env.reveal(), Reveal::All);
|
||||
let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env };
|
||||
|
||||
match *ty.kind() {
|
||||
ty::FnDef(..) => {
|
||||
assert!(valtree.unwrap_branch().is_empty());
|
||||
|
@ -299,10 +298,10 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
),
|
||||
}
|
||||
}
|
||||
ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
|
||||
ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree),
|
||||
ty::Ref(_, inner_ty, _) => {
|
||||
let mut ecx =
|
||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
|
||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
||||
let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
|
||||
let imm =
|
||||
ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap());
|
||||
|
@ -324,14 +323,14 @@ pub fn valtree_to_const_value<'tcx>(
|
|||
for (i, &inner_valtree) in branches.iter().enumerate() {
|
||||
let field = layout.field(&LayoutCx::new(tcx, typing_env), i);
|
||||
if !field.is_zst() {
|
||||
return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree);
|
||||
return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree);
|
||||
}
|
||||
}
|
||||
bug!("could not find non-ZST field during in {layout:#?}");
|
||||
}
|
||||
|
||||
let mut ecx =
|
||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
|
||||
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No);
|
||||
|
||||
// Need to create a place for this valtree.
|
||||
let place = create_valtree_place(&mut ecx, layout, valtree);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue