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.
This commit is contained in:
bors 2020-09-19 09:21:22 +00:00
commit fd702d2919
1 changed files with 147 additions and 133 deletions

View File

@ -450,6 +450,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
None => self.check_recursion_limit(&obligation, &obligation)?, None => self.check_recursion_limit(&obligation, &obligation)?,
} }
ensure_sufficient_stack(|| {
match obligation.predicate.skip_binders() { match obligation.predicate.skip_binders() {
ty::PredicateAtom::Trait(t, _) => { ty::PredicateAtom::Trait(t, _) => {
let t = ty::Binder::bind(t); let t = ty::Binder::bind(t);
@ -483,7 +484,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) { ) {
Some(mut obligations) => { Some(mut obligations) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
} }
None => Ok(EvaluatedToAmbig), None => Ok(EvaluatedToAmbig),
}, },
@ -557,7 +561,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
ty::PredicateAtom::ConstEquate(c1, c2) => { ty::PredicateAtom::ConstEquate(c1, c2) => {
debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); debug!(
"evaluate_predicate_recursively: equating consts c1={:?} c2={:?}",
c1, c2
);
let evaluate = |c: &'tcx ty::Const<'tcx>| { let evaluate = |c: &'tcx ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
@ -577,17 +584,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (evaluate(c1), evaluate(c2)) { match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => { (Ok(c1), Ok(c2)) => {
match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { match self
.infcx()
.at(&obligation.cause, obligation.param_env)
.eq(c1, c2)
{
Ok(_) => Ok(EvaluatedToOk), Ok(_) => Ok(EvaluatedToOk),
Err(_) => Ok(EvaluatedToErr), Err(_) => Ok(EvaluatedToErr),
} }
} }
(Err(ErrorHandled::Reported(ErrorReported)), _) (Err(ErrorHandled::Reported(ErrorReported)), _)
| (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
span_bug!(
obligation.cause.span(self.tcx()), obligation.cause.span(self.tcx()),
"ConstEquate: const_eval_resolve returned an unexpected error" "ConstEquate: const_eval_resolve returned an unexpected error"
), )
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
Ok(EvaluatedToAmbig) Ok(EvaluatedToAmbig)
} }
@ -597,6 +610,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bug!("TypeWellFormedFromEnv is only used for chalk") bug!("TypeWellFormedFromEnv is only used for chalk")
} }
} }
})
} }
fn evaluate_trait_predicate_recursively<'o>( fn evaluate_trait_predicate_recursively<'o>(