Auto merge of #116835 - oli-obk:evaluated_static_in_metadata2, r=RalfJung
Various const eval cleanups This pulls out the pure refactorings from https://github.com/rust-lang/rust/pull/116564 r? `@RalfJung`
This commit is contained in:
commit
8501f1c7ba
@ -3,7 +3,7 @@ use std::mem;
|
|||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir::interpret::{ErrorHandled, InterpErrorInfo};
|
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
|
||||||
use rustc_middle::mir::pretty::write_allocation_bytes;
|
use rustc_middle::mir::pretty::write_allocation_bytes;
|
||||||
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
|
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
|
||||||
use rustc_middle::traits::Reveal;
|
use rustc_middle::traits::Reveal;
|
||||||
@ -285,7 +285,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
let def = cid.instance.def.def_id();
|
let def = cid.instance.def.def_id();
|
||||||
let is_static = tcx.is_static(def);
|
let is_static = tcx.is_static(def);
|
||||||
|
|
||||||
let mut ecx = InterpCx::new(
|
let ecx = InterpCx::new(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.def_span(def),
|
tcx.def_span(def),
|
||||||
key.param_env,
|
key.param_env,
|
||||||
@ -293,7 +293,14 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
// they do not have to behave "as if" they were evaluated at runtime.
|
// they do not have to behave "as if" they were evaluated at runtime.
|
||||||
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
|
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
|
||||||
);
|
);
|
||||||
|
eval_in_interpreter(ecx, cid, is_static)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval_in_interpreter<'mir, 'tcx>(
|
||||||
|
mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
|
||||||
|
cid: GlobalId<'tcx>,
|
||||||
|
is_static: bool,
|
||||||
|
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
|
||||||
let res = ecx.load_mir(cid.instance.def, cid.promoted);
|
let res = ecx.load_mir(cid.instance.def, cid.promoted);
|
||||||
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
|
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@ -306,7 +313,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
// If the current item has generics, we'd like to enrich the message with the
|
// If the current item has generics, we'd like to enrich the message with the
|
||||||
// instance and its args: to show the actual compile-time values, in addition to
|
// instance and its args: to show the actual compile-time values, in addition to
|
||||||
// the expression, leading to the const eval error.
|
// the expression, leading to the const eval error.
|
||||||
let instance = &key.value.instance;
|
let instance = &cid.instance;
|
||||||
if !instance.args.is_empty() {
|
if !instance.args.is_empty() {
|
||||||
let instance = with_no_trimmed_paths!(instance.to_string());
|
let instance = with_no_trimmed_paths!(instance.to_string());
|
||||||
("const_with_path", instance)
|
("const_with_path", instance)
|
||||||
@ -331,56 +338,14 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
Ok(mplace) => {
|
Ok(mplace) => {
|
||||||
// Since evaluation had no errors, validate the resulting constant.
|
// Since evaluation had no errors, validate the resulting constant.
|
||||||
// This is a separate `try` block to provide more targeted error reporting.
|
// This is a separate `try` block to provide more targeted error reporting.
|
||||||
let validation: Result<_, InterpErrorInfo<'_>> = try {
|
let validation =
|
||||||
let mut ref_tracking = RefTracking::new(mplace.clone());
|
const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
|
||||||
let mut inner = false;
|
|
||||||
while let Some((mplace, path)) = ref_tracking.todo.pop() {
|
|
||||||
let mode = match tcx.static_mutability(cid.instance.def_id()) {
|
|
||||||
Some(_) if cid.promoted.is_some() => {
|
|
||||||
// Promoteds in statics are allowed to point to statics.
|
|
||||||
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
|
|
||||||
}
|
|
||||||
Some(_) => CtfeValidationMode::Regular, // a `static`
|
|
||||||
None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
|
|
||||||
};
|
|
||||||
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
|
|
||||||
inner = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let alloc_id = mplace.ptr().provenance.unwrap();
|
let alloc_id = mplace.ptr().provenance.unwrap();
|
||||||
|
|
||||||
// Validation failed, report an error.
|
// Validation failed, report an error.
|
||||||
if let Err(error) = validation {
|
if let Err(error) = validation {
|
||||||
let (error, backtrace) = error.into_parts();
|
Err(const_report_error(&ecx, error, alloc_id))
|
||||||
backtrace.print_backtrace();
|
|
||||||
|
|
||||||
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
|
|
||||||
|
|
||||||
let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
|
||||||
let mut bytes = String::new();
|
|
||||||
if alloc.size() != abi::Size::ZERO {
|
|
||||||
bytes = "\n".into();
|
|
||||||
// FIXME(translation) there might be pieces that are translatable.
|
|
||||||
write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
|
|
||||||
}
|
|
||||||
let raw_bytes = errors::RawBytesNote {
|
|
||||||
size: alloc.size().bytes(),
|
|
||||||
align: alloc.align.bytes(),
|
|
||||||
bytes,
|
|
||||||
};
|
|
||||||
|
|
||||||
Err(super::report(
|
|
||||||
*ecx.tcx,
|
|
||||||
error,
|
|
||||||
None,
|
|
||||||
|| super::get_span_and_frames(&ecx),
|
|
||||||
move |span, frames| errors::UndefinedBehavior {
|
|
||||||
span,
|
|
||||||
ub_note,
|
|
||||||
frames,
|
|
||||||
raw_bytes,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// Convert to raw constant
|
// Convert to raw constant
|
||||||
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
|
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
|
||||||
@ -388,3 +353,61 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn const_validate_mplace<'mir, 'tcx>(
|
||||||
|
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
|
||||||
|
mplace: &MPlaceTy<'tcx>,
|
||||||
|
is_static: bool,
|
||||||
|
is_promoted: bool,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
let mut ref_tracking = RefTracking::new(mplace.clone());
|
||||||
|
let mut inner = false;
|
||||||
|
while let Some((mplace, path)) = ref_tracking.todo.pop() {
|
||||||
|
let mode = if is_static {
|
||||||
|
if is_promoted {
|
||||||
|
// Promoteds in statics are allowed to point to statics.
|
||||||
|
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
|
||||||
|
} else {
|
||||||
|
// a `static`
|
||||||
|
CtfeValidationMode::Regular
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CtfeValidationMode::Const { inner, allow_static_ptrs: false }
|
||||||
|
};
|
||||||
|
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
|
||||||
|
inner = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn const_report_error<'mir, 'tcx>(
|
||||||
|
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
|
||||||
|
error: InterpErrorInfo<'tcx>,
|
||||||
|
alloc_id: AllocId,
|
||||||
|
) -> ErrorHandled {
|
||||||
|
let (error, backtrace) = error.into_parts();
|
||||||
|
backtrace.print_backtrace();
|
||||||
|
|
||||||
|
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
|
||||||
|
|
||||||
|
let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||||
|
let mut bytes = String::new();
|
||||||
|
if alloc.size() != abi::Size::ZERO {
|
||||||
|
bytes = "\n".into();
|
||||||
|
// FIXME(translation) there might be pieces that are translatable.
|
||||||
|
write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
|
||||||
|
}
|
||||||
|
let raw_bytes =
|
||||||
|
errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes };
|
||||||
|
|
||||||
|
crate::const_eval::report(
|
||||||
|
*ecx.tcx,
|
||||||
|
error,
|
||||||
|
None,
|
||||||
|
|| crate::const_eval::get_span_and_frames(ecx),
|
||||||
|
move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1074,17 +1074,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||||
let gid = GlobalId { instance, promoted: None };
|
let gid = GlobalId { instance, promoted: None };
|
||||||
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
|
let val = if self.tcx.is_static(gid.instance.def_id()) {
|
||||||
// and thus don't care about the parameter environment. While we could just use
|
let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id());
|
||||||
// `self.param_env`, that would mean we invoke the query to evaluate the static
|
|
||||||
// with different parameter environments, thus causing the static to be evaluated
|
let ty = instance.ty(self.tcx.tcx, self.param_env);
|
||||||
// multiple times.
|
mir::ConstAlloc { alloc_id, ty }
|
||||||
let param_env = if self.tcx.is_static(gid.instance.def_id()) {
|
|
||||||
ty::ParamEnv::reveal_all()
|
|
||||||
} else {
|
} else {
|
||||||
self.param_env
|
self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?
|
||||||
};
|
};
|
||||||
let val = self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
|
|
||||||
self.raw_const_to_mplace(val)
|
self.raw_const_to_mplace(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,7 +929,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
/// - no pointers to statics.
|
/// - no pointers to statics.
|
||||||
/// - no `UnsafeCell` or non-ZST `&mut`.
|
/// - no `UnsafeCell` or non-ZST `&mut`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn const_validate_operand(
|
pub(crate) fn const_validate_operand(
|
||||||
&self,
|
&self,
|
||||||
op: &OpTy<'tcx, M::Provenance>,
|
op: &OpTy<'tcx, M::Provenance>,
|
||||||
path: Vec<PathElem>,
|
path: Vec<PathElem>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user