Skip to content

Commit fd702d2

Browse files
committed
Auto merge of #76886 - Aaron1011:fix/ensure-stack-predicate, r=Mark-Simulacrum
Wrap recursive predicate evaluation with `ensure_sufficient_stack` I haven't been able to come up with a minimized test case for #76770, but this fixes a stack overflow in rustc as well.
2 parents 4e8a8b4 + 6a96aea commit fd702d2

File tree

1 file changed

+133
-119
lines changed
  • compiler/rustc_trait_selection/src/traits/select

1 file changed

+133
-119
lines changed

compiler/rustc_trait_selection/src/traits/select/mod.rs

+133-119
Original file line numberDiff line numberDiff line change
@@ -450,153 +450,167 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
450450
None => self.check_recursion_limit(&obligation, &obligation)?,
451451
}
452452

453-
match obligation.predicate.skip_binders() {
454-
ty::PredicateAtom::Trait(t, _) => {
455-
let t = ty::Binder::bind(t);
456-
debug_assert!(!t.has_escaping_bound_vars());
457-
let obligation = obligation.with(t);
458-
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
459-
}
453+
ensure_sufficient_stack(|| {
454+
match obligation.predicate.skip_binders() {
455+
ty::PredicateAtom::Trait(t, _) => {
456+
let t = ty::Binder::bind(t);
457+
debug_assert!(!t.has_escaping_bound_vars());
458+
let obligation = obligation.with(t);
459+
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
460+
}
461+
462+
ty::PredicateAtom::Subtype(p) => {
463+
let p = ty::Binder::bind(p);
464+
// Does this code ever run?
465+
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
466+
Some(Ok(InferOk { mut obligations, .. })) => {
467+
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
468+
self.evaluate_predicates_recursively(
469+
previous_stack,
470+
obligations.into_iter(),
471+
)
472+
}
473+
Some(Err(_)) => Ok(EvaluatedToErr),
474+
None => Ok(EvaluatedToAmbig),
475+
}
476+
}
460477

461-
ty::PredicateAtom::Subtype(p) => {
462-
let p = ty::Binder::bind(p);
463-
// Does this code ever run?
464-
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
465-
Some(Ok(InferOk { mut obligations, .. })) => {
478+
ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
479+
self.infcx,
480+
obligation.param_env,
481+
obligation.cause.body_id,
482+
arg,
483+
obligation.cause.span,
484+
) {
485+
Some(mut obligations) => {
466486
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
467487
self.evaluate_predicates_recursively(
468488
previous_stack,
469489
obligations.into_iter(),
470490
)
471491
}
472-
Some(Err(_)) => Ok(EvaluatedToErr),
473492
None => Ok(EvaluatedToAmbig),
474-
}
475-
}
493+
},
476494

477-
ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
478-
self.infcx,
479-
obligation.param_env,
480-
obligation.cause.body_id,
481-
arg,
482-
obligation.cause.span,
483-
) {
484-
Some(mut obligations) => {
485-
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
486-
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
495+
ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
496+
// We do not consider region relationships when evaluating trait matches.
497+
Ok(EvaluatedToOkModuloRegions)
487498
}
488-
None => Ok(EvaluatedToAmbig),
489-
},
490-
491-
ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
492-
// We do not consider region relationships when evaluating trait matches.
493-
Ok(EvaluatedToOkModuloRegions)
494-
}
495499

496-
ty::PredicateAtom::ObjectSafe(trait_def_id) => {
497-
if self.tcx().is_object_safe(trait_def_id) {
498-
Ok(EvaluatedToOk)
499-
} else {
500-
Ok(EvaluatedToErr)
500+
ty::PredicateAtom::ObjectSafe(trait_def_id) => {
501+
if self.tcx().is_object_safe(trait_def_id) {
502+
Ok(EvaluatedToOk)
503+
} else {
504+
Ok(EvaluatedToErr)
505+
}
501506
}
502-
}
503507

504-
ty::PredicateAtom::Projection(data) => {
505-
let data = ty::Binder::bind(data);
506-
let project_obligation = obligation.with(data);
507-
match project::poly_project_and_unify_type(self, &project_obligation) {
508-
Ok(Ok(Some(mut subobligations))) => {
509-
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
510-
let result = self.evaluate_predicates_recursively(
511-
previous_stack,
512-
subobligations.into_iter(),
513-
);
514-
if let Some(key) =
515-
ProjectionCacheKey::from_poly_projection_predicate(self, data)
516-
{
517-
self.infcx.inner.borrow_mut().projection_cache().complete(key);
508+
ty::PredicateAtom::Projection(data) => {
509+
let data = ty::Binder::bind(data);
510+
let project_obligation = obligation.with(data);
511+
match project::poly_project_and_unify_type(self, &project_obligation) {
512+
Ok(Ok(Some(mut subobligations))) => {
513+
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
514+
let result = self.evaluate_predicates_recursively(
515+
previous_stack,
516+
subobligations.into_iter(),
517+
);
518+
if let Some(key) =
519+
ProjectionCacheKey::from_poly_projection_predicate(self, data)
520+
{
521+
self.infcx.inner.borrow_mut().projection_cache().complete(key);
522+
}
523+
result
518524
}
519-
result
525+
Ok(Ok(None)) => Ok(EvaluatedToAmbig),
526+
// EvaluatedToRecur might also be acceptable here, but use
527+
// Unknown for now because it means that we won't dismiss a
528+
// selection candidate solely because it has a projection
529+
// cycle. This is closest to the previous behavior of
530+
// immediately erroring.
531+
Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
532+
Err(_) => Ok(EvaluatedToErr),
520533
}
521-
Ok(Ok(None)) => Ok(EvaluatedToAmbig),
522-
// EvaluatedToRecur might also be acceptable here, but use
523-
// Unknown for now because it means that we won't dismiss a
524-
// selection candidate solely because it has a projection
525-
// cycle. This is closest to the previous behavior of
526-
// immediately erroring.
527-
Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
528-
Err(_) => Ok(EvaluatedToErr),
529534
}
530-
}
531535

532-
ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
533-
match self.infcx.closure_kind(closure_substs) {
534-
Some(closure_kind) => {
535-
if closure_kind.extends(kind) {
536-
Ok(EvaluatedToOk)
537-
} else {
538-
Ok(EvaluatedToErr)
536+
ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
537+
match self.infcx.closure_kind(closure_substs) {
538+
Some(closure_kind) => {
539+
if closure_kind.extends(kind) {
540+
Ok(EvaluatedToOk)
541+
} else {
542+
Ok(EvaluatedToErr)
543+
}
539544
}
545+
None => Ok(EvaluatedToAmbig),
540546
}
541-
None => Ok(EvaluatedToAmbig),
542547
}
543-
}
544548

545-
ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
546-
match const_evaluatable::is_const_evaluatable(
547-
self.infcx,
548-
def_id,
549-
substs,
550-
obligation.param_env,
551-
obligation.cause.span,
552-
) {
553-
Ok(()) => Ok(EvaluatedToOk),
554-
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
555-
Err(_) => Ok(EvaluatedToErr),
549+
ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
550+
match const_evaluatable::is_const_evaluatable(
551+
self.infcx,
552+
def_id,
553+
substs,
554+
obligation.param_env,
555+
obligation.cause.span,
556+
) {
557+
Ok(()) => Ok(EvaluatedToOk),
558+
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
559+
Err(_) => Ok(EvaluatedToErr),
560+
}
556561
}
557-
}
558562

559-
ty::PredicateAtom::ConstEquate(c1, c2) => {
560-
debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
561-
562-
let evaluate = |c: &'tcx ty::Const<'tcx>| {
563-
if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
564-
self.infcx
565-
.const_eval_resolve(
566-
obligation.param_env,
567-
def,
568-
substs,
569-
promoted,
570-
Some(obligation.cause.span),
571-
)
572-
.map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
573-
} else {
574-
Ok(c)
575-
}
576-
};
563+
ty::PredicateAtom::ConstEquate(c1, c2) => {
564+
debug!(
565+
"evaluate_predicate_recursively: equating consts c1={:?} c2={:?}",
566+
c1, c2
567+
);
577568

578-
match (evaluate(c1), evaluate(c2)) {
579-
(Ok(c1), Ok(c2)) => {
580-
match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) {
581-
Ok(_) => Ok(EvaluatedToOk),
582-
Err(_) => Ok(EvaluatedToErr),
569+
let evaluate = |c: &'tcx ty::Const<'tcx>| {
570+
if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
571+
self.infcx
572+
.const_eval_resolve(
573+
obligation.param_env,
574+
def,
575+
substs,
576+
promoted,
577+
Some(obligation.cause.span),
578+
)
579+
.map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
580+
} else {
581+
Ok(c)
582+
}
583+
};
584+
585+
match (evaluate(c1), evaluate(c2)) {
586+
(Ok(c1), Ok(c2)) => {
587+
match self
588+
.infcx()
589+
.at(&obligation.cause, obligation.param_env)
590+
.eq(c1, c2)
591+
{
592+
Ok(_) => Ok(EvaluatedToOk),
593+
Err(_) => Ok(EvaluatedToErr),
594+
}
595+
}
596+
(Err(ErrorHandled::Reported(ErrorReported)), _)
597+
| (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
598+
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
599+
span_bug!(
600+
obligation.cause.span(self.tcx()),
601+
"ConstEquate: const_eval_resolve returned an unexpected error"
602+
)
603+
}
604+
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
605+
Ok(EvaluatedToAmbig)
583606
}
584-
}
585-
(Err(ErrorHandled::Reported(ErrorReported)), _)
586-
| (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
587-
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!(
588-
obligation.cause.span(self.tcx()),
589-
"ConstEquate: const_eval_resolve returned an unexpected error"
590-
),
591-
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
592-
Ok(EvaluatedToAmbig)
593607
}
594608
}
609+
ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
610+
bug!("TypeWellFormedFromEnv is only used for chalk")
611+
}
595612
}
596-
ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
597-
bug!("TypeWellFormedFromEnv is only used for chalk")
598-
}
599-
}
613+
})
600614
}
601615

602616
fn evaluate_trait_predicate_recursively<'o>(

0 commit comments

Comments
 (0)