Skip to content

Commit 7f8df04

Browse files
committed
Auto merge of #116835 - oli-obk:evaluated_static_in_metadata2, r=<try>
Various const eval cleanups This pulls out the pure refactorings from #116564 r? `@RalfJung`
2 parents 631a116 + 76869b4 commit 7f8df04

File tree

6 files changed

+121
-86
lines changed

6 files changed

+121
-86
lines changed

compiler/rustc_const_eval/src/const_eval/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ where
117117
/// This will use the `mk` function for creating the error which will get passed labels according to
118118
/// the `InterpError` and the span and a stacktrace of current execution according to
119119
/// `get_span_and_frames`.
120-
pub(super) fn report<'tcx, C, F, E>(
120+
pub(crate) fn report<'tcx, C, F, E>(
121121
tcx: TyCtxt<'tcx>,
122122
error: InterpError<'tcx>,
123123
span: Option<Span>,

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+18-57
Original file line numberDiff line numberDiff line change
@@ -3,8 +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};
7-
use rustc_middle::mir::pretty::write_allocation_bytes;
6+
use rustc_middle::mir::interpret::ErrorHandled;
87
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
98
use rustc_middle::traits::Reveal;
109
use rustc_middle::ty::layout::LayoutOf;
@@ -19,8 +18,8 @@ use crate::errors;
1918
use crate::errors::ConstEvalError;
2019
use crate::interpret::eval_nullary_intrinsic;
2120
use crate::interpret::{
22-
intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx,
23-
InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup,
21+
intern_const_alloc_recursive, GlobalId, Immediate, InternKind, InterpCx, InterpResult,
22+
MPlaceTy, MemoryKind, OpTy, StackPopCleanup,
2423
};
2524

2625
// Returns a pointer to where the result lives
@@ -285,15 +284,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
285284
let def = cid.instance.def.def_id();
286285
let is_static = tcx.is_static(def);
287286

288-
let mut ecx = InterpCx::new(
287+
let ecx = InterpCx::new(
289288
tcx,
290289
tcx.def_span(def),
291290
key.param_env,
292291
// Statics (and promoteds inside statics) may access other statics, because unlike consts
293292
// they do not have to behave "as if" they were evaluated at runtime.
294293
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
295294
);
295+
eval_in_interpreter(ecx, cid, is_static)
296+
}
296297

298+
pub fn eval_in_interpreter<'mir, 'tcx>(
299+
mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
300+
cid: GlobalId<'tcx>,
301+
is_static: bool,
302+
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
297303
let res = ecx.load_mir(cid.instance.def, cid.promoted);
298304
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
299305
Err(error) => {
@@ -306,7 +312,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
306312
// If the current item has generics, we'd like to enrich the message with the
307313
// instance and its args: to show the actual compile-time values, in addition to
308314
// the expression, leading to the const eval error.
309-
let instance = &key.value.instance;
315+
let instance = &cid.instance;
310316
if !instance.args.is_empty() {
311317
let instance = with_no_trimmed_paths!(instance.to_string());
312318
("const_with_path", instance)
@@ -331,60 +337,15 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
331337
Ok(mplace) => {
332338
// Since evaluation had no errors, validate the resulting constant.
333339
// 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-
};
350-
let alloc_id = mplace.ptr().provenance.unwrap();
340+
let validation = ecx.const_validate_mplace(&mplace, is_static, cid.promoted.is_some());
351341

352-
// Validation failed, report an error.
353-
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-
};
342+
let alloc_id = mplace.ptr().provenance.unwrap();
371343

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-
))
384-
} else {
344+
validation
345+
// Validation failed, report an error.
346+
.map_err(|error| ecx.const_report_error(error, alloc_id))
385347
// Convert to raw constant
386-
Ok(ConstAlloc { alloc_id, ty: mplace.layout.ty })
387-
}
348+
.map(|()| ConstAlloc { alloc_id, ty: mplace.layout.ty })
388349
}
389350
}
390351
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID;
77
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
88
use rustc_index::IndexVec;
99
use rustc_middle::mir;
10-
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
10+
use rustc_middle::mir::interpret::{alloc_range, ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
1111
use rustc_middle::query::TyCtxtAt;
1212
use rustc_middle::ty::layout::{
1313
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@@ -17,6 +17,7 @@ use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
1717
use rustc_mir_dataflow::storage::always_storage_live_locals;
1818
use rustc_session::Limit;
1919
use rustc_span::Span;
20+
use rustc_target::abi::{self, Abi};
2021
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
2122

2223
use super::{
@@ -1069,23 +1070,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10691070
})
10701071
}
10711072

1072-
pub fn eval_global(
1073+
pub fn eval_global_scalar(
10731074
&self,
10741075
instance: ty::Instance<'tcx>,
1075-
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
1076+
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
10761077
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()
1078+
let (alloc_id, alloc) = if self.tcx.is_static(gid.instance.def_id()) {
1079+
(
1080+
self.tcx.reserve_and_set_static_alloc(gid.instance.def_id()),
1081+
self.ctfe_query(|tcx| tcx.eval_static_initializer(gid.instance.def_id()))?,
1082+
)
10841083
} else {
1085-
self.param_env
1084+
let val = self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))?;
1085+
(val.alloc_id, self.tcx.global_alloc(val.alloc_id).unwrap_memory())
10861086
};
1087-
let val = self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
1088-
self.raw_const_to_mplace(val)
1087+
1088+
let ty = instance.ty(self.tcx.tcx, self.param_env);
1089+
let layout = self.layout_of(ty)?;
1090+
let read_provenance = matches!(
1091+
layout.abi,
1092+
Abi::Scalar(abi::Scalar::Initialized { value: abi::Primitive::Pointer(..), .. })
1093+
);
1094+
1095+
let scalar = alloc
1096+
.inner()
1097+
.read_scalar(self, alloc_range(Size::ZERO, layout.size), read_provenance)
1098+
.map_err(|err| err.to_interp_error(alloc_id))?;
1099+
self.adjust_const_scalar(scalar)
10891100
}
10901101

10911102
pub fn eval_mir_constant(

compiler/rustc_const_eval/src/interpret/operand.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -723,19 +723,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
723723
Ok(op)
724724
}
725725

726+
pub(super) fn adjust_const_scalar(
727+
&self,
728+
scalar: Scalar,
729+
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
730+
Ok(match scalar {
731+
Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size),
732+
Scalar::Int(int) => Scalar::Int(int),
733+
})
734+
}
735+
726736
pub(crate) fn const_val_to_op(
727737
&self,
728738
val_val: mir::ConstValue<'tcx>,
729739
ty: Ty<'tcx>,
730740
layout: Option<TyAndLayout<'tcx>>,
731741
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
732742
// Other cases need layout.
733-
let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
734-
Ok(match scalar {
735-
Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size),
736-
Scalar::Int(int) => Scalar::Int(int),
737-
})
738-
};
739743
let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
740744
let imm = match val_val {
741745
mir::ConstValue::Indirect { alloc_id, offset } => {
@@ -744,7 +748,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
744748
let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?;
745749
return Ok(self.ptr_to_mplace(ptr.into(), layout).into());
746750
}
747-
mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
751+
mir::ConstValue::Scalar(x) => self.adjust_const_scalar(x)?.into(),
748752
mir::ConstValue::ZeroSized => Immediate::Uninit,
749753
mir::ConstValue::Slice { data, meta } => {
750754
// We rely on mutability being set correctly in `data` to prevent writes

compiler/rustc_const_eval/src/interpret/validity.rs

+65-4
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ use rustc_ast::Mutability;
1313
use rustc_data_structures::fx::FxHashSet;
1414
use rustc_hir as hir;
1515
use rustc_middle::mir::interpret::{
16-
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, ValidationErrorInfo,
17-
ValidationErrorKind, ValidationErrorKind::*,
16+
ErrorHandled, ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment,
17+
PointerKind, ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
1818
};
19+
use rustc_middle::mir::pretty::write_allocation_bytes;
1920
use rustc_middle::ty;
2021
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
2122
use rustc_span::symbol::{sym, Symbol};
2223
use rustc_target::abi::{
23-
Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
24+
self, Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
2425
};
2526

2627
use std::hash::Hash;
2728

29+
use crate::errors;
30+
2831
use super::{
2932
AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
3033
Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor,
@@ -929,7 +932,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
929932
/// - no pointers to statics.
930933
/// - no `UnsafeCell` or non-ZST `&mut`.
931934
#[inline(always)]
932-
pub fn const_validate_operand(
935+
fn const_validate_operand(
933936
&self,
934937
op: &OpTy<'tcx, M::Provenance>,
935938
path: Vec<PathElem>,
@@ -939,6 +942,64 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
939942
self.validate_operand_internal(op, path, Some(ref_tracking), Some(ctfe_mode))
940943
}
941944

945+
#[inline(always)]
946+
pub fn const_validate_mplace(
947+
&self,
948+
mplace: &MPlaceTy<'tcx, M::Provenance>,
949+
is_static: bool,
950+
is_promoted: bool,
951+
) -> InterpResult<'tcx> {
952+
let mut ref_tracking = RefTracking::new(mplace.clone());
953+
let mut inner = false;
954+
while let Some((mplace, path)) = ref_tracking.todo.pop() {
955+
let mode = if is_static {
956+
if is_promoted {
957+
// Promoteds in statics are allowed to point to statics.
958+
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
959+
} else {
960+
// a `static`
961+
CtfeValidationMode::Regular
962+
}
963+
} else {
964+
CtfeValidationMode::Const { inner, allow_static_ptrs: false }
965+
};
966+
self.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
967+
inner = true;
968+
}
969+
970+
Ok(())
971+
}
972+
973+
#[inline(always)]
974+
pub fn const_report_error(
975+
&self,
976+
error: InterpErrorInfo<'tcx>,
977+
alloc_id: AllocId,
978+
) -> ErrorHandled {
979+
let (error, backtrace) = error.into_parts();
980+
backtrace.print_backtrace();
981+
982+
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
983+
984+
let alloc = self.tcx.global_alloc(alloc_id).unwrap_memory().inner();
985+
let mut bytes = String::new();
986+
if alloc.size() != abi::Size::ZERO {
987+
bytes = "\n".into();
988+
// FIXME(translation) there might be pieces that are translatable.
989+
write_allocation_bytes(*self.tcx, alloc, &mut bytes, " ").unwrap();
990+
}
991+
let raw_bytes =
992+
errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes };
993+
994+
crate::const_eval::report(
995+
*self.tcx,
996+
error,
997+
None,
998+
|| crate::const_eval::get_span_and_frames(self),
999+
move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes },
1000+
)
1001+
}
1002+
9421003
/// This function checks the data at `op` to be runtime-valid.
9431004
/// `op` is assumed to cover valid memory if it is an indirect operand.
9441005
/// It will error if the bits at the destination do not match the ones described by the layout.

src/tools/miri/src/helpers.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
141141
let this = self.eval_context_ref();
142142
let instance = this.resolve_path(path, Namespace::ValueNS);
143143
// We don't give a span -- this isn't actually used directly by the program anyway.
144-
let const_val = this.eval_global(instance).unwrap_or_else(|err| {
144+
this.eval_global_scalar(instance).unwrap_or_else(|err| {
145145
panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
146-
});
147-
this.read_scalar(&const_val)
148-
.unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
146+
})
149147
}
150148

151149
/// Helper function to get a `libc` constant as a `Scalar`.

0 commit comments

Comments
 (0)