Skip to content

Commit a371059

Browse files
Don't hang when there's an infinite loop of outlives obligations
1 parent 7d1fda7 commit a371059

File tree

2 files changed

+83
-58
lines changed

2 files changed

+83
-58
lines changed

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

+76-57
Original file line numberDiff line numberDiff line change
@@ -154,74 +154,93 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
154154
} = *self;
155155

156156
let mut outlives_predicates = vec![(predicate, constraint_category)];
157-
while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) =
158-
outlives_predicates.pop()
159-
{
160-
match k1.unpack() {
161-
GenericArgKind::Lifetime(r1) => {
162-
let r1_vid = self.to_region_vid(r1);
163-
let r2_vid = self.to_region_vid(r2);
164-
self.add_outlives(r1_vid, r2_vid, constraint_category);
165-
}
157+
for iteration in 0.. {
158+
if outlives_predicates.is_empty() {
159+
break;
160+
}
166161

167-
GenericArgKind::Type(mut t1) => {
168-
// Normalize the type we receive from a `TypeOutlives` obligation
169-
// in the new trait solver.
170-
if infcx.next_trait_solver() {
171-
let result = CustomTypeOp::new(
172-
|ocx| {
173-
match deeply_normalize(
174-
ocx.infcx.at(
175-
&ObligationCause::dummy_with_span(self.span),
176-
param_env,
177-
),
178-
t1,
179-
) {
180-
Ok(normalized_ty) => {
181-
t1 = normalized_ty;
182-
}
183-
Err(e) => {
184-
infcx.err_ctxt().report_fulfillment_errors(e);
162+
if !self.tcx.recursion_limit().value_within_limit(iteration) {
163+
bug!(
164+
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
165+
);
166+
}
167+
168+
let mut next_outlives_predicates = vec![];
169+
for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
170+
match k1.unpack() {
171+
GenericArgKind::Lifetime(r1) => {
172+
let r1_vid = self.to_region_vid(r1);
173+
let r2_vid = self.to_region_vid(r2);
174+
self.add_outlives(r1_vid, r2_vid, constraint_category);
175+
}
176+
177+
GenericArgKind::Type(mut t1) => {
178+
// Normalize the type we receive from a `TypeOutlives` obligation
179+
// in the new trait solver.
180+
if infcx.next_trait_solver() {
181+
let result = CustomTypeOp::new(
182+
|ocx| {
183+
match deeply_normalize(
184+
ocx.infcx.at(
185+
&ObligationCause::dummy_with_span(self.span),
186+
param_env,
187+
),
188+
t1,
189+
) {
190+
Ok(normalized_ty) => {
191+
t1 = normalized_ty;
192+
}
193+
Err(e) => {
194+
infcx.err_ctxt().report_fulfillment_errors(e);
195+
}
185196
}
186-
}
187197

188-
Ok(())
189-
},
190-
"normalize type outlives obligation",
191-
)
192-
.fully_perform(infcx, self.span);
198+
Ok(())
199+
},
200+
"normalize type outlives obligation",
201+
)
202+
.fully_perform(infcx, self.span);
193203

194-
match result {
195-
Ok(TypeOpOutput { output: (), constraints, .. }) => {
196-
if let Some(constraints) = constraints {
197-
assert!(
198-
constraints.member_constraints.is_empty(),
199-
"FIXME(-Znext-solver): How do I handle these?"
200-
);
201-
outlives_predicates
202-
.extend(constraints.outlives.iter().copied());
204+
match result {
205+
Ok(TypeOpOutput { output: (), constraints, .. }) => {
206+
if let Some(constraints) = constraints {
207+
assert!(
208+
constraints.member_constraints.is_empty(),
209+
"no member constraints expected from normalizing: {:#?}",
210+
constraints.member_constraints
211+
);
212+
next_outlives_predicates
213+
.extend(constraints.outlives.iter().copied());
214+
}
203215
}
216+
Err(_) => {}
204217
}
205-
Err(_) => {}
206218
}
207-
}
208219

209-
// we don't actually use this for anything, but
210-
// the `TypeOutlives` code needs an origin.
211-
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
220+
// we don't actually use this for anything, but
221+
// the `TypeOutlives` code needs an origin.
222+
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
212223

213-
TypeOutlives::new(
214-
&mut *self,
215-
tcx,
216-
region_bound_pairs,
217-
Some(implicit_region_bound),
218-
known_type_outlives_obligations,
219-
)
220-
.type_must_outlive(origin, t1, r2, constraint_category);
221-
}
224+
TypeOutlives::new(
225+
&mut *self,
226+
tcx,
227+
region_bound_pairs,
228+
Some(implicit_region_bound),
229+
known_type_outlives_obligations,
230+
)
231+
.type_must_outlive(
232+
origin,
233+
t1,
234+
r2,
235+
constraint_category,
236+
);
237+
}
222238

223-
GenericArgKind::Const(_) => unreachable!(),
239+
GenericArgKind::Const(_) => unreachable!(),
240+
}
224241
}
242+
243+
outlives_predicates = next_outlives_predicates;
225244
}
226245
}
227246

compiler/rustc_infer/src/infer/outlives/obligations.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,18 @@ impl<'tcx> InferCtxt<'tcx> {
154154
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
155155

156156
// Must loop since the process of normalizing may itself register region obligations.
157-
loop {
157+
for iteration in 0.. {
158158
let my_region_obligations = self.take_registered_region_obligations();
159159
if my_region_obligations.is_empty() {
160160
break;
161161
}
162162

163+
if !self.tcx.recursion_limit().value_within_limit(iteration) {
164+
bug!(
165+
"FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
166+
);
167+
}
168+
163169
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
164170
let sup_type = deeply_normalize_ty(sup_type, origin.clone())
165171
.map_err(|e| (e, origin.clone()))?;

0 commit comments

Comments
 (0)