208208mod autodiff;
209209
210210use std:: cell:: OnceCell ;
211+ use std:: ops:: ControlFlow ;
211212
212213use rustc_data_structures:: fx:: FxIndexMap ;
213214use rustc_data_structures:: sync:: { MTLock , par_for_each_in} ;
@@ -220,15 +221,17 @@ use rustc_hir::lang_items::LangItem;
220221use rustc_hir:: limit:: Limit ;
221222use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
222223use rustc_middle:: mir:: interpret:: { AllocId , ErrorHandled , GlobalAlloc , Scalar } ;
223- use rustc_middle:: mir:: mono:: { CollectionMode , InstantiationMode , MonoItem } ;
224+ use rustc_middle:: mir:: mono:: {
225+ CollectionMode , InstantiationMode , MonoItem , NormalizationErrorInMono ,
226+ } ;
224227use rustc_middle:: mir:: visit:: Visitor as MirVisitor ;
225- use rustc_middle:: mir:: { self , Location , MentionedItem , traversal} ;
228+ use rustc_middle:: mir:: { self , Body , Location , MentionedItem , traversal} ;
226229use rustc_middle:: query:: TyCtxtAt ;
227230use rustc_middle:: ty:: adjustment:: { CustomCoerceUnsized , PointerCoercion } ;
228231use rustc_middle:: ty:: layout:: ValidityRequirement ;
229232use rustc_middle:: ty:: {
230233 self , GenericArgs , GenericParamDefKind , Instance , InstanceKind , Ty , TyCtxt , TypeFoldable ,
231- TypeVisitableExt , VtblEntry ,
234+ TypeVisitable , TypeVisitableExt , TypeVisitor , VtblEntry ,
232235} ;
233236use rustc_middle:: util:: Providers ;
234237use rustc_middle:: { bug, span_bug} ;
@@ -474,7 +477,22 @@ fn collect_items_rec<'tcx>(
474477 ) ) ;
475478
476479 rustc_data_structures:: stack:: ensure_sufficient_stack ( || {
477- let ( used, mentioned) = tcx. items_of_instance ( ( instance, mode) ) ;
480+ let Ok ( ( used, mentioned) ) = tcx. items_of_instance ( ( instance, mode) ) else {
481+ // Normalization errors here are usually due to trait solving overflow.
482+ // FIXME: I assume that there are few type errors at post-analysis stage, but not
483+ // entirely sure.
484+ // We have to emit the error outside of `items_of_instance` to access the
485+ // span of the `starting_item`.
486+ let def_id = instance. def_id ( ) ;
487+ let def_span = tcx. def_span ( def_id) ;
488+ let def_path_str = tcx. def_path_str ( def_id) ;
489+ tcx. dcx ( ) . emit_fatal ( RecursionLimit {
490+ span : starting_item. span ,
491+ instance,
492+ def_span,
493+ def_path_str,
494+ } ) ;
495+ } ;
478496 used_items. extend ( used. into_iter ( ) . copied ( ) ) ;
479497 mentioned_items. extend ( mentioned. into_iter ( ) . copied ( ) ) ;
480498 } ) ;
@@ -603,6 +621,35 @@ fn collect_items_rec<'tcx>(
603621 }
604622}
605623
624+ // Check whether we can normalize every type in the instantiated MIR body.
625+ fn check_normalization_error < ' tcx > (
626+ tcx : TyCtxt < ' tcx > ,
627+ instance : Instance < ' tcx > ,
628+ body : & Body < ' tcx > ,
629+ ) -> Result < ( ) , NormalizationErrorInMono > {
630+ struct NormalizationChecker < ' tcx > {
631+ tcx : TyCtxt < ' tcx > ,
632+ instance : Instance < ' tcx > ,
633+ }
634+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for NormalizationChecker < ' tcx > {
635+ type Result = ControlFlow < ( ) > ;
636+
637+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
638+ match self . instance . try_instantiate_mir_and_normalize_erasing_regions (
639+ self . tcx ,
640+ ty:: TypingEnv :: fully_monomorphized ( ) ,
641+ ty:: EarlyBinder :: bind ( t) ,
642+ ) {
643+ Ok ( _) => ControlFlow :: Continue ( ( ) ) ,
644+ Err ( _) => ControlFlow :: Break ( ( ) ) ,
645+ }
646+ }
647+ }
648+
649+ let mut checker = NormalizationChecker { tcx, instance } ;
650+ if body. visit_with ( & mut checker) . is_break ( ) { Err ( NormalizationErrorInMono ) } else { Ok ( ( ) ) }
651+ }
652+
606653fn check_recursion_limit < ' tcx > (
607654 tcx : TyCtxt < ' tcx > ,
608655 instance : Instance < ' tcx > ,
@@ -1259,11 +1306,15 @@ fn collect_items_of_instance<'tcx>(
12591306 tcx : TyCtxt < ' tcx > ,
12601307 instance : Instance < ' tcx > ,
12611308 mode : CollectionMode ,
1262- ) -> ( MonoItems < ' tcx > , MonoItems < ' tcx > ) {
1309+ ) -> Result < ( MonoItems < ' tcx > , MonoItems < ' tcx > ) , NormalizationErrorInMono > {
12631310 // This item is getting monomorphized, do mono-time checks.
1311+ let body = tcx. instance_mir ( instance. def ) ;
1312+ // Plenty of code paths later assume that everything can be normalized. So we have to check
1313+ // normalization first.
1314+ // We choose to emit the error outside to provide helpful diagnostics.
1315+ check_normalization_error ( tcx, instance, body) ?;
12641316 tcx. ensure_ok ( ) . check_mono_item ( instance) ;
12651317
1266- let body = tcx. instance_mir ( instance. def ) ;
12671318 // Naively, in "used" collection mode, all functions get added to *both* `used_items` and
12681319 // `mentioned_items`. Mentioned items processing will then notice that they have already been
12691320 // visited, but at that point each mentioned item has been monomorphized, added to the
@@ -1313,19 +1364,22 @@ fn collect_items_of_instance<'tcx>(
13131364 }
13141365 }
13151366
1316- ( used_items, mentioned_items)
1367+ Ok ( ( used_items, mentioned_items) )
13171368}
13181369
13191370fn items_of_instance < ' tcx > (
13201371 tcx : TyCtxt < ' tcx > ,
13211372 ( instance, mode) : ( Instance < ' tcx > , CollectionMode ) ,
1322- ) -> ( & ' tcx [ Spanned < MonoItem < ' tcx > > ] , & ' tcx [ Spanned < MonoItem < ' tcx > > ] ) {
1323- let ( used_items, mentioned_items) = collect_items_of_instance ( tcx, instance, mode) ;
1373+ ) -> Result <
1374+ ( & ' tcx [ Spanned < MonoItem < ' tcx > > ] , & ' tcx [ Spanned < MonoItem < ' tcx > > ] ) ,
1375+ NormalizationErrorInMono ,
1376+ > {
1377+ let ( used_items, mentioned_items) = collect_items_of_instance ( tcx, instance, mode) ?;
13241378
13251379 let used_items = tcx. arena . alloc_from_iter ( used_items) ;
13261380 let mentioned_items = tcx. arena . alloc_from_iter ( mentioned_items) ;
13271381
1328- ( used_items, mentioned_items)
1382+ Ok ( ( used_items, mentioned_items) )
13291383}
13301384
13311385/// `item` must be already monomorphized.
0 commit comments