@@ -18,18 +18,18 @@ use crate::errors;
18
18
use crate :: errors:: ConstEvalError ;
19
19
use crate :: interpret:: eval_nullary_intrinsic;
20
20
use crate :: interpret:: {
21
- create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc , CtfeValidationMode ,
22
- GlobalId , Immediate , InternKind , InterpCx , InterpError , InterpResult , MPlaceTy , MemoryKind ,
23
- OpTy , RefTracking , StackPopCleanup ,
21
+ create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode , GlobalId , Immediate ,
22
+ InternKind , InterpCx , InterpError , InterpResult , MPlaceTy , MemoryKind , OpTy , RefTracking ,
23
+ StackPopCleanup ,
24
24
} ;
25
25
26
26
// Returns a pointer to where the result lives
27
- #[ instrument( level = "trace" , skip( ecx, body) , ret ) ]
28
- fn eval_body_using_ecx < ' mir , ' tcx > (
27
+ #[ instrument( level = "trace" , skip( ecx, body) ) ]
28
+ fn eval_body_using_ecx < ' mir , ' tcx , R : InterpretationResult < ' tcx > > (
29
29
ecx : & mut CompileTimeEvalContext < ' mir , ' tcx > ,
30
30
cid : GlobalId < ' tcx > ,
31
31
body : & ' mir mir:: Body < ' tcx > ,
32
- ) -> InterpResult < ' tcx , MPlaceTy < ' tcx > > {
32
+ ) -> InterpResult < ' tcx , R > {
33
33
trace ! ( ?ecx. param_env) ;
34
34
let tcx = * ecx. tcx ;
35
35
assert ! (
@@ -84,7 +84,10 @@ fn eval_body_using_ecx<'mir, 'tcx>(
84
84
// Intern the result
85
85
intern_const_alloc_recursive ( ecx, intern_kind, & ret) ?;
86
86
87
- Ok ( ret)
87
+ // Since evaluation had no errors, validate the resulting constant.
88
+ const_validate_mplace ( & ecx, & ret, cid) ?;
89
+
90
+ Ok ( R :: make_result ( ret, ecx) )
88
91
}
89
92
90
93
/// The `InterpCx` is only meant to be used to do field and index projections into constants for
@@ -282,18 +285,26 @@ pub fn eval_static_initializer_provider<'tcx>(
282
285
283
286
let instance = ty:: Instance :: mono ( tcx, def_id. to_def_id ( ) ) ;
284
287
let cid = rustc_middle:: mir:: interpret:: GlobalId { instance, promoted : None } ;
285
- let mut ecx = InterpCx :: new (
286
- tcx,
287
- tcx. def_span ( def_id) ,
288
- ty:: ParamEnv :: reveal_all ( ) ,
289
- // Statics (and promoteds inside statics) may access other statics, because unlike consts
290
- // they do not have to behave "as if" they were evaluated at runtime.
291
- CompileTimeInterpreter :: new ( CanAccessMutGlobal :: Yes , CheckAlignment :: Error ) ,
292
- ) ;
293
- let alloc_id = eval_in_interpreter ( & mut ecx, cid, true ) ?. alloc_id ;
294
- let alloc = take_static_root_alloc ( & mut ecx, alloc_id) ;
295
- let alloc = tcx. mk_const_alloc ( alloc) ;
296
- Ok ( alloc)
288
+ eval_in_interpreter ( tcx, cid, ty:: ParamEnv :: reveal_all ( ) )
289
+ }
290
+
291
+ pub trait InterpretationResult < ' tcx > {
292
+ /// This function takes the place where the result of the evaluation is stored
293
+ /// and prepares it for returning it in the appropriate format needed by the specific
294
+ /// evaluation query.
295
+ fn make_result < ' mir > (
296
+ mplace : MPlaceTy < ' tcx > ,
297
+ ecx : & mut InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
298
+ ) -> Self ;
299
+ }
300
+
301
+ impl < ' tcx > InterpretationResult < ' tcx > for ConstAlloc < ' tcx > {
302
+ fn make_result < ' mir > (
303
+ mplace : MPlaceTy < ' tcx > ,
304
+ _ecx : & mut InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
305
+ ) -> Self {
306
+ ConstAlloc { alloc_id : mplace. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) , ty : mplace. layout . ty }
307
+ }
297
308
}
298
309
299
310
#[ instrument( skip( tcx) , level = "debug" ) ]
@@ -319,92 +330,64 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
319
330
trace ! ( "const eval: {:?} ({})" , key, instance) ;
320
331
}
321
332
322
- let cid = key. value ;
333
+ eval_in_interpreter ( tcx, key. value , key. param_env )
334
+ }
335
+
336
+ fn eval_in_interpreter < ' tcx , R : InterpretationResult < ' tcx > > (
337
+ tcx : TyCtxt < ' tcx > ,
338
+ cid : GlobalId < ' tcx > ,
339
+ param_env : ty:: ParamEnv < ' tcx > ,
340
+ ) -> Result < R , ErrorHandled > {
323
341
let def = cid. instance . def . def_id ( ) ;
324
342
let is_static = tcx. is_static ( def) ;
325
343
326
344
let mut ecx = InterpCx :: new (
327
345
tcx,
328
346
tcx. def_span ( def) ,
329
- key . param_env ,
347
+ param_env,
330
348
// Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
331
349
// they do not have to behave "as if" they were evaluated at runtime.
332
350
// For consts however we want to ensure they behave "as if" they were evaluated at runtime,
333
351
// so we have to reject reading mutable global memory.
334
352
CompileTimeInterpreter :: new ( CanAccessMutGlobal :: from ( is_static) , CheckAlignment :: Error ) ,
335
353
) ;
336
- eval_in_interpreter ( & mut ecx, cid, is_static)
337
- }
338
-
339
- pub fn eval_in_interpreter < ' mir , ' tcx > (
340
- ecx : & mut InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
341
- cid : GlobalId < ' tcx > ,
342
- is_static : bool ,
343
- ) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
344
- // `is_static` just means "in static", it could still be a promoted!
345
- debug_assert_eq ! ( is_static, ecx. tcx. static_mutability( cid. instance. def_id( ) ) . is_some( ) ) ;
346
-
347
354
let res = ecx. load_mir ( cid. instance . def , cid. promoted ) ;
348
- match res. and_then ( |body| eval_body_using_ecx ( ecx, cid, body) ) {
349
- Err ( error) => {
350
- let ( error, backtrace) = error. into_parts ( ) ;
351
- backtrace. print_backtrace ( ) ;
352
-
353
- let ( kind, instance) = if is_static {
354
- ( "static" , String :: new ( ) )
355
- } else {
356
- // If the current item has generics, we'd like to enrich the message with the
357
- // instance and its args: to show the actual compile-time values, in addition to
358
- // the expression, leading to the const eval error.
359
- let instance = & cid. instance ;
360
- if !instance. args . is_empty ( ) {
361
- let instance = with_no_trimmed_paths ! ( instance. to_string( ) ) ;
362
- ( "const_with_path" , instance)
363
- } else {
364
- ( "const" , String :: new ( ) )
365
- }
366
- } ;
367
-
368
- Err ( super :: report (
369
- * ecx. tcx ,
370
- error,
371
- None ,
372
- || super :: get_span_and_frames ( ecx. tcx , & ecx. machine ) ,
373
- |span, frames| ConstEvalError {
374
- span,
375
- error_kind : kind,
376
- instance,
377
- frame_notes : frames,
378
- } ,
379
- ) )
380
- }
381
- Ok ( mplace) => {
382
- // Since evaluation had no errors, validate the resulting constant.
383
-
384
- // Temporarily allow access to the static_root_ids for the purpose of validation.
385
- let static_root_ids = ecx. machine . static_root_ids . take ( ) ;
386
- let res = const_validate_mplace ( & ecx, & mplace, cid) ;
387
- ecx. machine . static_root_ids = static_root_ids;
388
-
389
- let alloc_id = mplace. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) ;
390
-
391
- // Validation failed, report an error.
392
- if let Err ( error) = res {
393
- Err ( const_report_error ( & ecx, error, alloc_id) )
355
+ res. and_then ( |body| eval_body_using_ecx ( & mut ecx, cid, body) ) . map_err ( |error| {
356
+ let ( error, backtrace) = error. into_parts ( ) ;
357
+ backtrace. print_backtrace ( ) ;
358
+
359
+ let ( kind, instance) = if ecx. tcx . is_static ( cid. instance . def_id ( ) ) {
360
+ ( "static" , String :: new ( ) )
361
+ } else {
362
+ // If the current item has generics, we'd like to enrich the message with the
363
+ // instance and its args: to show the actual compile-time values, in addition to
364
+ // the expression, leading to the const eval error.
365
+ let instance = & cid. instance ;
366
+ if !instance. args . is_empty ( ) {
367
+ let instance = with_no_trimmed_paths ! ( instance. to_string( ) ) ;
368
+ ( "const_with_path" , instance)
394
369
} else {
395
- // Convert to raw constant
396
- Ok ( ConstAlloc { alloc_id, ty : mplace. layout . ty } )
370
+ ( "const" , String :: new ( ) )
397
371
}
398
- }
399
- }
372
+ } ;
373
+
374
+ super :: report (
375
+ * ecx. tcx ,
376
+ error,
377
+ None ,
378
+ || super :: get_span_and_frames ( ecx. tcx , ecx. stack ( ) ) ,
379
+ |span, frames| ConstEvalError { span, error_kind : kind, instance, frame_notes : frames } ,
380
+ )
381
+ } )
400
382
}
401
383
402
384
#[ inline( always) ]
403
- pub fn const_validate_mplace < ' mir , ' tcx > (
385
+ fn const_validate_mplace < ' mir , ' tcx > (
404
386
ecx : & InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
405
387
mplace : & MPlaceTy < ' tcx > ,
406
388
cid : GlobalId < ' tcx > ,
407
- ) -> InterpResult < ' tcx > {
389
+ ) -> Result < ( ) , ErrorHandled > {
390
+ let alloc_id = mplace. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) ;
408
391
let mut ref_tracking = RefTracking :: new ( mplace. clone ( ) ) ;
409
392
let mut inner = false ;
410
393
while let Some ( ( mplace, path) ) = ref_tracking. todo . pop ( ) {
@@ -418,15 +401,18 @@ pub fn const_validate_mplace<'mir, 'tcx>(
418
401
CtfeValidationMode :: Const { allow_immutable_unsafe_cell : !inner }
419
402
}
420
403
} ;
421
- ecx. const_validate_operand ( & mplace. into ( ) , path, & mut ref_tracking, mode) ?;
404
+ ecx. const_validate_operand ( & mplace. into ( ) , path, & mut ref_tracking, mode)
405
+ // Instead of just reporting the `InterpError` via the usual machinery, we give a more targetted
406
+ // error about the validation failure.
407
+ . map_err ( |error| report_validation_error ( & ecx, error, alloc_id) ) ?;
422
408
inner = true ;
423
409
}
424
410
425
411
Ok ( ( ) )
426
412
}
427
413
428
414
#[ inline( always) ]
429
- pub fn const_report_error < ' mir , ' tcx > (
415
+ fn report_validation_error < ' mir , ' tcx > (
430
416
ecx : & InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
431
417
error : InterpErrorInfo < ' tcx > ,
432
418
alloc_id : AllocId ,
@@ -444,7 +430,7 @@ pub fn const_report_error<'mir, 'tcx>(
444
430
* ecx. tcx ,
445
431
error,
446
432
None ,
447
- || crate :: const_eval:: get_span_and_frames ( ecx. tcx , & ecx. machine ) ,
448
- move |span, frames| errors:: UndefinedBehavior { span, ub_note, frames, raw_bytes } ,
433
+ || crate :: const_eval:: get_span_and_frames ( ecx. tcx , ecx. stack ( ) ) ,
434
+ move |span, frames| errors:: ValidationFailure { span, ub_note, frames, raw_bytes } ,
449
435
)
450
436
}
0 commit comments