@@ -42,7 +42,7 @@ use rustc_data_structures::bit_set::GrowableBitSet;
42
42
use rustc_data_structures:: sync:: Lock ;
43
43
use rustc_target:: spec:: abi:: Abi ;
44
44
use std:: cmp;
45
- use std:: fmt;
45
+ use std:: fmt:: { self , Display } ;
46
46
use std:: iter;
47
47
use std:: rc:: Rc ;
48
48
use util:: nodemap:: { FxHashMap , FxHashSet } ;
@@ -573,7 +573,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
573
573
574
574
let stack = self . push_stack ( TraitObligationStackList :: empty ( ) , obligation) ;
575
575
576
- let candidate = match self . candidate_from_obligation ( & stack) {
576
+ // 'select' is an entry point into SelectionContext - we never call it recursively
577
+ // from within SelectionContext. Therefore, we start our recursion depth at 0
578
+ let candidate = match self . candidate_from_obligation ( & stack, 0 ) {
577
579
Err ( SelectionError :: Overflow ) => {
578
580
// In standard mode, overflow must have been caught and reported
579
581
// earlier.
@@ -629,7 +631,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
629
631
obligation : & PredicateObligation < ' tcx > ,
630
632
) -> Result < EvaluationResult , OverflowError > {
631
633
self . evaluation_probe ( |this| {
632
- this. evaluate_predicate_recursively ( TraitObligationStackList :: empty ( ) , obligation)
634
+ // Like 'select', 'evaluate_obligation_recursively' is an entry point into
635
+ // SelectionContext, so our recursion depth is 0
636
+ this. evaluate_predicate_recursively ( TraitObligationStackList :: empty ( ) , obligation, 0 )
633
637
} )
634
638
}
635
639
@@ -653,14 +657,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
653
657
& mut self ,
654
658
stack : TraitObligationStackList < ' o , ' tcx > ,
655
659
predicates : I ,
660
+ recursion_depth : usize
656
661
) -> Result < EvaluationResult , OverflowError >
657
662
where
658
663
I : IntoIterator < Item = & ' a PredicateObligation < ' tcx > > ,
659
664
' tcx : ' a ,
660
665
{
661
666
let mut result = EvaluatedToOk ;
662
667
for obligation in predicates {
663
- let eval = self . evaluate_predicate_recursively ( stack, obligation) ?;
668
+ let eval = self . evaluate_predicate_recursively ( stack, obligation, recursion_depth ) ?;
664
669
debug ! (
665
670
"evaluate_predicate_recursively({:?}) = {:?}" ,
666
671
obligation, eval
@@ -680,14 +685,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
680
685
& mut self ,
681
686
previous_stack : TraitObligationStackList < ' o , ' tcx > ,
682
687
obligation : & PredicateObligation < ' tcx > ,
688
+ mut recursion_depth : usize
683
689
) -> Result < EvaluationResult , OverflowError > {
684
- debug ! ( "evaluate_predicate_recursively({:?})" , obligation) ;
690
+ debug ! ( "evaluate_predicate_recursively({:?}, recursion_depth={:?})" , obligation,
691
+ recursion_depth) ;
692
+
693
+ // We need to check for overflow here, since the normal
694
+ // recursion check uses the obligation from the stack.
695
+ // This is insufficient for two reasions:
696
+ // 1. That recursion depth is only incremented when a candidate is confirmed
697
+ // Since evaluation skips candidate confirmation, this will never happen
698
+ // 2. It relies on the trait obligation stack. However, it's possible for overflow
699
+ // to happen without involving the trait obligation stack. For example,
700
+ // we might end up trying to infinitely recurse with a projection predicate,
701
+ // which will never push anything onto the stack.
702
+ self . check_recursion_limit ( recursion_depth, obligation) ?;
703
+
704
+ // Now that we know that the recursion check has passed, increment our depth
705
+ recursion_depth += 1 ;
685
706
686
707
match obligation. predicate {
687
708
ty:: Predicate :: Trait ( ref t) => {
688
709
debug_assert ! ( !t. has_escaping_bound_vars( ) ) ;
689
710
let obligation = obligation. with ( t. clone ( ) ) ;
690
- self . evaluate_trait_predicate_recursively ( previous_stack, obligation)
711
+ self . evaluate_trait_predicate_recursively ( previous_stack, obligation, recursion_depth )
691
712
}
692
713
693
714
ty:: Predicate :: Subtype ( ref p) => {
@@ -696,7 +717,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
696
717
. subtype_predicate ( & obligation. cause , obligation. param_env , p)
697
718
{
698
719
Some ( Ok ( InferOk { obligations, .. } ) ) => {
699
- self . evaluate_predicates_recursively ( previous_stack, & obligations)
720
+ self . evaluate_predicates_recursively ( previous_stack, & obligations, recursion_depth )
700
721
}
701
722
Some ( Err ( _) ) => Ok ( EvaluatedToErr ) ,
702
723
None => Ok ( EvaluatedToAmbig ) ,
@@ -711,7 +732,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
711
732
obligation. cause . span ,
712
733
) {
713
734
Some ( obligations) => {
714
- self . evaluate_predicates_recursively ( previous_stack, obligations. iter ( ) )
735
+ self . evaluate_predicates_recursively ( previous_stack, obligations. iter ( ) , recursion_depth )
715
736
}
716
737
None => Ok ( EvaluatedToAmbig ) ,
717
738
} ,
@@ -737,6 +758,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
737
758
let result = self . evaluate_predicates_recursively (
738
759
previous_stack,
739
760
subobligations. iter ( ) ,
761
+ recursion_depth
740
762
) ;
741
763
if let Some ( key) =
742
764
ProjectionCacheKey :: from_poly_projection_predicate ( self , data)
@@ -795,6 +817,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
795
817
& mut self ,
796
818
previous_stack : TraitObligationStackList < ' o , ' tcx > ,
797
819
mut obligation : TraitObligation < ' tcx > ,
820
+ recursion_depth : usize
798
821
) -> Result < EvaluationResult , OverflowError > {
799
822
debug ! ( "evaluate_trait_predicate_recursively({:?})" , obligation) ;
800
823
@@ -822,7 +845,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
822
845
return Ok ( result) ;
823
846
}
824
847
825
- let ( result, dep_node) = self . in_task ( |this| this. evaluate_stack ( & stack) ) ;
848
+ let ( result, dep_node) = self . in_task ( |this| this. evaluate_stack ( & stack, recursion_depth ) ) ;
826
849
let result = result?;
827
850
828
851
debug ! ( "CACHE MISS: EVAL({:?})={:?}" , fresh_trait_ref, result) ;
@@ -834,6 +857,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
834
857
fn evaluate_stack < ' o > (
835
858
& mut self ,
836
859
stack : & TraitObligationStack < ' o , ' tcx > ,
860
+ recursion_depth : usize
837
861
) -> Result < EvaluationResult , OverflowError > {
838
862
// In intercrate mode, whenever any of the types are unbound,
839
863
// there can always be an impl. Even if there are no impls in
@@ -874,7 +898,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
874
898
// Heuristics: show the diagnostics when there are no candidates in crate.
875
899
if self . intercrate_ambiguity_causes . is_some ( ) {
876
900
debug ! ( "evaluate_stack: intercrate_ambiguity_causes is some" ) ;
877
- if let Ok ( candidate_set) = self . assemble_candidates ( stack) {
901
+ if let Ok ( candidate_set) = self . assemble_candidates ( stack, recursion_depth ) {
878
902
if !candidate_set. ambiguous && candidate_set. vec . is_empty ( ) {
879
903
let trait_ref = stack. obligation . predicate . skip_binder ( ) . trait_ref ;
880
904
let self_ty = trait_ref. self_ty ( ) ;
@@ -955,8 +979,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
955
979
}
956
980
}
957
981
958
- match self . candidate_from_obligation ( stack) {
959
- Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c) ,
982
+ match self . candidate_from_obligation ( stack, recursion_depth ) {
983
+ Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c, recursion_depth ) ,
960
984
Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
961
985
Err ( Overflow ) => Err ( OverflowError ) ,
962
986
Err ( ..) => Ok ( EvaluatedToErr ) ,
@@ -995,6 +1019,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
995
1019
& mut self ,
996
1020
stack : & TraitObligationStack < ' o , ' tcx > ,
997
1021
candidate : & SelectionCandidate < ' tcx > ,
1022
+ recursion_depth : usize
998
1023
) -> Result < EvaluationResult , OverflowError > {
999
1024
debug ! (
1000
1025
"evaluate_candidate: depth={} candidate={:?}" ,
@@ -1006,6 +1031,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1006
1031
Ok ( selection) => this. evaluate_predicates_recursively (
1007
1032
stack. list ( ) ,
1008
1033
selection. nested_obligations ( ) . iter ( ) ,
1034
+ recursion_depth
1009
1035
) ,
1010
1036
Err ( ..) => Ok ( EvaluatedToErr ) ,
1011
1037
}
@@ -1080,6 +1106,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1080
1106
. insert ( trait_ref, WithDepNode :: new ( dep_node, result) ) ;
1081
1107
}
1082
1108
1109
+ // The weird return type of this function allows it to be used with the 'try' (?)
1110
+ // operator within certain functions
1111
+ fn check_recursion_limit < T : Display + TypeFoldable < ' tcx > > ( & self , recursion_depth : usize , obligation : & Obligation < ' tcx , T > ,
1112
+ ) -> Result < ( ) , OverflowError > {
1113
+ let recursion_limit = * self . infcx . tcx . sess . recursion_limit . get ( ) ;
1114
+ if recursion_depth >= recursion_limit {
1115
+ match self . query_mode {
1116
+ TraitQueryMode :: Standard => {
1117
+ self . infcx ( ) . report_overflow_error ( obligation, true ) ;
1118
+ }
1119
+ TraitQueryMode :: Canonical => {
1120
+ return Err ( OverflowError ) ;
1121
+ }
1122
+ }
1123
+ }
1124
+ Ok ( ( ) )
1125
+ }
1126
+
1083
1127
///////////////////////////////////////////////////////////////////////////
1084
1128
// CANDIDATE ASSEMBLY
1085
1129
//
@@ -1093,20 +1137,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1093
1137
fn candidate_from_obligation < ' o > (
1094
1138
& mut self ,
1095
1139
stack : & TraitObligationStack < ' o , ' tcx > ,
1140
+ recursion_depth : usize
1096
1141
) -> SelectionResult < ' tcx , SelectionCandidate < ' tcx > > {
1097
1142
// Watch out for overflow. This intentionally bypasses (and does
1098
1143
// not update) the cache.
1099
- let recursion_limit = * self . infcx . tcx . sess . recursion_limit . get ( ) ;
1100
- if stack. obligation . recursion_depth >= recursion_limit {
1101
- match self . query_mode {
1102
- TraitQueryMode :: Standard => {
1103
- self . infcx ( ) . report_overflow_error ( & stack. obligation , true ) ;
1104
- }
1105
- TraitQueryMode :: Canonical => {
1106
- return Err ( Overflow ) ;
1107
- }
1108
- }
1109
- }
1144
+ self . check_recursion_limit ( stack. obligation . recursion_depth , & stack. obligation ) ?;
1110
1145
1111
1146
// Check the cache. Note that we freshen the trait-ref
1112
1147
// separately rather than using `stack.fresh_trait_ref` --
@@ -1128,7 +1163,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1128
1163
1129
1164
// If no match, compute result and insert into cache.
1130
1165
let ( candidate, dep_node) =
1131
- self . in_task ( |this| this. candidate_from_obligation_no_cache ( stack) ) ;
1166
+ self . in_task ( |this| this. candidate_from_obligation_no_cache ( stack, recursion_depth ) ) ;
1132
1167
1133
1168
debug ! (
1134
1169
"CACHE MISS: SELECT({:?})={:?}" ,
@@ -1172,6 +1207,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1172
1207
fn candidate_from_obligation_no_cache < ' o > (
1173
1208
& mut self ,
1174
1209
stack : & TraitObligationStack < ' o , ' tcx > ,
1210
+ recursion_depth : usize
1175
1211
) -> SelectionResult < ' tcx , SelectionCandidate < ' tcx > > {
1176
1212
if stack. obligation . predicate . references_error ( ) {
1177
1213
// If we encounter a `Error`, we generally prefer the
@@ -1189,13 +1225,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1189
1225
if self . intercrate_ambiguity_causes . is_some ( ) {
1190
1226
debug ! ( "evaluate_stack: intercrate_ambiguity_causes is some" ) ;
1191
1227
// Heuristics: show the diagnostics when there are no candidates in crate.
1192
- if let Ok ( candidate_set) = self . assemble_candidates ( stack) {
1228
+ if let Ok ( candidate_set) = self . assemble_candidates ( stack, recursion_depth ) {
1193
1229
let mut no_candidates_apply = true ;
1194
1230
{
1195
1231
let evaluated_candidates = candidate_set
1196
1232
. vec
1197
1233
. iter ( )
1198
- . map ( |c| self . evaluate_candidate ( stack, & c) ) ;
1234
+ . map ( |c| self . evaluate_candidate ( stack, & c, recursion_depth ) ) ;
1199
1235
1200
1236
for ec in evaluated_candidates {
1201
1237
match ec {
@@ -1241,7 +1277,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1241
1277
return Ok ( None ) ;
1242
1278
}
1243
1279
1244
- let candidate_set = self . assemble_candidates ( stack) ?;
1280
+ let candidate_set = self . assemble_candidates ( stack, recursion_depth ) ?;
1245
1281
1246
1282
if candidate_set. ambiguous {
1247
1283
debug ! ( "candidate set contains ambig" ) ;
@@ -1288,7 +1324,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1288
1324
// is needed for specialization. Propagate overflow if it occurs.
1289
1325
let mut candidates = candidates
1290
1326
. into_iter ( )
1291
- . map ( |c| match self . evaluate_candidate ( stack, & c) {
1327
+ . map ( |c| match self . evaluate_candidate ( stack, & c, recursion_depth ) {
1292
1328
Ok ( eval) if eval. may_apply ( ) => Ok ( Some ( EvaluatedCandidate {
1293
1329
candidate : c,
1294
1330
evaluation : eval,
@@ -1519,6 +1555,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1519
1555
fn assemble_candidates < ' o > (
1520
1556
& mut self ,
1521
1557
stack : & TraitObligationStack < ' o , ' tcx > ,
1558
+ recursion_depth : usize
1522
1559
) -> Result < SelectionCandidateSet < ' tcx > , SelectionError < ' tcx > > {
1523
1560
let TraitObligationStack { obligation, .. } = * stack;
1524
1561
let ref obligation = Obligation {
@@ -1594,7 +1631,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1594
1631
}
1595
1632
1596
1633
self . assemble_candidates_from_projected_tys ( obligation, & mut candidates) ;
1597
- self . assemble_candidates_from_caller_bounds ( stack, & mut candidates) ?;
1634
+ self . assemble_candidates_from_caller_bounds ( stack, & mut candidates, recursion_depth ) ?;
1598
1635
// Auto implementations have lower priority, so we only
1599
1636
// consider triggering a default if there is no other impl that can apply.
1600
1637
if candidates. vec . is_empty ( ) {
@@ -1727,6 +1764,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1727
1764
& mut self ,
1728
1765
stack : & TraitObligationStack < ' o , ' tcx > ,
1729
1766
candidates : & mut SelectionCandidateSet < ' tcx > ,
1767
+ recursion_depth : usize
1730
1768
) -> Result < ( ) , SelectionError < ' tcx > > {
1731
1769
debug ! (
1732
1770
"assemble_candidates_from_caller_bounds({:?})" ,
@@ -1748,7 +1786,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1748
1786
// keep only those bounds which may apply, and propagate overflow if it occurs
1749
1787
let mut param_candidates = vec ! [ ] ;
1750
1788
for bound in matching_bounds {
1751
- let wc = self . evaluate_where_clause ( stack, bound. clone ( ) ) ?;
1789
+ let wc = self . evaluate_where_clause ( stack, bound. clone ( ) , recursion_depth ) ?;
1752
1790
if wc. may_apply ( ) {
1753
1791
param_candidates. push ( ParamCandidate ( bound) ) ;
1754
1792
}
@@ -1763,11 +1801,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1763
1801
& mut self ,
1764
1802
stack : & TraitObligationStack < ' o , ' tcx > ,
1765
1803
where_clause_trait_ref : ty:: PolyTraitRef < ' tcx > ,
1804
+ recursion_depth : usize
1766
1805
) -> Result < EvaluationResult , OverflowError > {
1767
1806
self . evaluation_probe ( |this| {
1768
1807
match this. match_where_clause_trait_ref ( stack. obligation , where_clause_trait_ref) {
1769
1808
Ok ( obligations) => {
1770
- this. evaluate_predicates_recursively ( stack. list ( ) , obligations. iter ( ) )
1809
+ this. evaluate_predicates_recursively ( stack. list ( ) , obligations. iter ( ) , recursion_depth )
1771
1810
}
1772
1811
Err ( ( ) ) => Ok ( EvaluatedToErr ) ,
1773
1812
}
0 commit comments