@@ -2,12 +2,12 @@ use either::{Left, Right};
22
33use rustc_hir:: def:: DefKind ;
44use rustc_middle:: mir:: interpret:: { AllocId , ErrorHandled , InterpErrorInfo } ;
5- use rustc_middle:: mir:: pretty:: write_allocation_bytes;
65use rustc_middle:: mir:: { self , ConstAlloc , ConstValue } ;
76use rustc_middle:: traits:: Reveal ;
87use rustc_middle:: ty:: layout:: LayoutOf ;
98use rustc_middle:: ty:: print:: with_no_trimmed_paths;
109use rustc_middle:: ty:: { self , TyCtxt } ;
10+ use rustc_span:: def_id:: LocalDefId ;
1111use rustc_span:: Span ;
1212use rustc_target:: abi:: { self , Abi } ;
1313
@@ -17,8 +17,9 @@ use crate::errors;
1717use crate :: errors:: ConstEvalError ;
1818use crate :: interpret:: eval_nullary_intrinsic;
1919use 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 ,
2223} ;
2324
2425// Returns a pointer to where the result lives
@@ -46,7 +47,21 @@ fn eval_body_using_ecx<'mir, 'tcx>(
4647 ) ;
4748 let layout = ecx. layout_of ( body. bound_return_ty ( ) . instantiate ( tcx, cid. instance . args ) ) ?;
4849 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+ } ;
5065
5166 trace ! (
5267 "eval_body_using_ecx: pushing stack frame for global: {}{}" ,
@@ -66,14 +81,6 @@ fn eval_body_using_ecx<'mir, 'tcx>(
6681 while ecx. step ( ) ? { }
6782
6883 // 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- } ;
7784 intern_const_alloc_recursive ( ecx, intern_kind, & ret) ?;
7885
7986 Ok ( ret)
@@ -249,11 +256,37 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
249256 tcx. eval_to_allocation_raw ( key) . map ( |val| turn_into_const_value ( tcx, val, key) )
250257}
251258
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+
252282#[ instrument( skip( tcx) , level = "debug" ) ]
253283pub fn eval_to_allocation_raw_provider < ' tcx > (
254284 tcx : TyCtxt < ' tcx > ,
255285 key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
256286) -> :: 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( ) ) ) ;
257290 // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of
258291 // opaque types. This is needed for trivial things like `size_of`, but also for using associated
259292 // types that are not specified in the opaque type.
@@ -273,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
273306 let def = cid. instance . def . def_id ( ) ;
274307 let is_static = tcx. is_static ( def) ;
275308
276- let ecx = InterpCx :: new (
309+ let mut ecx = InterpCx :: new (
277310 tcx,
278311 tcx. def_span ( def) ,
279312 key. param_env ,
@@ -283,19 +316,19 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
283316 // so we have to reject reading mutable global memory.
284317 CompileTimeInterpreter :: new ( CanAccessMutGlobal :: from ( is_static) , CheckAlignment :: Error ) ,
285318 ) ;
286- eval_in_interpreter ( ecx, cid, is_static)
319+ eval_in_interpreter ( & mut ecx, cid, is_static)
287320}
288321
289322pub fn eval_in_interpreter < ' mir , ' tcx > (
290- mut ecx : InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
323+ ecx : & mut InterpCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
291324 cid : GlobalId < ' tcx > ,
292325 is_static : bool ,
293326) -> :: rustc_middle:: mir:: interpret:: EvalToAllocationRawResult < ' tcx > {
294327 // `is_static` just means "in static", it could still be a promoted!
295328 debug_assert_eq ! ( is_static, ecx. tcx. static_mutability( cid. instance. def_id( ) ) . is_some( ) ) ;
296329
297330 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) ) {
299332 Err ( error) => {
300333 let ( error, backtrace) = error. into_parts ( ) ;
301334 backtrace. print_backtrace ( ) ;
@@ -330,8 +363,11 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
330363 }
331364 Ok ( mplace) => {
332365 // 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 ( ) ;
334369 let validation = const_validate_mplace ( & ecx, & mplace, cid) ;
370+ ecx. machine . static_root_alloc_id = static_root_alloc_id;
335371
336372 let alloc_id = mplace. ptr ( ) . provenance . unwrap ( ) . alloc_id ( ) ;
337373
@@ -383,15 +419,9 @@ pub fn const_report_error<'mir, 'tcx>(
383419
384420 let ub_note = matches ! ( error, InterpError :: UndefinedBehavior ( _) ) . then ( || { } ) ;
385421
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 } ;
395425
396426 crate :: const_eval:: report (
397427 * ecx. tcx ,
0 commit comments