From 831ef6230c86448889e5b808e4f8d10978e7650e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:14:24 +0100 Subject: [PATCH 1/7] Prevent stack overflow for deeply recursive code --- src/Cargo.lock | 18 ++ src/librustc/Cargo.toml | 1 + src/librustc/hir/lowering.rs | 257 +++++++++++---------- src/librustc/lib.rs | 1 + src/librustc/middle/recursion_limit.rs | 9 + src/librustc/traits/project.rs | 5 +- src/librustc/traits/query/normalize.rs | 3 +- src/librustc/traits/select.rs | 133 ++++++----- src/librustc/ty/inhabitedness/mod.rs | 5 +- src/librustc/ty/query/plumbing.rs | 4 +- src/librustc_mir/build/expr/as_temp.rs | 7 +- src/librustc_mir/monomorphize/collector.rs | 8 +- src/librustc_traits/dropck_outlives.rs | 12 +- src/librustc_typeck/check/mod.rs | 3 +- 14 files changed, 264 insertions(+), 202 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index a4246b26c2268..205e4f04eae30 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -815,6 +815,11 @@ dependencies = [ "termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "getopts" version = "0.2.17" @@ -1904,6 +1909,7 @@ dependencies = [ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "stacker 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2662,6 +2668,16 @@ name = "stable_deref_trait" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stacker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "std" version = "0.0.0" @@ -3230,6 +3246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" "checksum git2-curl 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0173e317f8ba21f3fff0f71549fead5e42e67961dbd402bf69f42775f3cc78b4" @@ -3369,6 +3386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" +"checksum stacker 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "82c150485b78a81ed189dbdd1947397344bc296b86f7fcc7ca3cdae8bfe882e0" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index d0ec8640ce9ef..39f1f0f155afa 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -34,6 +34,7 @@ byteorder = { version = "1.1", features = ["i128"]} chalk-engine = { version = "0.8.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.5", features = ["union"] } +stacker = "0.1.3" # Note that these dependencies are a lie, they're just here to get linkage to # work. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd5d4b8f6afff..2c8e9e3738ab1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,6 +50,7 @@ use hir::GenericArg; use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; use middle::cstore::CrateStore; +use middle::recursion_limit::guarantee_one_mb_stack_left; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; @@ -3659,8 +3660,8 @@ impl<'a> LoweringContext<'a> { }) } - fn lower_expr(&mut self, e: &Expr) -> hir::Expr { - let kind = match e.node { + fn lower_expr_kind(&mut self, e: &Expr) -> hir::ExprKind { + match e.node { ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))), ExprKind::ObsoleteInPlace(..) => { self.sess.abort_if_errors(); @@ -3959,19 +3960,11 @@ impl<'a> LoweringContext<'a> { let struct_path = self.std_path(e.span, &struct_path, None, is_unit); let struct_path = hir::QPath::Resolved(None, P(struct_path)); - let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); - - return hir::Expr { - id: node_id, - hir_id, - node: if is_unit { + if is_unit { hir::ExprKind::Path(struct_path) } else { hir::ExprKind::Struct(struct_path, fields, None) - }, - span: e.span, - attrs: e.attrs.clone(), - }; + } } ExprKind::Path(ref qself, ref path) => { let qpath = self.lower_qpath( @@ -4050,18 +4043,7 @@ impl<'a> LoweringContext<'a> { fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| P(self.lower_expr(x))), ), - ExprKind::Paren(ref ex) => { - let mut ex = self.lower_expr(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::Paren(_) => bug!("parens are handled in `lower_expr`"), ExprKind::Yield(ref opt_expr) => { self.is_generator = true; @@ -4173,6 +4155,128 @@ impl<'a> LoweringContext<'a> { loop_expr } + ExprKind::ForLoop(..) => bug!(), + + // Desugar ExprKind::Try + // From: `?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // match Try::into_result() { + // Ok(val) => #[allow(unreachable_code)] val, + // Err(err) => #[allow(unreachable_code)] + // // If there is an enclosing `catch {...}` + // break 'catch_target Try::from_error(From::from(err)), + // // Otherwise + // return Try::from_error(From::from(err)), + // } + + let unstable_span = + self.allow_internal_unstable(CompilerDesugaringKind::QuestionMark, e.span); + + // Try::into_result() + let discr = { + // expand + let sub_expr = self.lower_expr(sub_expr); + + let path = &["ops", "Try", "into_result"]; + let path = P(self.expr_std_path( + unstable_span, path, None, ThinVec::new())); + P(self.expr_call(e.span, path, hir_vec![sub_expr])) + }; + + // #[allow(unreachable_code)] + let attr = { + // allow(unreachable_code) + let allow = { + let allow_ident = Ident::from_str("allow").with_span_pos(e.span); + let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span); + let uc_nested = attr::mk_nested_word_item(uc_ident); + attr::mk_list_item(e.span, allow_ident, vec![uc_nested]) + }; + attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) + }; + let attrs = vec![attr]; + + // Ok(val) => #[allow(unreachable_code)] val, + let ok_arm = { + let val_ident = self.str_to_ident("val"); + let val_pat = self.pat_ident(e.span, val_ident); + let val_expr = P(self.expr_ident_with_attrs( + e.span, + val_ident, + val_pat.id, + ThinVec::from(attrs.clone()), + )); + let ok_pat = self.pat_ok(e.span, val_pat); + + self.arm(hir_vec![ok_pat], val_expr) + }; + + // Err(err) => #[allow(unreachable_code)] + // return Try::from_error(From::from(err)), + let err_arm = { + let err_ident = self.str_to_ident("err"); + let err_local = self.pat_ident(e.span, err_ident); + let from_expr = { + let path = &["convert", "From", "from"]; + let from = P(self.expr_std_path( + e.span, path, None, ThinVec::new())); + let err_expr = self.expr_ident(e.span, err_ident, err_local.id); + + self.expr_call(e.span, from, hir_vec![err_expr]) + }; + let from_err_expr = + self.wrap_in_try_constructor("from_error", from_expr, unstable_span); + let thin_attrs = ThinVec::from(attrs); + let catch_scope = self.catch_scopes.last().map(|x| *x); + let ret_expr = if let Some(catch_node) = catch_scope { + P(self.expr( + e.span, + hir::ExprKind::Break( + hir::Destination { + label: None, + target_id: Ok(catch_node), + }, + Some(from_err_expr), + ), + thin_attrs, + )) + } else { + P(self.expr(e.span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) + }; + + let err_pat = self.pat_err(e.span, err_local); + self.arm(hir_vec![err_pat], ret_expr) + }; + + hir::ExprKind::Match( + discr, + hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar, + ) + } + + ExprKind::Mac(_) => panic!("Shouldn't exist here"), + } + } + + + fn lower_expr(&mut self, e: &Expr) -> hir::Expr { + // parens and for loops have some custom desugaring going on where the node ids aren't + // just lowered from the expression + let kind = match e.node { + ExprKind::Paren(ref ex) => { + let mut ex = guarantee_one_mb_stack_left(|| self.lower_expr(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. + ex.attrs.extend(e.attrs.iter().cloned()); + return ex; + }, + // Desugar ExprForLoop // From: `[opt_ident]: for in ` ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { @@ -4341,109 +4445,8 @@ impl<'a> LoweringContext<'a> { let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result))); // add the attributes to the outer returned expr node return self.expr_block(block, e.attrs.clone()); - } - - // Desugar ExprKind::Try - // From: `?` - ExprKind::Try(ref sub_expr) => { - // to: - // - // match Try::into_result() { - // Ok(val) => #[allow(unreachable_code)] val, - // Err(err) => #[allow(unreachable_code)] - // // If there is an enclosing `catch {...}` - // break 'catch_target Try::from_error(From::from(err)), - // // Otherwise - // return Try::from_error(From::from(err)), - // } - - let unstable_span = - self.allow_internal_unstable(CompilerDesugaringKind::QuestionMark, e.span); - - // Try::into_result() - let discr = { - // expand - let sub_expr = self.lower_expr(sub_expr); - - let path = &["ops", "Try", "into_result"]; - let path = P(self.expr_std_path( - unstable_span, path, None, ThinVec::new())); - P(self.expr_call(e.span, path, hir_vec![sub_expr])) - }; - - // #[allow(unreachable_code)] - let attr = { - // allow(unreachable_code) - let allow = { - let allow_ident = Ident::from_str("allow").with_span_pos(e.span); - let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span); - let uc_nested = attr::mk_nested_word_item(uc_ident); - attr::mk_list_item(e.span, allow_ident, vec![uc_nested]) - }; - attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow) - }; - let attrs = vec![attr]; - - // Ok(val) => #[allow(unreachable_code)] val, - let ok_arm = { - let val_ident = self.str_to_ident("val"); - let val_pat = self.pat_ident(e.span, val_ident); - let val_expr = P(self.expr_ident_with_attrs( - e.span, - val_ident, - val_pat.id, - ThinVec::from(attrs.clone()), - )); - let ok_pat = self.pat_ok(e.span, val_pat); - - self.arm(hir_vec![ok_pat], val_expr) - }; - - // Err(err) => #[allow(unreachable_code)] - // return Try::from_error(From::from(err)), - let err_arm = { - let err_ident = self.str_to_ident("err"); - let err_local = self.pat_ident(e.span, err_ident); - let from_expr = { - let path = &["convert", "From", "from"]; - let from = P(self.expr_std_path( - e.span, path, None, ThinVec::new())); - let err_expr = self.expr_ident(e.span, err_ident, err_local.id); - - self.expr_call(e.span, from, hir_vec![err_expr]) - }; - let from_err_expr = - self.wrap_in_try_constructor("from_error", from_expr, unstable_span); - let thin_attrs = ThinVec::from(attrs); - let catch_scope = self.catch_scopes.last().map(|x| *x); - let ret_expr = if let Some(catch_node) = catch_scope { - P(self.expr( - e.span, - hir::ExprKind::Break( - hir::Destination { - label: None, - target_id: Ok(catch_node), - }, - Some(from_err_expr), - ), - thin_attrs, - )) - } else { - P(self.expr(e.span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) - }; - - let err_pat = self.pat_err(e.span, err_local); - self.arm(hir_vec![err_pat], ret_expr) - }; - - hir::ExprKind::Match( - discr, - hir_vec![err_arm, ok_arm], - hir::MatchSource::TryDesugar, - ) - } - - ExprKind::Mac(_) => panic!("Shouldn't exist here"), + }, + _ => guarantee_one_mb_stack_left(|| self.lower_expr_kind(e)), }; let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 0aa964a44fd2c..4c59c45eb61ad 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -106,6 +106,7 @@ extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_apfloat; extern crate byteorder; extern crate backtrace; +extern crate stacker; #[macro_use] extern crate smallvec; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 077a20315a2af..91cd58bab25c2 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -20,6 +20,15 @@ use syntax::ast; use rustc_data_structures::sync::Once; +const RED_ZONE: usize = 1024*1024; // 1MB +const STACK_PER_RECURSION: usize = 8 * 1024 * 1024; // 8MB + +pub fn guarantee_one_mb_stack_left 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, "recursion_limit", "recursion limit", 64); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b59bd0e238873..df07d3929b0be 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,6 +33,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; +use middle::recursion_limit::guarantee_one_mb_stack_left; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -298,7 +299,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>( { debug!("normalize_with_depth(depth={}, value={:?})", depth, value); let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth); - let result = normalizer.fold(value); + let result = guarantee_one_mb_stack_left(|| normalizer.fold(value)); debug!("normalize_with_depth: depth={} result={:?} with {} obligations", depth, result, normalizer.obligations.len()); debug!("normalize_with_depth: depth={} obligations={:?}", @@ -383,7 +384,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); + let folded_ty = guarantee_one_mb_stack_left(|| self.fold_ty(concrete_ty)); self.depth -= 1; folded_ty } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 59b086e35de31..fd99b3ed2f8e8 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -21,6 +21,7 @@ use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use ty::fold::{TypeFoldable, TypeFolder}; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt}; +use middle::recursion_limit::guarantee_one_mb_stack_left; use super::NoSolution; @@ -131,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx ty ); } - let folded_ty = self.fold_ty(concrete_ty); + let folded_ty = guarantee_one_mb_stack_left(|| self.fold_ty(concrete_ty)); self.anon_depth -= 1; folded_ty } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 550c27ca0ab8b..bd27d67d2d720 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,6 +42,7 @@ use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; +use middle::recursion_limit::guarantee_one_mb_stack_left; use mir::interpret::GlobalId; use ty::fast_reject; use ty::relate::TypeRelation; @@ -2855,13 +2856,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) + guarantee_one_mb_stack_left(|| { + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) + }) } else { vec![] }; @@ -2903,42 +2906,44 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested: ty::Binder>>, ) -> VtableAutoImplData> { debug!("vtable_auto_impl: nested={:?}", nested); + guarantee_one_mb_stack_left(|| { - 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.in_snapshot(|this, snapshot| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - this.impl_or_trait_obligations( + let cause = obligation.derived_cause(BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, cause, obligation.recursion_depth + 1, - obligation.param_env, trait_def_id, - &trait_ref.substs, - placeholder_map, - snapshot, - ) - }); + nested, + ); - // 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); + let trait_obligations: Vec<_> = self.in_snapshot(|this, snapshot| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, placeholder_map) = this.infcx() + .replace_late_bound_regions_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + this.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + placeholder_map, + snapshot, + ) + }); - debug!("vtable_auto_impl: obligations={:?}", 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); - VtableAutoImplData { - trait_def_id, - nested: obligations, - } + debug!("vtable_auto_impl: obligations={:?}", obligations); + + VtableAutoImplData { + trait_def_id, + nested: obligations, + } + }) } fn confirm_impl_candidate( @@ -2954,7 +2959,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - this.vtable_impl( + guarantee_one_mb_stack_left(|| this.vtable_impl( impl_def_id, substs, cause, @@ -2962,7 +2967,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.param_env, placeholder_map, snapshot, - ) + )) }) } @@ -3087,13 +3092,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, obligations, - } = project::normalize_with_depth( + } = guarantee_one_mb_stack_left(|| 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(), @@ -3170,13 +3175,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, mut obligations, - } = normalize_with_depth( + } = guarantee_one_mb_stack_left(|| normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, &trait_ref, - ); + )); debug!( "confirm_generator_candidate(generator_def_id={:?}, \ @@ -3223,13 +3228,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, mut obligations, - } = normalize_with_depth( + } = guarantee_one_mb_stack_left(|| 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={:?})", @@ -3481,14 +3486,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested.extend(obligations); // Construct the nested Field: Unsize> predicate. - nested.push(tcx.predicate_for_trait_def( - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], - )); + nested.push(guarantee_one_mb_stack_left(|| { + tcx.predicate_for_trait_def( + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + inner_source, + &[inner_target.into()], + ) + })); } // (.., T) -> (.., U). @@ -3513,14 +3520,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested.extend(obligations); // Construct the nested T: Unsize predicate. - nested.push(tcx.predicate_for_trait_def( - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last, - &[b_last.into()], - )); + nested.push(guarantee_one_mb_stack_left(|| { + tcx.predicate_for_trait_def( + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + a_last, + &[b_last.into()], + ) + })); } _ => bug!(), @@ -3593,13 +3602,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: impl_trait_ref, obligations: mut nested_obligations, - } = project::normalize_with_depth( + } = guarantee_one_mb_stack_left(|| 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/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 56fe479ffc555..79dabedef7e6c 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -14,6 +14,7 @@ use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; use ty::{DefId, Substs}; use ty::{AdtKind, Visibility}; use ty::TyKind::*; +use middle::recursion_limit::guarantee_one_mb_stack_left; pub use self::def_id_forest::DefIdForest; @@ -249,7 +250,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { tcx.sess.fatal(&error); } } - let ret = def.uninhabited_from(visited, tcx, substs); + let ret = guarantee_one_mb_stack_left(|| { + def.uninhabited_from(visited, tcx, substs) + }); let substs_set = visited.get_mut(&def.did).unwrap(); substs_set.remove(substs); ret diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 8bbfd92d688ed..841b61ce29330 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { p.record_query(Q::CATEGORY); }); - let res = job.start(self, |tcx| { + let res = ::middle::recursion_limit::guarantee_one_mb_stack_left(|| job.start(self, |tcx| { if dep_node.kind.is_eval_always() { tcx.dep_graph.with_eval_always_task(dep_node, tcx, @@ -552,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { key, Q::compute) } - }); + })); self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index e0bf02c6739e3..d80980135d16a 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -14,6 +14,7 @@ use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use hair::*; use rustc::middle::region; use rustc::mir::*; +use rustc::middle::recursion_limit::guarantee_one_mb_stack_left; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building @@ -29,7 +30,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, '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 + guarantee_one_mb_stack_left(|| self.expr_as_temp(block, temp_lifetime, expr, mutability)) } fn expr_as_temp( diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 8e27635dee8c1..34af509136e53 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -409,7 +409,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, recursion_depths)); check_type_length_limit(tcx, instance); - collect_neighbours(tcx, instance, &mut neighbors); + rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + collect_neighbours(tcx, instance, &mut neighbors); + }); } MonoItem::GlobalAsm(..) => { recursion_depth_reset = None; @@ -1178,7 +1180,9 @@ fn collect_miri<'a, 'tcx>( Some(AllocType::Memory(alloc)) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &((), inner) in alloc.relocations.values() { - collect_miri(tcx, inner, output); + rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + collect_miri(tcx, inner, output); + }); } }, Some(AllocType::Function(fn_instance)) => { diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index af64522f18398..066a6b167fcf1 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -193,16 +193,22 @@ fn dtorck_constraint_for_ty<'a, 'gcx, '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) + rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety) + }) } ty::Tuple(tys) => tys.iter() - .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .map(|ty| rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty) + })) .collect(), ty::Closure(def_id, substs) => substs .upvar_tys(def_id, tcx) - .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) + .map(|ty| rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty) + })) .collect(), ty::Generator(def_id, substs, _movability) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2e6797ef23ad2..b53ebc208c613 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -94,6 +94,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; +use rustc::middle::recursion_limit::guarantee_one_mb_stack_left; use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; @@ -3754,7 +3755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let ty = self.check_expr_kind(expr, expected, needs); + let ty = guarantee_one_mb_stack_left(|| self.check_expr_kind(expr, expected, needs)); // Warn for non-block expressions with diverging children. match expr.node { From d835e4e4e416c3a91f56cdf218a5c7e74f7b340a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:25:16 +0100 Subject: [PATCH 2/7] Document `guarantee_one_mb_stack_left` --- src/librustc/middle/recursion_limit.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 91cd58bab25c2..c122f7d09c6d4 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Recursion limit. -// -// There are various parts of the compiler that must impose arbitrary limits -// on how deeply they recurse to prevent stack overflow. Users can override -// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass -// just peeks and looks for that attribute. +//! Recursion limit. +//! +//! There are various parts of the compiler that must impose arbitrary limits +//! on how deeply they recurse to prevent stack overflow. Users can override +//! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass +//! just peeks and looks for that attribute. use session::Session; use syntax::ast; @@ -23,6 +23,11 @@ use rustc_data_structures::sync::Once; const RED_ZONE: usize = 1024*1024; // 1MB const STACK_PER_RECURSION: usize = 8 * 1024 * 1024; // 8MB +/// 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 guarantee_one_mb_stack_left R>( f: F ) -> R { From 3c1a935ce74213ba32bfa3eb99a7cfc48494469a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:45:59 +0100 Subject: [PATCH 3/7] Use more reasonable stack sizes and growth factors --- src/librustc/middle/recursion_limit.rs | 4 ++-- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index c122f7d09c6d4..604327e77df6c 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -20,8 +20,8 @@ use syntax::ast; use rustc_data_structures::sync::Once; -const RED_ZONE: usize = 1024*1024; // 1MB -const STACK_PER_RECURSION: usize = 8 * 1024 * 1024; // 8MB +const RED_ZONE: usize = 100*1024; // 100k +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 diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 7ad012409b53a..07803d0659823 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -91,7 +91,7 @@ pub fn spawn_thread_pool R + sync::Send, R: sync:: let config = ThreadPoolBuilder::new() .num_threads(Session::query_threads_from_opts(&opts)) .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) - .stack_size(16 * 1024 * 1024); + .stack_size(::STACK_SIZE); let with_pool = move |pool: &ThreadPool| { pool.install(move || f(opts)) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6c7982242bfad..a3053ae6aefb9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1468,6 +1468,8 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(name: String, f: F) -> Result R + Send + 'static, R: Send + 'static, { - // Temporarily have stack size set to 16MB to deal with nom-using crates failing - const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB #[cfg(all(unix, not(target_os = "haiku")))] let spawn_thread = unsafe { From 596d33cc38ace2ca698e047ecfd9d999bad6f76e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:46:52 +0100 Subject: [PATCH 4/7] Don't hardcode stack growth in stack growing function name --- src/librustc/hir/lowering.rs | 6 +++--- src/librustc/middle/recursion_limit.rs | 2 +- src/librustc/traits/project.rs | 6 +++--- src/librustc/traits/query/normalize.rs | 4 ++-- src/librustc/traits/select.rs | 20 ++++++++++---------- src/librustc/ty/inhabitedness/mod.rs | 4 ++-- src/librustc/ty/query/plumbing.rs | 2 +- src/librustc_mir/build/expr/as_temp.rs | 4 ++-- src/librustc_mir/monomorphize/collector.rs | 4 ++-- src/librustc_traits/dropck_outlives.rs | 6 +++--- src/librustc_typeck/check/mod.rs | 4 ++-- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2c8e9e3738ab1..51a007a60b9cc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,7 +50,7 @@ use hir::GenericArg; use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; use middle::cstore::CrateStore; -use middle::recursion_limit::guarantee_one_mb_stack_left; +use middle::recursion_limit::ensure_sufficient_stack; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; @@ -4267,7 +4267,7 @@ impl<'a> LoweringContext<'a> { // just lowered from the expression let kind = match e.node { ExprKind::Paren(ref ex) => { - let mut ex = guarantee_one_mb_stack_left(|| self.lower_expr(ex)); + let mut ex = ensure_sufficient_stack(|| self.lower_expr(ex)); // include parens in span, but only if it is a super-span. if e.span.contains(ex.span) { ex.span = e.span; @@ -4446,7 +4446,7 @@ impl<'a> LoweringContext<'a> { // add the attributes to the outer returned expr node return self.expr_block(block, e.attrs.clone()); }, - _ => guarantee_one_mb_stack_left(|| self.lower_expr_kind(e)), + _ => ensure_sufficient_stack(|| self.lower_expr_kind(e)), }; let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id); diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 604327e77df6c..bb9e3d5dd5bb3 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -28,7 +28,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 guarantee_one_mb_stack_left R>( +pub fn ensure_sufficient_stack R>( f: F ) -> R { stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index df07d3929b0be..4e3261d0b7346 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,7 +33,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use middle::recursion_limit::guarantee_one_mb_stack_left; +use middle::recursion_limit::ensure_sufficient_stack; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -299,7 +299,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>( { debug!("normalize_with_depth(depth={}, value={:?})", depth, value); let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth); - let result = guarantee_one_mb_stack_left(|| normalizer.fold(value)); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); debug!("normalize_with_depth: depth={} result={:?} with {} obligations", depth, result, normalizer.obligations.len()); debug!("normalize_with_depth: depth={} obligations={:?}", @@ -384,7 +384,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.depth += 1; - let folded_ty = guarantee_one_mb_stack_left(|| self.fold_ty(concrete_ty)); + let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty)); self.depth -= 1; folded_ty } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index fd99b3ed2f8e8..640c1da84d9a7 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -21,7 +21,7 @@ use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use ty::fold::{TypeFoldable, TypeFolder}; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt}; -use middle::recursion_limit::guarantee_one_mb_stack_left; +use middle::recursion_limit::ensure_sufficient_stack; use super::NoSolution; @@ -132,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx ty ); } - let folded_ty = guarantee_one_mb_stack_left(|| 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/traits/select.rs b/src/librustc/traits/select.rs index bd27d67d2d720..93afc6a64a7e7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -42,7 +42,7 @@ use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; -use middle::recursion_limit::guarantee_one_mb_stack_left; +use middle::recursion_limit::ensure_sufficient_stack; use mir::interpret::GlobalId; use ty::fast_reject; use ty::relate::TypeRelation; @@ -2856,7 +2856,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - guarantee_one_mb_stack_left(|| { + ensure_sufficient_stack(|| { self.collect_predicates_for_types( obligation.param_env, cause, @@ -2906,7 +2906,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested: ty::Binder>>, ) -> VtableAutoImplData> { debug!("vtable_auto_impl: nested={:?}", nested); - guarantee_one_mb_stack_left(|| { + ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); let mut obligations = self.collect_predicates_for_types( @@ -2959,7 +2959,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let (substs, placeholder_map) = this.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - guarantee_one_mb_stack_left(|| this.vtable_impl( + ensure_sufficient_stack(|| this.vtable_impl( impl_def_id, substs, cause, @@ -3092,7 +3092,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, obligations, - } = guarantee_one_mb_stack_left(|| project::normalize_with_depth( + } = ensure_sufficient_stack(|| project::normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), @@ -3175,7 +3175,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, mut obligations, - } = guarantee_one_mb_stack_left(|| normalize_with_depth( + } = ensure_sufficient_stack(|| normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), @@ -3228,7 +3228,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: trait_ref, mut obligations, - } = guarantee_one_mb_stack_left(|| normalize_with_depth( + } = ensure_sufficient_stack(|| normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), @@ -3486,7 +3486,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested.extend(obligations); // Construct the nested Field: Unsize> predicate. - nested.push(guarantee_one_mb_stack_left(|| { + nested.push(ensure_sufficient_stack(|| { tcx.predicate_for_trait_def( obligation.param_env, obligation.cause.clone(), @@ -3520,7 +3520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested.extend(obligations); // Construct the nested T: Unsize predicate. - nested.push(guarantee_one_mb_stack_left(|| { + nested.push(ensure_sufficient_stack(|| { tcx.predicate_for_trait_def( obligation.param_env, obligation.cause.clone(), @@ -3602,7 +3602,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let Normalized { value: impl_trait_ref, obligations: mut nested_obligations, - } = guarantee_one_mb_stack_left(|| project::normalize_with_depth( + } = ensure_sufficient_stack(|| project::normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 79dabedef7e6c..77336f6301e6f 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -14,7 +14,7 @@ use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; use ty::{DefId, Substs}; use ty::{AdtKind, Visibility}; use ty::TyKind::*; -use middle::recursion_limit::guarantee_one_mb_stack_left; +use middle::recursion_limit::ensure_sufficient_stack; pub use self::def_id_forest::DefIdForest; @@ -250,7 +250,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { tcx.sess.fatal(&error); } } - let ret = guarantee_one_mb_stack_left(|| { + let ret = ensure_sufficient_stack(|| { def.uninhabited_from(visited, tcx, substs) }); let substs_set = visited.get_mut(&def.did).unwrap(); diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 841b61ce29330..0bb7dfc218c23 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { p.record_query(Q::CATEGORY); }); - let res = ::middle::recursion_limit::guarantee_one_mb_stack_left(|| job.start(self, |tcx| { + let res = ::middle::recursion_limit::ensure_sufficient_stack(|| job.start(self, |tcx| { if dep_node.kind.is_eval_always() { tcx.dep_graph.with_eval_always_task(dep_node, tcx, diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index d80980135d16a..856b1d1cb91d5 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -14,7 +14,7 @@ use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use hair::*; use rustc::middle::region; use rustc::mir::*; -use rustc::middle::recursion_limit::guarantee_one_mb_stack_left; +use rustc::middle::recursion_limit::ensure_sufficient_stack; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building @@ -34,7 +34,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // 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 - guarantee_one_mb_stack_left(|| self.expr_as_temp(block, temp_lifetime, expr, mutability)) + ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability)) } fn expr_as_temp( diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 34af509136e53..05c88dba2c71f 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -409,7 +409,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, recursion_depths)); check_type_length_limit(tcx, instance); - rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + rustc::middle::recursion_limit::ensure_sufficient_stack(|| { collect_neighbours(tcx, instance, &mut neighbors); }); } @@ -1180,7 +1180,7 @@ fn collect_miri<'a, 'tcx>( Some(AllocType::Memory(alloc)) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &((), inner) in alloc.relocations.values() { - rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + rustc::middle::recursion_limit::ensure_sufficient_stack(|| { collect_miri(tcx, inner, output); }); } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 066a6b167fcf1..a45f19b138adb 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -193,20 +193,20 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element - rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + rustc::middle::recursion_limit::ensure_sufficient_stack(|| { dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety) }) } ty::Tuple(tys) => tys.iter() - .map(|ty| rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + .map(|ty| rustc::middle::recursion_limit::ensure_sufficient_stack(|| { dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty) })) .collect(), ty::Closure(def_id, substs) => substs .upvar_tys(def_id, tcx) - .map(|ty| rustc::middle::recursion_limit::guarantee_one_mb_stack_left(|| { + .map(|ty| rustc::middle::recursion_limit::ensure_sufficient_stack(|| { dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty) })) .collect(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b53ebc208c613..a85e14bbf47bd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -94,7 +94,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; -use rustc::middle::recursion_limit::guarantee_one_mb_stack_left; +use rustc::middle::recursion_limit::ensure_sufficient_stack; use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; @@ -3755,7 +3755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let ty = guarantee_one_mb_stack_left(|| self.check_expr_kind(expr, expected, needs)); + let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected, needs)); // Warn for non-block expressions with diverging children. match expr.node { From a5f9b53b7ec18b2cd71ff3b7c3b7c527539bb86c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 2 Nov 2018 16:49:20 +0100 Subject: [PATCH 5/7] Whitelist new dependencies --- src/tools/tidy/src/deps.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 72c47273e63b5..f55c8049057cd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -87,6 +87,7 @@ const WHITELIST: &[Crate] = &[ Crate("fuchsia-zircon"), Crate("fuchsia-zircon-sys"), Crate("getopts"), + Crate("gcc"), Crate("humantime"), Crate("jobserver"), Crate("kernel32-sys"), @@ -122,6 +123,7 @@ const WHITELIST: &[Crate] = &[ Crate("scopeguard"), Crate("smallvec"), Crate("stable_deref_trait"), + Crate("stacker"), Crate("tempfile"), Crate("termcolor"), Crate("terminon"), From 7da6fc20763fb1f9793e5c97bc52e3203be4326d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 3 Nov 2018 23:29:51 +0100 Subject: [PATCH 6/7] Ensure large enough stack on all jobs, not just at the query call site --- src/librustc/ty/query/plumbing.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 0bb7dfc218c23..b2d052b66ae2c 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -205,7 +205,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { // Use the ImplicitCtxt while we execute the query tls::enter_context(&new_icx, |_| { - compute(tcx) + ::middle::recursion_limit::ensure_sufficient_stack(|| compute(tcx)) }) }); @@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { p.record_query(Q::CATEGORY); }); - let res = ::middle::recursion_limit::ensure_sufficient_stack(|| job.start(self, |tcx| { + let res = job.start(self, |tcx| { if dep_node.kind.is_eval_always() { tcx.dep_graph.with_eval_always_task(dep_node, tcx, @@ -552,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { key, Q::compute) } - })); + }); self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); From a4ebef00605d09924787cd9de41746ebea44609b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 13 Nov 2018 11:46:16 +0100 Subject: [PATCH 7/7] Add temporary dependency on git-stacker --- src/Cargo.lock | 16 +++++----------- src/librustc/Cargo.toml | 2 +- src/tools/tidy/src/extdeps.rs | 1 + 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 205e4f04eae30..76e256bcd8e5c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -815,11 +815,6 @@ dependencies = [ "termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.17" @@ -1909,7 +1904,7 @@ dependencies = [ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "stacker 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "stacker 0.1.4 (git+https://github.com/oli-obk/stacker.git)", "syntax 0.0.0", "syntax_pos 0.0.0", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2670,11 +2665,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stacker" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.1.4" +source = "git+https://github.com/oli-obk/stacker.git#30b32ea0514bac734539eccd4157e6d8684abcb6" dependencies = [ + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3246,7 +3241,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" "checksum git2-curl 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0173e317f8ba21f3fff0f71549fead5e42e67961dbd402bf69f42775f3cc78b4" @@ -3386,7 +3380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" -"checksum stacker 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "82c150485b78a81ed189dbdd1947397344bc296b86f7fcc7ca3cdae8bfe882e0" +"checksum stacker 0.1.4 (git+https://github.com/oli-obk/stacker.git)" = "" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 39f1f0f155afa..40a888e475e18 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -34,7 +34,7 @@ byteorder = { version = "1.1", features = ["i128"]} chalk-engine = { version = "0.8.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.5", features = ["union"] } -stacker = "0.1.3" +stacker = { git = "https://github.com/oli-obk/stacker.git" } # Note that these dependencies are a lie, they're just here to get linkage to # work. diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index 7f58b440a833e..0fbd940b79563 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -17,6 +17,7 @@ use std::path::Path; /// List of whitelisted sources for packages const WHITELISTED_SOURCES: &[&str] = &[ "\"registry+https://github.com/rust-lang/crates.io-index\"", + "\"git+https://github.com/oli-obk/stacker.git#30b32ea0514bac734539eccd4157e6d8684abcb6\"", ]; /// check for external package sources