Prevent stack overflow for deeply recursive code
This commit is contained in:
parent
7184d137f6
commit
26edcee093
14 changed files with 448 additions and 354 deletions
23
Cargo.lock
23
Cargo.lock
|
@ -2630,6 +2630,15 @@ dependencies = [
|
|||
"core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b14fc68b454f875abc8354c2555e1d56596f74833ddc0f77f87f4871ed6a30e0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "1.5.3"
|
||||
|
@ -3152,6 +3161,7 @@ checksum = "81dfcfbb0ddfd533abf8c076e3b49d1e5042d1962526a12ce2c66d514b24cca3"
|
|||
dependencies = [
|
||||
"rustc-ap-rustc_data_structures",
|
||||
"smallvec 1.0.0",
|
||||
"stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4657,6 +4667,19 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "std"
|
||||
version = "0.0.0"
|
||||
|
|
|
@ -7,6 +7,7 @@ use rustc_data_structures::thin_vec::ThinVec;
|
|||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
|
@ -20,6 +21,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
||||
ensure_sufficient_stack(|| {
|
||||
let kind = match e.kind {
|
||||
ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
|
||||
ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
|
@ -72,15 +74,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let ohs = self.lower_expr(ohs);
|
||||
hir::ExprKind::AddrOf(k, m, ohs)
|
||||
}
|
||||
ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee),
|
||||
ExprKind::Let(ref pat, ref scrutinee) => {
|
||||
self.lower_expr_let(e.span, pat, scrutinee)
|
||||
}
|
||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||
self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
|
||||
}
|
||||
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
|
||||
ExprKind::While(ref cond, ref body, opt_label) => self
|
||||
.with_loop_scope(e.id, |this| {
|
||||
this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
|
||||
}),
|
||||
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
|
||||
hir::ExprKind::Loop(this.lower_block(body, false), opt_label, hir::LoopSource::Loop)
|
||||
hir::ExprKind::Loop(
|
||||
this.lower_block(body, false),
|
||||
opt_label,
|
||||
hir::LoopSource::Loop,
|
||||
)
|
||||
}),
|
||||
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
|
||||
ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
|
||||
|
@ -88,7 +97,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
|
||||
hir::MatchSource::Normal,
|
||||
),
|
||||
ExprKind::Async(capture_clause, closure_node_id, ref block) => self.make_async_expr(
|
||||
ExprKind::Async(capture_clause, closure_node_id, ref block) => self
|
||||
.make_async_expr(
|
||||
capture_clause,
|
||||
closure_node_id,
|
||||
None,
|
||||
|
@ -114,7 +124,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn_decl_span,
|
||||
)
|
||||
} else {
|
||||
self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span)
|
||||
self.lower_expr_closure(
|
||||
capture_clause,
|
||||
movability,
|
||||
decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
)
|
||||
}
|
||||
}
|
||||
ExprKind::Block(ref blk, opt_label) => {
|
||||
|
@ -174,6 +190,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
maybe_expr,
|
||||
)
|
||||
}
|
||||
ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => hir::ExprKind::Err,
|
||||
ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
ExprKind::Paren(ref ex) => {
|
||||
let mut ex = self.lower_expr_mut(ex);
|
||||
// Include parens in span, but only if it is a super-span.
|
||||
|
@ -187,17 +206,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
return ex;
|
||||
}
|
||||
|
||||
ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
|
||||
ExprKind::Err => hir::ExprKind::Err,
|
||||
|
||||
// Desugar `ExprForLoop`
|
||||
// from: `[opt_ident]: for <pat> in <head> <body>`
|
||||
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
|
||||
return self.lower_expr_for(e, pat, head, body, opt_label);
|
||||
}
|
||||
ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
ExprKind::MacCall(_) => panic!("Shouldn't exist here"),
|
||||
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
|
||||
};
|
||||
|
||||
hir::Expr {
|
||||
|
@ -206,6 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span: e.span,
|
||||
attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
||||
|
|
|
@ -4,10 +4,12 @@ use rustc_ast::ast::*;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
ensure_sufficient_stack(|| {
|
||||
let node = match p.kind {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, ident, ref sub) => {
|
||||
|
@ -27,9 +29,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
hir::PatKind::TupleStruct(qpath, pats, ddpos)
|
||||
}
|
||||
PatKind::Or(ref pats) => {
|
||||
hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
|
||||
}
|
||||
PatKind::Or(ref pats) => hir::PatKind::Or(
|
||||
self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))),
|
||||
),
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
let qpath = self.lower_qpath(
|
||||
p.id,
|
||||
|
@ -64,21 +66,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||
PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
|
||||
PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
|
||||
PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
|
||||
hir::PatKind::Range(
|
||||
e1.as_deref().map(|e| self.lower_expr(e)),
|
||||
e2.as_deref().map(|e| self.lower_expr(e)),
|
||||
self.lower_range_end(end, e2.is_some()),
|
||||
),
|
||||
)
|
||||
}
|
||||
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
// If we reach here the `..` pattern is not semantically allowed.
|
||||
self.ban_illegal_rest_pat(p.span)
|
||||
}
|
||||
// FIXME: consider not using recursion to lower this.
|
||||
PatKind::Paren(ref inner) => return self.lower_pat(inner),
|
||||
PatKind::MacCall(_) => panic!("Shouldn't exist here"),
|
||||
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", p.span),
|
||||
};
|
||||
|
||||
self.pat_with_node_id_of(p, node)
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_pat_tuple(
|
||||
|
|
|
@ -80,14 +80,7 @@ pub fn create_session(
|
|||
(Lrc::new(sess), Lrc::new(codegen_backend), source_map)
|
||||
}
|
||||
|
||||
// Temporarily have stack size set to 32MB to deal with various crates with long method
|
||||
// chains or deep syntax trees, except when on Haiku.
|
||||
// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line
|
||||
#[cfg(not(target_os = "haiku"))]
|
||||
const STACK_SIZE: usize = 32 * 1024 * 1024;
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
const STACK_SIZE: usize = 16 * 1024 * 1024;
|
||||
const STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
||||
fn get_stack_size() -> Option<usize> {
|
||||
// FIXME: Hacks on hacks. If the env is trying to override the stack size
|
||||
|
|
|
@ -34,3 +34,4 @@ byteorder = { version = "1.3" }
|
|||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
measureme = "0.7.1"
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
stacker = "0.1.6"
|
||||
|
|
|
@ -13,6 +13,24 @@ use rustc_span::symbol::{sym, Symbol};
|
|||
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
// This is the amount of bytes that need to be left on the stack before increasing the size.
|
||||
// It must be at least as large as the stack required by any code that does not call
|
||||
// `ensure_sufficient_stack`.
|
||||
const RED_ZONE: usize = 100 * 1024; // 100k
|
||||
|
||||
// Ony the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
|
||||
// on. This flag has performance relevant characteristics. Don't set it too high.
|
||||
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
|
||||
|
||||
/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
|
||||
/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit
|
||||
/// from this.
|
||||
///
|
||||
/// Should not be sprinkled around carelessly, as it causes a little bit of overhead.
|
||||
pub fn ensure_sufficient_stack<R, F: FnOnce() -> R>(f: F) -> R {
|
||||
stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)
|
||||
}
|
||||
|
||||
pub fn update_limits(sess: &Session, krate: &ast::Crate) {
|
||||
update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128);
|
||||
update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub use self::def_id_forest::DefIdForest;
|
||||
|
||||
use crate::middle::limits::ensure_sufficient_stack;
|
||||
use crate::ty;
|
||||
use crate::ty::context::TyCtxt;
|
||||
use crate::ty::TyKind::*;
|
||||
|
@ -196,7 +197,9 @@ impl<'tcx> TyS<'tcx> {
|
|||
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
|
||||
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
|
||||
match self.kind {
|
||||
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
|
||||
Adt(def, substs) => {
|
||||
ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
|
||||
}
|
||||
|
||||
Never => DefIdForest::full(tcx),
|
||||
|
||||
|
|
|
@ -68,7 +68,9 @@ impl QueryContext for TyCtxt<'tcx> {
|
|||
};
|
||||
|
||||
// Use the `ImplicitCtxt` while we execute the query.
|
||||
tls::enter_context(&new_icx, |_| compute(*self))
|
||||
tls::enter_context(&new_icx, |_| {
|
||||
crate::middle::limits::ensure_sufficient_stack(|| compute(*self))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -369,7 +369,9 @@ fn collect_items_rec<'tcx>(
|
|||
recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths));
|
||||
check_type_length_limit(tcx, instance);
|
||||
|
||||
rustc::middle::limits::ensure_sufficient_stack(|| {
|
||||
collect_neighbours(tcx, instance, &mut neighbors);
|
||||
});
|
||||
}
|
||||
MonoItem::GlobalAsm(..) => {
|
||||
recursion_depth_reset = None;
|
||||
|
@ -1146,7 +1148,9 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
|
|||
Some(GlobalAlloc::Memory(alloc)) => {
|
||||
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
|
||||
for &((), inner) in alloc.relocations().values() {
|
||||
rustc_middle::limits::ensure_sufficient_stack(|| {
|
||||
collect_miri(tcx, inner, output);
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(GlobalAlloc::Function(fn_instance)) => {
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::build::scope::DropKind;
|
|||
use crate::build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use crate::hair::*;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
|
||||
|
@ -21,7 +22,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
M: Mirror<'tcx, Output = Expr<'tcx>>,
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_temp(block, temp_lifetime, expr, mutability)
|
||||
//
|
||||
// this is the only place in mir building that we need to truly need to worry about
|
||||
// infinite recursion. Everything else does recurse, too, but it always gets broken up
|
||||
// at some point by inserting an intermediate temporary
|
||||
ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability))
|
||||
}
|
||||
|
||||
fn expr_as_temp(
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::traits::error_reporting::InferCtxtExt;
|
|||
use rustc_ast::ast::Ident;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
|
@ -261,7 +262,7 @@ where
|
|||
{
|
||||
debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
|
||||
let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
|
||||
let result = normalizer.fold(value);
|
||||
let result = ensure_sufficient_stack(|| normalizer.fold(value));
|
||||
debug!(
|
||||
"normalize_with_depth: depth={} result={:?} with {} obligations",
|
||||
depth,
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::infer::{InferCtxt, InferOk};
|
|||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
||||
use rustc_infer::traits::Normalized;
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -131,7 +132,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
ty
|
||||
);
|
||||
}
|
||||
let folded_ty = self.fold_ty(concrete_ty);
|
||||
let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty));
|
||||
self.anon_depth -= 1;
|
||||
folded_ty
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::lang_items;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::limits::ensure_sufficient_stack;
|
||||
use rustc_middle::ty::fast_reject;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
|
@ -2365,13 +2366,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx.commit_unconditionally(|_| {
|
||||
let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
|
||||
let Normalized { value: normalized_ty, mut obligations } =
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
self,
|
||||
param_env,
|
||||
cause.clone(),
|
||||
recursion_depth,
|
||||
&skol_ty,
|
||||
);
|
||||
)
|
||||
});
|
||||
let skol_obligation = predicate_for_trait_def(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
|
@ -2525,6 +2528,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
let cause = obligation.derived_cause(BuiltinDerivedObligation);
|
||||
ensure_sufficient_stack(|| {
|
||||
self.collect_predicates_for_types(
|
||||
obligation.param_env,
|
||||
cause,
|
||||
|
@ -2532,6 +2536,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
trait_def,
|
||||
nested,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
@ -2568,7 +2573,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
nested: ty::Binder<Vec<Ty<'tcx>>>,
|
||||
) -> VtableAutoImplData<PredicateObligation<'tcx>> {
|
||||
debug!("vtable_auto_impl: nested={:?}", nested);
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
let cause = obligation.derived_cause(BuiltinDerivedObligation);
|
||||
let mut obligations = self.collect_predicates_for_types(
|
||||
obligation.param_env,
|
||||
|
@ -2600,6 +2605,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
debug!("vtable_auto_impl: obligations={:?}", obligations);
|
||||
|
||||
VtableAutoImplData { trait_def_id, nested: obligations }
|
||||
})
|
||||
}
|
||||
|
||||
fn confirm_impl_candidate(
|
||||
|
@ -2615,6 +2621,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
|
||||
debug!("confirm_impl_candidate: substs={:?}", substs);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
ensure_sufficient_stack(|| {
|
||||
self.vtable_impl(
|
||||
impl_def_id,
|
||||
substs,
|
||||
|
@ -2623,6 +2630,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation.param_env,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn vtable_impl(
|
||||
|
@ -2734,13 +2742,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
)
|
||||
.map_bound(|(trait_ref, _)| trait_ref);
|
||||
|
||||
let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
|
||||
let Normalized { value: trait_ref, obligations } = ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&trait_ref,
|
||||
);
|
||||
)
|
||||
});
|
||||
|
||||
self.confirm_poly_trait_refs(
|
||||
obligation.cause.clone(),
|
||||
|
@ -2798,13 +2808,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
|
||||
|
||||
let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs);
|
||||
let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
|
||||
let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
|
||||
normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&trait_ref,
|
||||
);
|
||||
)
|
||||
});
|
||||
|
||||
debug!(
|
||||
"confirm_generator_candidate(generator_def_id={:?}, \
|
||||
|
@ -2843,13 +2855,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
|
||||
let Normalized { value: trait_ref, mut obligations } = normalize_with_depth(
|
||||
let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
|
||||
normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&trait_ref,
|
||||
);
|
||||
)
|
||||
});
|
||||
|
||||
debug!(
|
||||
"confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
|
||||
|
@ -3139,7 +3153,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
nested.extend(obligations);
|
||||
|
||||
// Construct the nested `T: Unsize<U>` predicate.
|
||||
nested.push(predicate_for_trait_def(
|
||||
nested.push(ensure_sufficient_stack(|| {
|
||||
predicate_for_trait_def(
|
||||
tcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
|
@ -3147,7 +3162,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation.recursion_depth + 1,
|
||||
a_last.expect_ty(),
|
||||
&[b_last],
|
||||
));
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
_ => bug!(),
|
||||
|
@ -3208,13 +3224,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs);
|
||||
|
||||
let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
|
||||
ensure_sufficient_stack(|| {
|
||||
project::normalize_with_depth(
|
||||
self,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1,
|
||||
&impl_trait_ref,
|
||||
);
|
||||
)
|
||||
});
|
||||
|
||||
debug!(
|
||||
"match_impl(impl_def_id={:?}, obligation={:?}, \
|
||||
|
|
|
@ -191,10 +191,12 @@ fn dtorck_constraint_for_ty<'tcx>(
|
|||
|
||||
ty::Array(ety, _) | ty::Slice(ety) => {
|
||||
// single-element containers, behave like their element
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)?;
|
||||
rustc_middle::limits::ensure_sufficient_stack(|| {
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)
|
||||
})?;
|
||||
}
|
||||
|
||||
ty::Tuple(tys) => {
|
||||
ty::Tuple(tys) => rustc_middle::limits::ensure_sufficient_stack(|| {
|
||||
for ty in tys.iter() {
|
||||
dtorck_constraint_for_ty(
|
||||
tcx,
|
||||
|
@ -205,13 +207,15 @@ fn dtorck_constraint_for_ty<'tcx>(
|
|||
constraints,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?,
|
||||
|
||||
ty::Closure(_, substs) => {
|
||||
ty::Closure(_, substs) => rustc_middle::limits::ensure_sufficient_stack(|| {
|
||||
for ty in substs.as_closure().upvar_tys() {
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
|
||||
}
|
||||
}
|
||||
Ok::<_, NoSolution>(())
|
||||
})?,
|
||||
|
||||
ty::Generator(_, substs, _movability) => {
|
||||
// rust-lang/rust#49918: types can be constructed, stored
|
||||
|
|
Loading…
Add table
Reference in a new issue