1+ use crate :: error;
12use crate :: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
2- use crate :: ty:: print:: { FmtPrinter , Printer } ;
3- use crate :: ty:: { self , Ty , TyCtxt , TypeFoldable , TypeSuperFoldable } ;
4- use crate :: ty:: { EarlyBinder , GenericArgs , GenericArgsRef , TypeVisitableExt } ;
3+ use crate :: ty:: print:: { shrunk_instance_name, FmtPrinter , Printer } ;
4+ use crate :: ty:: {
5+ self , EarlyBinder , GenericArgs , GenericArgsRef , Ty , TyCtxt , TypeFoldable , TypeSuperFoldable ,
6+ TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
7+ } ;
58use rustc_errors:: ErrorGuaranteed ;
69use rustc_hir as hir;
710use rustc_hir:: def:: Namespace ;
811use rustc_hir:: def_id:: { CrateNum , DefId } ;
912use rustc_hir:: lang_items:: LangItem ;
1013use rustc_index:: bit_set:: FiniteBitSet ;
11- use rustc_macros:: {
12- Decodable , Encodable , HashStable , Lift , TyDecodable , TyEncodable , TypeVisitable ,
13- } ;
14+ use rustc_macros:: { Decodable , Encodable , HashStable , Lift , TyDecodable , TyEncodable } ;
1415use rustc_middle:: ty:: normalize_erasing_regions:: NormalizationError ;
1516use rustc_span:: def_id:: LOCAL_CRATE ;
16- use rustc_span:: { Span , Symbol } ;
17+ use rustc_span:: { Span , Symbol , DUMMY_SP } ;
1718use tracing:: { debug, instrument} ;
1819
1920use std:: assert_matches:: assert_matches;
2021use std:: fmt;
22+ use std:: path:: PathBuf ;
2123
2224/// An `InstanceKind` along with the args that are needed to substitute the instance.
2325///
@@ -385,7 +387,28 @@ impl<'tcx> InstanceKind<'tcx> {
385387 }
386388}
387389
388- fn fmt_instance (
390+ fn type_length < ' tcx > ( item : impl TypeVisitable < TyCtxt < ' tcx > > ) -> usize {
391+ struct Visitor {
392+ type_length : usize ,
393+ }
394+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for Visitor {
395+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) {
396+ self . type_length += 1 ;
397+ t. super_visit_with ( self ) ;
398+ }
399+
400+ fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) {
401+ self . type_length += 1 ;
402+ ct. super_visit_with ( self ) ;
403+ }
404+ }
405+ let mut visitor = Visitor { type_length : 0 } ;
406+ item. visit_with ( & mut visitor) ;
407+
408+ visitor. type_length
409+ }
410+
411+ pub fn fmt_instance (
389412 f : & mut fmt:: Formatter < ' _ > ,
390413 instance : Instance < ' _ > ,
391414 type_length : Option < rustc_session:: Limit > ,
@@ -485,7 +508,8 @@ impl<'tcx> Instance<'tcx> {
485508 ///
486509 /// Presuming that coherence and type-check have succeeded, if this method is invoked
487510 /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
488- /// `Ok(Some(instance))`.
511+ /// `Ok(Some(instance))`, **except** for when the instance's inputs hit the type size limit,
512+ /// in which case it may bail out and return `Ok(None)`.
489513 ///
490514 /// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
491515 /// couldn't complete due to errors elsewhere - this is distinct
@@ -498,6 +522,16 @@ impl<'tcx> Instance<'tcx> {
498522 def_id : DefId ,
499523 args : GenericArgsRef < ' tcx > ,
500524 ) -> Result < Option < Instance < ' tcx > > , ErrorGuaranteed > {
525+ // Rust code can easily create exponentially-long types using only a
526+ // polynomial recursion depth. Even with the default recursion
527+ // depth, you can easily get cases that take >2^60 steps to run,
528+ // which means that rustc basically hangs.
529+ //
530+ // Bail out in these cases to avoid that bad user experience.
531+ if !tcx. type_length_limit ( ) . value_within_limit ( type_length ( args) ) {
532+ return Ok ( None ) ;
533+ }
534+
501535 // All regions in the result of this query are erased, so it's
502536 // fine to erase all of the input regions.
503537
@@ -517,6 +551,36 @@ impl<'tcx> Instance<'tcx> {
517551 ) -> Instance < ' tcx > {
518552 match ty:: Instance :: resolve ( tcx, param_env, def_id, args) {
519553 Ok ( Some ( instance) ) => instance,
554+ Ok ( None ) => {
555+ let type_length = type_length ( args) ;
556+ if !tcx. type_length_limit ( ) . value_within_limit ( type_length) {
557+ let ( shrunk, written_to_path) =
558+ shrunk_instance_name ( tcx, Instance :: new ( def_id, args) ) ;
559+ let mut path = PathBuf :: new ( ) ;
560+ let was_written = if let Some ( path2) = written_to_path {
561+ path = path2;
562+ Some ( ( ) )
563+ } else {
564+ None
565+ } ;
566+ tcx. dcx ( ) . emit_fatal ( error:: TypeLengthLimit {
567+ // We don't use `def_span(def_id)` so that diagnostics point
568+ // to the crate root during mono instead of to foreign items.
569+ // This is arguably better.
570+ span : span. unwrap_or ( DUMMY_SP ) ,
571+ shrunk,
572+ was_written,
573+ path,
574+ type_length,
575+ } ) ;
576+ } else {
577+ span_bug ! (
578+ span. unwrap_or( tcx. def_span( def_id) ) ,
579+ "failed to resolve instance for {}" ,
580+ tcx. def_path_str_with_args( def_id, args)
581+ )
582+ }
583+ }
520584 instance => span_bug ! (
521585 span. unwrap_or( tcx. def_span( def_id) ) ,
522586 "failed to resolve instance for {}: {instance:#?}" ,
0 commit comments