]> git.lizzy.rs Git - rust.git/commitdiff
Prevent stack overflow for deeply recursive code
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Fri, 2 Nov 2018 15:14:24 +0000 (16:14 +0100)
committerMateusz Mikuła <mati865@gmail.com>
Sat, 2 May 2020 14:37:57 +0000 (16:37 +0200)
14 files changed:
Cargo.lock
src/librustc_ast_lowering/expr.rs
src/librustc_ast_lowering/pat.rs
src/librustc_interface/util.rs
src/librustc_middle/Cargo.toml
src/librustc_middle/middle/limits.rs
src/librustc_middle/ty/inhabitedness/mod.rs
src/librustc_middle/ty/query/plumbing.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir_build/build/expr/as_temp.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_trait_selection/traits/query/normalize.rs
src/librustc_trait_selection/traits/select.rs
src/librustc_traits/dropck_outlives.rs

index 8bd1e5f3308b443f69267f5129e991ba06281e7f..7231bedb6ae8b077725cde8ea30bc98f6b7d3b1e 100644 (file)
@@ -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"
index cbe192d35e5934cb748fb3f5add321c4220fba48..b295da8ecb95256b49a7bfe6351a3da3512c03b2 100644 (file)
@@ -7,6 +7,7 @@
 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,192 +21,206 @@ pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {
     }
 
     pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
-        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)),
-            ExprKind::Repeat(ref expr, ref count) => {
-                let expr = self.lower_expr(expr);
-                let count = self.lower_anon_const(count);
-                hir::ExprKind::Repeat(expr, count)
-            }
-            ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
-            ExprKind::Call(ref f, ref args) => {
-                let f = self.lower_expr(f);
-                hir::ExprKind::Call(f, self.lower_exprs(args))
-            }
-            ExprKind::MethodCall(ref seg, ref args) => {
-                let hir_seg = self.arena.alloc(self.lower_path_segment(
-                    e.span,
-                    seg,
-                    ParamMode::Optional,
-                    0,
-                    ParenthesizedGenericArgs::Err,
-                    ImplTraitContext::disallowed(),
-                    None,
-                ));
-                let args = self.lower_exprs(args);
-                hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
-            }
-            ExprKind::Binary(binop, ref lhs, ref rhs) => {
-                let binop = self.lower_binop(binop);
-                let lhs = self.lower_expr(lhs);
-                let rhs = self.lower_expr(rhs);
-                hir::ExprKind::Binary(binop, lhs, rhs)
-            }
-            ExprKind::Unary(op, ref ohs) => {
-                let op = self.lower_unop(op);
-                let ohs = self.lower_expr(ohs);
-                hir::ExprKind::Unary(op, ohs)
-            }
-            ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.kind.clone())),
-            ExprKind::Cast(ref expr, ref ty) => {
-                let expr = self.lower_expr(expr);
-                let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
-                hir::ExprKind::Cast(expr, ty)
-            }
-            ExprKind::Type(ref expr, ref ty) => {
-                let expr = self.lower_expr(expr);
-                let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
-                hir::ExprKind::Type(expr, ty)
-            }
-            ExprKind::AddrOf(k, m, ref ohs) => {
-                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::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| {
-                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)
-            }),
-            ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
-            ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
-                self.lower_expr(expr),
-                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(
-                capture_clause,
-                closure_node_id,
-                None,
-                block.span,
-                hir::AsyncGeneratorKind::Block,
-                |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
-            ),
-            ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
-            ExprKind::Closure(
-                capture_clause,
-                asyncness,
-                movability,
-                ref decl,
-                ref body,
-                fn_decl_span,
-            ) => {
-                if let Async::Yes { closure_id, .. } = asyncness {
-                    self.lower_expr_async_closure(
-                        capture_clause,
-                        closure_id,
-                        decl,
-                        body,
-                        fn_decl_span,
+        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)),
+                ExprKind::Repeat(ref expr, ref count) => {
+                    let expr = self.lower_expr(expr);
+                    let count = self.lower_anon_const(count);
+                    hir::ExprKind::Repeat(expr, count)
+                }
+                ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
+                ExprKind::Call(ref f, ref args) => {
+                    let f = self.lower_expr(f);
+                    hir::ExprKind::Call(f, self.lower_exprs(args))
+                }
+                ExprKind::MethodCall(ref seg, ref args) => {
+                    let hir_seg = self.arena.alloc(self.lower_path_segment(
+                        e.span,
+                        seg,
+                        ParamMode::Optional,
+                        0,
+                        ParenthesizedGenericArgs::Err,
+                        ImplTraitContext::disallowed(),
+                        None,
+                    ));
+                    let args = self.lower_exprs(args);
+                    hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
+                }
+                ExprKind::Binary(binop, ref lhs, ref rhs) => {
+                    let binop = self.lower_binop(binop);
+                    let lhs = self.lower_expr(lhs);
+                    let rhs = self.lower_expr(rhs);
+                    hir::ExprKind::Binary(binop, lhs, rhs)
+                }
+                ExprKind::Unary(op, ref ohs) => {
+                    let op = self.lower_unop(op);
+                    let ohs = self.lower_expr(ohs);
+                    hir::ExprKind::Unary(op, ohs)
+                }
+                ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.kind.clone())),
+                ExprKind::Cast(ref expr, ref ty) => {
+                    let expr = self.lower_expr(expr);
+                    let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+                    hir::ExprKind::Cast(expr, ty)
+                }
+                ExprKind::Type(ref expr, ref ty) => {
+                    let expr = self.lower_expr(expr);
+                    let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+                    hir::ExprKind::Type(expr, ty)
+                }
+                ExprKind::AddrOf(k, m, ref ohs) => {
+                    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::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| {
+                        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,
                     )
-                } else {
-                    self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span)
+                }),
+                ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
+                ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
+                    self.lower_expr(expr),
+                    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(
+                        capture_clause,
+                        closure_node_id,
+                        None,
+                        block.span,
+                        hir::AsyncGeneratorKind::Block,
+                        |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
+                    ),
+                ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
+                ExprKind::Closure(
+                    capture_clause,
+                    asyncness,
+                    movability,
+                    ref decl,
+                    ref body,
+                    fn_decl_span,
+                ) => {
+                    if let Async::Yes { closure_id, .. } = asyncness {
+                        self.lower_expr_async_closure(
+                            capture_clause,
+                            closure_id,
+                            decl,
+                            body,
+                            fn_decl_span,
+                        )
+                    } else {
+                        self.lower_expr_closure(
+                            capture_clause,
+                            movability,
+                            decl,
+                            body,
+                            fn_decl_span,
+                        )
+                    }
                 }
-            }
-            ExprKind::Block(ref blk, opt_label) => {
-                hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
-            }
-            ExprKind::Assign(ref el, ref er, span) => {
-                hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span)
-            }
-            ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
-                self.lower_binop(op),
-                self.lower_expr(el),
-                self.lower_expr(er),
-            ),
-            ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident),
-            ExprKind::Index(ref el, ref er) => {
-                hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
-            }
-            ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
-                self.lower_expr_range_closed(e.span, e1, e2)
-            }
-            ExprKind::Range(ref e1, ref e2, lims) => {
-                self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
-            }
-            ExprKind::Path(ref qself, ref path) => {
-                let qpath = self.lower_qpath(
-                    e.id,
-                    qself,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-                hir::ExprKind::Path(qpath)
-            }
-            ExprKind::Break(opt_label, ref opt_expr) => {
-                let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));
-                hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr)
-            }
-            ExprKind::Continue(opt_label) => {
-                hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label))
-            }
-            ExprKind::Ret(ref e) => {
-                let e = e.as_ref().map(|x| self.lower_expr(x));
-                hir::ExprKind::Ret(e)
-            }
-            ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_asm(asm),
-            ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
-                let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x));
-                hir::ExprKind::Struct(
-                    self.arena.alloc(self.lower_qpath(
+                ExprKind::Block(ref blk, opt_label) => {
+                    hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
+                }
+                ExprKind::Assign(ref el, ref er, span) => {
+                    hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span)
+                }
+                ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
+                    self.lower_binop(op),
+                    self.lower_expr(el),
+                    self.lower_expr(er),
+                ),
+                ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident),
+                ExprKind::Index(ref el, ref er) => {
+                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
+                }
+                ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
+                    self.lower_expr_range_closed(e.span, e1, e2)
+                }
+                ExprKind::Range(ref e1, ref e2, lims) => {
+                    self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
+                }
+                ExprKind::Path(ref qself, ref path) => {
+                    let qpath = self.lower_qpath(
                         e.id,
-                        &None,
+                        qself,
                         path,
                         ParamMode::Optional,
                         ImplTraitContext::disallowed(),
-                    )),
-                    self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))),
-                    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;
+                    );
+                    hir::ExprKind::Path(qpath)
+                }
+                ExprKind::Break(opt_label, ref opt_expr) => {
+                    let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));
+                    hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr)
+                }
+                ExprKind::Continue(opt_label) => {
+                    hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label))
+                }
+                ExprKind::Ret(ref e) => {
+                    let e = e.as_ref().map(|x| self.lower_expr(x));
+                    hir::ExprKind::Ret(e)
+                }
+                ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_asm(asm),
+                ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
+                    let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x));
+                    hir::ExprKind::Struct(
+                        self.arena.alloc(self.lower_qpath(
+                            e.id,
+                            &None,
+                            path,
+                            ParamMode::Optional,
+                            ImplTraitContext::disallowed(),
+                        )),
+                        self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))),
+                        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.
+                    if e.span.contains(ex.span) {
+                        ex.span = e.span;
+                    }
+                    // Merge attributes into the inner expression.
+                    let mut attrs = e.attrs.clone();
+                    attrs.extend::<Vec<_>>(ex.attrs.into());
+                    ex.attrs = attrs;
+                    return ex;
                 }
-                // Merge attributes into the inner expression.
-                let mut attrs = e.attrs.clone();
-                attrs.extend::<Vec<_>>(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 <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::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
+            };
 
-            // 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);
+            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::<Vec<_>>().into(),
             }
-            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::<Vec<_>>().into(),
-        }
+        })
     }
 
     fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
index 28469dc5367be851b685d5a6152019f6835f469a..614450ed7cf7f0c033d35ad444b5192ad35213d4 100644 (file)
@@ -4,81 +4,87 @@
 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> {
-        let node = 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));
-                let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
-                node
-            }
-            PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
-            PatKind::TupleStruct(ref path, ref pats) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    &None,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-                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::Path(ref qself, ref path) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    qself,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-                hir::PatKind::Path(qpath)
-            }
-            PatKind::Struct(ref path, ref fields, etc) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    &None,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
+        ensure_sufficient_stack(|| {
+            let node = 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));
+                    let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
+                    node
+                }
+                PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
+                PatKind::TupleStruct(ref path, ref pats) => {
+                    let qpath = self.lower_qpath(
+                        p.id,
+                        &None,
+                        path,
+                        ParamMode::Optional,
+                        ImplTraitContext::disallowed(),
+                    );
+                    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::Path(ref qself, ref path) => {
+                    let qpath = self.lower_qpath(
+                        p.id,
+                        qself,
+                        path,
+                        ParamMode::Optional,
+                        ImplTraitContext::disallowed(),
+                    );
+                    hir::PatKind::Path(qpath)
+                }
+                PatKind::Struct(ref path, ref fields, etc) => {
+                    let qpath = self.lower_qpath(
+                        p.id,
+                        &None,
+                        path,
+                        ParamMode::Optional,
+                        ImplTraitContext::disallowed(),
+                    );
 
-                let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
-                    hir_id: self.next_id(),
-                    ident: f.ident,
-                    pat: self.lower_pat(&f.pat),
-                    is_shorthand: f.is_shorthand,
-                    span: f.span,
-                }));
-                hir::PatKind::Struct(qpath, fs, etc)
-            }
-            PatKind::Tuple(ref pats) => {
-                let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
-                hir::PatKind::Tuple(pats, ddpos)
-            }
-            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(
-                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)
-            }
-            PatKind::Paren(ref inner) => return self.lower_pat(inner),
-            PatKind::MacCall(_) => panic!("Shouldn't exist here"),
-        };
+                    let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
+                        hir_id: self.next_id(),
+                        ident: f.ident,
+                        pat: self.lower_pat(&f.pat),
+                        is_shorthand: f.is_shorthand,
+                        span: f.span,
+                    }));
+                    hir::PatKind::Struct(qpath, fs, etc)
+                }
+                PatKind::Tuple(ref pats) => {
+                    let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
+                    hir::PatKind::Tuple(pats, ddpos)
+                }
+                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(
+                        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", p.span),
+            };
 
-        self.pat_with_node_id_of(p, node)
+            self.pat_with_node_id_of(p, node)
+        })
     }
 
     fn lower_pat_tuple(
index 72c25270a5d6918b662877de71ccc17f3c619152..01d92f3d8699d64e6ec90153982049fcc9d03df1 100644 (file)
@@ -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
index 398ba4d72d44901ea2213c88aa4b2b39d6053ec8..6d3980ef68989ff641b5025c5ebfce07957f5a97 100644 (file)
@@ -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"
index c43c22cd61ba64eb107af9e0ebbc58ef308af0e6..8704c4c46aa9cc3ea88730b9b5dd49773efc9d63 100644 (file)
 
 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);
index b166c4dea0c850f1e50259a2044cbdc3fed74c95..35b5bde7c9e1e6429e86bae58f72332b4a35c811 100644 (file)
@@ -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),
 
index d6d4335e9388d7bdaf653b2ea0a0f210225f7edd..76e5a65472ebee70009dedc2ceef8f03e39492de 100644 (file)
@@ -68,7 +68,9 @@ fn start_query<R>(
             };
 
             // 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))
+            })
         })
     }
 }
index dfcd2c3c93600d85a82d319167b5c996008d062e..6c844dd407b8c1ca507735e59b98033332cb9fda 100644 (file)
@@ -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);
 
-            collect_neighbours(tcx, instance, &mut neighbors);
+            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() {
-                collect_miri(tcx, inner, output);
+                rustc_middle::limits::ensure_sufficient_stack(|| {
+                    collect_miri(tcx, inner, output);
+                });
             }
         }
         Some(GlobalAlloc::Function(fn_instance)) => {
index b4ef536afb7409ba9de0168d1a5354585915d583..ccd6829b65397f82c6ae7f2e2431c55e71c62a11 100644 (file)
@@ -4,6 +4,7 @@
 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(
index 2b4a0409fd1e23a2e90f95d3e34f6ad318259e8e..7621516a73217eec99c147d7f0ec2c30f057c251 100644 (file)
@@ -20,6 +20,7 @@
 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 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
 {
     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,
index 0da26abc330ac17e2204c463d0859fe2009287a7..98693d21d7ffbb7a4266ea1804cfdec3fcccab19 100644 (file)
@@ -8,6 +8,7 @@
 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 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'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
                     }
index dfbb07424487d43a786ec1c62a117a8fb71cb62f..adb1997502d510f8692f43e7d1cfac714cead20e 100644 (file)
@@ -42,6 +42,7 @@
 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 @@ fn collect_predicates_for_types(
                 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,
@@ -2525,13 +2528,15 @@ fn confirm_builtin_candidate(
             };
 
             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![]
         };
@@ -2568,38 +2573,39 @@ fn vtable_auto_impl(
         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,
+                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<PredicateObligation<'_>> =
-            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<PredicateObligation<'_>> =
+                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(
@@ -2615,13 +2621,15 @@ fn confirm_impl_candidate(
             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,
+                )
+            })
         })
     }
 
@@ -2734,13 +2742,15 @@ fn confirm_fn_pointer_candidate(
         )
         .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(),
@@ -2798,13 +2808,15 @@ fn confirm_generator_candidate(
         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(
-            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={:?}, \
@@ -2843,13 +2855,15 @@ fn confirm_closure_candidate(
         };
 
         let trait_ref = self.closure_trait_ref_unnormalized(obligation, 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={:?})",
@@ -3139,15 +3153,17 @@ fn confirm_builtin_unsize_candidate(
                 nested.extend(obligations);
 
                 // Construct the nested `T: Unsize<U>` 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!(),
@@ -3208,13 +3224,15 @@ fn match_impl(
         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={:?}, \
index 93b15e146ec1071dc3743fffe5dd4c2e7d9ccc47..460b84e6326c05ad3475f663df962b60755dba85 100644 (file)
@@ -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