@@ -13,6 +13,7 @@ use rustc_hir::intravisit::{self, Visitor};
13
13
use rustc_hir:: Node ;
14
14
use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrFlags , CodegenFnAttrs } ;
15
15
use rustc_middle:: middle:: privacy:: { self , Level } ;
16
+ use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc } ;
16
17
use rustc_middle:: query:: Providers ;
17
18
use rustc_middle:: ty:: { self , TyCtxt } ;
18
19
use rustc_session:: config:: CrateType ;
@@ -64,23 +65,8 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
64
65
_ => None ,
65
66
} ;
66
67
67
- if let Some ( res) = res
68
- && let Some ( def_id) = res. opt_def_id ( ) . and_then ( |el| el. as_local ( ) )
69
- {
70
- if self . def_id_represents_local_inlined_item ( def_id. to_def_id ( ) ) {
71
- self . worklist . push ( def_id) ;
72
- } else {
73
- match res {
74
- // Reachable constants and reachable statics can have their contents inlined
75
- // into other crates. Mark them as reachable and recurse into their body.
76
- Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: Static ( _) , _) => {
77
- self . worklist . push ( def_id) ;
78
- }
79
- _ => {
80
- self . reachable_symbols . insert ( def_id) ;
81
- }
82
- }
83
- }
68
+ if let Some ( res) = res {
69
+ self . propagate_item ( res) ;
84
70
}
85
71
86
72
intravisit:: walk_expr ( self , expr)
@@ -197,9 +183,14 @@ impl<'tcx> ReachableContext<'tcx> {
197
183
// Reachable constants will be inlined into other crates
198
184
// unconditionally, so we need to make sure that their
199
185
// contents are also reachable.
200
- hir:: ItemKind :: Const ( _, _, init) | hir :: ItemKind :: Static ( _ , _ , init ) => {
186
+ hir:: ItemKind :: Const ( _, _, init) => {
201
187
self . visit_nested_body ( init) ;
202
188
}
189
+ hir:: ItemKind :: Static ( ..) => {
190
+ if let Ok ( alloc) = self . tcx . eval_static_initializer ( item. owner_id . def_id ) {
191
+ self . propagate_from_alloc ( item. owner_id . def_id , alloc) ;
192
+ }
193
+ }
203
194
204
195
// These are normal, nothing reachable about these
205
196
// inherently and their children are already in the
@@ -266,6 +257,50 @@ impl<'tcx> ReachableContext<'tcx> {
266
257
}
267
258
}
268
259
}
260
+
261
+ /// Finds things to add to `reachable_symbols` within allocations.
262
+ /// In contrast to visit_nested_body this ignores things that were only needed to evaluate
263
+ /// to the allocation.
264
+ fn propagate_from_alloc ( & mut self , root : LocalDefId , alloc : ConstAllocation < ' tcx > ) {
265
+ if !self . any_library {
266
+ return ;
267
+ }
268
+ for ( _, prov) in alloc. 0 . provenance ( ) . ptrs ( ) . iter ( ) {
269
+ match self . tcx . global_alloc ( prov. alloc_id ( ) ) {
270
+ GlobalAlloc :: Static ( def_id) => {
271
+ self . propagate_item ( Res :: Def ( self . tcx . def_kind ( def_id) , def_id) )
272
+ }
273
+ GlobalAlloc :: Function ( instance) => {
274
+ self . propagate_item ( Res :: Def (
275
+ self . tcx . def_kind ( instance. def_id ( ) ) ,
276
+ instance. def_id ( ) ,
277
+ ) )
278
+ // TODO: walk generic args
279
+ }
280
+ GlobalAlloc :: VTable ( ty, trait_ref) => todo ! ( "{ty:?}, {trait_ref:?}" ) ,
281
+ GlobalAlloc :: Memory ( alloc) => self . propagate_from_alloc ( root, alloc) ,
282
+ }
283
+ }
284
+ }
285
+
286
+ fn propagate_item ( & mut self , res : Res ) {
287
+ let Res :: Def ( kind, def_id) = res else { return } ;
288
+ let Some ( def_id) = def_id. as_local ( ) else { return } ;
289
+ if self . def_id_represents_local_inlined_item ( def_id. to_def_id ( ) ) {
290
+ self . worklist . push ( def_id) ;
291
+ } else {
292
+ match kind {
293
+ // Reachable constants and reachable statics can have their contents inlined
294
+ // into other crates. Mark them as reachable and recurse into their body.
295
+ DefKind :: Const | DefKind :: AssocConst | DefKind :: Static ( _) => {
296
+ self . worklist . push ( def_id) ;
297
+ }
298
+ _ => {
299
+ self . reachable_symbols . insert ( def_id) ;
300
+ }
301
+ }
302
+ }
303
+ }
269
304
}
270
305
271
306
fn check_item < ' tcx > (
0 commit comments