@@ -1513,16 +1513,26 @@ fn collect_const_value<'tcx>(
1513
1513
// Find all non-generic items by walking the HIR. These items serve as roots to
1514
1514
// start monomorphizing from.
1515
1515
#[ 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 ) > {
1517
1520
debug ! ( "collecting roots" ) ;
1518
- let mut roots = Vec :: new ( ) ;
1521
+ let mut used_roots = MonoItems :: new ( ) ;
1522
+ let mut mentioned_roots = MonoItems :: new ( ) ;
1519
1523
1520
1524
{
1521
1525
let entry_fn = tcx. entry_fn ( ( ) ) ;
1522
1526
1523
1527
debug ! ( "collect_roots: entry_fn = {:?}" , entry_fn) ;
1524
1528
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
+ } ;
1526
1536
1527
1537
let crate_items = tcx. hir_crate_items ( ( ) ) ;
1528
1538
@@ -1537,21 +1547,30 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoI
1537
1547
collector. push_extra_entry_roots ( ) ;
1538
1548
}
1539
1549
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.
1540
1552
// We can only codegen items that are instantiable - items all of
1541
1553
// whose predicates hold. Luckily, items that aren't instantiable
1542
1554
// can't actually be used, so we can just skip codegenning them.
1543
- roots
1555
+ used_roots
1544
1556
. 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) )
1548
1564
. collect ( )
1549
1565
}
1550
1566
1551
1567
struct RootCollector < ' a , ' tcx > {
1552
1568
tcx : TyCtxt < ' tcx > ,
1553
1569
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 > ,
1555
1574
entry_fn : Option < ( DefId , EntryFnType ) > ,
1556
1575
}
1557
1576
@@ -1565,33 +1584,33 @@ impl<'v> RootCollector<'_, 'v> {
1565
1584
debug ! ( "RootCollector: ADT drop-glue for `{id:?}`" , ) ;
1566
1585
1567
1586
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 ) ;
1569
1588
}
1570
1589
}
1571
1590
DefKind :: GlobalAsm => {
1572
1591
debug ! (
1573
1592
"RootCollector: ItemKind::GlobalAsm({})" ,
1574
1593
self . tcx. def_path_str( id. owner_id)
1575
1594
) ;
1576
- self . output . push ( dummy_spanned ( MonoItem :: GlobalAsm ( id) ) ) ;
1595
+ self . used_roots . push ( dummy_spanned ( MonoItem :: GlobalAsm ( id) ) ) ;
1577
1596
}
1578
1597
DefKind :: Static { .. } => {
1579
1598
let def_id = id. owner_id . to_def_id ( ) ;
1580
1599
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) ) ) ;
1582
1601
}
1583
1602
DefKind :: Const => {
1584
1603
// const items only generate mono items if they are
1585
1604
// actually used somewhere. Just declaring them is insufficient.
1586
1605
1587
1606
// but even just declaring them must collect the items they refer to
1588
1607
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 ) ;
1590
1609
}
1591
1610
}
1592
1611
DefKind :: Impl { .. } => {
1593
1612
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 ) ;
1595
1614
}
1596
1615
}
1597
1616
DefKind :: Fn => {
@@ -1607,31 +1626,54 @@ impl<'v> RootCollector<'_, 'v> {
1607
1626
}
1608
1627
}
1609
1628
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 )
1623
1655
}
1656
+ } ;
1657
+ if is_used_root {
1658
+ Some ( CollectionMode :: UsedItems )
1659
+ } else {
1660
+ Some ( CollectionMode :: MentionedItems )
1661
+ }
1624
1662
}
1625
1663
1626
1664
/// If `def_id` represents a root, pushes it onto the list of
1627
1665
/// outputs. (Note that all roots must be monomorphic.)
1628
1666
#[ instrument( skip( self ) , level = "debug" ) ]
1629
1667
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) {
1631
1669
debug ! ( "found root" ) ;
1632
1670
1633
1671
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
+ }
1635
1677
}
1636
1678
}
1637
1679
@@ -1667,7 +1709,7 @@ impl<'v> RootCollector<'_, 'v> {
1667
1709
self . tcx . mk_args ( & [ main_ret_ty. into ( ) ] ) ,
1668
1710
) ;
1669
1711
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 ) ) ;
1671
1713
}
1672
1714
}
1673
1715
@@ -1772,15 +1814,15 @@ pub fn collect_crate_mono_items(
1772
1814
let state: LRef < ' _ , _ > = & mut state;
1773
1815
1774
1816
tcx. sess . time ( "monomorphization_collector_graph_walk" , || {
1775
- par_for_each_in ( roots, |root| {
1817
+ par_for_each_in ( roots, |( root, mode ) | {
1776
1818
let mut recursion_depths = DefIdMap :: default ( ) ;
1777
1819
collect_items_rec (
1778
1820
tcx,
1779
1821
dummy_spanned ( root) ,
1780
1822
state,
1781
1823
& mut recursion_depths,
1782
1824
recursion_limit,
1783
- CollectionMode :: UsedItems ,
1825
+ mode ,
1784
1826
) ;
1785
1827
} ) ;
1786
1828
} ) ;
0 commit comments