@@ -22,7 +22,7 @@ use rustc::ty::subst::Subst;
22
22
use rustc_data_structures:: indexed_vec:: IndexVec ;
23
23
24
24
use syntax:: ast:: Mutability ;
25
- use syntax:: source_map:: Span ;
25
+ use syntax:: source_map:: { Span , DUMMY_SP } ;
26
26
27
27
use rustc:: mir:: interpret:: {
28
28
EvalResult , EvalError , EvalErrorKind , GlobalId ,
@@ -31,17 +31,18 @@ use rustc::mir::interpret::{
31
31
use interpret:: { self ,
32
32
Place , PlaceTy , MemPlace , OpTy , Operand , Value ,
33
33
EvalContext , StackPopCleanup , MemoryKind ,
34
+ snapshot,
34
35
} ;
35
36
36
37
pub fn mk_borrowck_eval_cx < ' a , ' mir , ' tcx > (
37
38
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
38
39
instance : Instance < ' tcx > ,
39
40
mir : & ' mir mir:: Mir < ' tcx > ,
40
41
span : Span ,
41
- ) -> EvalResult < ' tcx , EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > > {
42
+ ) -> EvalResult < ' tcx , CompileTimeEvalContext < ' a , ' mir , ' tcx > > {
42
43
debug ! ( "mk_borrowck_eval_cx: {:?}" , instance) ;
43
44
let param_env = tcx. param_env ( instance. def_id ( ) ) ;
44
- let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator , ( ) ) ;
45
+ let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator :: new ( ) , ( ) ) ;
45
46
// insert a stack frame so any queries have the correct substs
46
47
ecx. stack . push ( interpret:: Frame {
47
48
block : mir:: START_BLOCK ,
@@ -60,10 +61,10 @@ pub fn mk_eval_cx<'a, 'tcx>(
60
61
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
61
62
instance : Instance < ' tcx > ,
62
63
param_env : ty:: ParamEnv < ' tcx > ,
63
- ) -> EvalResult < ' tcx , EvalContext < ' a , ' tcx , ' tcx , CompileTimeEvaluator > > {
64
+ ) -> EvalResult < ' tcx , CompileTimeEvalContext < ' a , ' tcx , ' tcx > > {
64
65
debug ! ( "mk_eval_cx: {:?}, {:?}" , instance, param_env) ;
65
66
let span = tcx. def_span ( instance. def_id ( ) ) ;
66
- let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator , ( ) ) ;
67
+ let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator :: new ( ) , ( ) ) ;
67
68
let mir = ecx. load_mir ( instance. def ) ?;
68
69
// insert a stack frame so any queries have the correct substs
69
70
ecx. push_stack_frame (
@@ -77,18 +78,17 @@ pub fn mk_eval_cx<'a, 'tcx>(
77
78
}
78
79
79
80
pub fn eval_promoted < ' a , ' mir , ' tcx > (
80
- ecx : & mut EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > ,
81
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
81
82
cid : GlobalId < ' tcx > ,
82
83
mir : & ' mir mir:: Mir < ' tcx > ,
83
84
param_env : ty:: ParamEnv < ' tcx > ,
84
85
) -> EvalResult < ' tcx , OpTy < ' tcx > > {
85
- ecx. with_fresh_body ( |ecx| {
86
- eval_body_using_ecx ( ecx, cid, Some ( mir) , param_env)
87
- } )
86
+ let mut ecx = mk_borrowck_eval_cx ( tcx, cid. instance , mir, DUMMY_SP ) . unwrap ( ) ;
87
+ eval_body_using_ecx ( & mut ecx, cid, Some ( mir) , param_env)
88
88
}
89
89
90
90
pub fn op_to_const < ' tcx > (
91
- ecx : & EvalContext < ' _ , ' _ , ' tcx , CompileTimeEvaluator > ,
91
+ ecx : & CompileTimeEvalContext < ' _ , ' _ , ' tcx > ,
92
92
op : OpTy < ' tcx > ,
93
93
normalize : bool ,
94
94
) -> EvalResult < ' tcx , & ' tcx ty:: Const < ' tcx > > {
@@ -128,19 +128,19 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
128
128
cid : GlobalId < ' tcx > ,
129
129
mir : Option < & ' mir mir:: Mir < ' tcx > > ,
130
130
param_env : ty:: ParamEnv < ' tcx > ,
131
- ) -> ( EvalResult < ' tcx , OpTy < ' tcx > > , EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > ) {
131
+ ) -> ( EvalResult < ' tcx , OpTy < ' tcx > > , CompileTimeEvalContext < ' a , ' mir , ' tcx > ) {
132
132
// we start out with the best span we have
133
133
// and try improving it down the road when more information is available
134
134
let span = tcx. def_span ( cid. instance . def_id ( ) ) ;
135
135
let span = mir. map ( |mir| mir. span ) . unwrap_or ( span) ;
136
- let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator , ( ) ) ;
136
+ let mut ecx = EvalContext :: new ( tcx. at ( span) , param_env, CompileTimeEvaluator :: new ( ) , ( ) ) ;
137
137
let r = eval_body_using_ecx ( & mut ecx, cid, mir, param_env) ;
138
138
( r, ecx)
139
139
}
140
140
141
141
// Returns a pointer to where the result lives
142
- fn eval_body_using_ecx < ' a , ' mir , ' tcx > (
143
- ecx : & mut EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator > ,
142
+ fn eval_body_using_ecx < ' mir , ' tcx > (
143
+ ecx : & mut CompileTimeEvalContext < ' _ , ' mir , ' tcx > ,
144
144
cid : GlobalId < ' tcx > ,
145
145
mir : Option < & ' mir mir:: Mir < ' tcx > > ,
146
146
param_env : ty:: ParamEnv < ' tcx > ,
@@ -187,17 +187,12 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
187
187
Ok ( ret. into ( ) )
188
188
}
189
189
190
- #[ derive( Debug , Clone , Eq , PartialEq , Hash ) ]
191
- pub struct CompileTimeEvaluator ;
192
-
193
190
impl < ' tcx > Into < EvalError < ' tcx > > for ConstEvalError {
194
191
fn into ( self ) -> EvalError < ' tcx > {
195
192
EvalErrorKind :: MachineError ( self . to_string ( ) ) . into ( )
196
193
}
197
194
}
198
195
199
- impl_stable_hash_for ! ( struct CompileTimeEvaluator { } ) ;
200
-
201
196
#[ derive( Clone , Debug ) ]
202
197
enum ConstEvalError {
203
198
NeedsRfc ( String ) ,
@@ -234,14 +229,39 @@ impl Error for ConstEvalError {
234
229
}
235
230
}
236
231
237
- impl < ' mir , ' tcx > interpret:: Machine < ' mir , ' tcx > for CompileTimeEvaluator {
232
+ // Extra machine state for CTFE, and the Machine instance
233
+ pub struct CompileTimeEvaluator < ' a , ' mir , ' tcx : ' a +' mir > {
234
+ /// When this value is negative, it indicates the number of interpreter
235
+ /// steps *until* the loop detector is enabled. When it is positive, it is
236
+ /// the number of steps after the detector has been enabled modulo the loop
237
+ /// detector period.
238
+ pub ( super ) steps_since_detector_enabled : isize ,
239
+
240
+ /// Extra state to detect loops.
241
+ pub ( super ) loop_detector : snapshot:: InfiniteLoopDetector < ' a , ' mir , ' tcx > ,
242
+ }
243
+
244
+ impl < ' a , ' mir , ' tcx > CompileTimeEvaluator < ' a , ' mir , ' tcx > {
245
+ fn new ( ) -> Self {
246
+ CompileTimeEvaluator {
247
+ loop_detector : Default :: default ( ) ,
248
+ steps_since_detector_enabled : -snapshot:: STEPS_UNTIL_DETECTOR_ENABLED ,
249
+ }
250
+ }
251
+ }
252
+
253
+ type CompileTimeEvalContext < ' a , ' mir , ' tcx > =
254
+ EvalContext < ' a , ' mir , ' tcx , CompileTimeEvaluator < ' a , ' mir , ' tcx > > ;
255
+
256
+ impl < ' a , ' mir , ' tcx > interpret:: Machine < ' a , ' mir , ' tcx >
257
+ for CompileTimeEvaluator < ' a , ' mir , ' tcx >
258
+ {
238
259
type MemoryData = ( ) ;
239
260
type MemoryKinds = !;
240
261
241
262
const MUT_STATIC_KIND : Option < !> = None ; // no mutating of statics allowed
242
- const DETECT_LOOPS : bool = true ;
243
263
244
- fn find_fn < ' a > (
264
+ fn find_fn (
245
265
ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ,
246
266
instance : ty:: Instance < ' tcx > ,
247
267
args : & [ OpTy < ' tcx > ] ,
@@ -275,7 +295,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
275
295
} ) )
276
296
}
277
297
278
- fn call_intrinsic < ' a > (
298
+ fn call_intrinsic (
279
299
ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ,
280
300
instance : ty:: Instance < ' tcx > ,
281
301
args : & [ OpTy < ' tcx > ] ,
@@ -291,7 +311,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
291
311
)
292
312
}
293
313
294
- fn ptr_op < ' a > (
314
+ fn ptr_op (
295
315
_ecx : & EvalContext < ' a , ' mir , ' tcx , Self > ,
296
316
_bin_op : mir:: BinOp ,
297
317
_left : Scalar ,
@@ -304,21 +324,51 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
304
324
)
305
325
}
306
326
307
- fn find_foreign_static < ' a > (
327
+ fn find_foreign_static (
308
328
_tcx : TyCtxtAt < ' a , ' tcx , ' tcx > ,
309
329
_def_id : DefId ,
310
330
) -> EvalResult < ' tcx , & ' tcx Allocation > {
311
331
err ! ( ReadForeignStatic )
312
332
}
313
333
314
- fn box_alloc < ' a > (
334
+ fn box_alloc (
315
335
_ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ,
316
336
_dest : PlaceTy < ' tcx > ,
317
337
) -> EvalResult < ' tcx > {
318
338
Err (
319
339
ConstEvalError :: NeedsRfc ( "heap allocations via `box` keyword" . to_string ( ) ) . into ( ) ,
320
340
)
321
341
}
342
+
343
+ fn before_terminator ( ecx : & mut EvalContext < ' a , ' mir , ' tcx , Self > ) -> EvalResult < ' tcx > {
344
+ {
345
+ let steps = & mut ecx. machine . steps_since_detector_enabled ;
346
+
347
+ * steps += 1 ;
348
+ if * steps < 0 {
349
+ return Ok ( ( ) ) ;
350
+ }
351
+
352
+ * steps %= snapshot:: DETECTOR_SNAPSHOT_PERIOD ;
353
+ if * steps != 0 {
354
+ return Ok ( ( ) ) ;
355
+ }
356
+ }
357
+
358
+ if ecx. machine . loop_detector . is_empty ( ) {
359
+ // First run of the loop detector
360
+
361
+ // FIXME(#49980): make this warning a lint
362
+ ecx. tcx . sess . span_warn ( ecx. frame ( ) . span ,
363
+ "Constant evaluating a complex constant, this might take some time" ) ;
364
+ }
365
+
366
+ ecx. machine . loop_detector . observe_and_analyze (
367
+ & ecx. tcx ,
368
+ & ecx. memory ,
369
+ & ecx. stack [ ..] ,
370
+ )
371
+ }
322
372
}
323
373
324
374
/// Project to a field of a (variant of a) const
0 commit comments