@@ -2,12 +2,12 @@ use either::{Left, Right};
2
2
3
3
use rustc_hir:: def:: DefKind ;
4
4
use rustc_middle:: mir:: interpret:: { AllocId , ErrorHandled , InterpErrorInfo } ;
5
- use rustc_middle:: mir:: pretty:: write_allocation_bytes;
6
5
use rustc_middle:: mir:: { self , ConstAlloc , ConstValue } ;
7
6
use rustc_middle:: traits:: Reveal ;
8
7
use rustc_middle:: ty:: layout:: LayoutOf ;
9
8
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
10
9
use rustc_middle:: ty:: { self , TyCtxt } ;
10
+ use rustc_span:: def_id:: LocalDefId ;
11
11
use rustc_span:: Span ;
12
12
use rustc_target:: abi:: { self , Abi } ;
13
13
@@ -17,8 +17,9 @@ use crate::errors;
17
17
use crate :: errors:: ConstEvalError ;
18
18
use crate :: interpret:: eval_nullary_intrinsic;
19
19
use crate :: interpret:: {
20
- intern_const_alloc_recursive, CtfeValidationMode , GlobalId , Immediate , InternKind , InterpCx ,
21
- InterpError , InterpResult , MPlaceTy , MemoryKind , OpTy , RefTracking , StackPopCleanup ,
20
+ create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc, CtfeValidationMode ,
21
+ GlobalId , Immediate , InternKind , InterpCx , InterpError , InterpResult , MPlaceTy , MemoryKind ,
22
+ OpTy , RefTracking , StackPopCleanup ,
22
23
} ;
23
24
24
25
// Returns a pointer to where the result lives
@@ -46,7 +47,21 @@ fn eval_body_using_ecx<'mir, 'tcx>(
46
47
) ;
47
48
let layout = ecx. layout_of ( body. bound_return_ty ( ) . instantiate ( tcx, cid. instance . args ) ) ?;
48
49
assert ! ( layout. is_sized( ) ) ;
49
- let ret = ecx. allocate ( layout, MemoryKind :: Stack ) ?;
50
+
51
+ let intern_kind = if cid. promoted . is_some ( ) {
52
+ InternKind :: Promoted
53
+ } else {
54
+ match tcx. static_mutability ( cid. instance . def_id ( ) ) {
55
+ Some ( m) => InternKind :: Static ( m) ,
56
+ None => InternKind :: Constant ,
57
+ }
58
+ } ;
59
+
60
+ let ret = if let InternKind :: Static ( _) = intern_kind {
61
+ create_static_alloc ( ecx, cid. instance . def_id ( ) , layout) ?
62
+ } else {
63
+ ecx. allocate ( layout, MemoryKind :: Stack ) ?
64
+ } ;
50
65
51
66
trace ! (
52
67
"eval_body_using_ecx: pushing stack frame for global: {}{}" ,
@@ -66,14 +81,6 @@ fn eval_body_using_ecx<'mir, 'tcx>(
66
81
while ecx. step ( ) ? { }
67
82
68
83
// Intern the result
69
- let intern_kind = if cid. promoted . is_some ( ) {
70
- InternKind :: Promoted
71
- } else {
72
- match tcx. static_mutability ( cid. instance . def_id ( ) ) {
73
- Some ( m) => InternKind :: Static ( m) ,
74
- None => InternKind :: Constant ,
75
- }
76
- } ;
77
84
intern_const_alloc_recursive ( ecx, intern_kind, & ret) ?;
78
85
79
86
Ok ( ret)
@@ -249,11 +256,37 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
249
256
tcx. eval_to_allocation_raw ( key) . map ( |val| turn_into_const_value ( tcx, val, key) )
250
257
}
251
258
259
+ #[ instrument( skip( tcx) , level = "debug" ) ]
260
+ pub fn eval_static_initializer_provider < ' tcx > (
261
+ tcx : TyCtxt < ' tcx > ,
262
+ def_id : LocalDefId ,
263
+ ) -> :: rustc_middle:: mir:: interpret:: EvalStaticInitializerRawResult < ' tcx > {
264
+ assert ! ( tcx. is_static( def_id. to_def_id( ) ) ) ;
265
+
266
+ let instance = ty:: Instance :: mono ( tcx, def_id. to_def_id ( ) ) ;
267
+ let cid = rustc_middle:: mir:: interpret:: GlobalId { instance, promoted : None } ;
268
+ let mut ecx = InterpCx :: new (
269
+ tcx,
270
+ tcx. def_span ( def_id) ,
271
+ ty:: ParamEnv :: reveal_all ( ) ,
272
+ // Statics (and promoteds inside statics) may access other statics, because unlike consts
273
+ // they do not have to behave "as if" they were evaluated at runtime.
274
+ CompileTimeInterpreter :: new ( CanAccessMutGlobal :: Yes , CheckAlignment :: Error ) ,
275
+ ) ;
276
+ let alloc_id = eval_in_interpreter ( & mut ecx, cid, true ) ?. alloc_id ;
277
+ let alloc = take_static_root_alloc ( & mut ecx, alloc_id) ;
278
+ let alloc = tcx. mk_const_alloc ( alloc) ;
279
+ Ok ( alloc)
280
+ }
281
+
252
282
#[ instrument( skip( tcx) , level = "debug" ) ]
253
283
pub fn eval_to_allocation_raw_provider < ' tcx > (
254
284
tcx : TyCtxt < ' tcx > ,
255
285
key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
256
286
) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
287
+ // This shouldn't be used for statics, since statics are conceptually places,
288
+ // not values -- so what we do here could break pointer identity.
289
+ assert ! ( key. value. promoted. is_some( ) || !tcx. is_static( key. value. instance. def_id( ) ) ) ;
257
290
// Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
258
291
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
259
292
// types that are not specified in the opaque type.
@@ -273,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
273
306
let def = cid. instance . def . def_id ( ) ;
274
307
let is_static = tcx. is_static ( def) ;
275
308
276
- let ecx = InterpCx :: new (
309
+ let mut ecx = InterpCx :: new (
277
310
tcx,
278
311
tcx. def_span ( def) ,
279
312
key. param_env ,
@@ -283,19 +316,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
283
316
// so we have to reject reading mutable global memory.
284
317
CompileTimeInterpreter :: new ( CanAccessMutGlobal :: from ( is_static) , CheckAlignment :: Error ) ,
285
318
) ;
286
- eval_in_interpreter ( ecx, cid, is_static)
319
+ eval_in_interpreter ( & mut ecx, cid, is_static)
287
320
}
288
321
289
322
pub fn eval_in_interpreter < ' mir , ' tcx > (
290
- mut ecx : InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
323
+ ecx : & mut InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
291
324
cid : GlobalId < ' tcx > ,
292
325
is_static : bool ,
293
326
) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
294
327
// `is_static` just means "in static", it could still be a promoted!
295
328
debug_assert_eq ! ( is_static, ecx. tcx. static_mutability( cid. instance. def_id( ) ) . is_some( ) ) ;
296
329
297
330
let res = ecx. load_mir ( cid. instance . def , cid. promoted ) ;
298
- match res. and_then ( |body| eval_body_using_ecx ( & mut ecx, cid, body) ) {
331
+ match res. and_then ( |body| eval_body_using_ecx ( ecx, cid, body) ) {
299
332
Err ( error) => {
300
333
let ( error, backtrace) = error. into_parts ( ) ;
301
334
backtrace. print_backtrace ( ) ;
@@ -330,8 +363,11 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
330
363
}
331
364
Ok ( mplace) => {
332
365
// Since evaluation had no errors, validate the resulting constant.
333
- // This is a separate `try` block to provide more targeted error reporting.
366
+
367
+ // Temporarily allow access to the static_root_alloc_id for the purpose of validation.
368
+ let static_root_alloc_id = ecx. machine . static_root_alloc_id . take ( ) ;
334
369
let validation = const_validate_mplace ( & ecx, & mplace, cid) ;
370
+ ecx. machine . static_root_alloc_id = static_root_alloc_id;
335
371
336
372
let alloc_id = mplace. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) ;
337
373
@@ -383,15 +419,9 @@ pub fn const_report_error<'mir, 'tcx>(
383
419
384
420
let ub_note = matches ! ( error, InterpError :: UndefinedBehavior ( _) ) . then ( || { } ) ;
385
421
386
- let alloc = ecx. tcx . global_alloc ( alloc_id) . unwrap_memory ( ) . inner ( ) ;
387
- let mut bytes = String :: new ( ) ;
388
- if alloc. size ( ) != abi:: Size :: ZERO {
389
- bytes = "\n " . into ( ) ;
390
- // FIXME(translation) there might be pieces that are translatable.
391
- write_allocation_bytes ( * ecx. tcx , alloc, & mut bytes, " " ) . unwrap ( ) ;
392
- }
393
- let raw_bytes =
394
- errors:: RawBytesNote { size : alloc. size ( ) . bytes ( ) , align : alloc. align . bytes ( ) , bytes } ;
422
+ let bytes = ecx. print_alloc_bytes_for_diagnostics ( alloc_id) ;
423
+ let ( size, align, _) = ecx. get_alloc_info ( alloc_id) ;
424
+ let raw_bytes = errors:: RawBytesNote { size : size. bytes ( ) , align : align. bytes ( ) , bytes } ;
395
425
396
426
crate :: const_eval:: report (
397
427
* ecx. tcx ,
0 commit comments