173
173
//! do not use a failing constant. This is reflected via the [`CollectionMode`], which determines
174
174
//! whether we are visiting a used item or merely a mentioned item.
175
175
//!
176
+ //! The collector and "mentioned items" gathering (which lives in `rustc_mir_transform::mentioned_items`)
177
+ //! need to stay in sync in the following sense:
178
+ //!
179
+ //! - For every item that the collector gather that could eventually lead to build failure (most
180
+ //! likely due to containing a constant that fails to evaluate), a corresponding mentioned item
181
+ //! must be added. This should use the exact same strategy as the ecollector to make sure they are
182
+ //! in sync. However, while the collector works on monomorphized types, mentioned items are
183
+ //! collected on generic MIR -- so any time the collector checks for a particular type (such as
184
+ //! `ty::FnDef`), we have to just onconditionally add this as a mentioned item.
185
+ //! - In `visit_mentioned_item`, we then do with that mentioned item exactly what the collector
186
+ //! would have done during regular MIR visiting. Basically you can think of the collector having
187
+ //! two stages, a pre-monomorphization stage and a post-monomorphization stage (usually quite
188
+ //! literally separated by a call to `self.monomorphize`); the pre-monomorphizationn stage is
189
+ //! duplicated in mentioned items gathering and the post-monomorphization stage is duplicated in
190
+ //! `visit_mentioned_item`.
191
+ //! - Finally, as a performance optimization, the collector should fill `used_mentioned_item` during
192
+ //! its MIR traversal with exactly what mentioned item gathering would have added in the same
193
+ //! situation. This detects mentioned items that have *not* been optimized away and hence don't
194
+ //! need a dedicated traversal.
195
+ //!
176
196
//! Open Issues
177
197
//! -----------
178
198
//! Some things are not yet fully implemented in the current version of this
@@ -904,8 +924,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
904
924
target_ty,
905
925
)
906
926
| mir:: Rvalue :: Cast ( mir:: CastKind :: DynStar , ref operand, target_ty) => {
907
- let target_ty = self . monomorphize ( target_ty) ;
908
927
let source_ty = operand. ty ( self . body , self . tcx ) ;
928
+ // *Before* monomorphizing, record that we already handled this mention.
929
+ self . used_mentioned_items
930
+ . insert ( MentionedItem :: UnsizeCast { source_ty, target_ty } ) ;
931
+ let target_ty = self . monomorphize ( target_ty) ;
909
932
let source_ty = self . monomorphize ( source_ty) ;
910
933
let ( source_ty, target_ty) =
911
934
find_vtable_types_for_unsizing ( self . tcx . at ( span) , source_ty, target_ty) ;
@@ -930,6 +953,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
930
953
_,
931
954
) => {
932
955
let fn_ty = operand. ty ( self . body , self . tcx ) ;
956
+ // *Before* monomorphizing, record that we already handled this mention.
957
+ self . used_mentioned_items . insert ( MentionedItem :: Fn ( fn_ty) ) ;
933
958
let fn_ty = self . monomorphize ( fn_ty) ;
934
959
visit_fn_use ( self . tcx , fn_ty, false , span, self . used_items ) ;
935
960
}
@@ -939,20 +964,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
939
964
_,
940
965
) => {
941
966
let source_ty = operand. ty ( self . body , self . tcx ) ;
967
+ // *Before* monomorphizing, record that we already handled this mention.
968
+ self . used_mentioned_items . insert ( MentionedItem :: Closure ( source_ty) ) ;
942
969
let source_ty = self . monomorphize ( source_ty) ;
943
- match * source_ty. kind ( ) {
944
- ty:: Closure ( def_id, args) => {
945
- let instance = Instance :: resolve_closure (
946
- self . tcx ,
947
- def_id,
948
- args,
949
- ty:: ClosureKind :: FnOnce ,
950
- ) ;
951
- if should_codegen_locally ( self . tcx , & instance) {
952
- self . used_items . push ( create_fn_mono_item ( self . tcx , instance, span) ) ;
953
- }
970
+ if let ty:: Closure ( def_id, args) = * source_ty. kind ( ) {
971
+ let instance =
972
+ Instance :: resolve_closure ( self . tcx , def_id, args, ty:: ClosureKind :: FnOnce ) ;
973
+ if should_codegen_locally ( self . tcx , & instance) {
974
+ self . used_items . push ( create_fn_mono_item ( self . tcx , instance, span) ) ;
954
975
}
955
- _ => bug ! ( ) ,
976
+ } else {
977
+ bug ! ( )
956
978
}
957
979
}
958
980
mir:: Rvalue :: ThreadLocalRef ( def_id) => {
@@ -994,9 +1016,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
994
1016
mir:: TerminatorKind :: Call { ref func, ref args, ref fn_span, .. } => {
995
1017
let callee_ty = func. ty ( self . body , tcx) ;
996
1018
// *Before* monomorphizing, record that we already handled this mention.
997
- if let ty:: FnDef ( def_id, args) = callee_ty. kind ( ) {
998
- self . used_mentioned_items . insert ( MentionedItem :: Fn ( * def_id, args) ) ;
999
- }
1019
+ self . used_mentioned_items . insert ( MentionedItem :: Fn ( callee_ty) ) ;
1000
1020
let callee_ty = self . monomorphize ( callee_ty) ;
1001
1021
self . check_fn_args_move_size ( callee_ty, args, * fn_span, location) ;
1002
1022
visit_fn_use ( self . tcx , callee_ty, true , source, & mut self . used_items )
@@ -1012,7 +1032,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
1012
1032
for op in operands {
1013
1033
match * op {
1014
1034
mir:: InlineAsmOperand :: SymFn { ref value } => {
1015
- let fn_ty = self . monomorphize ( value. const_ . ty ( ) ) ;
1035
+ let fn_ty = value. const_ . ty ( ) ;
1036
+ // *Before* monomorphizing, record that we already handled this mention.
1037
+ self . used_mentioned_items . insert ( MentionedItem :: Fn ( fn_ty) ) ;
1038
+ let fn_ty = self . monomorphize ( fn_ty) ;
1016
1039
visit_fn_use ( self . tcx , fn_ty, false , source, self . used_items ) ;
1017
1040
}
1018
1041
mir:: InlineAsmOperand :: SymStatic { def_id } => {
@@ -1076,6 +1099,8 @@ fn visit_drop_use<'tcx>(
1076
1099
visit_instance_use ( tcx, instance, is_direct_call, source, output) ;
1077
1100
}
1078
1101
1102
+ /// For every call of this function in the visitor, make sure there is a matching call in the
1103
+ /// `mentioned_items` pass!
1079
1104
fn visit_fn_use < ' tcx > (
1080
1105
tcx : TyCtxt < ' tcx > ,
1081
1106
ty : Ty < ' tcx > ,
@@ -1653,13 +1678,13 @@ fn collect_items_of_instance<'tcx>(
1653
1678
// Naively, in "used" collection mode, all functions get added to *both* `used_items` and
1654
1679
// `mentioned_items`. Mentioned items processing will then notice that they have already been
1655
1680
// visited, but at that point each mentioned item has been monomorphized, added to the
1656
- // `mentioned_items` worklist, and checked in the global set of visited items. To removes that
1681
+ // `mentioned_items` worklist, and checked in the global set of visited items. To remove that
1657
1682
// overhead, we have a special optimization that avoids adding items to `mentioned_items` when
1658
1683
// they are already added in `used_items`. We could just scan `used_items`, but that's a linear
1659
1684
// scan and not very efficient. Furthermore we can only do that *after* monomorphizing the
1660
1685
// mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
1661
1686
// added to `used_items` in a hash set, which can efficiently query in the
1662
- // `body.mentioned_items` loop below.
1687
+ // `body.mentioned_items` loop below without even having to monomorphize the item .
1663
1688
let mut used_mentioned_items = FxHashSet :: < MentionedItem < ' tcx > > :: default ( ) ;
1664
1689
let mut collector = MirUsedCollector {
1665
1690
tcx,
@@ -1704,13 +1729,16 @@ fn visit_mentioned_item<'tcx>(
1704
1729
output : & mut MonoItems < ' tcx > ,
1705
1730
) {
1706
1731
match * item {
1707
- MentionedItem :: Fn ( def_id, args) => {
1708
- let instance = Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args) ;
1709
- // `visit_instance_use` was written for "used" item collection but works just as well
1710
- // for "mentioned" item collection.
1711
- // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
1712
- // can't have their own failing constants.
1713
- visit_instance_use ( tcx, instance, /*is_direct_call*/ true , span, output) ;
1732
+ MentionedItem :: Fn ( ty) => {
1733
+ if let ty:: FnDef ( def_id, args) = * ty. kind ( ) {
1734
+ let instance =
1735
+ Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args) ;
1736
+ // `visit_instance_use` was written for "used" item collection but works just as well
1737
+ // for "mentioned" item collection.
1738
+ // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
1739
+ // can't have their own failing constants.
1740
+ visit_instance_use ( tcx, instance, /*is_direct_call*/ true , span, output) ;
1741
+ }
1714
1742
}
1715
1743
MentionedItem :: Drop ( ty) => {
1716
1744
visit_drop_use ( tcx, ty, /*is_direct_call*/ true , span, output) ;
@@ -1727,10 +1755,15 @@ fn visit_mentioned_item<'tcx>(
1727
1755
create_mono_items_for_vtable_methods ( tcx, target_ty, source_ty, span, output) ;
1728
1756
}
1729
1757
}
1730
- MentionedItem :: Closure ( def_id, args) => {
1731
- let instance = Instance :: resolve_closure ( tcx, def_id, args, ty:: ClosureKind :: FnOnce ) ;
1732
- if should_codegen_locally ( tcx, & instance) {
1733
- output. push ( create_fn_mono_item ( tcx, instance, span) ) ;
1758
+ MentionedItem :: Closure ( source_ty) => {
1759
+ if let ty:: Closure ( def_id, args) = * source_ty. kind ( ) {
1760
+ let instance =
1761
+ Instance :: resolve_closure ( tcx, def_id, args, ty:: ClosureKind :: FnOnce ) ;
1762
+ if should_codegen_locally ( tcx, & instance) {
1763
+ output. push ( create_fn_mono_item ( tcx, instance, span) ) ;
1764
+ }
1765
+ } else {
1766
+ bug ! ( )
1734
1767
}
1735
1768
}
1736
1769
}
0 commit comments