Skip to content

Commit dcc6c28

Browse files
committed
Introduce a ConstPropMachine
This allows us to avoid changing things directly in the miri engine just for const prop.
1 parent 4e58e2e commit dcc6c28

File tree

8 files changed

+177
-39
lines changed

8 files changed

+177
-39
lines changed

src/librustc/mir/interpret/error.rs

-12
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,6 @@ pub enum UnsupportedOpInfo<'tcx> {
389389
/// Free-form case. Only for errors that are never caught!
390390
Unsupported(String),
391391

392-
/// Error used by the `ConstProp` pass when an attempt is made
393-
/// to read an uninitialized local.
394-
UninitializedLocal,
395-
396-
/// Error used by the `ConstProp` pass to prevent reading statics
397-
/// while evaluating `const` items.
398-
ReadOfStaticInConst,
399-
400392
/// FIXME(#64506) Error used to work around accessing projections of
401393
/// uninhabited types.
402394
UninhabitedValue,
@@ -523,8 +515,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
523515
addresses, e.g., comparing pointers into different allocations"),
524516
DeadLocal =>
525517
write!(f, "tried to access a dead local variable"),
526-
UninitializedLocal =>
527-
write!(f, "tried to access an uninitialized local variable"),
528518
DerefFunctionPointer =>
529519
write!(f, "tried to dereference a function pointer"),
530520
ExecuteMemory =>
@@ -566,8 +556,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
566556
not a power of two"),
567557
Unsupported(ref msg) =>
568558
write!(f, "{}", msg),
569-
ReadOfStaticInConst =>
570-
write!(f, "tried to read from a static during const evaluation"),
571559
UninhabitedValue =>
572560
write!(f, "tried to use an uninhabited value"),
573561
}

src/librustc_mir/const_eval.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use syntax::source_map::{Span, DUMMY_SP};
2121

2222
use crate::interpret::{self,
2323
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
24-
RawConst, ConstValue,
24+
RawConst, ConstValue, Machine,
2525
InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
2626
Allocation, AllocId, MemoryKind, Memory,
2727
snapshot, RefTracking, intern_const_alloc_recursive,
@@ -41,7 +41,7 @@ const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
4141
/// that inform us about the generic bounds of the constant. E.g., using an associated constant
4242
/// of a function's generic parameter will require knowledge about the bounds on the generic
4343
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
44-
pub(crate) fn mk_eval_cx<'mir, 'tcx>(
44+
fn mk_eval_cx<'mir, 'tcx>(
4545
tcx: TyCtxt<'tcx>,
4646
span: Span,
4747
param_env: ty::ParamEnv<'tcx>,
@@ -169,7 +169,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
169169
}
170170

171171
#[derive(Clone, Debug)]
172-
enum ConstEvalError {
172+
pub enum ConstEvalError {
173173
NeedsRfc(String),
174174
}
175175

@@ -521,8 +521,8 @@ pub fn const_variant_index<'tcx>(
521521
/// Turn an interpreter error into something to report to the user.
522522
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
523523
/// Should be called only if the error is actually going to to be reported!
524-
pub fn error_to_const_error<'mir, 'tcx>(
525-
ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
524+
pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>(
525+
ecx: &InterpCx<'mir, 'tcx, M>,
526526
mut error: InterpErrorInfo<'tcx>,
527527
) -> ConstEvalErr<'tcx> {
528528
error.print_backtrace();

src/librustc_mir/interpret/eval_context.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
135135
match self.value {
136136
LocalValue::Dead => throw_unsup!(DeadLocal),
137137
LocalValue::Uninitialized =>
138-
// this is reachable from ConstProp
139-
throw_unsup!(UninitializedLocal),
138+
bug!("The type checker should prevent reading from a never-written local"),
140139
LocalValue::Live(val) => Ok(val),
141140
}
142141
}

src/librustc_mir/interpret/machine.rs

+18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc::ty::{self, Ty, TyCtxt};
1212
use super::{
1313
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
1414
InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
15+
Frame, Operand,
1516
};
1617

1718
/// Whether this kind of memory is allowed to leak
@@ -184,6 +185,23 @@ pub trait Machine<'mir, 'tcx>: Sized {
184185
dest: PlaceTy<'tcx, Self::PointerTag>,
185186
) -> InterpResult<'tcx>;
186187

188+
/// Called to read the specified `local` from the `frame`.
189+
fn access_local(
190+
_ecx: &InterpCx<'mir, 'tcx, Self>,
191+
frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
192+
local: mir::Local,
193+
) -> InterpResult<'tcx, Operand<Self::PointerTag>> {
194+
frame.locals[local].access()
195+
}
196+
197+
/// Called before a `StaticKind::Static` value is read.
198+
fn before_eval_static(
199+
_ecx: &InterpCx<'mir, 'tcx, Self>,
200+
_place_static: &mir::Static<'tcx>,
201+
) -> InterpResult<'tcx> {
202+
Ok(())
203+
}
204+
187205
/// Called to initialize the "extra" state of an allocation and make the pointers
188206
/// it contains (in relocations) tagged. The way we construct allocations is
189207
/// to always first construct it without extra and then add the extra.

src/librustc_mir/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
458458
// Do not read from ZST, they might not be initialized
459459
Operand::Immediate(Scalar::zst().into())
460460
} else {
461-
frame.locals[local].access()?
461+
M::access_local(&self, frame, local)?
462462
};
463463
Ok(OpTy { op, layout })
464464
}

src/librustc_mir/interpret/place.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -601,15 +601,8 @@ where
601601
}
602602

603603
StaticKind::Static => {
604-
//if the first frame on the stack isn't a static item, then we shouldn't
605-
//eval any static places (unless -Z unleash-the-miri-inside-of-you is on)
606-
if let ty::InstanceDef::Item(item_def_id) = self.stack[0].instance.def {
607-
if !self.tcx.is_static(item_def_id) &&
608-
!self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
609-
trace!("eval_static_to_mplace: can't eval static in constant");
610-
throw_unsup!(ReadOfStaticInConst);
611-
}
612-
}
604+
M::before_eval_static(self, place_static)?;
605+
613606
let ty = place_static.ty;
614607
assert!(!ty.needs_subst());
615608
let layout = self.layout_of(ty)?;

src/librustc_mir/transform/const_prop.rs

+149-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
//! Propagates constants for early reporting of statically known
22
//! assertion failures
33
4+
use std::borrow::Cow;
45
use std::cell::Cell;
56

67
use rustc::hir::def::DefKind;
8+
use rustc::hir::def_id::DefId;
79
use rustc::mir::{
810
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
9-
Local, NullOp, UnOp, StatementKind, Statement, LocalKind,
11+
Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static,
1012
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp,
11-
SourceScope, SourceScopeLocalData, LocalDecl,
13+
SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
1214
};
1315
use rustc::mir::visit::{
1416
Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
@@ -17,18 +19,19 @@ use rustc::mir::interpret::{Scalar, InterpResult, PanicInfo};
1719
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
1820
use syntax_pos::{Span, DUMMY_SP};
1921
use rustc::ty::subst::InternalSubsts;
22+
use rustc_data_structures::fx::FxHashMap;
2023
use rustc_data_structures::indexed_vec::IndexVec;
2124
use rustc::ty::layout::{
2225
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout,
2326
};
2427

2528
use crate::interpret::{
2629
self, InterpCx, ScalarMaybeUndef, Immediate, OpTy,
27-
StackPopCleanup, LocalValue, LocalState,
28-
};
29-
use crate::const_eval::{
30-
CompileTimeInterpreter, error_to_const_error, mk_eval_cx,
30+
StackPopCleanup, LocalValue, LocalState, AllocId, Frame,
31+
Allocation, MemoryKind, ImmTy, Pointer, Memory, PlaceTy,
32+
Operand as InterpOperand,
3133
};
34+
use crate::const_eval::error_to_const_error;
3235
use crate::transform::{MirPass, MirSource};
3336

3437
pub struct ConstProp;
@@ -111,11 +114,149 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
111114
}
112115
}
113116

117+
struct ConstPropMachine;
118+
119+
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
120+
type MemoryKinds= !;
121+
type PointerTag = ();
122+
type ExtraFnVal = !;
123+
124+
type FrameExtra = ();
125+
type MemoryExtra = ();
126+
type AllocExtra = ();
127+
128+
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
129+
130+
const STATIC_KIND: Option<!> = None;
131+
132+
const CHECK_ALIGN: bool = false;
133+
134+
#[inline(always)]
135+
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
136+
false
137+
}
138+
139+
fn find_fn(
140+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
141+
_instance: ty::Instance<'tcx>,
142+
_args: &[OpTy<'tcx>],
143+
_dest: Option<PlaceTy<'tcx>>,
144+
_ret: Option<BasicBlock>,
145+
) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
146+
Ok(None)
147+
}
148+
149+
fn call_extra_fn(
150+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
151+
fn_val: !,
152+
_args: &[OpTy<'tcx>],
153+
_dest: Option<PlaceTy<'tcx>>,
154+
_ret: Option<BasicBlock>,
155+
) -> InterpResult<'tcx> {
156+
match fn_val {}
157+
}
158+
159+
fn call_intrinsic(
160+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
161+
_instance: ty::Instance<'tcx>,
162+
_args: &[OpTy<'tcx>],
163+
_dest: PlaceTy<'tcx>,
164+
) -> InterpResult<'tcx> {
165+
throw_unsup_format!("calling intrinsics isn't supported in ConstProp");
166+
}
167+
168+
fn ptr_to_int(
169+
_mem: &Memory<'mir, 'tcx, Self>,
170+
_ptr: Pointer,
171+
) -> InterpResult<'tcx, u64> {
172+
throw_unsup_format!("ptr-to-int casts aren't supported in ConstProp");
173+
}
174+
175+
fn binary_ptr_op(
176+
_ecx: &InterpCx<'mir, 'tcx, Self>,
177+
_bin_op: BinOp,
178+
_left: ImmTy<'tcx>,
179+
_right: ImmTy<'tcx>,
180+
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
181+
// We can't do this because aliasing of memory can differ between const eval and llvm
182+
throw_unsup_format!("pointer arithmetic or comparisons aren't supported in ConstProp");
183+
}
184+
185+
fn find_foreign_static(
186+
_tcx: TyCtxt<'tcx>,
187+
_def_id: DefId,
188+
) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
189+
throw_unsup!(ReadForeignStatic)
190+
}
191+
192+
#[inline(always)]
193+
fn tag_allocation<'b>(
194+
_memory_extra: &(),
195+
_id: AllocId,
196+
alloc: Cow<'b, Allocation>,
197+
_kind: Option<MemoryKind<!>>,
198+
) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
199+
// We do not use a tag so we can just cheaply forward the allocation
200+
(alloc, ())
201+
}
202+
203+
#[inline(always)]
204+
fn tag_static_base_pointer(
205+
_memory_extra: &(),
206+
_id: AllocId,
207+
) -> Self::PointerTag {
208+
()
209+
}
210+
211+
fn box_alloc(
212+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
213+
_dest: PlaceTy<'tcx>,
214+
) -> InterpResult<'tcx> {
215+
throw_unsup_format!("can't const prop `box` keyword");
216+
}
217+
218+
fn access_local(
219+
_ecx: &InterpCx<'mir, 'tcx, Self>,
220+
frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
221+
local: Local,
222+
) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
223+
let l = &frame.locals[local];
224+
225+
if l.value == LocalValue::Uninitialized {
226+
throw_unsup_format!("tried to access an uninitialized local");
227+
}
228+
229+
l.access()
230+
}
231+
232+
fn before_eval_static(
233+
_ecx: &InterpCx<'mir, 'tcx, Self>,
234+
_place_static: &Static<'tcx>,
235+
) -> InterpResult<'tcx> {
236+
throw_unsup_format!("can't eval statics in ConstProp");
237+
}
238+
239+
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
240+
Ok(())
241+
}
242+
243+
#[inline(always)]
244+
fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
245+
Ok(())
246+
}
247+
248+
/// Called immediately before a stack frame gets popped.
249+
#[inline(always)]
250+
fn stack_pop(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _extra: ()) -> InterpResult<'tcx> {
251+
Ok(())
252+
}
253+
}
254+
114255
type Const<'tcx> = OpTy<'tcx>;
115256

116257
/// Finds optimization opportunities on the MIR.
117258
struct ConstPropagator<'mir, 'tcx> {
118-
ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
259+
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
119260
tcx: TyCtxt<'tcx>,
120261
source: MirSource<'tcx>,
121262
can_const_prop: IndexVec<Local, bool>,
@@ -158,7 +299,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
158299
let def_id = source.def_id();
159300
let param_env = tcx.param_env(def_id);
160301
let span = tcx.def_span(def_id);
161-
let mut ecx = mk_eval_cx(tcx, span, param_env);
302+
let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine, ());
162303
let can_const_prop = CanConstProp::check(body);
163304

164305
ecx.push_stack_frame(

src/test/ui/issues/issue-52060.stderr

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,4 @@ LL | static B: [u32; 1] = [0; A.len()];
66

77
error: aborting due to previous error
88

9-
Some errors have detailed explanations: E0013, E0080.
10-
For more information about an error, try `rustc --explain E0013`.
9+
For more information about this error, try `rustc --explain E0013`.

0 commit comments

Comments
 (0)