Skip to content

Commit dc6ffae

Browse files
committed
make miri InterpCx TyCtxtAt a TyCtxt, and separately remember the root span of the evaluation
1 parent 871513d commit dc6ffae

File tree

15 files changed

+123
-109
lines changed

15 files changed

+123
-109
lines changed

src/librustc_middle/ty/util.rs

+1
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ impl<'tcx> ty::TyS<'tcx> {
705705
/// optimization as well as the rules around static values. Note
706706
/// that the `Freeze` trait is not exposed to end users and is
707707
/// effectively an implementation detail.
708+
// FIXME: use `TyCtxtAt` instead of separate `Span`.
708709
pub fn is_freeze(
709710
&'tcx self,
710711
tcx: TyCtxt<'tcx>,

src/librustc_mir/const_eval/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,5 @@ pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
5656
) -> ConstEvalErr<'tcx> {
5757
error.print_backtrace();
5858
let stacktrace = ecx.generate_stacktrace();
59-
ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
59+
ConstEvalErr { error: error.kind, stacktrace, span: ecx.cur_span() }
6060
}

src/librustc_mir/const_eval/eval_queries.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
2727
body: &'mir mir::Body<'tcx>,
2828
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
2929
debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
30-
let tcx = ecx.tcx.tcx;
30+
let tcx = ecx.tcx;
3131
let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
3232
assert!(!layout.is_unsized());
3333
let ret = ecx.allocate(layout, MemoryKind::Stack);
@@ -81,13 +81,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
8181
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
8282
pub(super) fn mk_eval_cx<'mir, 'tcx>(
8383
tcx: TyCtxt<'tcx>,
84-
span: Span,
84+
root_span: Span,
8585
param_env: ty::ParamEnv<'tcx>,
8686
can_access_statics: bool,
8787
) -> CompileTimeEvalContext<'mir, 'tcx> {
8888
debug!("mk_eval_cx: {:?}", param_env);
8989
InterpCx::new(
90-
tcx.at(span),
90+
tcx,
91+
root_span,
9192
param_env,
9293
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
9394
MemoryExtra { can_access_statics },
@@ -163,7 +164,7 @@ pub(super) fn op_to_const<'tcx>(
163164
0,
164165
),
165166
};
166-
let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap();
167+
let len = b.to_machine_usize(ecx).unwrap();
167168
let start = start.try_into().unwrap();
168169
let len: usize = len.try_into().unwrap();
169170
ConstValue::Slice { data, start, end: start + len }
@@ -213,7 +214,7 @@ fn validate_and_turn_into_const<'tcx>(
213214

214215
val.map_err(|error| {
215216
let err = error_to_const_error(&ecx, error);
216-
err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
217+
err.struct_error(ecx.tcx_at(), "it is undefined behavior to use this value", |mut diag| {
217218
diag.note(note_on_undefined_behavior_error());
218219
diag.emit();
219220
})
@@ -299,9 +300,9 @@ pub fn const_eval_raw_provider<'tcx>(
299300

300301
let is_static = tcx.is_static(def_id);
301302

302-
let span = tcx.def_span(cid.instance.def_id());
303303
let mut ecx = InterpCx::new(
304-
tcx.at(span),
304+
tcx,
305+
tcx.def_span(cid.instance.def_id()),
305306
key.param_env,
306307
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
307308
MemoryExtra { can_access_statics: is_static },
@@ -316,7 +317,7 @@ pub fn const_eval_raw_provider<'tcx>(
316317
if is_static {
317318
// Ensure that if the above error was either `TooGeneric` or `Reported`
318319
// an error must be reported.
319-
let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
320+
let v = err.report_as_error(ecx.tcx_at(), "could not evaluate static initializer");
320321

321322
// If this is `Reveal:All`, then we need to make sure an error is reported but if
322323
// this is `Reveal::UserFacing`, then it's expected that we could get a
@@ -372,13 +373,13 @@ pub fn const_eval_raw_provider<'tcx>(
372373
// anything else (array lengths, enum initializers, constant patterns) are
373374
// reported as hard errors
374375
} else {
375-
err.report_as_error(ecx.tcx, "evaluation of constant value failed")
376+
err.report_as_error(ecx.tcx_at(), "evaluation of constant value failed")
376377
}
377378
}
378379
}
379380
} else {
380381
// use of broken constant from other crate
381-
err.report_as_error(ecx.tcx, "could not evaluate constant")
382+
err.report_as_error(ecx.tcx_at(), "could not evaluate constant")
382383
}
383384
})
384385
}

src/librustc_mir/interpret/cast.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5656
}
5757

5858
let instance = ty::Instance::resolve_for_fn_ptr(
59-
*self.tcx,
59+
self.tcx,
6060
self.param_env,
6161
def_id,
6262
substs,
@@ -91,7 +91,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9191
}
9292

9393
let instance = ty::Instance::resolve_closure(
94-
*self.tcx,
94+
self.tcx,
9595
def_id,
9696
substs,
9797
ty::ClosureKind::FnOnce,
@@ -140,7 +140,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
140140
// Handle cast from a univariant (ZST) enum.
141141
match src.layout.variants {
142142
Variants::Single { index } => {
143-
if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
143+
if let Some(discr) = src.layout.ty.discriminant_for_variant(self.tcx, index) {
144144
assert!(src.layout.is_zst());
145145
let discr_layout = self.layout_of(discr.ty)?;
146146
return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
@@ -270,7 +270,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
270270
// u64 cast is from usize to u64, which is always good
271271
let val = Immediate::new_slice(
272272
ptr,
273-
length.eval_usize(self.tcx.tcx, self.param_env),
273+
length.eval_usize(self.tcx, self.param_env),
274274
self,
275275
);
276276
self.write_immediate(val, dest)

src/librustc_mir/interpret/eval_context.rs

+38-22
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
3333
pub machine: M,
3434

3535
/// The results of the type checker, from rustc.
36-
pub tcx: TyCtxtAt<'tcx>,
36+
pub tcx: TyCtxt<'tcx>,
37+
38+
/// The span of the "root" of the evaluation, i.e., the const
39+
/// we are evaluating (if this is CTFE).
40+
pub(super) root_span: Span,
3741

3842
/// Bounds in scope for polymorphic evaluations.
3943
pub(crate) param_env: ty::ParamEnv<'tcx>,
@@ -196,7 +200,7 @@ where
196200
{
197201
#[inline]
198202
fn tcx(&self) -> TyCtxt<'tcx> {
199-
*self.tcx
203+
self.tcx
200204
}
201205
}
202206

@@ -209,13 +213,13 @@ where
209213
}
210214
}
211215

212-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
216+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
213217
type Ty = Ty<'tcx>;
214218
type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>;
215219

216220
#[inline]
217221
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
218-
self.tcx
222+
self.tcx_at()
219223
.layout_of(self.param_env.and(ty))
220224
.map_err(|layout| err_inval!(Layout(layout)).into())
221225
}
@@ -292,23 +296,35 @@ pub(super) fn from_known_layout<'tcx>(
292296

293297
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
294298
pub fn new(
295-
tcx: TyCtxtAt<'tcx>,
299+
tcx: TyCtxt<'tcx>,
300+
root_span: Span,
296301
param_env: ty::ParamEnv<'tcx>,
297302
machine: M,
298303
memory_extra: M::MemoryExtra,
299304
) -> Self {
300305
InterpCx {
301306
machine,
302307
tcx,
308+
root_span,
303309
param_env,
304-
memory: Memory::new(*tcx, memory_extra),
310+
memory: Memory::new(tcx, memory_extra),
305311
vtables: FxHashMap::default(),
306312
}
307313
}
308314

309315
#[inline(always)]
310-
pub fn set_span(&mut self, span: Span) {
311-
self.tcx.span = span;
316+
pub fn cur_span(&self) -> Span {
317+
self
318+
.stack()
319+
.last()
320+
.and_then(|f| f.current_source_info())
321+
.map(|si| si.span)
322+
.unwrap_or(self.root_span)
323+
}
324+
325+
#[inline(always)]
326+
pub fn tcx_at(&self) -> TyCtxtAt<'tcx> {
327+
self.tcx.at(self.cur_span())
312328
}
313329

314330
#[inline(always)]
@@ -386,12 +402,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
386402

387403
#[inline]
388404
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
389-
ty.is_sized(self.tcx, self.param_env)
405+
ty.is_sized(self.tcx_at(), self.param_env)
390406
}
391407

392408
#[inline]
393409
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
394-
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
410+
ty.is_freeze(self.tcx, self.param_env, self.cur_span())
395411
}
396412

397413
pub fn load_mir(
@@ -402,20 +418,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
402418
// do not continue if typeck errors occurred (can only occur in local crate)
403419
let did = instance.def_id();
404420
if let Some(did) = did.as_local() {
405-
if self.tcx.has_typeck_tables(did) {
406-
if let Some(error_reported) = self.tcx.typeck_tables_of(did).tainted_by_errors {
421+
if self.tcx_at().has_typeck_tables(did) {
422+
if let Some(error_reported) = self.tcx_at().typeck_tables_of(did).tainted_by_errors {
407423
throw_inval!(TypeckError(error_reported))
408424
}
409425
}
410426
}
411427
trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
412428
if let Some(promoted) = promoted {
413-
return Ok(&self.tcx.promoted_mir(did)[promoted]);
429+
return Ok(&self.tcx_at().promoted_mir(did)[promoted]);
414430
}
415431
match instance {
416432
ty::InstanceDef::Item(def_id) => {
417-
if self.tcx.is_mir_available(did) {
418-
Ok(self.tcx.optimized_mir(did))
433+
if self.tcx_at().is_mir_available(did) {
434+
Ok(self.tcx_at().optimized_mir(did))
419435
} else {
420436
throw_unsup!(NoMirFor(def_id))
421437
}
@@ -456,7 +472,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
456472
trace!("resolve: {:?}, {:#?}", def_id, substs);
457473
trace!("param_env: {:#?}", self.param_env);
458474
trace!("substs: {:#?}", substs);
459-
match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) {
475+
match ty::Instance::resolve(self.tcx, self.param_env, def_id, substs) {
460476
Ok(Some(instance)) => Ok(instance),
461477
Ok(None) => throw_inval!(TooGeneric),
462478

@@ -475,7 +491,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
475491
// have to support that case (mostly by skipping all caching).
476492
match frame.locals.get(local).and_then(|state| state.layout.get()) {
477493
None => {
478-
let layout = from_known_layout(self.tcx, layout, || {
494+
let layout = from_known_layout(self.tcx_at(), layout, || {
479495
let local_ty = frame.body.local_decls[local].ty;
480496
let local_ty =
481497
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
@@ -560,7 +576,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
560576
let size = size.align_to(align);
561577

562578
// Check if this brought us over the size limit.
563-
if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
579+
if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
564580
throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
565581
}
566582
Ok(Some((size, align)))
@@ -576,7 +592,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
576592
let elem = layout.field(self, 0)?;
577593

578594
// Make sure the slice is not too big.
579-
let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| {
595+
let size = elem.size.checked_mul(len, self).ok_or_else(|| {
580596
err_ub!(InvalidMeta("slice is bigger than largest supported object"))
581597
})?;
582598
Ok(Some((size, elem.align.abi)))
@@ -627,7 +643,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
627643
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
628644

629645
// Now mark those locals as dead that we do not want to initialize
630-
match self.tcx.def_kind(instance.def_id()) {
646+
match self.tcx_at().def_kind(instance.def_id()) {
631647
// statics and constants don't have `Storage*` statements, no need to look for them
632648
//
633649
// FIXME: The above is likely untrue. See
@@ -842,7 +858,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
842858
} else {
843859
self.param_env
844860
};
845-
let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?;
861+
let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.cur_span()))?;
846862

847863
// Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
848864
// recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
@@ -873,7 +889,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
873889
// FIXME: We can hit delay_span_bug if this is an invalid const, interning finds
874890
// that problem, but we never run validation to show an error. Can we ensure
875891
// this does not happen?
876-
let val = self.tcx.const_eval_raw(param_env.and(gid))?;
892+
let val = self.tcx_at().const_eval_raw(param_env.and(gid))?;
877893
self.raw_const_to_mplace(val)
878894
}
879895

src/librustc_mir/interpret/intern.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
9393
// in the value the dangling reference lies.
9494
// The `delay_span_bug` ensures that we don't forget such a check in validation.
9595
if tcx.get_global_alloc(alloc_id).is_none() {
96-
tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
96+
tcx.sess.delay_span_bug(ecx.root_span, "tried to intern dangling pointer");
9797
}
9898
// treat dangling pointers like other statics
9999
// just to stop trying to recurse into them
@@ -111,7 +111,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
111111
if let InternMode::Static(mutability) = mode {
112112
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
113113
// no interior mutability.
114-
let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx.tcx, ecx.param_env, ecx.tcx.span));
114+
let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env, ecx.root_span));
115115
// For statics, allocation mutability is the combination of the place mutability and
116116
// the type mutability.
117117
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
@@ -174,7 +174,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
174174
// they caused. It also helps us to find cases where const-checking
175175
// failed to prevent an `UnsafeCell` (but as `ignore_interior_mut_in_const`
176176
// shows that part is not airtight).
177-
mutable_memory_in_const(self.ecx.tcx, "`UnsafeCell`");
177+
mutable_memory_in_const(self.ecx.tcx_at(), "`UnsafeCell`");
178178
}
179179
// We are crossing over an `UnsafeCell`, we can mutate again. This means that
180180
// References we encounter inside here are interned as pointing to mutable
@@ -192,7 +192,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
192192
fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
193193
// Handle Reference types, as these are the only relocations supported by const eval.
194194
// Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
195-
let tcx = self.ecx.tcx;
195+
let tcx = self.ecx.tcx.at(self.ecx.root_span);
196196
let ty = mplace.layout.ty;
197197
if let ty::Ref(_, referenced_ty, ref_mutability) = ty.kind {
198198
let value = self.ecx.read_immediate(mplace.into())?;
@@ -254,7 +254,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
254254
if ref_mutability == Mutability::Mut {
255255
match referenced_ty.kind {
256256
ty::Array(_, n)
257-
if n.eval_usize(tcx.tcx, self.ecx.param_env) == 0 => {}
257+
if n.eval_usize(self.ecx.tcx, self.ecx.param_env) == 0 => {}
258258
ty::Slice(_)
259259
if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)?
260260
== 0 => {}
@@ -358,7 +358,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
358358
Ok(()) => {}
359359
Err(error) => {
360360
ecx.tcx.sess.delay_span_bug(
361-
ecx.tcx.span,
361+
ecx.root_span,
362362
"error during interning should later cause validation failure",
363363
);
364364
// Some errors shouldn't come up because creating them causes
@@ -407,7 +407,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
407407
// such as `const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _;`.
408408
ecx.tcx
409409
.sess
410-
.span_err(ecx.tcx.span, "untyped pointers are not allowed in constant");
410+
.span_err(ecx.root_span, "untyped pointers are not allowed in constant");
411411
// For better errors later, mark the allocation as immutable.
412412
alloc.mutability = Mutability::Not;
413413
}
@@ -422,11 +422,11 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
422422
} else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
423423
// Codegen does not like dangling pointers, and generally `tcx` assumes that
424424
// all allocations referenced anywhere actually exist. So, make sure we error here.
425-
ecx.tcx.sess.span_err(ecx.tcx.span, "encountered dangling pointer in final constant");
425+
ecx.tcx.sess.span_err(ecx.root_span, "encountered dangling pointer in final constant");
426426
} else if ecx.tcx.get_global_alloc(alloc_id).is_none() {
427427
// We have hit an `AllocId` that is neither in local or global memory and isn't
428428
// marked as dangling by local memory. That should be impossible.
429-
span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
429+
span_bug!(ecx.root_span, "encountered unknown alloc id {:?}", alloc_id);
430430
}
431431
}
432432
}

0 commit comments

Comments
 (0)