From 9eabdc2a4cc896065004fb8566509daa11d6562a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Feb 2024 14:18:06 +0100 Subject: [PATCH] make it possible for outside crates to inspect a mir::ConstValue with the interpreter --- .../src/const_eval/eval_queries.rs | 25 ++++++++++++++++--- .../rustc_const_eval/src/const_eval/mod.rs | 3 +-- .../src/const_eval/valtrees.rs | 10 +++++--- .../src/util/caller_location.rs | 9 +++++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7099cdd5a7540..9e4e7911c3a73 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -3,10 +3,11 @@ use either::{Left, Right}; use rustc_hir::def::DefKind; 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, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::abi::{self, Abi}; @@ -87,13 +88,16 @@ fn eval_body_using_ecx<'mir, 'tcx>( } /// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. It never performs alignment checks. +/// `simd_shuffle` and const patterns in match arms. +/// +/// This should *not* be used to do any actual interpretation. In particular, alignment checks are +/// turned off! /// /// The function containing the `match` that is currently being analyzed may have generic bounds /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx<'mir, 'tcx>( +pub(crate) fn mk_eval_cx_to_read_const_val<'mir, 'tcx>( tcx: TyCtxt<'tcx>, root_span: Span, param_env: ty::ParamEnv<'tcx>, @@ -108,6 +112,19 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( ) } +/// Create an interpreter context to inspect the given `ConstValue`. +/// Returns both the context and an `OpTy` that represents the constant. +pub fn mk_eval_cx_for_const_val<'mir, 'tcx>( + tcx: TyCtxtAt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: mir::ConstValue<'tcx>, + ty: Ty<'tcx>, +) -> Option<(CompileTimeEvalContext<'mir, 'tcx>, OpTy<'tcx>)> { + let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); + let op = ecx.const_val_to_op(val, ty, None).ok()?; + Some((ecx, op)) +} + /// This function converts an interpreter value into a MIR constant. /// /// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a @@ -203,7 +220,7 @@ pub(crate) fn turn_into_const_value<'tcx>( let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); // This is just accessing an already computed constant, so no need to check alignment here. - let ecx = mk_eval_cx( + let ecx = mk_eval_cx_to_read_const_val( tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index cd50701040e82..289dcb7d01d68 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -47,8 +47,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( ty: Ty<'tcx>, ) -> Option> { let param_env = ty::ParamEnv::reveal_all(); - let ecx = mk_eval_cx(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; + let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?; // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 514a6a7df7617..d3428d27d52fd 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_target::abi::{Abi, VariantIdx}; -use super::eval_queries::{mk_eval_cx, op_to_const}; +use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; use super::machine::CompileTimeEvalContext; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessMutGlobal; @@ -223,7 +223,7 @@ pub(crate) fn eval_to_valtree<'tcx>( let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; // FIXME Need to provide a span to `eval_to_valtree` - let ecx = mk_eval_cx( + let ecx = mk_eval_cx_to_read_const_val( tcx, DUMMY_SP, param_env, @@ -287,7 +287,8 @@ pub fn valtree_to_const_value<'tcx>( } } ty::Ref(_, inner_ty, _) => { - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + let mut ecx = + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty); let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) @@ -314,7 +315,8 @@ pub fn valtree_to_const_value<'tcx>( bug!("could not find non-ZST field during in {layout:#?}"); } - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + let mut ecx = + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); // Need to create a place for this valtree. let place = create_valtree_place(&mut ecx, layout, valtree); diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index d1c2d22b5a912..b8e15c485f58f 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_span::symbol::Symbol; use rustc_type_ir::Mutability; -use crate::const_eval::{mk_eval_cx, CanAccessMutGlobal, CompileTimeEvalContext}; +use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. @@ -57,7 +57,12 @@ pub(crate) fn const_caller_location_provider( col: u32, ) -> mir::ConstValue<'_> { trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx(tcx.tcx, tcx.span, ty::ParamEnv::reveal_all(), CanAccessMutGlobal::No); + let mut ecx = mk_eval_cx_to_read_const_val( + tcx.tcx, + tcx.span, + ty::ParamEnv::reveal_all(), + CanAccessMutGlobal::No, + ); let loc_place = alloc_caller_location(&mut ecx, file, line, col); if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {