From 548b182cf30779b9fa9a159f61c61071c241b492 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:14:24 +0100 Subject: [PATCH 1/4] Prevent stack overflow for deeply recursive code --- Cargo.lock | 23 +++ src/librustc/Cargo.toml | 1 + src/librustc/middle/limits.rs | 18 ++ src/librustc/ty/inhabitedness/mod.rs | 5 +- src/librustc/ty/query/plumbing.rs | 4 +- src/librustc_ast_lowering/expr.rs | 63 +++--- src/librustc_ast_lowering/pat.rs | 19 +- src/librustc_interface/util.rs | 9 +- src/librustc_mir/monomorphize/collector.rs | 8 +- src/librustc_mir_build/build/expr/as_temp.rs | 8 +- .../traits/project.rs | 3 +- .../traits/query/normalize.rs | 3 +- src/librustc_trait_selection/traits/select.rs | 191 ++++++++++-------- src/librustc_traits/dropck_outlives.rs | 44 ++-- src/tools/tidy/src/deps.rs | 1 + 15 files changed, 246 insertions(+), 154 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42049da8e6add..f35798e0b3f9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2580,6 +2580,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" @@ -3123,6 +3132,7 @@ dependencies = [ "scoped-tls", "serialize", "smallvec 1.0.0", + "stacker", ] [[package]] @@ -4542,6 +4552,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" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 481d691b8e9b2..12ed608dcc35e 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -36,3 +36,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" diff --git a/src/librustc/middle/limits.rs b/src/librustc/middle/limits.rs index 22e4f5ea22261..053f02ee8dbb8 100644 --- a/src/librustc/middle/limits.rs +++ b/src/librustc/middle/limits.rs @@ -13,6 +13,24 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_data_structures::sync::Once; +// 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: 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); diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index b166c4dea0c85..35b5bde7c9e1e 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -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), diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index acf67f52dceaa..33b348811d91a 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -321,7 +321,9 @@ impl<'tcx> 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)) + }) }) } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index a4cbae5196635..a78dd158b0036 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1,6 +1,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use rustc::bug; +use rustc::middle::limits::ensure_sufficient_stack; use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::ptr::P as AstP; @@ -22,6 +23,37 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { let kind = match e.kind { + ExprKind::Paren(ref ex) => { + let mut ex = self.lower_expr_mut(ex); + // Include parens in span, but only if it is a super-span. + if e.span.contains(ex.span) { + ex.span = e.span; + } + // Merge attributes into the inner expression. + let mut attrs = e.attrs.clone(); + attrs.extend::>(ex.attrs.into()); + ex.attrs = attrs; + return ex; + } + + // Desugar `ExprForLoop` + // from: `[opt_ident]: for in ` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { + return self.lower_expr_for(e, pat, head, body, opt_label); + } + _ => ensure_sufficient_stack(|| self.lower_expr_kind(e)), + }; + + hir::Expr { + hir_id: self.lower_node_id(e.id), + kind, + span: e.span, + attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::>().into(), + } + } + + fn lower_expr_kind(&mut self, e: &Expr) -> hir::ExprKind<'hir> { + 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)), ExprKind::Repeat(ref expr, ref count) => { @@ -175,37 +207,14 @@ impl<'hir> LoweringContext<'_, 'hir> { maybe_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. - if e.span.contains(ex.span) { - ex.span = e.span; - } - // Merge attributes into the inner expression. - let mut attrs = e.attrs.clone(); - attrs.extend::>(ex.attrs.into()); - ex.attrs = attrs; - 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 in ` - 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"), - }; - hir::Expr { - hir_id: self.lower_node_id(e.id), - kind, - span: e.span, - attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::>().into(), + ExprKind::ForLoop(..) | ExprKind::Paren(_) => { + span_bug!(e.span, "Should be handled by `lower_expr`") + } + ExprKind::MacCall(_) => span_bug!(e.span, "Shouldn't exist here"), } } diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 8ba6576f69265..c7d55c757f360 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -1,5 +1,6 @@ use super::{ImplTraitContext, LoweringContext, ParamMode}; +use rustc::{middle::limits::ensure_sufficient_stack, span_bug}; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_hir as hir; @@ -9,6 +10,16 @@ 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> { let node = match p.kind { + // FIXME: consider not using recursion to lower this. + PatKind::Paren(ref inner) => return self.lower_pat(inner), + _ => ensure_sufficient_stack(|| self.lower_pat_kind(p)), + }; + + self.pat_with_node_id_of(p, node) + } + + fn lower_pat_kind(&mut self, p: &Pat) -> hir::PatKind<'hir> { + match p.kind { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, ident, ref sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); @@ -74,11 +85,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If we reach here the `..` pattern is not semantically allowed. self.ban_illegal_rest_pat(p.span) } - PatKind::Paren(ref inner) => return self.lower_pat(inner), - PatKind::MacCall(_) => panic!("Shouldn't exist here"), - }; - - self.pat_with_node_id_of(p, node) + PatKind::Paren(_) => span_bug!(p.span, "Should be handled by `lower_pat`"), + PatKind::MacCall(_) => span_bug!(p.span, "Shouldn't exist here"), + } } fn lower_pat_tuple( diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 9521195a1b6c0..73eae4b22fb74 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -83,14 +83,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 { // FIXME: Hacks on hacks. If the env is trying to override the stack size diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f56bef031a748..119b11c724aca 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -368,7 +368,9 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths)); check_type_length_limit(tcx, instance); - collect_neighbours(tcx, instance, &mut neighbors); + rustc::middle::limits::ensure_sufficient_stack(|| { + collect_neighbours(tcx, instance, &mut neighbors); + }); } MonoItem::GlobalAsm(..) => { recursion_depth_reset = None; @@ -1134,7 +1136,9 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &((), inner) in alloc.relocations().values() { - collect_miri(tcx, inner, output); + rustc::middle::limits::ensure_sufficient_stack(|| { + collect_miri(tcx, inner, output); + }); } } Some(GlobalAlloc::Function(fn_instance)) => { diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs index 34dd10cbc0fc8..95ce94a055d83 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/src/librustc_mir_build/build/expr/as_temp.rs @@ -3,7 +3,7 @@ use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; -use rustc::middle::region; +use rustc::middle::{region, limits::ensure_sufficient_stack}; use rustc::mir::*; use rustc_hir as hir; use rustc_span::symbol::sym; @@ -22,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( diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 1ad915742127e..05656b9aebb0d 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -17,6 +17,7 @@ use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableI use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::traits::error_reporting::InferCtxtExt; +use rustc::middle::limits::ensure_sufficient_stack; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::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, diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index adec2ddb25322..68bc6dd12843c 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc::middle::limits::ensure_sufficient_stack; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; @@ -120,7 +121,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 } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index ab3214d8d2d23..0202fc83fb3f1 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -36,7 +36,7 @@ use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFre use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectionCacheKeyExt; use rustc::dep_graph::{DepKind, DepNodeIndex}; -use rustc::middle::lang_items; +use rustc::middle::{lang_items, limits::ensure_sufficient_stack}; use rustc::ty::fast_reject; use rustc::ty::relate::TypeRelation; use rustc::ty::subst::{Subst, SubstsRef}; @@ -2379,13 +2379,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 } = - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - &skol_ty, - ); + 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, @@ -2539,13 +2541,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) + ensure_sufficient_stack(|| { + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) + }) } else { vec![] }; @@ -2582,38 +2586,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: ty::Binder>>, ) -> VtableAutoImplData> { 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, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); - let cause = obligation.derived_cause(BuiltinDerivedObligation); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); - - let trait_obligations: Vec> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); + let trait_obligations: Vec> = + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, _) = + self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + ) + }); - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It won't have any effect since auto traits are coinductive. + obligations.extend(trait_obligations); - debug!("vtable_auto_impl: obligations={:?}", obligations); + debug!("vtable_auto_impl: obligations={:?}", obligations); - VtableAutoImplData { trait_def_id, nested: obligations } + VtableAutoImplData { trait_def_id, nested: obligations } + }) } fn confirm_impl_candidate( @@ -2629,13 +2634,15 @@ 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); - self.vtable_impl( - impl_def_id, - substs, - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ) + ensure_sufficient_stack(|| { + self.vtable_impl( + impl_def_id, + substs, + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ) + }) }) } @@ -2748,13 +2755,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) .map_bound(|(trait_ref, _)| trait_ref); - let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + 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(), @@ -2812,13 +2821,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, generator_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + 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={:?}, \ @@ -2857,13 +2868,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + 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={:?})", @@ -3146,15 +3159,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `T: Unsize` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last.expect_ty(), - &[b_last], - )); + nested.push(ensure_sufficient_stack(|| { + predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + a_last.expect_ty(), + &[b_last], + ) + })); } _ => bug!(), @@ -3215,13 +3230,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 } = - project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref, - ); + 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={:?}, \ diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index b13a7a3acb165..82380bb65e64d 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -191,27 +191,33 @@ 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) => { - for ty in tys.iter() { - dtorck_constraint_for_ty( - tcx, - span, - for_ty, - depth + 1, - ty.expect_ty(), - constraints, - )?; - } - } - - ty::Closure(def_id, substs) => { - for ty in substs.as_closure().upvar_tys(def_id, tcx) { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - } + ty::Tuple(tys) => rustc::middle::limits::ensure_sufficient_stack(|| { + tys.iter() + .map(|ty| { + dtorck_constraint_for_ty( + tcx, + span, + for_ty, + depth + 1, + ty.expect_ty(), + constraints, + ) + }) + .collect::>() + })?, + + ty::Closure(def_id, substs) => rustc::middle::limits::ensure_sufficient_stack(|| { + substs + .as_closure() + .upvar_tys(def_id, tcx) + .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)) + .collect::>() + })?, ty::Generator(def_id, substs, _movability) => { // rust-lang/rust#49918: types can be constructed, stored diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 7a20a96130ccb..c5d4a1a3e9c71 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -162,6 +162,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("serde_derive"), Crate("smallvec"), Crate("stable_deref_trait"), + Crate("stacker"), Crate("syn"), Crate("synstructure"), Crate("tempfile"), From 6c2530771fd39ce2c285762b7f61c0e16b4f9eaa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 26 Nov 2019 14:12:59 +0100 Subject: [PATCH 2/4] Add `psm` to the crate whitelist --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index c5d4a1a3e9c71..54b42bd34c69c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -134,6 +134,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("polonius-engine"), Crate("ppv-lite86"), Crate("proc-macro2"), + Crate("psm"), Crate("punycode"), Crate("quick-error"), Crate("quote"), From 410cdd7a0262b26414a8176336ec326a758b51f5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 23 Feb 2020 22:23:45 +0200 Subject: [PATCH 3/4] Set the default stack size to 8MB This was the value used before we originally started raising the stack size to infinity. --- src/librustc_interface/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 73eae4b22fb74..6d615419aaec5 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -83,7 +83,7 @@ pub fn create_session( (Lrc::new(sess), Lrc::new(codegen_backend), source_map) } -const STACK_SIZE: usize = 2 * 1024 * 1024; +const STACK_SIZE: usize = 8 * 1024 * 1024; fn get_stack_size() -> Option { // FIXME: Hacks on hacks. If the env is trying to override the stack size From fb10e5cca3b4d01f850d82198ad51f3406b3a1c3 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 14 Mar 2020 20:13:55 +0200 Subject: [PATCH 4/4] Resolve some review comments --- src/librustc/middle/limits.rs | 4 ++-- src/librustc_ast_lowering/expr.rs | 5 ++--- src/librustc_ast_lowering/pat.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/limits.rs b/src/librustc/middle/limits.rs index 053f02ee8dbb8..6f6fc8b881a32 100644 --- a/src/librustc/middle/limits.rs +++ b/src/librustc/middle/limits.rs @@ -18,7 +18,7 @@ use rustc_data_structures::sync::Once; // `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 +// Only 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 @@ -27,7 +27,7 @@ const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB /// from this. /// /// Should not be sprinkled around carelessly, as it causes a little bit of overhead. -pub fn ensure_sufficient_stack R>(f: F) -> R { +pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index a78dd158b0036..842dc10ea7bdc 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1,7 +1,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; -use rustc::bug; use rustc::middle::limits::ensure_sufficient_stack; +use rustc::{bug, span_bug}; use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::ptr::P as AstP; @@ -210,9 +210,8 @@ impl<'hir> LoweringContext<'_, 'hir> { 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::ForLoop(..) | ExprKind::Paren(_) => { - span_bug!(e.span, "Should be handled by `lower_expr`") + span_bug!(e.span, "Should have been handled by `lower_expr`") } ExprKind::MacCall(_) => span_bug!(e.span, "Shouldn't exist here"), } diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index c7d55c757f360..316a600e3c599 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -85,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If we reach here the `..` pattern is not semantically allowed. self.ban_illegal_rest_pat(p.span) } - PatKind::Paren(_) => span_bug!(p.span, "Should be handled by `lower_pat`"), + PatKind::Paren(_) => span_bug!(p.span, "Should have been handled by `lower_pat`"), PatKind::MacCall(_) => span_bug!(p.span, "Shouldn't exist here"), } }