6
6
// reachable as well.
7
7
8
8
use hir:: def_id:: LocalDefIdSet ;
9
+ use rustc_data_structures:: stack:: ensure_sufficient_stack;
9
10
use rustc_hir as hir;
10
11
use rustc_hir:: def:: { DefKind , Res } ;
11
12
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
@@ -15,7 +16,8 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}
15
16
use rustc_middle:: middle:: privacy:: { self , Level } ;
16
17
use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc } ;
17
18
use rustc_middle:: query:: Providers ;
18
- use rustc_middle:: ty:: { self , TyCtxt } ;
19
+ use rustc_middle:: ty:: { self , ExistentialTraitRef , TyCtxt } ;
20
+ use rustc_privacy:: DefIdVisitor ;
19
21
use rustc_session:: config:: CrateType ;
20
22
use rustc_target:: spec:: abi:: Abi ;
21
23
@@ -65,23 +67,8 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
65
67
_ => None ,
66
68
} ;
67
69
68
- if let Some ( res) = res
69
- && let Some ( def_id) = res. opt_def_id ( ) . and_then ( |el| el. as_local ( ) )
70
- {
71
- if self . def_id_represents_local_inlined_item ( def_id. to_def_id ( ) ) {
72
- self . worklist . push ( def_id) ;
73
- } else {
74
- match res {
75
- // Reachable constants and reachable statics can have their contents inlined
76
- // into other crates. Mark them as reachable and recurse into their body.
77
- Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: Static { .. } , _) => {
78
- self . worklist . push ( def_id) ;
79
- }
80
- _ => {
81
- self . reachable_symbols . insert ( def_id) ;
82
- }
83
- }
84
- }
70
+ if let Some ( res) = res {
71
+ self . propagate_item ( res) ;
85
72
}
86
73
87
74
intravisit:: walk_expr ( self , expr)
@@ -198,17 +185,9 @@ impl<'tcx> ReachableContext<'tcx> {
198
185
hir:: ItemKind :: Const ( _, _, init) => {
199
186
self . visit_nested_body ( init) ;
200
187
}
201
-
202
- // Reachable statics are inlined if read from another constant or static
203
- // in other crates. Additionally anonymous nested statics may be created
204
- // when evaluating a static, so preserve those, too.
205
- hir:: ItemKind :: Static ( _, _, init) => {
206
- // FIXME(oli-obk): remove this body walking and instead walk the evaluated initializer
207
- // to find nested items that end up in the final value instead of also marking symbols
208
- // as reachable that are only needed for evaluation.
209
- self . visit_nested_body ( init) ;
188
+ hir:: ItemKind :: Static ( ..) => {
210
189
if let Ok ( alloc) = self . tcx . eval_static_initializer ( item. owner_id . def_id ) {
211
- self . propagate_statics_from_alloc ( item . owner_id . def_id , alloc) ;
190
+ self . propagate_from_alloc ( alloc) ;
212
191
}
213
192
}
214
193
@@ -279,28 +258,89 @@ impl<'tcx> ReachableContext<'tcx> {
279
258
}
280
259
}
281
260
282
- /// Finds anonymous nested statics created for nested allocations and adds them to `reachable_symbols`.
283
- fn propagate_statics_from_alloc ( & mut self , root : LocalDefId , alloc : ConstAllocation < ' tcx > ) {
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
+ /// the allocation.
264
+ fn propagate_from_alloc ( & mut self , alloc : ConstAllocation < ' tcx > ) {
284
265
if !self . any_library {
285
266
return ;
286
267
}
287
268
for ( _, prov) in alloc. 0 . provenance ( ) . ptrs ( ) . iter ( ) {
288
269
match self . tcx . global_alloc ( prov. alloc_id ( ) ) {
289
270
GlobalAlloc :: Static ( def_id) => {
290
- if let Some ( def_id) = def_id. as_local ( )
291
- && self . tcx . local_parent ( def_id) == root
292
- // This is the main purpose of this function: add the def_id we find
293
- // to `reachable_symbols`.
294
- && self . reachable_symbols . insert ( def_id)
295
- && let Ok ( alloc) = self . tcx . eval_static_initializer ( def_id)
296
- {
297
- self . propagate_statics_from_alloc ( root, alloc) ;
271
+ self . propagate_item ( Res :: Def ( self . tcx . def_kind ( def_id) , def_id) )
272
+ }
273
+ GlobalAlloc :: Function ( instance) => {
274
+ // Manually visit to actually see the instance's `DefId`. Type visitors won't see it
275
+ self . propagate_item ( Res :: Def (
276
+ self . tcx . def_kind ( instance. def_id ( ) ) ,
277
+ instance. def_id ( ) ,
278
+ ) ) ;
279
+ self . visit ( instance. args ) ;
280
+ }
281
+ GlobalAlloc :: VTable ( ty, trait_ref) => {
282
+ self . visit ( ty) ;
283
+ // Manually visit to actually see the trait's `DefId`. Type visitors won't see it
284
+ if let Some ( trait_ref) = trait_ref {
285
+ let ExistentialTraitRef { def_id, args } = trait_ref. skip_binder ( ) ;
286
+ self . visit_def_id ( def_id, "" , & "" ) ;
287
+ self . visit ( args) ;
298
288
}
299
289
}
300
- GlobalAlloc :: Function ( _ ) | GlobalAlloc :: VTable ( _ , _ ) | GlobalAlloc :: Memory ( _ ) => { }
290
+ GlobalAlloc :: Memory ( alloc ) => self . propagate_from_alloc ( alloc ) ,
301
291
}
302
292
}
303
293
}
294
+
295
+ fn propagate_item ( & mut self , res : Res ) {
296
+ let Res :: Def ( kind, def_id) = res else { return } ;
297
+ let Some ( def_id) = def_id. as_local ( ) else { return } ;
298
+ match kind {
299
+ DefKind :: Static { nested : true , .. } => {
300
+ // This is the main purpose of this function: add the def_id we find
301
+ // to `reachable_symbols`.
302
+ if self . reachable_symbols . insert ( def_id) {
303
+ if let Ok ( alloc) = self . tcx . eval_static_initializer ( def_id) {
304
+ // This cannot cause infinite recursion, because we abort by inserting into the
305
+ // work list once we hit a normal static. Nested statics, even if they somehow
306
+ // become recursive, are also not infinitely recursing, because of the
307
+ // `reachable_symbols` check above.
308
+ // We still need to protect against stack overflow due to deeply nested statics.
309
+ ensure_sufficient_stack ( || self . propagate_from_alloc ( alloc) ) ;
310
+ }
311
+ }
312
+ }
313
+ // Reachable constants and reachable statics can have their contents inlined
314
+ // into other crates. Mark them as reachable and recurse into their body.
315
+ DefKind :: Const | DefKind :: AssocConst | DefKind :: Static { .. } => {
316
+ self . worklist . push ( def_id) ;
317
+ }
318
+ _ => {
319
+ if self . def_id_represents_local_inlined_item ( def_id. to_def_id ( ) ) {
320
+ self . worklist . push ( def_id) ;
321
+ } else {
322
+ self . reachable_symbols . insert ( def_id) ;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ impl < ' tcx > DefIdVisitor < ' tcx > for ReachableContext < ' tcx > {
330
+ type Result = ( ) ;
331
+
332
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
333
+ self . tcx
334
+ }
335
+
336
+ fn visit_def_id (
337
+ & mut self ,
338
+ def_id : DefId ,
339
+ _kind : & str ,
340
+ _descr : & dyn std:: fmt:: Display ,
341
+ ) -> Self :: Result {
342
+ self . propagate_item ( Res :: Def ( self . tcx . def_kind ( def_id) , def_id) )
343
+ }
304
344
}
305
345
306
346
fn check_item < ' tcx > (
0 commit comments