1
+ use crate :: error;
1
2
use 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
+ } ;
5
8
use rustc_errors:: ErrorGuaranteed ;
6
9
use rustc_hir as hir;
7
10
use rustc_hir:: def:: Namespace ;
8
11
use rustc_hir:: def_id:: { CrateNum , DefId } ;
9
12
use rustc_hir:: lang_items:: LangItem ;
10
13
use 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 } ;
14
15
use rustc_middle:: ty:: normalize_erasing_regions:: NormalizationError ;
15
16
use rustc_span:: def_id:: LOCAL_CRATE ;
16
- use rustc_span:: { Span , Symbol } ;
17
+ use rustc_span:: { Span , Symbol , DUMMY_SP } ;
17
18
use tracing:: { debug, instrument} ;
18
19
19
20
use std:: assert_matches:: assert_matches;
20
21
use std:: fmt;
22
+ use std:: path:: PathBuf ;
21
23
22
24
/// An `InstanceKind` along with the args that are needed to substitute the instance.
23
25
///
@@ -385,7 +387,28 @@ impl<'tcx> InstanceKind<'tcx> {
385
387
}
386
388
}
387
389
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 (
389
412
f : & mut fmt:: Formatter < ' _ > ,
390
413
instance : Instance < ' _ > ,
391
414
type_length : Option < rustc_session:: Limit > ,
@@ -485,7 +508,8 @@ impl<'tcx> Instance<'tcx> {
485
508
///
486
509
/// Presuming that coherence and type-check have succeeded, if this method is invoked
487
510
/// 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)`.
489
513
///
490
514
/// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process
491
515
/// couldn't complete due to errors elsewhere - this is distinct
@@ -498,6 +522,16 @@ impl<'tcx> Instance<'tcx> {
498
522
def_id : DefId ,
499
523
args : GenericArgsRef < ' tcx > ,
500
524
) -> 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
+
501
535
// All regions in the result of this query are erased, so it's
502
536
// fine to erase all of the input regions.
503
537
@@ -517,6 +551,36 @@ impl<'tcx> Instance<'tcx> {
517
551
) -> Instance < ' tcx > {
518
552
match ty:: Instance :: resolve ( tcx, param_env, def_id, args) {
519
553
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
+ }
520
584
instance => span_bug ! (
521
585
span. unwrap_or( tcx. def_span( def_id) ) ,
522
586
"failed to resolve instance for {}: {instance:#?}" ,
0 commit comments