Skip to content

Commit 8501f1c

Browse files
committed
Auto merge of #116835 - oli-obk:evaluated_static_in_metadata2, r=RalfJung
Various const eval cleanups This pulls out the pure refactorings from #116564 r? `@RalfJung`
2 parents a56bd2b + 066ec12 commit 8501f1c

File tree

3 files changed

+79
-59
lines changed

3 files changed

+79
-59
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+72-49
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::mem;
33
use either::{Left, Right};
44

55
use rustc_hir::def::DefKind;
6-
use rustc_middle::mir::interpret::{ErrorHandled, InterpErrorInfo};
6+
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
77
use rustc_middle::mir::pretty::write_allocation_bytes;
88
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
99
use rustc_middle::traits::Reveal;
@@ -285,15 +285,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
285285
let def = cid.instance.def.def_id();
286286
let is_static = tcx.is_static(def);
287287

288-
let mut ecx = InterpCx::new(
288+
let ecx = InterpCx::new(
289289
tcx,
290290
tcx.def_span(def),
291291
key.param_env,
292292
// Statics (and promoteds inside statics) may access other statics, because unlike consts
293293
// they do not have to behave "as if" they were evaluated at runtime.
294294
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
295295
);
296+
eval_in_interpreter(ecx, cid, is_static)
297+
}
296298

299+
pub fn eval_in_interpreter<'mir, 'tcx>(
300+
mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
301+
cid: GlobalId<'tcx>,
302+
is_static: bool,
303+
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
297304
let res = ecx.load_mir(cid.instance.def, cid.promoted);
298305
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
299306
Err(error) => {
@@ -306,7 +313,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
306313
// If the current item has generics, we'd like to enrich the message with the
307314
// instance and its args: to show the actual compile-time values, in addition to
308315
// the expression, leading to the const eval error.
309-
let instance = &key.value.instance;
316+
let instance = &cid.instance;
310317
if !instance.args.is_empty() {
311318
let instance = with_no_trimmed_paths!(instance.to_string());
312319
("const_with_path", instance)
@@ -331,60 +338,76 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
331338
Ok(mplace) => {
332339
// Since evaluation had no errors, validate the resulting constant.
333340
// This is a separate `try` block to provide more targeted error reporting.
334-
let validation: Result<_, InterpErrorInfo<'_>> = try {
335-
let mut ref_tracking = RefTracking::new(mplace.clone());
336-
let mut inner = false;
337-
while let Some((mplace, path)) = ref_tracking.todo.pop() {
338-
let mode = match tcx.static_mutability(cid.instance.def_id()) {
339-
Some(_) if cid.promoted.is_some() => {
340-
// Promoteds in statics are allowed to point to statics.
341-
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
342-
}
343-
Some(_) => CtfeValidationMode::Regular, // a `static`
344-
None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
345-
};
346-
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
347-
inner = true;
348-
}
349-
};
341+
let validation =
342+
const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some());
343+
350344
let alloc_id = mplace.ptr().provenance.unwrap();
351345

352346
// Validation failed, report an error.
353347
if let Err(error) = validation {
354-
let (error, backtrace) = error.into_parts();
355-
backtrace.print_backtrace();
356-
357-
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
358-
359-
let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
360-
let mut bytes = String::new();
361-
if alloc.size() != abi::Size::ZERO {
362-
bytes = "\n".into();
363-
// FIXME(translation) there might be pieces that are translatable.
364-
write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
365-
}
366-
let raw_bytes = errors::RawBytesNote {
367-
size: alloc.size().bytes(),
368-
align: alloc.align.bytes(),
369-
bytes,
370-
};
371-
372-
Err(super::report(
373-
*ecx.tcx,
374-
error,
375-
None,
376-
|| super::get_span_and_frames(&ecx),
377-
move |span, frames| errors::UndefinedBehavior {
378-
span,
379-
ub_note,
380-
frames,
381-
raw_bytes,
382-
},
383-
))
348+
Err(const_report_error(&ecx, error, alloc_id))
384349
} else {
385350
// Convert to raw constant
386351
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
387352
}
388353
}
389354
}
390355
}
356+
357+
#[inline(always)]
358+
pub fn const_validate_mplace<'mir, 'tcx>(
359+
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
360+
mplace: &MPlaceTy<'tcx>,
361+
is_static: bool,
362+
is_promoted: bool,
363+
) -> InterpResult<'tcx> {
364+
let mut ref_tracking = RefTracking::new(mplace.clone());
365+
let mut inner = false;
366+
while let Some((mplace, path)) = ref_tracking.todo.pop() {
367+
let mode = if is_static {
368+
if is_promoted {
369+
// Promoteds in statics are allowed to point to statics.
370+
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
371+
} else {
372+
// a `static`
373+
CtfeValidationMode::Regular
374+
}
375+
} else {
376+
CtfeValidationMode::Const { inner, allow_static_ptrs: false }
377+
};
378+
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
379+
inner = true;
380+
}
381+
382+
Ok(())
383+
}
384+
385+
#[inline(always)]
386+
pub fn const_report_error<'mir, 'tcx>(
387+
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
388+
error: InterpErrorInfo<'tcx>,
389+
alloc_id: AllocId,
390+
) -> ErrorHandled {
391+
let (error, backtrace) = error.into_parts();
392+
backtrace.print_backtrace();
393+
394+
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
395+
396+
let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
397+
let mut bytes = String::new();
398+
if alloc.size() != abi::Size::ZERO {
399+
bytes = "\n".into();
400+
// FIXME(translation) there might be pieces that are translatable.
401+
write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap();
402+
}
403+
let raw_bytes =
404+
errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes };
405+
406+
crate::const_eval::report(
407+
*ecx.tcx,
408+
error,
409+
None,
410+
|| crate::const_eval::get_span_and_frames(ecx),
411+
move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
412+
)
413+
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -1074,17 +1074,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10741074
instance: ty::Instance<'tcx>,
10751075
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
10761076
let gid = GlobalId { instance, promoted: None };
1077-
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
1078-
// and thus don't care about the parameter environment. While we could just use
1079-
// `self.param_env`, that would mean we invoke the query to evaluate the static
1080-
// with different parameter environments, thus causing the static to be evaluated
1081-
// multiple times.
1082-
let param_env = if self.tcx.is_static(gid.instance.def_id()) {
1083-
ty::ParamEnv::reveal_all()
1077+
let val = if self.tcx.is_static(gid.instance.def_id()) {
1078+
let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id());
1079+
1080+
let ty = instance.ty(self.tcx.tcx, self.param_env);
1081+
mir::ConstAlloc { alloc_id, ty }
10841082
} else {
1085-
self.param_env
1083+
self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?
10861084
};
1087-
let val = self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
10881085
self.raw_const_to_mplace(val)
10891086
}
10901087

compiler/rustc_const_eval/src/interpret/validity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
929929
/// - no pointers to statics.
930930
/// - no `UnsafeCell` or non-ZST `&mut`.
931931
#[inline(always)]
932-
pub fn const_validate_operand(
932+
pub(crate) fn const_validate_operand(
933933
&self,
934934
op: &OpTy<'tcx, M::Provenance>,
935935
path: Vec<PathElem>,

0 commit comments

Comments
 (0)