@@ -255,7 +255,44 @@ pub(crate) struct UsageMap<'tcx> {
255255 user_map : UnordMap < MonoItem < ' tcx > , Vec < MonoItem < ' tcx > > > ,
256256}
257257
258- type MonoItems < ' tcx > = Vec < Spanned < MonoItem < ' tcx > > > ;
258+ struct MonoItems < ' tcx > {
259+ tcx : TyCtxt < ' tcx > ,
260+ // We want a set of MonoItem + Span where trying to re-insert a MonoItem with a different Span
261+ // is ignored. Map does that, but it looks wrong.
262+ items : UnordMap < MonoItem < ' tcx > , Span > ,
263+ }
264+
265+ impl < ' tcx > MonoItems < ' tcx > {
266+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
267+ Self { tcx, items : UnordMap :: default ( ) }
268+ }
269+
270+ fn is_empty ( & self ) -> bool {
271+ self . items . is_empty ( )
272+ }
273+
274+ fn push ( & mut self , item : Spanned < MonoItem < ' tcx > > ) {
275+ // Insert only if the entry does not exist. A normal insert would stomp the first span that
276+ // got inserted.
277+ self . items . entry ( item. node ) . or_insert ( item. span ) ;
278+ }
279+
280+ fn extend ( & mut self , iter : impl IntoIterator < Item = Spanned < MonoItem < ' tcx > > > ) {
281+ for item in iter {
282+ self . push ( item. clone ( ) ) ;
283+ }
284+ }
285+
286+ fn into_iter ( self ) -> impl Iterator < Item = Spanned < MonoItem < ' tcx > > > {
287+ self . tcx . with_stable_hashing_context ( |hcx| {
288+ self . items . into_sorted ( & hcx, true ) . into_iter ( ) . map ( |( item, span) | respan ( span, item) )
289+ } )
290+ }
291+
292+ fn items ( & self ) -> Vec < MonoItem < ' tcx > > {
293+ self . tcx . with_stable_hashing_context ( |hcx| self . items . keys ( ) . cloned ( ) . into_sorted ( & hcx) )
294+ }
295+ }
259296
260297/// The state that is shared across the concurrent threads that are doing collection.
261298struct SharedState < ' tcx > {
@@ -273,14 +310,11 @@ impl<'tcx> UsageMap<'tcx> {
273310 UsageMap { used_map : Default :: default ( ) , user_map : Default :: default ( ) }
274311 }
275312
276- fn record_used < ' a > (
277- & mut self ,
278- user_item : MonoItem < ' tcx > ,
279- used_items : & ' a [ Spanned < MonoItem < ' tcx > > ] ,
280- ) where
313+ fn record_used < ' a > ( & mut self , user_item : MonoItem < ' tcx > , used_items : & ' a MonoItems < ' tcx > )
314+ where
281315 ' tcx : ' a ,
282316 {
283- let used_items: Vec < _ > = used_items. iter ( ) . map ( |item| item . node ) . collect ( ) ;
317+ let used_items = used_items. items ( ) ;
284318 for & used_item in used_items. iter ( ) {
285319 self . user_map . entry ( used_item) . or_default ( ) . push ( user_item) ;
286320 }
@@ -343,8 +377,8 @@ fn collect_items_rec<'tcx>(
343377 // harm in that, the mention visit will trigger all the queries and the results are cached.
344378 }
345379
346- let mut used_items = MonoItems :: new ( ) ;
347- let mut mentioned_items = MonoItems :: new ( ) ;
380+ let mut used_items = MonoItems :: new ( tcx ) ;
381+ let mut mentioned_items = MonoItems :: new ( tcx ) ;
348382 let recursion_depth_reset;
349383
350384 // Post-monomorphization errors MVP
@@ -430,8 +464,8 @@ fn collect_items_rec<'tcx>(
430464
431465 rustc_data_structures:: stack:: ensure_sufficient_stack ( || {
432466 let ( used, mentioned) = tcx. items_of_instance ( ( instance, mode) ) ;
433- used_items. extend ( used) ;
434- mentioned_items. extend ( mentioned) ;
467+ used_items. extend ( used. into_iter ( ) . copied ( ) ) ;
468+ mentioned_items. extend ( mentioned. into_iter ( ) . copied ( ) ) ;
435469 } ) ;
436470 }
437471 MonoItem :: GlobalAsm ( item_id) => {
@@ -503,7 +537,7 @@ fn collect_items_rec<'tcx>(
503537 if mode == CollectionMode :: MentionedItems {
504538 assert ! ( used_items. is_empty( ) , "'mentioned' collection should never encounter used items" ) ;
505539 } else {
506- for used_item in used_items {
540+ for used_item in used_items. into_iter ( ) {
507541 collect_items_rec (
508542 tcx,
509543 used_item,
@@ -517,7 +551,7 @@ fn collect_items_rec<'tcx>(
517551
518552 // Walk over mentioned items *after* used items, so that if an item is both mentioned and used then
519553 // the loop above has fully collected it, so this loop will skip it.
520- for mentioned_item in mentioned_items {
554+ for mentioned_item in mentioned_items. into_iter ( ) {
521555 collect_items_rec (
522556 tcx,
523557 mentioned_item,
@@ -1194,8 +1228,8 @@ fn collect_items_of_instance<'tcx>(
11941228 // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
11951229 // added to `used_items` in a hash set, which can efficiently query in the
11961230 // `body.mentioned_items` loop below without even having to monomorphize the item.
1197- let mut used_items = Default :: default ( ) ;
1198- let mut mentioned_items = Default :: default ( ) ;
1231+ let mut used_items = MonoItems :: new ( tcx ) ;
1232+ let mut mentioned_items = MonoItems :: new ( tcx ) ;
11991233 let mut used_mentioned_items = Default :: default ( ) ;
12001234 let mut collector = MirUsedCollector {
12011235 tcx,
@@ -1238,7 +1272,11 @@ fn items_of_instance<'tcx>(
12381272 ( instance, mode) : ( Instance < ' tcx > , CollectionMode ) ,
12391273) -> ( & ' tcx [ Spanned < MonoItem < ' tcx > > ] , & ' tcx [ Spanned < MonoItem < ' tcx > > ] ) {
12401274 let ( used_items, mentioned_items) = collect_items_of_instance ( tcx, instance, mode) ;
1241- ( tcx. arena . alloc_slice ( & used_items) , tcx. arena . alloc_slice ( & mentioned_items) )
1275+
1276+ let used_items = tcx. arena . alloc_from_iter ( used_items. into_iter ( ) ) ;
1277+ let mentioned_items = tcx. arena . alloc_from_iter ( mentioned_items. into_iter ( ) ) ;
1278+
1279+ ( used_items, mentioned_items)
12421280}
12431281
12441282/// `item` must be already monomorphized.
@@ -1319,7 +1357,7 @@ fn collect_const_value<'tcx>(
13191357#[ instrument( skip( tcx, mode) , level = "debug" ) ]
13201358fn collect_roots ( tcx : TyCtxt < ' _ > , mode : MonoItemCollectionStrategy ) -> Vec < MonoItem < ' _ > > {
13211359 debug ! ( "collecting roots" ) ;
1322- let mut roots = Vec :: new ( ) ;
1360+ let mut roots = MonoItems :: new ( tcx ) ;
13231361
13241362 {
13251363 let entry_fn = tcx. entry_fn ( ( ) ) ;
0 commit comments