@@ -1513,16 +1513,26 @@ fn collect_const_value<'tcx>(
15131513// Find all non-generic items by walking the HIR. These items serve as roots to
15141514// start monomorphizing from.
15151515#[ instrument( skip( tcx, mode) , level = "debug" ) ]
1516- fn collect_roots ( tcx : TyCtxt < ' _ > , mode : MonoItemCollectionStrategy ) -> Vec < MonoItem < ' _ > > {
1516+ fn collect_roots (
1517+ tcx : TyCtxt < ' _ > ,
1518+ mode : MonoItemCollectionStrategy ,
1519+ ) -> Vec < ( MonoItem < ' _ > , CollectionMode ) > {
15171520 debug ! ( "collecting roots" ) ;
1518- let mut roots = Vec :: new ( ) ;
1521+ let mut used_roots = MonoItems :: new ( ) ;
1522+ let mut mentioned_roots = MonoItems :: new ( ) ;
15191523
15201524 {
15211525 let entry_fn = tcx. entry_fn ( ( ) ) ;
15221526
15231527 debug ! ( "collect_roots: entry_fn = {:?}" , entry_fn) ;
15241528
1525- let mut collector = RootCollector { tcx, strategy : mode, entry_fn, output : & mut roots } ;
1529+ let mut collector = RootCollector {
1530+ tcx,
1531+ strategy : mode,
1532+ entry_fn,
1533+ used_roots : & mut used_roots,
1534+ mentioned_roots : & mut mentioned_roots,
1535+ } ;
15261536
15271537 let crate_items = tcx. hir_crate_items ( ( ) ) ;
15281538
@@ -1537,21 +1547,30 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoI
15371547 collector. push_extra_entry_roots ( ) ;
15381548 }
15391549
1550+ // Chain the two root lists together. Used items go first, to make it
1551+ // more likely that when we visit a mentioned item, we can stop immediately as it was already used.
15401552 // We can only codegen items that are instantiable - items all of
15411553 // whose predicates hold. Luckily, items that aren't instantiable
15421554 // can't actually be used, so we can just skip codegenning them.
1543- roots
1555+ used_roots
15441556 . into_iter ( )
1545- . filter_map ( |Spanned { node : mono_item, .. } | {
1546- mono_item. is_instantiable ( tcx) . then_some ( mono_item)
1547- } )
1557+ . map ( |mono_item| ( mono_item. node , CollectionMode :: UsedItems ) )
1558+ . chain (
1559+ mentioned_roots
1560+ . into_iter ( )
1561+ . map ( |mono_item| ( mono_item. node , CollectionMode :: MentionedItems ) ) ,
1562+ )
1563+ . filter ( |( mono_item, _mode) | mono_item. is_instantiable ( tcx) )
15481564 . collect ( )
15491565}
15501566
15511567struct RootCollector < ' a , ' tcx > {
15521568 tcx : TyCtxt < ' tcx > ,
15531569 strategy : MonoItemCollectionStrategy ,
1554- output : & ' a mut MonoItems < ' tcx > ,
1570+ // `MonoItems` includes spans we don't actually want... but this lets us reuse some of the
1571+ // collector's functions.
1572+ used_roots : & ' a mut MonoItems < ' tcx > ,
1573+ mentioned_roots : & ' a mut MonoItems < ' tcx > ,
15551574 entry_fn : Option < ( DefId , EntryFnType ) > ,
15561575}
15571576
@@ -1565,33 +1584,33 @@ impl<'v> RootCollector<'_, 'v> {
15651584 debug ! ( "RootCollector: ADT drop-glue for `{id:?}`" , ) ;
15661585
15671586 let ty = self . tcx . type_of ( id. owner_id . to_def_id ( ) ) . no_bound_vars ( ) . unwrap ( ) ;
1568- visit_drop_use ( self . tcx , ty, true , DUMMY_SP , self . output ) ;
1587+ visit_drop_use ( self . tcx , ty, true , DUMMY_SP , self . used_roots ) ;
15691588 }
15701589 }
15711590 DefKind :: GlobalAsm => {
15721591 debug ! (
15731592 "RootCollector: ItemKind::GlobalAsm({})" ,
15741593 self . tcx. def_path_str( id. owner_id)
15751594 ) ;
1576- self . output . push ( dummy_spanned ( MonoItem :: GlobalAsm ( id) ) ) ;
1595+ self . used_roots . push ( dummy_spanned ( MonoItem :: GlobalAsm ( id) ) ) ;
15771596 }
15781597 DefKind :: Static { .. } => {
15791598 let def_id = id. owner_id . to_def_id ( ) ;
15801599 debug ! ( "RootCollector: ItemKind::Static({})" , self . tcx. def_path_str( def_id) ) ;
1581- self . output . push ( dummy_spanned ( MonoItem :: Static ( def_id) ) ) ;
1600+ self . used_roots . push ( dummy_spanned ( MonoItem :: Static ( def_id) ) ) ;
15821601 }
15831602 DefKind :: Const => {
15841603 // const items only generate mono items if they are
15851604 // actually used somewhere. Just declaring them is insufficient.
15861605
15871606 // but even just declaring them must collect the items they refer to
15881607 if let Ok ( val) = self . tcx . const_eval_poly ( id. owner_id . to_def_id ( ) ) {
1589- collect_const_value ( self . tcx , val, self . output ) ;
1608+ collect_const_value ( self . tcx , val, self . used_roots ) ;
15901609 }
15911610 }
15921611 DefKind :: Impl { .. } => {
15931612 if self . strategy == MonoItemCollectionStrategy :: Eager {
1594- create_mono_items_for_default_impls ( self . tcx , id, self . output ) ;
1613+ create_mono_items_for_default_impls ( self . tcx , id, self . used_roots ) ;
15951614 }
15961615 }
15971616 DefKind :: Fn => {
@@ -1607,31 +1626,54 @@ impl<'v> RootCollector<'_, 'v> {
16071626 }
16081627 }
16091628
1610- fn is_root ( & self , def_id : LocalDefId ) -> bool {
1611- !self . tcx . generics_of ( def_id) . requires_monomorphization ( self . tcx )
1612- && match self . strategy {
1613- MonoItemCollectionStrategy :: Eager => true ,
1614- MonoItemCollectionStrategy :: Lazy => {
1615- self . entry_fn . and_then ( |( id, _) | id. as_local ( ) ) == Some ( def_id)
1616- || self . tcx . is_reachable_non_generic ( def_id)
1617- || self
1618- . tcx
1619- . codegen_fn_attrs ( def_id)
1620- . flags
1621- . contains ( CodegenFnAttrFlags :: RUSTC_STD_INTERNAL_SYMBOL )
1622- }
1629+ /// Determines whether this is an item we start walking, and in which mode. The "real" roots are
1630+ /// walked as "used" items, but that set is optimization-dependent. We add all other non-generic
1631+ /// items as "mentioned" roots. This makes the set of items where `is_root` return `Some`
1632+ /// optimization-independent, which is crucial to ensure that optimized and unoptimized builds
1633+ /// evaluate the same constants.
1634+ fn is_root ( & self , def_id : LocalDefId ) -> Option < CollectionMode > {
1635+ // Generic things are never roots.
1636+ if self . tcx . generics_of ( def_id) . requires_monomorphization ( self . tcx ) {
1637+ return None ;
1638+ }
1639+ // We have to skip `must_be_overridden` bodies; asking for their MIR ICEs.
1640+ if self . tcx . intrinsic ( def_id) . is_some_and ( |i| i. must_be_overridden ) {
1641+ return None ;
1642+ }
1643+ // The rest is definitely a root, but is it used or merely mentioned?
1644+ // Determine whether this item is reachable, which makes it "used".
1645+ let is_used_root = match self . strategy {
1646+ MonoItemCollectionStrategy :: Eager => true ,
1647+ MonoItemCollectionStrategy :: Lazy => {
1648+ self . entry_fn . and_then ( |( id, _) | id. as_local ( ) ) == Some ( def_id)
1649+ || self . tcx . is_reachable_non_generic ( def_id)
1650+ || self
1651+ . tcx
1652+ . codegen_fn_attrs ( def_id)
1653+ . flags
1654+ . contains ( CodegenFnAttrFlags :: RUSTC_STD_INTERNAL_SYMBOL )
16231655 }
1656+ } ;
1657+ if is_used_root {
1658+ Some ( CollectionMode :: UsedItems )
1659+ } else {
1660+ Some ( CollectionMode :: MentionedItems )
1661+ }
16241662 }
16251663
16261664 /// If `def_id` represents a root, pushes it onto the list of
16271665 /// outputs. (Note that all roots must be monomorphic.)
16281666 #[ instrument( skip( self ) , level = "debug" ) ]
16291667 fn push_if_root ( & mut self , def_id : LocalDefId ) {
1630- if self . is_root ( def_id) {
1668+ if let Some ( mode ) = self . is_root ( def_id) {
16311669 debug ! ( "found root" ) ;
16321670
16331671 let instance = Instance :: mono ( self . tcx , def_id. to_def_id ( ) ) ;
1634- self . output . push ( create_fn_mono_item ( self . tcx , instance, DUMMY_SP ) ) ;
1672+ let mono_item = create_fn_mono_item ( self . tcx , instance, DUMMY_SP ) ;
1673+ match mode {
1674+ CollectionMode :: UsedItems => self . used_roots . push ( mono_item) ,
1675+ CollectionMode :: MentionedItems => self . mentioned_roots . push ( mono_item) ,
1676+ }
16351677 }
16361678 }
16371679
@@ -1667,7 +1709,7 @@ impl<'v> RootCollector<'_, 'v> {
16671709 self . tcx . mk_args ( & [ main_ret_ty. into ( ) ] ) ,
16681710 ) ;
16691711
1670- self . output . push ( create_fn_mono_item ( self . tcx , start_instance, DUMMY_SP ) ) ;
1712+ self . used_roots . push ( create_fn_mono_item ( self . tcx , start_instance, DUMMY_SP ) ) ;
16711713 }
16721714}
16731715
@@ -1772,15 +1814,15 @@ pub fn collect_crate_mono_items(
17721814 let state: LRef < ' _ , _ > = & mut state;
17731815
17741816 tcx. sess . time ( "monomorphization_collector_graph_walk" , || {
1775- par_for_each_in ( roots, |root| {
1817+ par_for_each_in ( roots, |( root, mode ) | {
17761818 let mut recursion_depths = DefIdMap :: default ( ) ;
17771819 collect_items_rec (
17781820 tcx,
17791821 dummy_spanned ( root) ,
17801822 state,
17811823 & mut recursion_depths,
17821824 recursion_limit,
1783- CollectionMode :: UsedItems ,
1825+ mode ,
17841826 ) ;
17851827 } ) ;
17861828 } ) ;
0 commit comments