@@ -13,8 +13,10 @@ use rustc_hir::intravisit::{self, Visitor};
1313use rustc_hir:: Node ;
1414use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrFlags , CodegenFnAttrs } ;
1515use rustc_middle:: middle:: privacy:: { self , Level } ;
16+ use rustc_middle:: mir:: interpret:: { ConstAllocation , GlobalAlloc } ;
1617use rustc_middle:: query:: Providers ;
17- use rustc_middle:: ty:: { self , TyCtxt } ;
18+ use rustc_middle:: ty:: { self , ExistentialTraitRef , TyCtxt } ;
19+ use rustc_privacy:: DefIdVisitor ;
1820use rustc_session:: config:: CrateType ;
1921use rustc_target:: spec:: abi:: Abi ;
2022
@@ -64,23 +66,8 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
6466 _ => None ,
6567 } ;
6668
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) ;
8471 }
8572
8673 intravisit:: walk_expr ( self , expr)
@@ -197,9 +184,14 @@ impl<'tcx> ReachableContext<'tcx> {
197184 // Reachable constants will be inlined into other crates
198185 // unconditionally, so we need to make sure that their
199186 // contents are also reachable.
200- hir:: ItemKind :: Const ( _, _, init) | hir :: ItemKind :: Static ( _ , _ , init ) => {
187+ hir:: ItemKind :: Const ( _, _, init) => {
201188 self . visit_nested_body ( init) ;
202189 }
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+ }
203195
204196 // These are normal, nothing reachable about these
205197 // inherently and their children are already in the
@@ -266,6 +258,76 @@ impl<'tcx> ReachableContext<'tcx> {
266258 }
267259 }
268260 }
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+ }
269331}
270332
271333fn check_item < ' tcx > (
0 commit comments