@@ -13,8 +13,10 @@ 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
- use rustc_middle:: ty:: { self , TyCtxt } ;
18
+ use rustc_middle:: ty:: { self , ExistentialTraitRef , TyCtxt } ;
19
+ use rustc_privacy:: DefIdVisitor ;
18
20
use rustc_session:: config:: CrateType ;
19
21
use rustc_target:: spec:: abi:: Abi ;
20
22
@@ -64,23 +66,8 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
64
66
_ => None ,
65
67
} ;
66
68
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
- }
69
+ if let Some ( res) = res {
70
+ self . propagate_item ( res) ;
84
71
}
85
72
86
73
intravisit:: walk_expr ( self , expr)
@@ -197,9 +184,14 @@ impl<'tcx> ReachableContext<'tcx> {
197
184
// Reachable constants will be inlined into other crates
198
185
// unconditionally, so we need to make sure that their
199
186
// contents are also reachable.
200
- hir:: ItemKind :: Const ( _, _, init) | hir :: ItemKind :: Static ( _ , _ , init ) => {
187
+ hir:: ItemKind :: Const ( _, _, init) => {
201
188
self . visit_nested_body ( init) ;
202
189
}
190
+ hir:: ItemKind :: Static ( ..) => {
191
+ if let Ok ( alloc) = self . tcx . eval_static_initializer ( item. owner_id . def_id ) {
192
+ self . propagate_from_alloc ( item. owner_id . def_id , alloc) ;
193
+ }
194
+ }
203
195
204
196
// These are normal, nothing reachable about these
205
197
// inherently and their children are already in the
@@ -266,6 +258,76 @@ impl<'tcx> ReachableContext<'tcx> {
266
258
}
267
259
}
268
260
}
261
+
262
+ /// Finds things to add to `reachable_symbols` within allocations.
263
+ /// In contrast to visit_nested_body this ignores things that were only needed to evaluate
264
+ /// to the allocation.
265
+ fn propagate_from_alloc ( & mut self , root : LocalDefId , alloc : ConstAllocation < ' tcx > ) {
266
+ if !self . any_library {
267
+ return ;
268
+ }
269
+ for ( _, prov) in alloc. 0 . provenance ( ) . ptrs ( ) . iter ( ) {
270
+ match self . tcx . global_alloc ( prov. alloc_id ( ) ) {
271
+ GlobalAlloc :: Static ( def_id) => {
272
+ self . propagate_item ( Res :: Def ( self . tcx . def_kind ( def_id) , def_id) )
273
+ }
274
+ GlobalAlloc :: Function ( instance) => {
275
+ // Manually visit to actually see the instance's `DefId`. Type visitors won't see it
276
+ self . propagate_item ( Res :: Def (
277
+ self . tcx . def_kind ( instance. def_id ( ) ) ,
278
+ instance. def_id ( ) ,
279
+ ) ) ;
280
+ self . visit ( instance. args ) ;
281
+ }
282
+ GlobalAlloc :: VTable ( ty, trait_ref) => {
283
+ self . visit ( ty) ;
284
+ // Manually visit to actually see the trait's `DefId`. Type visitors won't see it
285
+ if let Some ( trait_ref) = trait_ref {
286
+ let ExistentialTraitRef { def_id, args } = trait_ref. skip_binder ( ) ;
287
+ self . visit_def_id ( def_id, "" , & "" ) ;
288
+ self . visit ( args) ;
289
+ }
290
+ }
291
+ GlobalAlloc :: Memory ( alloc) => self . propagate_from_alloc ( root, alloc) ,
292
+ }
293
+ }
294
+ }
295
+
296
+ fn propagate_item ( & mut self , res : Res ) {
297
+ let Res :: Def ( kind, def_id) = res else { return } ;
298
+ let Some ( def_id) = def_id. as_local ( ) else { return } ;
299
+ if self . def_id_represents_local_inlined_item ( def_id. to_def_id ( ) ) {
300
+ self . worklist . push ( def_id) ;
301
+ } else {
302
+ match kind {
303
+ // Reachable constants and reachable statics can have their contents inlined
304
+ // into other crates. Mark them as reachable and recurse into their body.
305
+ DefKind :: Const | DefKind :: AssocConst | DefKind :: Static ( _) => {
306
+ self . worklist . push ( def_id) ;
307
+ }
308
+ _ => {
309
+ self . reachable_symbols . insert ( def_id) ;
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ impl < ' tcx > DefIdVisitor < ' tcx > for ReachableContext < ' tcx > {
317
+ type Result = ( ) ;
318
+
319
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
320
+ self . tcx
321
+ }
322
+
323
+ fn visit_def_id (
324
+ & mut self ,
325
+ def_id : DefId ,
326
+ _kind : & str ,
327
+ _descr : & dyn std:: fmt:: Display ,
328
+ ) -> Self :: Result {
329
+ self . propagate_item ( Res :: Def ( self . tcx . def_kind ( def_id) , def_id) )
330
+ }
269
331
}
270
332
271
333
fn check_item < ' tcx > (
0 commit comments