diff --git a/Cargo.lock b/Cargo.lock index 5fc3a5ac71722..7f1d44eca7b9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3930,7 +3930,6 @@ dependencies = [ "rustc_serialize", "rustc_thread_pool", "smallvec", - "stacker", "tempfile", "thin-vec", "tracing", @@ -4601,7 +4600,6 @@ dependencies = [ "rustc_abi", "rustc_apfloat", "rustc_arena", - "rustc_data_structures", "rustc_errors", "rustc_hir", "rustc_index", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 110c64c103acb..0acd2c28ff7ef 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -26,7 +26,6 @@ pub use UnsafeSource::*; pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, StableHash, Walkable}; pub use rustc_span::AttrId; @@ -2447,7 +2446,7 @@ pub struct Ty { impl Clone for Ty { fn clone(&self) -> Self { - ensure_sufficient_stack(|| Self { id: self.id, kind: self.kind.clone(), span: self.span }) + Self { id: self.id, kind: self.kind.clone(), span: self.span } } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b173130d2cc98..003ca39a5bda9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::*; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::msg; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; @@ -162,352 +161,331 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { - ensure_sufficient_stack(|| { - let mut span = self.lower_span(e.span); - match &e.kind { - // Parenthesis expression does not have a HirId and is handled specially. - ExprKind::Paren(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 = self.lower_span(e.span.with_ctxt(ex.span.ctxt())); - } - // Merge attributes into the inner expression. - if !e.attrs.is_empty() { - let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); - let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) - .into_iter() - .chain(old_attrs.iter().cloned()); - let new_attrs = &*self.arena.alloc_from_iter(new_attrs); - if new_attrs.is_empty() { - return ex; - } - self.attrs.insert(ex.hir_id.local_id, new_attrs); - } - return ex; + let mut span = self.lower_span(e.span); + match &e.kind { + // Parenthesis expression does not have a HirId and is handled specially. + ExprKind::Paren(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 = self.lower_span(e.span.with_ctxt(ex.span.ctxt())); } - // Desugar `ExprForLoop` - // from: `[opt_ident]: for await? in ` - // - // This also needs special handling because the HirId of the returned `hir::Expr` will not - // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself. - ExprKind::ForLoop(ForLoop { pat, iter, body, label, kind }) => { - return self.lower_expr_for(e, pat, iter, body, *label, *kind); + // Merge attributes into the inner expression. + if !e.attrs.is_empty() { + let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); + let new_attrs = self + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) + .into_iter() + .chain(old_attrs.iter().cloned()); + let new_attrs = &*self.arena.alloc_from_iter(new_attrs); + if new_attrs.is_empty() { + return ex; + } + self.attrs.insert(ex.hir_id.local_id, new_attrs); } - ExprKind::Closure(closure) => return self.lower_expr_closure_expr(e, closure), - _ => (), + return ex; } + // Desugar `ExprForLoop` + // from: `[opt_ident]: for await? in ` + // + // This also needs special handling because the HirId of the returned `hir::Expr` will not + // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself. + ExprKind::ForLoop(ForLoop { pat, iter, body, label, kind }) => { + return self.lower_expr_for(e, pat, iter, body, *label, *kind); + } + ExprKind::Closure(closure) => return self.lower_expr_closure_expr(e, closure), + _ => (), + } - let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); + let expr_hir_id = self.lower_node_id(e.id); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); - let kind = match &e.kind { - ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), - ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)), - ExprKind::Repeat(expr, count) => { - let expr = self.lower_expr(expr); - let count = self.lower_array_length_to_const_arg(count); - hir::ExprKind::Repeat(expr, count) + let kind = match &e.kind { + ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), + ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)), + ExprKind::Repeat(expr, count) => { + let expr = self.lower_expr(expr); + let count = self.lower_array_length_to_const_arg(count); + hir::ExprKind::Repeat(expr, count) + } + ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), + ExprKind::Call(f, args) => { + if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx) { + self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) + } else { + let f = self.lower_expr(f); + hir::ExprKind::Call(f, self.lower_exprs(args)) } - ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), - ExprKind::Call(f, args) => { - if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx) - { - self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) - } else { - let f = self.lower_expr(f); - hir::ExprKind::Call(f, self.lower_exprs(args)) - } + } + ExprKind::MethodCall(MethodCall { seg, receiver, args, span }) => { + let hir_seg = self.arena.alloc(self.lower_path_segment( + e.span, + seg, + ParamMode::Optional, + GenericArgsMode::Err, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + // Method calls can't have bound modifiers + None, + )); + let receiver = self.lower_expr(receiver); + let args = self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x))); + hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span)) + } + ExprKind::Binary(binop, lhs, 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, ohs) => { + let op = self.lower_unop(*op); + let ohs = self.lower_expr(ohs); + hir::ExprKind::Unary(op, ohs) + } + ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), + ExprKind::IncludedBytes(byte_sym) => { + let lit = + respan(self.lower_span(e.span), LitKind::ByteStr(*byte_sym, StrStyle::Cooked)); + hir::ExprKind::Lit(lit) + } + ExprKind::Cast(expr, ty) => { + let expr = self.lower_expr(expr); + let ty = + self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + hir::ExprKind::Cast(expr, ty) + } + ExprKind::Type(expr, ty) => { + let expr = self.lower_expr(expr); + let ty = + self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + hir::ExprKind::Type(expr, ty) + } + ExprKind::AddrOf(k, m, ohs) => { + let ohs = self.lower_expr(ohs); + hir::ExprKind::AddrOf(*k, *m, ohs) + } + ExprKind::Let(pat, scrutinee, span, recovered) => { + hir::ExprKind::Let(self.arena.alloc(hir::LetExpr { + span: self.lower_span(*span), + pat: self.lower_pat(pat), + ty: None, + init: self.lower_expr(scrutinee), + recovered: *recovered, + })) + } + ExprKind::If(cond, then, else_opt) => { + self.lower_expr_if(cond, then, else_opt.as_deref()) + } + ExprKind::While(cond, body, opt_label) => self.with_loop_scope(expr_hir_id, |this| { + let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }), + ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(expr_hir_id, |this| { + let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, + this.lower_span(*span), + ) + }), + ExprKind::TryBlock(body, opt_ty) => self.lower_expr_try_block(body, opt_ty.as_deref()), + ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( + self.lower_expr(expr), + self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), + match kind { + MatchKind::Prefix => hir::MatchSource::Normal, + MatchKind::Postfix => hir::MatchSource::Postfix, + }, + ), + ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), + ExprKind::Move(inner, move_kw_span) => { + if !self.tcx.features().move_expr() { + return self.expr_err(*move_kw_span, self.dcx().has_errors().unwrap()); } - ExprKind::MethodCall(MethodCall { seg, receiver, args, span }) => { - let hir_seg = self.arena.alloc(self.lower_path_segment( - e.span, - seg, - ParamMode::Optional, - GenericArgsMode::Err, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - // Method calls can't have bound modifiers + if let Some(state) = self.move_expr_bindings.last().and_then(Option::as_ref) { + let existing = state.bindings.get(&e.id).copied(); + let (ident, binding) = existing.unwrap_or_else(|| { + for nested in MoveExprInitializerFinder::collect(inner) { + self.record_move_expr( + nested.id, + nested.expr, + nested.move_kw_span, + false, + ); + } + self.record_move_expr(e.id, inner, *move_kw_span, true) + }); + hir::ExprKind::Path(hir::QPath::Resolved( None, - )); - let receiver = self.lower_expr(receiver); - let args = - self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x))); - hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(*span)) - } - ExprKind::Binary(binop, lhs, 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, ohs) => { - let op = self.lower_unop(*op); - let ohs = self.lower_expr(ohs); - hir::ExprKind::Unary(op, ohs) - } - ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)), - ExprKind::IncludedBytes(byte_sym) => { - let lit = respan( - self.lower_span(e.span), - LitKind::ByteStr(*byte_sym, StrStyle::Cooked), - ); - hir::ExprKind::Lit(lit) - } - ExprKind::Cast(expr, ty) => { - let expr = self.lower_expr(expr); - let ty = self - .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); - hir::ExprKind::Cast(expr, ty) - } - ExprKind::Type(expr, ty) => { - let expr = self.lower_expr(expr); - let ty = self - .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); - hir::ExprKind::Type(expr, ty) - } - ExprKind::AddrOf(k, m, ohs) => { - let ohs = self.lower_expr(ohs); - hir::ExprKind::AddrOf(*k, *m, ohs) - } - ExprKind::Let(pat, scrutinee, span, recovered) => { - hir::ExprKind::Let(self.arena.alloc(hir::LetExpr { - span: self.lower_span(*span), - pat: self.lower_pat(pat), - ty: None, - init: self.lower_expr(scrutinee), - recovered: *recovered, - })) - } - ExprKind::If(cond, then, else_opt) => { - self.lower_expr_if(cond, then, else_opt.as_deref()) - } - ExprKind::While(cond, body, opt_label) => { - self.with_loop_scope(expr_hir_id, |this| { - let span = - this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); - let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); - this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) - }) - } - ExprKind::Loop(body, opt_label, span) => { - self.with_loop_scope(expr_hir_id, |this| { - let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id); - hir::ExprKind::Loop( - this.lower_block(body, false), - opt_label, - hir::LoopSource::Loop, - this.lower_span(*span), - ) - }) - } - ExprKind::TryBlock(body, opt_ty) => { - self.lower_expr_try_block(body, opt_ty.as_deref()) + self.arena.alloc(hir::Path { + span: self.lower_span(e.span), + res: Res::Local(binding), + segments: arena_vec![ + self; + hir::PathSegment::new( + self.lower_ident(ident), + self.next_id(), + Res::Local(binding), + ) + ], + }), + )) + } else { + let guar = + self.dcx().emit_err(MoveExprOnlyInPlainClosures { span: *move_kw_span }); + hir::ExprKind::Err(guar) } - ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match( - self.lower_expr(expr), - self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), - match kind { - MatchKind::Prefix => hir::MatchSource::Normal, - MatchKind::Postfix => hir::MatchSource::Postfix, + } + ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), + ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { + let desugaring_kind = match genblock_kind { + GenBlockKind::Async => hir::CoroutineDesugaring::Async, + GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, + GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen, + }; + self.make_desugared_coroutine_expr( + *capture_clause, + e.id, + None, + *decl_span, + e.span, + desugaring_kind, + hir::CoroutineSource::Block, + |this| { + this.with_new_scopes(e.span, |this| { + let (expr, _) = this + .with_move_expr_bindings(None, |this| this.lower_block_expr(block)); + expr + }) }, + ) + } + ExprKind::Block(blk, opt_label) => { + // Different from loops, label of block resolves to block id rather than + // expr node id. + let block_hir_id = self.lower_node_id(blk.id); + let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); + let hir_block = self.arena.alloc(self.lower_block_noalloc( + block_hir_id, + blk, + opt_label.is_some(), + )); + hir::ExprKind::Block(hir_block, opt_label) + } + ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), + ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( + self.lower_assign_op(*op), + self.lower_expr(el), + self.lower_expr(er), + ), + ExprKind::Field(el, ident) => { + hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident)) + } + ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index( + self.lower_expr(el), + self.lower_expr(er), + self.lower_span(*brackets_span), + ), + ExprKind::Range(e1, e2, lims) => { + span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None); + self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims) + } + ExprKind::Underscore => { + let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span }); + hir::ExprKind::Err(guar) + } + ExprKind::Path(qself, path) => { + let qpath = self.lower_qpath( + e.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + hir::ExprKind::Path(qpath) + } + ExprKind::Break(opt_label, 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(e) => { + let expr = e.as_ref().map(|x| self.lower_expr(x)); + self.checked_return(expr) + } + ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), + ExprKind::Become(sub_expr) => { + let sub_expr = self.lower_expr(sub_expr); + hir::ExprKind::Become(sub_expr) + } + ExprKind::InlineAsm(asm) => { + hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) + } + ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), + ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( + self.lower_ty_alloc( + container, + ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), ), - ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), - ExprKind::Move(inner, move_kw_span) => { - if !self.tcx.features().move_expr() { - return self.expr_err(*move_kw_span, self.dcx().has_errors().unwrap()); - } - if let Some(state) = self.move_expr_bindings.last().and_then(Option::as_ref) { - let existing = state.bindings.get(&e.id).copied(); - let (ident, binding) = existing.unwrap_or_else(|| { - for nested in MoveExprInitializerFinder::collect(inner) { - self.record_move_expr( - nested.id, - nested.expr, - nested.move_kw_span, - false, - ); - } - self.record_move_expr(e.id, inner, *move_kw_span, true) - }); - hir::ExprKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - span: self.lower_span(e.span), - res: Res::Local(binding), - segments: arena_vec![ - self; - hir::PathSegment::new( - self.lower_ident(ident), - self.next_id(), - Res::Local(binding), - ) - ], - }), - )) - } else { - let guar = self - .dcx() - .emit_err(MoveExprOnlyInPlainClosures { span: *move_kw_span }); - hir::ExprKind::Err(guar) - } - } - ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), - ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { - let desugaring_kind = match genblock_kind { - GenBlockKind::Async => hir::CoroutineDesugaring::Async, - GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, - GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen, - }; - self.make_desugared_coroutine_expr( - *capture_clause, - e.id, - None, - *decl_span, - e.span, - desugaring_kind, - hir::CoroutineSource::Block, - |this| { - this.with_new_scopes(e.span, |this| { - let (expr, _) = this.with_move_expr_bindings(None, |this| { - this.lower_block_expr(block) - }); - expr - }) - }, - ) - } - ExprKind::Block(blk, opt_label) => { - // Different from loops, label of block resolves to block id rather than - // expr node id. - let block_hir_id = self.lower_node_id(blk.id); - let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id); - let hir_block = self.arena.alloc(self.lower_block_noalloc( - block_hir_id, - blk, - opt_label.is_some(), - )); - hir::ExprKind::Block(hir_block, opt_label) - } - ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span), - ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp( - self.lower_assign_op(*op), - self.lower_expr(el), - self.lower_expr(er), - ), - ExprKind::Field(el, ident) => { - hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident)) - } - ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index( - self.lower_expr(el), - self.lower_expr(er), - self.lower_span(*brackets_span), - ), - ExprKind::Range(e1, e2, lims) => { - span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None); - self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims) - } - ExprKind::Underscore => { - let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span }); - hir::ExprKind::Err(guar) - } - ExprKind::Path(qself, path) => { - let qpath = self.lower_qpath( + self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), + ), + ExprKind::Struct(se) => { + let rest = match se.rest { + StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)), + StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(self.lower_span(sp)), + StructRest::None => hir::StructTailExpr::None, + StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar), + }; + hir::ExprKind::Struct( + self.arena.alloc(self.lower_qpath( e.id, - qself, - path, + &se.qself, + &se.path, ParamMode::Optional, AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, - ); - hir::ExprKind::Path(qpath) - } - ExprKind::Break(opt_label, 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(e) => { - let expr = e.as_ref().map(|x| self.lower_expr(x)); - self.checked_return(expr) - } - ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), - ExprKind::Become(sub_expr) => { - let sub_expr = self.lower_expr(sub_expr); - hir::ExprKind::Become(sub_expr) - } - ExprKind::InlineAsm(asm) => { - hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) - } - ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), - ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( - self.lower_ty_alloc( - container, - ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), - ), - self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), - ), - ExprKind::Struct(se) => { - let rest = match se.rest { - StructRest::Base(ref e) => hir::StructTailExpr::Base(self.lower_expr(e)), - StructRest::Rest(sp) => { - hir::StructTailExpr::DefaultFields(self.lower_span(sp)) - } - StructRest::None => hir::StructTailExpr::None, - StructRest::NoneWithError(guar) => hir::StructTailExpr::NoneWithError(guar), - }; - hir::ExprKind::Struct( - self.arena.alloc(self.lower_qpath( - e.id, - &se.qself, - &se.path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - )), - self.arena - .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))), - rest, - ) - } - ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)), - ExprKind::Err(guar) => hir::ExprKind::Err(*guar), - - ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( - *kind, - self.lower_expr(expr), - ty.as_ref().map(|ty| { - self.lower_ty_alloc( - ty, - ImplTraitContext::Disallowed(ImplTraitPosition::Cast), - ) - }), - ), + )), + self.arena.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))), + rest, + ) + } + ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)), + ExprKind::Err(guar) => hir::ExprKind::Err(*guar), + + ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( + *kind, + self.lower_expr(expr), + ty.as_ref().map(|ty| { + self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + }), + ), - ExprKind::Dummy => { - span_bug!(e.span, "lowered ExprKind::Dummy") - } + ExprKind::Dummy => { + span_bug!(e.span, "lowered ExprKind::Dummy") + } - ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), + ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), - ExprKind::Paren(_) | ExprKind::ForLoop { .. } | ExprKind::Closure(..) => { - unreachable!("already handled") - } + ExprKind::Paren(_) | ExprKind::ForLoop { .. } | ExprKind::Closure(..) => { + unreachable!("already handled") + } - ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), + ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), - ExprKind::DirectConstArg(expr) => { - let e = self.emit_bad_direct_const_arg(e.span, expr, "expression"); - hir::ExprKind::Err(e) - } - }; + ExprKind::DirectConstArg(expr) => { + let e = self.emit_bad_direct_const_arg(e.span, expr, "expression"); + hir::ExprKind::Err(e) + } + }; - hir::Expr { hir_id: expr_hir_id, kind, span } - }) + hir::Expr { hir_id: expr_hir_id, kind, span } } pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index e14597c04742a..f83658d815bb1 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use rustc_ast::*; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, Target}; @@ -21,141 +20,136 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { - ensure_sufficient_stack(|| { - // loop here to avoid recursion - let pat_hir_id = self.lower_node_id(pattern.id); - let node = loop { - match &pattern.kind { - PatKind::Missing => break hir::PatKind::Missing, - PatKind::Wild => break hir::PatKind::Wild, - PatKind::Never => break hir::PatKind::Never, - PatKind::Ident(binding_mode, ident, sub) => { - let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); - break self.lower_pat_ident( - pattern, - *binding_mode, - *ident, - pat_hir_id, - lower_sub, - ); - } - PatKind::Expr(e) => { - break hir::PatKind::Expr(self.lower_expr_within_pat(e, false)); - } - PatKind::TupleStruct(qself, path, pats) => { - let qpath = self.lower_qpath( - pattern.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); - break hir::PatKind::TupleStruct(qpath, pats, ddpos); - } - PatKind::Or(pats) => { - break hir::PatKind::Or( - self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))), - ); - } - PatKind::Path(qself, path) => { - let qpath = self.lower_qpath( - pattern.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - let kind = hir::PatExprKind::Path(qpath); - let span = self.lower_span(pattern.span); - let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind }; - let expr = self.arena.alloc(expr); - return hir::Pat { - hir_id: self.next_id(), - kind: hir::PatKind::Expr(expr), - span, - default_binding_modes: true, - }; - } - PatKind::Struct(qself, path, fields, etc) => { - let qpath = self.lower_qpath( - pattern.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { - let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField); - - hir::PatField { - hir_id, - ident: self.lower_ident(f.ident), - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: self.lower_span(f.span), - } - })); - break hir::PatKind::Struct( - qpath, - fs, - match etc { - ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), - ast::PatFieldsRest::Recovered(_) => Some(Span::default()), - _ => None, - }, - ); - } - PatKind::Tuple(pats) => { - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); - break hir::PatKind::Tuple(pats, ddpos); - } - PatKind::Box(inner) => { - break hir::PatKind::Box(self.lower_pat(inner)); - } - PatKind::Deref(inner) => { - break hir::PatKind::Deref(self.lower_pat(inner)); - } - PatKind::Ref(inner, pinned, mutbl) => { - break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl); - } - PatKind::Range(e1, e2, Spanned { node: end, .. }) => { - break hir::PatKind::Range( - e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)), - e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)), - self.lower_range_end(end, e2.is_some()), - ); - } - PatKind::Guard(inner, guard) => { - break hir::PatKind::Guard( - self.lower_pat(inner), - self.lower_expr(&guard.cond), - ); - } - PatKind::Slice(pats) => break self.lower_pat_slice(pats), - PatKind::Rest => { - // If we reach here the `..` pattern is not semantically allowed. - break self.ban_illegal_rest_pat(pattern.span); - } - // return inner to be processed in next loop - PatKind::Paren(inner) => pattern = inner, - PatKind::MacCall(_) => { - panic!("{pattern:#?} shouldn't exist here") - } - PatKind::Err(guar) => break hir::PatKind::Err(*guar), + // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); + let node = loop { + match &pattern.kind { + PatKind::Missing => break hir::PatKind::Missing, + PatKind::Wild => break hir::PatKind::Wild, + PatKind::Never => break hir::PatKind::Never, + PatKind::Ident(binding_mode, ident, sub) => { + let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); + break self.lower_pat_ident( + pattern, + *binding_mode, + *ident, + pat_hir_id, + lower_sub, + ); } - }; + PatKind::Expr(e) => { + break hir::PatKind::Expr(self.lower_expr_within_pat(e, false)); + } + PatKind::TupleStruct(qself, path, pats) => { + let qpath = self.lower_qpath( + pattern.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); + break hir::PatKind::TupleStruct(qpath, pats, ddpos); + } + PatKind::Or(pats) => { + break hir::PatKind::Or( + self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))), + ); + } + PatKind::Path(qself, path) => { + let qpath = self.lower_qpath( + pattern.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + let kind = hir::PatExprKind::Path(qpath); + let span = self.lower_span(pattern.span); + let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind }; + let expr = self.arena.alloc(expr); + return hir::Pat { + hir_id: self.next_id(), + kind: hir::PatKind::Expr(expr), + span, + default_binding_modes: true, + }; + } + PatKind::Struct(qself, path, fields, etc) => { + let qpath = self.lower_qpath( + pattern.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); - self.pat_with_node_id_of(pattern, node, pat_hir_id) - }) + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { + let hir_id = self.lower_node_id(f.id); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField); + + hir::PatField { + hir_id, + ident: self.lower_ident(f.ident), + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: self.lower_span(f.span), + } + })); + break hir::PatKind::Struct( + qpath, + fs, + match etc { + ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), + ast::PatFieldsRest::Recovered(_) => Some(Span::default()), + _ => None, + }, + ); + } + PatKind::Tuple(pats) => { + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); + break hir::PatKind::Tuple(pats, ddpos); + } + PatKind::Box(inner) => { + break hir::PatKind::Box(self.lower_pat(inner)); + } + PatKind::Deref(inner) => { + break hir::PatKind::Deref(self.lower_pat(inner)); + } + PatKind::Ref(inner, pinned, mutbl) => { + break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl); + } + PatKind::Range(e1, e2, Spanned { node: end, .. }) => { + break hir::PatKind::Range( + e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)), + e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)), + self.lower_range_end(end, e2.is_some()), + ); + } + PatKind::Guard(inner, guard) => { + break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(&guard.cond)); + } + PatKind::Slice(pats) => break self.lower_pat_slice(pats), + PatKind::Rest => { + // If we reach here the `..` pattern is not semantically allowed. + break self.ban_illegal_rest_pat(pattern.span); + } + // return inner to be processed in next loop + PatKind::Paren(inner) => pattern = inner, + PatKind::MacCall(_) => { + panic!("{pattern:#?} shouldn't exist here") + } + PatKind::Err(guar) => break hir::PatKind::Err(*guar), + } + }; + + self.pat_with_node_id_of(pattern, node, pat_hir_id) } fn lower_pat_tuple( diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 7295df0ab2210..8edab56a0dceb 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,6 +1,5 @@ use rustc_abi::{BackendRepr, FieldIdx, VariantIdx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::layout::{LayoutCx, TyAndLayout}; @@ -106,7 +105,7 @@ fn const_to_valtree_inner<'tcx>( visited.insert(place.clone()); - let result = ensure_sufficient_stack(|| match ty.kind() { + let result = match ty.kind() { ty::FnDef(..) => { *num_nodes += 1; Ok(ty::ValTree::zst(tcx)) @@ -209,7 +208,7 @@ fn const_to_valtree_inner<'tcx>( | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::UnsafeBinder(_) => Err(ValTreeCreationError::NonSupportedType(ty)), - }); + }; visited.remove(place); settled.insert(place.clone(), result); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index bd91b744be0e3..daae72a9b358a 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -28,7 +28,6 @@ smallvec = { version = "1.8.1", features = [ "union", "may_dangle", ] } -stacker = "0.1.17" tempfile = "3.2" thin-vec = "0.2.19" tracing = "0.1" diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index a8af6d4ccc1d2..9714fb2123b08 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -77,7 +77,6 @@ pub mod snapshot_map; pub mod sorted_map; pub mod sso; pub mod stable_hash; -pub mod stack; pub mod steal; pub mod svh; pub mod sync; diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs deleted file mode 100644 index 3d6d000348324..0000000000000 --- a/compiler/rustc_data_structures/src/stack.rs +++ /dev/null @@ -1,22 +0,0 @@ -// 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 - -// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then -// on. This flag has performance relevant characteristics. Don't set it too high. -#[cfg(not(target_os = "aix"))] -const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB -// LLVM for AIX doesn't feature TCO, increase recursion size for workaround. -#[cfg(target_os = "aix")] -const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB - -/// 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. -#[inline] -pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { - stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) -} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c80ffe625f248..63877cb92f1d1 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,6 @@ use rustc_attr_parsing::{ }; use rustc_data_structures::Limit; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; use rustc_feature::Features; use rustc_hir::Target; @@ -2574,7 +2573,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = node.attrs.first() { self.cfg().maybe_emit_expr_attr_err(attr); } - ensure_sufficient_stack(|| self.visit_node(node)) + self.visit_node(node) } fn visit_method_receiver_expr(&mut self, node: &mut ast::Expr) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 37b8b194ed9ac..cbbd66f648eb8 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -9,7 +9,6 @@ use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; @@ -265,13 +264,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.diverges.set(self.function_diverges_because_of_empty_arguments.get()) }; - let ty = ensure_sufficient_stack(|| match &expr.kind { + let ty = match &expr.kind { // Intercept the callee path expr and give it better spans. hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), ) => self.check_expr_path(qpath, expr, call_expr_and_args), _ => self.check_expr_kind(expr, expected), - }); + }; let ty = self.resolve_vars_if_possible(ty); // Warn for non-block expressions with diverging children. diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index c647226106d91..0e4ebdfb90085 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,7 +1,6 @@ use std::mem; use rustc_data_structures::sso::SsoHashMap; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::error::TypeError; @@ -476,7 +475,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { debug!(?self.ambient_variance, "new ambient variance"); // Recursive calls to `relate` can overflow the stack. For example a deeper version of // `ui/associated-consts/issue-93775.rs`. - let r = ensure_sufficient_stack(|| self.relate(a, b)); + let r = self.relate(a, b); self.ambient_variance = old_ambient_variance; r } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 654a782262e22..f6ea8ca19ce69 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -121,7 +121,7 @@ pub(crate) fn check_abi_required_features(sess: &Session) { } pub static STACK_SIZE: OnceLock = OnceLock::new(); -pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024; +pub const DEFAULT_STACK_SIZE: usize = 16 * 1024 * 1024; fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize { // Obey the environment setting or default diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index e7459eb86e4db..40b1d5d737a62 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -6,7 +6,6 @@ use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, AttrVec, HasAttrs}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{BufferedEarlyLint, LintBuffer}; use rustc_feature::Features; use rustc_middle::ty::RegisteredTools; @@ -57,7 +56,7 @@ impl<'ecx, T: EarlyLintPass> EarlyContextAndPass<'ecx, T> { debug!("early context: enter_attrs({:?})", attrs); lint_callback!(self, check_attributes, attrs); - ensure_sufficient_stack(|| f(self)); + f(self); debug!("early context: exit_attrs({:?})", attrs); lint_callback!(self, check_attributes_post, attrs); self.context.builder.pop(push); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 7827253c0bb22..144eb7c87327d 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,5 +1,4 @@ use rustc_abi::FIRST_VARIANT; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -271,135 +270,133 @@ fn structurally_same_type_impl<'tcx>( let is_primitive_or_pointer = |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), ty::RawPtr(..) | ty::Ref(..)); - ensure_sufficient_stack(|| { - match (a.kind(), b.kind()) { - (&ty::Adt(a_def, a_gen_args), &ty::Adt(b_def, b_gen_args)) => { - // Only `repr(C)` types can be compared structurally. - if !(a_def.repr().c() && b_def.repr().c()) { - return false; - } - // If the types differ in their packed-ness, align, or simd-ness they conflict. - let repr_characteristica = - |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd()); - if repr_characteristica(a_def) != repr_characteristica(b_def) { - return false; - } - - // Grab a flattened representation of all fields. - let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter()); - let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter()); - - // Perform a structural comparison for each field. - a_fields.eq_by( - b_fields, - |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { - structurally_same_type_impl( - seen_types, - tcx, - typing_env, - tcx.type_of(a_did).instantiate(tcx, a_gen_args).skip_norm_wip(), - tcx.type_of(b_did).instantiate(tcx, b_gen_args).skip_norm_wip(), - ) - }, - ) + match (a.kind(), b.kind()) { + (&ty::Adt(a_def, a_gen_args), &ty::Adt(b_def, b_gen_args)) => { + // Only `repr(C)` types can be compared structurally. + if !(a_def.repr().c() && b_def.repr().c()) { + return false; } - (ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => { - // For arrays, we also check the length. - a_len == b_len - && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) + // If the types differ in their packed-ness, align, or simd-ness they conflict. + let repr_characteristica = + |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd()); + if repr_characteristica(a_def) != repr_characteristica(b_def) { + return false; } - (ty::Slice(a_ty), ty::Slice(b_ty)) => { - structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) - } - (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { - a_mutbl == b_mutbl - && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) - } - (ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => { - // For structural sameness, we don't need the region to be same. - a_mut == b_mut - && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) - } - (ty::FnDef(..), ty::FnDef(..)) => { - let a_poly_sig = a.fn_sig(tcx); - let b_poly_sig = b.fn_sig(tcx); - - // We don't compare regions, but leaving bound regions around ICEs, so - // we erase them. - let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig); - let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig); - // FIXME(splat): Is splatting ever repr(C)? - // Can two splatted functions to have the same structure? - // Can a splatted and non-splatted function have the same structure? - // For now, we require splatting to match exactly. - if a_sig.splatted() != b_sig.splatted() { - return false; - } + // Grab a flattened representation of all fields. + let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter()); + let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter()); - (a_sig.abi(), a_sig.safety(), a_sig.c_variadic()) - == (b_sig.abi(), b_sig.safety(), b_sig.c_variadic()) - && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b) - }) - && structurally_same_type_impl( + // Perform a structural comparison for each field. + a_fields.eq_by( + b_fields, + |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { + structurally_same_type_impl( seen_types, tcx, typing_env, - a_sig.output(), - b_sig.output(), + tcx.type_of(a_did).instantiate(tcx, a_gen_args).skip_norm_wip(), + tcx.type_of(b_did).instantiate(tcx, b_gen_args).skip_norm_wip(), ) - } - (ty::Tuple(..), ty::Tuple(..)) => { - // Tuples are not `repr(C)` so these cannot be compared structurally. - false - } - // For these, it's not quite as easy to define structural-sameness quite so easily. - // For the purposes of this lint, take the conservative approach and mark them as - // not structurally same. - (ty::Dynamic(..), ty::Dynamic(..)) - | (ty::Error(..), ty::Error(..)) - | (ty::Closure(..), ty::Closure(..)) - | (ty::Coroutine(..), ty::Coroutine(..)) - | (ty::CoroutineWitness(..), ty::CoroutineWitness(..)) - | ( - ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }), - ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }), - ) - | ( - ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }), - ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }), + }, ) - | ( - ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), - ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), - ) => false, + } + (ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => { + // For arrays, we also check the length. + a_len == b_len + && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) + } + (ty::Slice(a_ty), ty::Slice(b_ty)) => { + structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) + } + (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { + a_mutbl == b_mutbl + && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) + } + (ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => { + // For structural sameness, we don't need the region to be same. + a_mut == b_mut + && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty) + } + (ty::FnDef(..), ty::FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); - // These definitely should have been caught above. - (ty::Bool, ty::Bool) - | (ty::Char, ty::Char) - | (ty::Never, ty::Never) - | (ty::Str, ty::Str) => unreachable!(), + // We don't compare regions, but leaving bound regions around ICEs, so + // we erase them. + let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig); + let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig); - // An Adt and a primitive or pointer type. This can be FFI-safe if non-null - // enum layout optimisation is being applied. - (ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => { - if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a) { - a_inner == b - } else { - false - } - } - (_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => { - if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b) { - b_inner == a - } else { - false - } + // FIXME(splat): Is splatting ever repr(C)? + // Can two splatted functions to have the same structure? + // Can a splatted and non-splatted function have the same structure? + // For now, we require splatting to match exactly. + if a_sig.splatted() != b_sig.splatted() { + return false; } - _ => false, + (a_sig.abi(), a_sig.safety(), a_sig.c_variadic()) + == (b_sig.abi(), b_sig.safety(), b_sig.c_variadic()) + && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { + structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b) + }) + && structurally_same_type_impl( + seen_types, + tcx, + typing_env, + a_sig.output(), + b_sig.output(), + ) } - }) + (ty::Tuple(..), ty::Tuple(..)) => { + // Tuples are not `repr(C)` so these cannot be compared structurally. + false + } + // For these, it's not quite as easy to define structural-sameness quite so easily. + // For the purposes of this lint, take the conservative approach and mark them as + // not structurally same. + (ty::Dynamic(..), ty::Dynamic(..)) + | (ty::Error(..), ty::Error(..)) + | (ty::Closure(..), ty::Closure(..)) + | (ty::Coroutine(..), ty::Coroutine(..)) + | (ty::CoroutineWitness(..), ty::CoroutineWitness(..)) + | ( + ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }), + ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }), + ) + | ( + ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }), + ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }), + ) + | ( + ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), + ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }), + ) => false, + + // These definitely should have been caught above. + (ty::Bool, ty::Bool) + | (ty::Char, ty::Char) + | (ty::Never, ty::Never) + | (ty::Str, ty::Str) => unreachable!(), + + // An Adt and a primitive or pointer type. This can be FFI-safe if non-null + // enum layout optimisation is being applied. + (ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => { + if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a) { + a_inner == b + } else { + false + } + } + (_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => { + if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b) { + b_inner == a + } else { + false + } + } + + _ => false, + } } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 05975187b3180..f513374d89950 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -5,7 +5,6 @@ use std::any::Any; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::par_join; use rustc_hir::def_id::{LocalDefId, LocalModId}; use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit}; @@ -160,12 +159,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { - ensure_sufficient_stack(|| { - self.with_lint_attrs(e.hir_id, |cx| { - lint_callback!(cx, check_expr, e); - hir_visit::walk_expr(cx, e); - lint_callback!(cx, check_expr_post, e); - }) + self.with_lint_attrs(e.hir_id, |cx| { + lint_callback!(cx, check_expr, e); + hir_visit::walk_expr(cx, e); + lint_callback!(cx, check_expr_post, e); }) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 0c4e1a85351fd..fa4850599369c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -7,7 +7,6 @@ use rustc_apfloat::Float as _; use rustc_data_structures::Limit; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hash::{StableHash, StableHasher}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hashes::Hash128; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -1080,13 +1079,12 @@ impl<'tcx> TypeFolder> for FreeAliasTypeExpander<'tcx> { } self.depth += 1; - let ty = ensure_sufficient_stack(|| { - self.tcx - .type_of(def_id) - .instantiate(self.tcx, args) - .skip_normalization() - .fold_with(self) - }); + let ty = self + .tcx + .type_of(def_id) + .instantiate(self.tcx, args) + .skip_normalization() + .fold_with(self); self.depth -= 1; ty } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index 80d0e061487a7..1c22058f630d6 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -1,6 +1,5 @@ //! See docs in build/expr/mod.rs -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::HirId; use rustc_middle::middle::region::{Scope, ScopeData, TempLifetime}; use rustc_middle::mir::*; @@ -23,7 +22,7 @@ impl<'a, 'tcx> Builder<'a, '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 - ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr_id, mutability)) + self.as_temp_inner(block, temp_lifetime, expr_id, mutability) } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 977c126e588e3..13a64346c36c4 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -3,7 +3,6 @@ use rustc_abi::FieldIdx; use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_middle::mir::*; @@ -48,10 +47,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let block_and = match expr.kind { ExprKind::Scope { region_scope, hir_id, value } => { let region_scope = (region_scope, source_info); - ensure_sufficient_stack(|| { - this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { - this.expr_into_dest(destination, block, value) - }) + this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| { + this.expr_into_dest(destination, block, value) }) } ExprKind::Block { block: ast_block } => { diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 22da174c5ca77..ddeb9e084b21d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -12,7 +12,6 @@ use std::{debug_assert_matches, mem}; use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; use rustc_middle::middle::region::{self, TempLifetime}; @@ -1747,9 +1746,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { start_block: BasicBlock, candidates: &mut [&mut Candidate<'tcx>], ) -> BasicBlock { - ensure_sufficient_stack(|| { - self.match_candidates_inner(span, scrutinee_span, start_block, candidates) - }) + self.match_candidates_inner(span, scrutinee_span, start_block, candidates) } /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates` diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 057e9e727a39e..a7b6ff87a29fd 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -1,5 +1,4 @@ use rustc_abi::ExternAbi; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Applicability; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::DefKind; @@ -444,14 +443,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'a Expr<'tcx>) { - ensure_sufficient_stack(|| { - if let ExprKind::Become { value } = expr.kind { - let call = &self.thir[value]; - self.check_tail_call(call, expr); - } + if let ExprKind::Become { value } = expr.kind { + let call = &self.thir[value]; + self.check_tail_call(call, expr); + } - visit::walk_expr(self, expr); - }); + visit::walk_expr(self, expr); } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0ca3e26d9867f..29a93e2994d0d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::mem; use rustc_ast::AsmMacro; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagArgValue; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::DefKind; @@ -406,9 +405,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ExprKind::Scope { value, hir_id, region_scope: _ } => { let prev_id = self.hir_context; self.hir_context = hir_id; - ensure_sufficient_stack(|| { - self.visit_expr(&self.thir[value]); - }); + self.visit_expr(&self.thir[value]); self.hir_context = prev_id; return; // don't visit the whole expression } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8e93c50f82005..3cade7d6a0a7a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,7 +1,6 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_ast::UnsafeBinderCastKind; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; @@ -79,15 +78,11 @@ impl<'tcx> ThirBuildCx<'tcx> { /// /// [dev-guide]: https://rustc-dev-guide.rust-lang.org/thir.html pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { - // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. - ensure_sufficient_stack(|| self.mirror_expr_inner(expr)) + self.mirror_expr_inner(expr) } pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { - // `mirror_exprs` may also recurse deeply, so it needs protection from stack overflow. - // Note that we *could* forward to `mirror_expr` for that, but we can consolidate the - // overhead of stack growth by doing it outside the iteration. - ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()) + exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() } #[instrument(level = "trace", skip(self, hir_expr))] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 41806547932cd..62a0cbc24fd73 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,7 +1,6 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, msg, struct_span_code_err}; use rustc_hir::def::*; @@ -200,7 +199,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { let old_let_source = self.let_source; self.let_source = let_source; - ensure_sufficient_stack(|| f(self)); + f(self); self.let_source = old_let_source; } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 5efeb6e7617be..3b5884f5bc5fb 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -4,7 +4,6 @@ use std::ops::Range; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; @@ -699,7 +698,7 @@ impl<'tcx> Map<'tcx> { // We manually iterate instead of using `children` as we need to mutate `self`. let mut next_child = self.places[root].first_child; while let Some(child) = next_child { - ensure_sufficient_stack(|| self.cache_preorder_invoke(child)); + self.cache_preorder_invoke(child); next_child = self.places[child].next_sibling; } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index ce34c6ad07758..dc9cc38fcb733 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -1,6 +1,5 @@ use rustc_data_structures::Limit; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; @@ -118,18 +117,17 @@ fn process<'tcx>( trace!(?callee, recursion = *recursion); let callee_reaches_root = if recursion_limit.value_within_limit(*recursion) { *recursion += 1; - ensure_sufficient_stack(|| { - process( - tcx, - typing_env, - callee, - target, - seen, - involved, - recursion_limiter, - recursion_limit, - ) - })? + + process( + tcx, + typing_env, + callee, + target, + seen, + involved, + recursion_limiter, + recursion_limit, + )? } else { return None; }; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 105c8e0ed7388..1ee6e0506dcdd 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -471,26 +471,24 @@ fn collect_items_rec<'tcx>( recursion_limit, )); - rustc_data_structures::stack::ensure_sufficient_stack(|| { - let Ok((used, mentioned)) = tcx.items_of_instance((instance, mode)) else { - // Normalization errors here are usually due to trait solving overflow. - // FIXME: I assume that there are few type errors at post-analysis stage, but not - // entirely sure. - // We have to emit the error outside of `items_of_instance` to access the - // span of the `starting_item`. - let def_id = instance.def_id(); - let def_span = tcx.def_span(def_id); - let def_path_str = tcx.def_path_str(def_id); - tcx.dcx().emit_fatal(RecursionLimit { - span: starting_item.span, - instance, - def_span, - def_path_str, - }); - }; - used_items.extend(used.into_iter().copied()); - mentioned_items.extend(mentioned.into_iter().copied()); - }); + let Ok((used, mentioned)) = tcx.items_of_instance((instance, mode)) else { + // Normalization errors here are usually due to trait solving overflow. + // FIXME: I assume that there are few type errors at post-analysis stage, but not + // entirely sure. + // We have to emit the error outside of `items_of_instance` to access the + // span of the `starting_item`. + let def_id = instance.def_id(); + let def_span = tcx.def_span(def_id); + let def_path_str = tcx.def_path_str(def_id); + tcx.dcx().emit_fatal(RecursionLimit { + span: starting_item.span, + instance, + def_span, + def_path_str, + }); + }; + used_items.extend(used.into_iter().copied()); + mentioned_items.extend(mentioned.into_iter().copied()); } MonoItem::GlobalAsm(item_id) => { assert!( @@ -1288,13 +1286,10 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt GlobalAlloc::Memory(alloc) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); let ptrs = alloc.inner().provenance().ptrs(); - // avoid `ensure_sufficient_stack` in the common case of "no pointers" if !ptrs.is_empty() { - rustc_data_structures::stack::ensure_sufficient_stack(move || { - for &prov in ptrs.values() { - collect_alloc(tcx, prov.alloc_id(), output); - } - }); + for &prov in ptrs.values() { + collect_alloc(tcx, prov.alloc_id(), output); + } } } GlobalAlloc::Function { instance, .. } => { diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 73d969a398198..32476ed21372b 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -1,6 +1,6 @@ use std::collections::hash_map::Entry; -use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; +use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ @@ -382,7 +382,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { | ty::Alias(_, _) | ty::Bound(_, _) | ty::Error(_) => { - return ensure_sufficient_stack(|| t.super_fold_with(self)); + return t.super_fold_with(self); } }; diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index e2036f0ab0cc3..ff9ed6cb06cfd 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -1,6 +1,5 @@ use std::fmt::Debug; -use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::inherent::*; use rustc_type_ir::{ self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, TypeFoldable, @@ -118,9 +117,8 @@ where let normalized = if ty.has_escaping_bound_vars() { let (alias_ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_ty); - let Some(result) = ensure_sufficient_stack(|| { - self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes) - })? + let Some(result) = + self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes)? else { return Ok(ty); }; @@ -134,11 +132,9 @@ where result.expect_ty(), ) } else { - ensure_sufficient_stack(|| { - self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No) - })? - .map(|term| term.expect_ty()) - .unwrap_or(ty) + self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No)? + .map(|term| term.expect_ty()) + .unwrap_or(ty) }; if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { @@ -172,9 +168,8 @@ where let normalized = if ct.has_escaping_bound_vars() { let (alias_const, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_const); - let Some(result) = ensure_sufficient_stack(|| { - self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::Yes) - })? + let Some(result) = + self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::Yes)? else { return Ok(ct); }; @@ -187,11 +182,9 @@ where result.expect_const(), ) } else { - ensure_sufficient_stack(|| { - self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::No) - })? - .map(|term| term.expect_const()) - .unwrap_or(ct) + self.normalize_alias_term(alias_const.into(), HasEscapingBoundVars::No)? + .map(|term| term.expect_const()) + .unwrap_or(ct) }; if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index fb44782ffb039..ac9d6ca02893c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,7 +1,6 @@ use std::convert::Infallible; use std::marker::PhantomData; -use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{ AccessedOpaques, CanonicalInput, Certainty, NoSolution, QueryResult, RerunResultExt, @@ -133,14 +132,12 @@ where input: CanonicalInput, inspect: &mut Self::ProofTreeBuilder, ) -> (QueryResult, AccessedOpaques) { - ensure_sufficient_stack(|| { - EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| { - // if we're in `RerunNonErased`, don't even bother with inspect, and immediately return - let result = ecx.compute_goal(goal).map_err_to_rerun()?; - - ecx.inspect.query_result(result); - result.map_err(Into::into) - }) + EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| { + // if we're in `RerunNonErased`, don't even bother with inspect, and immediately return + let result = ecx.compute_goal(goal).map_err_to_rerun()?; + + ecx.inspect.query_result(result); + result.map_err(Into::into) }) } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index af20b0957ecee..f81727eda4fb6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -18,7 +18,6 @@ use rustc_ast::{ Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_ast_pretty::pprust; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_literal_escaper::unescape_char; use rustc_session::diagnostics::report_lit_error; @@ -912,49 +911,46 @@ impl<'a> Parser<'a> { mut e: Box, lo: Span, ) -> PResult<'a, Box> { - let mut res = ensure_sufficient_stack(|| { - loop { - let has_question = - if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // We are using noexpect here because we don't expect a `?` directly after - // a `return` which could be suggested otherwise. - self.eat_noexpect(&token::Question) - } else { - self.eat(exp!(Question)) - }; - if has_question { - // `expr?` - e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); - continue; - } - let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // We are using noexpect here because we don't expect a `.` directly after - // a `return` which could be suggested otherwise. - self.eat_noexpect(&token::Dot) - } else if self.token == TokenKind::RArrow && self.may_recover() { - // Recovery for `expr->suffix`. - self.bump(); - let span = self.prev_token.span; - self.dcx().emit_err(diagnostics::ExprRArrowCall { span }); - true - } else { - self.eat(exp!(Dot)) - }; - if has_dot { - // expr.f - e = self.parse_dot_suffix_expr(lo, e)?; - continue; - } - if self.expr_is_complete(&e) { - return Ok(e); - } - e = match self.token.kind { - token::OpenParen => self.parse_expr_fn_call(lo, e), - token::OpenBracket => self.parse_expr_index(lo, e)?, - _ => return Ok(e), - } + let mut res = loop { + let has_question = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `?` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Question) + } else { + self.eat(exp!(Question)) + }; + if has_question { + // `expr?` + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); + continue; } - }); + let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `.` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Dot) + } else if self.token == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(diagnostics::ExprRArrowCall { span }); + true + } else { + self.eat(exp!(Dot)) + }; + if has_dot { + // expr.f + e = self.parse_dot_suffix_expr(lo, e)?; + continue; + } + if self.expr_is_complete(&e) { + break Ok(e); + } + e = match self.token.kind { + token::OpenParen => self.parse_expr_fn_call(lo, e), + token::OpenBracket => self.parse_expr_index(lo, e)?, + _ => break Ok(e), + } + }; // Stitch the list of outer attributes onto the return value. A little // bit ugly, but the best way given the current code structure. @@ -2872,7 +2868,7 @@ impl<'a> Parser<'a> { let else_span = self.prev_token.span; // `else` let attrs = self.parse_outer_attributes()?; // For recovery. let expr = if self.eat_keyword(exp!(If)) { - ensure_sufficient_stack(|| self.parse_expr_if())? + self.parse_expr_if()? } else if self.check(exp!(OpenBrace)) { self.parse_simple_block()? } else { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 98593c3c303c2..f93bc1639ffed 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -6,7 +6,6 @@ use rustc_ast::{ Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -114,16 +113,14 @@ impl<'a> Parser<'a> { return Ok(self.mk_ty(span, kind)); } // Make sure deeply nested types don't overflow the stack. - ensure_sufficient_stack(|| { - self.parse_ty_common( - AllowPlus::Yes, - AllowCVariadic::No, - RecoverQPath::Yes, - RecoverReturnSign::Yes, - None, - RecoverQuestionMark::Yes, - ) - }) + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + None, + RecoverQuestionMark::Yes, + ) } pub(super) fn parse_ty_with_generics_recovery( diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b8497aefb7767..05f12aaedcfce 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -23,7 +23,6 @@ //! considering here as at that point, everything is monomorphic. use hir::def_id::LocalDefIdSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::Node; use rustc_hir::def::{DefKind, Res}; @@ -362,7 +361,7 @@ impl<'tcx> ReachableContext<'tcx> { // become recursive, are also not infinitely recursing, because of the // `reachable_symbols` check above. // We still need to protect against stack overflow due to deeply nested statics. - ensure_sufficient_stack(|| self.propagate_from_alloc(alloc)); + self.propagate_from_alloc(alloc); } } } diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 57dc75961e24f..f1fd669b13d64 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -9,7 +9,6 @@ rustc-hash = "2.0.0" rustc_abi = { path = "../rustc_abi", optional = true } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_errors = { path = "../rustc_errors", optional = true } rustc_hir = { path = "../rustc_hir", optional = true } rustc_index = { path = "../rustc_index", default-features = false } @@ -33,7 +32,6 @@ default = ["rustc"] rustc = [ "dep:rustc_abi", "dep:rustc_arena", - "dep:rustc_data_structures", "dep:rustc_errors", "dep:rustc_hir", "dep:rustc_macros", diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index bf236b7737d9f..1f19bfd732892 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -710,8 +710,6 @@ use std::fmt; -#[cfg(feature = "rustc")] -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_index::bit_set::DenseBitSet; use smallvec::{SmallVec, smallvec}; @@ -721,10 +719,6 @@ use self::PlaceValidity::*; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; use crate::{MatchArm, PatCx, PrivateUninhabitedField, checks}; -#[cfg(not(feature = "rustc"))] -pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { - f() -} /// A pattern is a "branch" if it is the immediate child of an or-pattern, or if it is the whole /// pattern of a match arm. These are the patterns that can be meaningfully considered "redundant", @@ -1752,9 +1746,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( || missing_ctors.is_empty() || mcx.tycx.exhaustive_witnesses(); let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant)?; - let mut witnesses = ensure_sufficient_stack(|| { - compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix) - })?; + let mut witnesses = compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix)?; // Transform witnesses for `spec_matrix` into witnesses for `matrix`. witnesses.apply_constructor(pcx, &missing_ctors, &ctor); diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index c053f961df925..190bfaec8887a 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -3,7 +3,6 @@ use std::mem::ManuallyDrop; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::hash_table::{Entry, HashTable}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::{defer, outline, sharded, sync}; use rustc_errors::FatalError; @@ -628,7 +627,7 @@ pub(super) fn execute_query_non_incr_inner<'tcx, C: QueryCache>( span: Span, key: C::Key, ) -> C::Value { - ensure_sufficient_stack(|| try_execute_query::(query, tcx, span, key, None).0) + try_execute_query::(query, tcx, span, key, None).0 } /// Called by a macro-generated impl of [`QueryVTable::execute_query_fn`], @@ -650,9 +649,8 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>( return None; } - let (result, dep_node_index) = ensure_sufficient_stack(|| { - try_execute_query::(query, tcx, span, key, Some(dep_node)) - }); + let (result, dep_node_index) = + try_execute_query::(query, tcx, span, key, Some(dep_node)); if let Some(dep_node_index) = dep_node_index { tcx.dep_graph.read_index(dep_node_index) } @@ -674,9 +672,7 @@ pub(crate) fn force_query_dep_node<'tcx, C: QueryCache>( return false; }; - ensure_sufficient_stack(|| { - try_execute_query::(query, tcx, DUMMY_SP, key, Some(dep_node)) - }); + try_execute_query::(query, tcx, DUMMY_SP, key, Some(dep_node)); // We did manage to recover a key and force the node, though it's up to // the caller to check whether the node ended up marked red or green. diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 8de442309d7b2..e358be327f240 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -1,7 +1,6 @@ use std::num::NonZero; use rustc_data_structures::Limit; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_middle::bug; #[expect(unused_imports, reason = "used by doc comments")] @@ -169,7 +168,7 @@ pub(crate) fn promote_from_disk_inner<'tcx, C: QueryCache>( tcx.dep_graph.data().expect("should always be present in incremental mode"); let prof_timer = tcx.prof.incr_cache_loading(); - let value = ensure_sufficient_stack(|| (query.try_load_from_disk_fn)(tcx, prev_index)); + let value = (query.try_load_from_disk_fn)(tcx, prev_index); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); let Some(value) = value else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index bc4d33b346efa..24b7e93320f9c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -8,7 +8,6 @@ pub mod suggestions; use std::{fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordSet; use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -76,20 +75,18 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> { } fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - ensure_sufficient_stack(|| { - if self.span == ex.span { + if self.span == ex.span { + self.result = Some(ex); + } else { + if let hir::ExprKind::Closure(..) = ex.kind + && self.include_closures + && let closure_header_sp = self.span.with_hi(ex.span.hi()) + && closure_header_sp == ex.span + { self.result = Some(ex); - } else { - if let hir::ExprKind::Closure(..) = ex.kind - && self.include_closures - && let closure_header_sp = self.span.with_hi(ex.span.hi()) - && closure_header_sp == ex.span - { - self.result = Some(ex); - } - hir::intravisit::walk_expr(self, ex); } - }); + hir::intravisit::walk_expr(self, ex); + } } fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 15f82012b75ab..094b64b734077 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -7,7 +7,6 @@ use std::{debug_assert_matches, iter}; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize, @@ -4247,30 +4246,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let parent_predicate = parent_trait_ref; if !self.is_recursive_obligation(obligated_types, &data.parent_code) { - // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - ) - }); + self.note_obligation_cause_code( + body_def_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ); } else { - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - cause_code.peel_derives(), - obligated_types, - seen_requirements, - ) - }); + self.note_obligation_cause_code( + body_def_id, + err, + parent_predicate, + param_env, + cause_code.peel_derives(), + obligated_types, + seen_requirements, + ); } } ObligationCauseCode::ImplDerived(ref data) => { @@ -4290,17 +4284,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.resolve_vars_if_possible(data.derived.parent_trait_pred); // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.derived.parent_code, - obligated_types, - seen_requirements, - ) - }); + + self.note_obligation_cause_code( + body_def_id, + err, + parent_predicate, + param_env, + &data.derived.parent_code, + obligated_types, + seen_requirements, + ); return; } let self_ty_str = @@ -4445,18 +4438,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); err.note(format!("required for `{self_ty}` to implement `{trait_path}`")); } - // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - ) - }); + self.note_obligation_cause_code( + body_def_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ) } ObligationCauseCode::ImplDerivedHost(ref data) => { let self_ty = tcx.short_string( @@ -4489,60 +4479,52 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note(msg); } } - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - data.derived.parent_host_pred, - param_env, - &data.derived.parent_code, - obligated_types, - seen_requirements, - ) - }); + + self.note_obligation_cause_code( + body_def_id, + err, + data.derived.parent_host_pred, + param_env, + &data.derived.parent_code, + obligated_types, + seen_requirements, + ); } ObligationCauseCode::BuiltinDerivedHost(ref data) => { - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - data.parent_host_pred, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - ) - }); + self.note_obligation_cause_code( + body_def_id, + err, + data.parent_host_pred, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ); } ObligationCauseCode::WellFormedDerived(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_predicate = parent_trait_ref; - // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - ) - }); + + self.note_obligation_cause_code( + body_def_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + ); } ObligationCauseCode::TypeAlias(ref nested, span, def_id) => { - // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - predicate, - param_env, - nested, - obligated_types, - seen_requirements, - ) - }); + self.note_obligation_cause_code( + body_def_id, + err, + predicate, + param_env, + nested, + obligated_types, + seen_requirements, + ); let mut multispan = MultiSpan::from(span); multispan.push_span_label(span, "required by this bound"); err.span_note( @@ -4562,17 +4544,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate, call_hir_id, ); - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - predicate, - param_env, - parent_code, - obligated_types, - seen_requirements, - ) - }); + + self.note_obligation_cause_code( + body_def_id, + err, + predicate, + param_env, + parent_code, + obligated_types, + seen_requirements, + ); } // Suppress `compare_type_clause_entailment` errors for RPITITs, since they // should be implied by the parent method. diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 74908ea577d0d..f00b300c7e971 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,6 +1,5 @@ //! Deeply normalize types using the old trait solver. -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::msg; use rustc_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; @@ -124,9 +123,7 @@ where { debug!(obligations.len = obligations.len()); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = ensure_sufficient_stack(|| { - AssocTypeNormalizer::fold(&mut normalizer, value.skip_normalization()) - }); + let result = AssocTypeNormalizer::fold(&mut normalizer, value.skip_normalization()); debug!(?result, obligations.len = normalizer.obligations.len()); debug!(?normalizer.obligations,); result diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 72954c0818415..7da8c68ff894a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -3,7 +3,6 @@ use std::ops::ControlFlow; use rustc_data_structures::sso::SsoHashSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -1946,27 +1945,23 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let mut cache_projection = cache_entry.projection_term; let mut nested_obligations = PredicateObligations::new(); let obligation_projection = obligation.predicate; - let obligation_projection = ensure_sufficient_stack(|| { - normalize_with_depth_to( + let obligation_projection = normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty::Unnormalized::new_wip(obligation_projection), + &mut nested_obligations, + ); + if potentially_unnormalized_candidate { + cache_projection = normalize_with_depth_to( selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - ty::Unnormalized::new_wip(obligation_projection), + ty::Unnormalized::new_wip(cache_projection), &mut nested_obligations, - ) - }); - if potentially_unnormalized_candidate { - cache_projection = ensure_sufficient_stack(|| { - normalize_with_depth_to( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty::Unnormalized::new_wip(cache_projection), - &mut nested_obligations, - ) - }); + ); } debug!(?cache_projection, ?obligation_projection); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 42923fa2869bd..e9e1cea48ba20 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -288,36 +288,25 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element - rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ety, constraints) - }); + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ety, constraints); } - ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { + ty::Tuple(tys) => { for ty in tys.iter() { dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - }), + } - ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { + ty::Closure(_, args) => { for ty in args.as_closure().upvar_tys() { dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - }), + } ty::CoroutineClosure(_, args) => { - rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in args.as_coroutine_closure().upvar_tys() { - dtorck_constraint_for_ty_inner( - tcx, - typing_env, - span, - depth + 1, - ty, - constraints, - ); - } - }) + for ty in args.as_coroutine_closure().upvar_tys() { + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); + } } ty::Coroutine(def_id, args) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index fb15ed8a74c07..489e4f7a93d53 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -3,7 +3,6 @@ //! `normalize_canonicalized_projection` query when it encounters projections. use rustc_data_structures::sso::SsoHashMap; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; @@ -248,7 +247,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { "recursive opaque type", ); } - let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); + let folded_ty = self.try_fold_ty(concrete_ty); self.anon_depth -= 1; folded_ty? } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d04f4ea587dc5..203ed5a62a8b9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,7 +9,6 @@ use std::ops::ControlFlow; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::attrs::lang_items::LangItem; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_infer::traits::ObligationCauseCode; @@ -386,47 +385,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - ensure_sufficient_stack(|| { - assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); + assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); - let self_ty = - obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); - let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); + let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); + let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); - let constituents = self.constituent_types_for_auto_trait(self_ty)?; - let constituents = self.infcx.enter_forall_and_leak_universe(constituents); + let constituents = self.constituent_types_for_auto_trait(self_ty)?; + let constituents = self.infcx.enter_forall_and_leak_universe(constituents); - let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - obligation.predicate.def_id(), - constituents.types, - ); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + obligation.predicate.def_id(), + constituents.types, + ); - // Only normalize these goals if `-Zhigher-ranked-assumptions` is enabled, since - // we don't want to cause ourselves to do extra work if we're not even able to - // take advantage of these assumption clauses. - if self.tcx().sess.opts.unstable_opts.higher_ranked_assumptions { - // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` - // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really - // matter yet. - for assumption in constituents.assumptions { - let assumption = normalize_with_depth_to( - self, - obligation.param_env, - cause.clone(), - obligation.recursion_depth + 1, - Unnormalized::new_wip(assumption), - &mut obligations, - ); - self.infcx.register_region_assumption(assumption); - } + // Only normalize these goals if `-Zhigher-ranked-assumptions` is enabled, since + // we don't want to cause ourselves to do extra work if we're not even able to + // take advantage of these assumption clauses. + if self.tcx().sess.opts.unstable_opts.higher_ranked_assumptions { + // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` + // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really + // matter yet. + for assumption in constituents.assumptions { + let assumption = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + Unnormalized::new_wip(assumption), + &mut obligations, + ); + self.infcx.register_region_assumption(assumption); } + } - Ok(obligations) - }) + Ok(obligations) } fn confirm_impl_candidate( @@ -440,16 +436,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this time not in a probe. let args = self.rematch_impl(impl_def_id, obligation); debug!(?args, "impl args"); - ensure_sufficient_stack(|| { - self.vtable_impl( - impl_def_id, - args, - &obligation.cause, - obligation.recursion_depth + 1, - obligation.param_env, - obligation.predicate, - ) - }) + + self.vtable_impl( + impl_def_id, + args, + &obligation.cause, + obligation.recursion_depth + 1, + obligation.param_env, + obligation.predicate, + ) } fn vtable_impl( @@ -972,15 +967,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); // Normalize the obligation and expected trait refs together, because why not let Normalized { obligations: nested, value: (obligation_trait_ref, found_trait_ref) } = - ensure_sufficient_stack(|| { - normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - Unnormalized::new_wip((obligation.predicate.trait_ref, found_trait_ref)), - ) - }); + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + Unnormalized::new_wip((obligation.predicate.trait_ref, found_trait_ref)), + ); // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs self.infcx diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4af20d1ad59a2..9b4ee13bf1b63 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,7 +9,6 @@ use std::ops::ControlFlow; use hir::def::DefKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -620,408 +619,387 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(EvaluatedToOk); } - ensure_sufficient_stack(|| { - let bound_predicate = obligation.predicate.kind(); - match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - let t = bound_predicate.rebind(t); - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(self.tcx(), t); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } + let bound_predicate = obligation.predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { + let t = bound_predicate.rebind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(self.tcx(), t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { - self.infcx.enter_forall(bound_predicate.rebind(data), |data| { - match effects::evaluate_host_effect_obligation( - self, - &obligation.with(self.tcx(), data), - ) { - Ok(nested) => { - self.evaluate_predicates_recursively(previous_stack, nested) - } - Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig), - Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr), - } - }) - } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { + self.infcx.enter_forall(bound_predicate.rebind(data), |data| { + match effects::evaluate_host_effect_obligation( + self, + &obligation.with(self.tcx(), data), + ) { + Ok(nested) => self.evaluate_predicates_recursively(previous_stack, nested), + Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig), + Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr), + } + }) + } - ty::PredicateKind::Subtype(p) => { - let p = bound_predicate.rebind(p); - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, obligations) - } - Ok(Err(_)) => Ok(EvaluatedToErr), - Err(..) => Ok(EvaluatedToAmbig), + ty::PredicateKind::Subtype(p) => { + let p = bound_predicate.rebind(p); + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } + Ok(Err(_)) => Ok(EvaluatedToErr), + Err(..) => Ok(EvaluatedToAmbig), } + } - ty::PredicateKind::Coerce(p) => { - let p = bound_predicate.rebind(p); - // Does this code ever run? - match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, obligations) - } - Ok(Err(_)) => Ok(EvaluatedToErr), - Err(..) => Ok(EvaluatedToAmbig), + ty::PredicateKind::Coerce(p) => { + let p = bound_predicate.rebind(p); + // Does this code ever run? + match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } + Ok(Err(_)) => Ok(EvaluatedToErr), + Err(..) => Ok(EvaluatedToAmbig), } + } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { - if term.is_trivially_wf(self.tcx()) { - return Ok(EvaluatedToOk); - } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => { + if term.is_trivially_wf(self.tcx()) { + return Ok(EvaluatedToOk); + } - // So, there is a bit going on here. First, `WellFormed` predicates - // are coinductive, like trait predicates with auto traits. - // This means that we need to detect if we have recursively - // evaluated `WellFormed(X)`. Otherwise, we would run into - // a "natural" overflow error. - // - // Now, the next question is whether we need to do anything - // special with caching. Considering the following tree: - // - `WF(Foo)` - // - `Bar: Send` - // - `WF(Foo)` - // - `Foo: Trait` - // In this case, the innermost `WF(Foo)` should return - // `EvaluatedToOk`, since it's coinductive. Then if - // `Bar: Send` is resolved to `EvaluatedToOk`, it can be - // inserted into a cache (because without thinking about `WF` - // goals, it isn't in a cycle). If `Foo: Trait` later doesn't - // hold, then `Bar: Send` shouldn't hold. Therefore, we - // *do* need to keep track of coinductive cycles. - - let cache = previous_stack.cache; - let dfn = cache.next_dfn(); - - for stack_term in previous_stack.cache.wf_args.borrow().iter().rev() { - if stack_term.0 != term { - continue; - } - debug!("WellFormed({:?}) on stack", term); - if let Some(stack) = previous_stack.head { - // Okay, let's imagine we have two different stacks: - // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait` - // `WF(T) -> T: NonAutoTrait -> WF(T)` - // Because of this, we need to check that all - // predicates between the WF goals are coinductive. - // Otherwise, we can say that `T: NonAutoTrait` is - // true. - // Let's imagine we have a predicate stack like - // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto` - // depth ^1 ^2 ^3 - // and the current predicate is `WF(T)`. `wf_args` - // would contain `(T, 1)`. We want to check all - // trait predicates greater than `1`. The previous - // stack would be `T: Auto`. - let cycle = stack.iter().take_while(|s| s.depth > stack_term.1); - let tcx = self.tcx(); - let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx)); - if self.coinductive_match(cycle) { - stack.update_reached_depth(stack_term.1); - return Ok(EvaluatedToOk); - } else { - return Ok(EvaluatedToAmbigStackDependent); - } - } - return Ok(EvaluatedToOk); + // So, there is a bit going on here. First, `WellFormed` predicates + // are coinductive, like trait predicates with auto traits. + // This means that we need to detect if we have recursively + // evaluated `WellFormed(X)`. Otherwise, we would run into + // a "natural" overflow error. + // + // Now, the next question is whether we need to do anything + // special with caching. Considering the following tree: + // - `WF(Foo)` + // - `Bar: Send` + // - `WF(Foo)` + // - `Foo: Trait` + // In this case, the innermost `WF(Foo)` should return + // `EvaluatedToOk`, since it's coinductive. Then if + // `Bar: Send` is resolved to `EvaluatedToOk`, it can be + // inserted into a cache (because without thinking about `WF` + // goals, it isn't in a cycle). If `Foo: Trait` later doesn't + // hold, then `Bar: Send` shouldn't hold. Therefore, we + // *do* need to keep track of coinductive cycles. + + let cache = previous_stack.cache; + let dfn = cache.next_dfn(); + + for stack_term in previous_stack.cache.wf_args.borrow().iter().rev() { + if stack_term.0 != term { + continue; } - - match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_def_id, - obligation.recursion_depth + 1, - term, - obligation.cause.span, - ) { - Some(obligations) => { - cache.wf_args.borrow_mut().push((term, previous_stack.depth())); - let result = - self.evaluate_predicates_recursively(previous_stack, obligations); - cache.wf_args.borrow_mut().pop(); - - let result = result?; - - if !result.must_apply_modulo_regions() { - cache.on_failure(dfn); - } - - cache.on_completion(dfn); - - Ok(result) + debug!("WellFormed({:?}) on stack", term); + if let Some(stack) = previous_stack.head { + // Okay, let's imagine we have two different stacks: + // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait` + // `WF(T) -> T: NonAutoTrait -> WF(T)` + // Because of this, we need to check that all + // predicates between the WF goals are coinductive. + // Otherwise, we can say that `T: NonAutoTrait` is + // true. + // Let's imagine we have a predicate stack like + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto` + // depth ^1 ^2 ^3 + // and the current predicate is `WF(T)`. `wf_args` + // would contain `(T, 1)`. We want to check all + // trait predicates greater than `1`. The previous + // stack would be `T: Auto`. + let cycle = stack.iter().take_while(|s| s.depth > stack_term.1); + let tcx = self.tcx(); + let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx)); + if self.coinductive_match(cycle) { + stack.update_reached_depth(stack_term.1); + return Ok(EvaluatedToOk); + } else { + return Ok(EvaluatedToAmbigStackDependent); } - None => Ok(EvaluatedToAmbig), } + return Ok(EvaluatedToOk); } - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { - // A global type with no free lifetimes or generic parameters - // outlives anything. - if pred.0.has_free_regions() - || pred.0.has_bound_regions() - || pred.0.has_non_region_infer() - || pred.0.has_non_region_param() - { - Ok(EvaluatedToOkModuloRegions) - } else { - Ok(EvaluatedToOk) + match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_def_id, + obligation.recursion_depth + 1, + term, + obligation.cause.span, + ) { + Some(obligations) => { + cache.wf_args.borrow_mut().push((term, previous_stack.depth())); + let result = + self.evaluate_predicates_recursively(previous_stack, obligations); + cache.wf_args.borrow_mut().pop(); + + let result = result?; + + if !result.must_apply_modulo_regions() { + cache.on_failure(dfn); + } + + cache.on_completion(dfn); + + Ok(result) } + None => Ok(EvaluatedToAmbig), } + } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { - // We do not consider region relationships when evaluating trait matches. + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => { + // A global type with no free lifetimes or generic parameters + // outlives anything. + if pred.0.has_free_regions() + || pred.0.has_bound_regions() + || pred.0.has_non_region_infer() + || pred.0.has_non_region_param() + { Ok(EvaluatedToOkModuloRegions) + } else { + Ok(EvaluatedToOk) } + } - ty::PredicateKind::DynCompatible(trait_def_id) => { - // `DynCompatible` obligations are only emitted as - // nested obligations of `WellFormed` goals. It is quite - // rare, but possible, that we encounter them during - // evaluation. See #158665 for more details here. - if self.tcx().is_dyn_compatible(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) + } + + ty::PredicateKind::DynCompatible(trait_def_id) => { + // `DynCompatible` obligations are only emitted as + // nested obligations of `WellFormed` goals. It is quite + // rare, but possible, that we encounter them during + // evaluation. See #158665 for more details here. + if self.tcx().is_dyn_compatible(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) } + } + + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { + let data = bound_predicate.rebind(data); + let project_obligation = obligation.with(self.tcx(), data); + match project::poly_project_and_unify_term(self, &project_obligation) { + ProjectAndUnifyResult::Holds(mut subobligations) => { + 'compute_res: { + // If we've previously marked this projection as 'complete', then + // use the final cached result (either `EvaluatedToOk` or + // `EvaluatedToOkModuloRegions`), and skip re-evaluating the + // sub-obligations. + if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( + self, + &project_obligation, + ) && let Some(cached_res) = + self.infcx.inner.borrow_mut().projection_cache().is_complete(key) + { + break 'compute_res Ok(cached_res); + } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { - let data = bound_predicate.rebind(data); - let project_obligation = obligation.with(self.tcx(), data); - match project::poly_project_and_unify_term(self, &project_obligation) { - ProjectAndUnifyResult::Holds(mut subobligations) => { - 'compute_res: { - // If we've previously marked this projection as 'complete', then - // use the final cached result (either `EvaluatedToOk` or - // `EvaluatedToOkModuloRegions`), and skip re-evaluating the - // sub-obligations. - if let Some(key) = + // Need to explicitly set the depth of nested goals here as + // projection obligations can cycle by themselves and in + // `evaluate_predicates_recursively` we only add the depth + // for parent trait goals because only these get added to the + // `TraitObligationStackList`. + for subobligation in subobligations.iter_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + let res = self + .evaluate_predicates_recursively(previous_stack, subobligations); + if let Ok(eval_rslt) = res + && (eval_rslt == EvaluatedToOk + || eval_rslt == EvaluatedToOkModuloRegions) + && let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( self, &project_obligation, ) - && let Some(cached_res) = self - .infcx - .inner - .borrow_mut() - .projection_cache() - .is_complete(key) - { - break 'compute_res Ok(cached_res); - } - - // Need to explicitly set the depth of nested goals here as - // projection obligations can cycle by themselves and in - // `evaluate_predicates_recursively` we only add the depth - // for parent trait goals because only these get added to the - // `TraitObligationStackList`. - for subobligation in subobligations.iter_mut() { - subobligation.set_depth_from_parent(obligation.recursion_depth); - } - let res = self.evaluate_predicates_recursively( - previous_stack, - subobligations, - ); - if let Ok(eval_rslt) = res - && (eval_rslt == EvaluatedToOk - || eval_rslt == EvaluatedToOkModuloRegions) - && let Some(key) = - ProjectionCacheKey::from_poly_projection_obligation( - self, - &project_obligation, - ) - { - // If the result is something that we can cache, then mark this - // entry as 'complete'. This will allow us to skip evaluating the - // subobligations at all the next time we evaluate the projection - // predicate. - self.infcx - .inner - .borrow_mut() - .projection_cache() - .complete(key, eval_rslt); - } - res + { + // If the result is something that we can cache, then mark this + // entry as 'complete'. This will allow us to skip evaluating the + // subobligations at all the next time we evaluate the projection + // predicate. + self.infcx + .inner + .borrow_mut() + .projection_cache() + .complete(key, eval_rslt); } + res } - ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), - ProjectAndUnifyResult::Recursive => Ok(EvaluatedToAmbigStackDependent), - ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), } + ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig), + ProjectAndUnifyResult::Recursive => Ok(EvaluatedToAmbigStackDependent), + ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr), } + } - ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { - if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToAmbig) - } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToAmbig) } + } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(alias_const)) => { - match const_evaluatable::is_const_evaluatable( - self.infcx, - alias_const, - obligation.param_env, - obligation.cause.span, - ) { - Ok(()) => Ok(EvaluatedToOk), - Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig), - Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr), - Err(_) => Ok(EvaluatedToErr), - } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(alias_const)) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + alias_const, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig), + Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr), + Err(_) => Ok(EvaluatedToErr), } + } - ty::PredicateKind::ConstEquate(c1, c2) => { - let tcx = self.tcx(); - assert!( - tcx.features().generic_const_exprs(), - "`ConstEquate` without a feature gate: {c1:?} {c2:?}", - ); + ty::PredicateKind::ConstEquate(c1, c2) => { + let tcx = self.tcx(); + assert!( + tcx.features().generic_const_exprs(), + "`ConstEquate` without a feature gate: {c1:?} {c2:?}", + ); - { - let c1 = tcx.expand_abstract_consts(c1); - let c2 = tcx.expand_abstract_consts(c2); - debug!( - "evaluate_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}", - c1, c2 - ); + { + let c1 = tcx.expand_abstract_consts(c1); + let c2 = tcx.expand_abstract_consts(c2); + debug!( + "evaluate_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}", + c1, c2 + ); - match (c1.kind(), c2.kind()) { - (ty::ConstKind::Alias(_, a), ty::ConstKind::Alias(_, b)) - if a.kind == b.kind - && matches!( - a.kind, - ty::AliasConstKind::Projection { .. } - | ty::AliasConstKind::Inherent { .. } - ) => + match (c1.kind(), c2.kind()) { + (ty::ConstKind::Alias(_, a), ty::ConstKind::Alias(_, b)) + if a.kind == b.kind + && matches!( + a.kind, + ty::AliasConstKind::Projection { .. } + | ty::AliasConstKind::Inherent { .. } + ) => + { + if let Ok(InferOk { obligations, value: () }) = self + .infcx + .at(&obligation.cause, obligation.param_env) + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + .eq( + DefineOpaqueTypes::Yes, + ty::AliasTerm::from(a), + ty::AliasTerm::from(b), + ) { - if let Ok(InferOk { obligations, value: () }) = self - .infcx - .at(&obligation.cause, obligation.param_env) - // Can define opaque types as this is only reachable with - // `generic_const_exprs` - .eq( - DefineOpaqueTypes::Yes, - ty::AliasTerm::from(a), - ty::AliasTerm::from(b), - ) - { - return self.evaluate_predicates_recursively( - previous_stack, - obligations, - ); - } - } - (_, ty::ConstKind::Alias(_, _)) | (ty::ConstKind::Alias(_, _), _) => (), - (_, _) => { - if let Ok(InferOk { obligations, value: () }) = self - .infcx - .at(&obligation.cause, obligation.param_env) - // Can define opaque types as this is only reachable with - // `generic_const_exprs` - .eq(DefineOpaqueTypes::Yes, c1, c2) - { - return self.evaluate_predicates_recursively( - previous_stack, - obligations, - ); - } + return self + .evaluate_predicates_recursively(previous_stack, obligations); } } - } - - let evaluate = |c: ty::Const<'tcx>| { - if let ty::ConstKind::Alias(_, _) = c.kind() { - match crate::traits::try_evaluate_const( - self.infcx, - c, - obligation.param_env, - ) { - Ok(val) => Ok(val), - Err(e) => Err(e), - } - } else { - Ok(c) - } - }; - - match (evaluate(c1), evaluate(c2)) { - (Ok(c1), Ok(c2)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq( + (_, ty::ConstKind::Alias(_, _)) | (ty::ConstKind::Alias(_, _), _) => (), + (_, _) => { + if let Ok(InferOk { obligations, value: () }) = self + .infcx + .at(&obligation.cause, obligation.param_env) // Can define opaque types as this is only reachable with // `generic_const_exprs` - DefineOpaqueTypes::Yes, - c1, - c2, - ) { - Ok(inf_ok) => self.evaluate_predicates_recursively( - previous_stack, - inf_ok.into_obligations(), - ), - Err(_) => Ok(EvaluatedToErr), - } - } - (Err(EvaluateConstErr::InvalidConstParamTy(..)), _) - | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr), - (Err(EvaluateConstErr::EvaluationFailure(..)), _) - | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr), - (Err(EvaluateConstErr::HasGenericsOrInfers), _) - | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => { - if c1.has_non_region_infer() || c2.has_non_region_infer() { - Ok(EvaluatedToAmbig) - } else { - // Two different constants using generic parameters ~> error. - Ok(EvaluatedToErr) + .eq(DefineOpaqueTypes::Yes, c1, c2) + { + return self + .evaluate_predicates_recursively(previous_stack, obligations); } } } } - ty::PredicateKind::NormalizesTo(..) => { - bug!("NormalizesTo is only used by the new solver") - } - ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - let ct = self.infcx.shallow_resolve_const(ct); - let ct_ty = match ct.kind() { - ty::ConstKind::Infer(_) => { - return Ok(EvaluatedToAmbig); - } - ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), - ty::ConstKind::Value(cv) => cv.ty, - ty::ConstKind::Alias(_, alias_const) => { - alias_const.type_of(self.tcx()).skip_norm_wip() + + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Alias(_, _) = c.kind() { + match crate::traits::try_evaluate_const(self.infcx, c, obligation.param_env) + { + Ok(val) => Ok(val), + Err(e) => Err(e), } - // FIXME(generic_const_exprs): See comment in `fulfill.rs` - ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk), - ty::ConstKind::Placeholder(_) => { - bug!("placeholder const {:?} in old solver", ct) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + DefineOpaqueTypes::Yes, + c1, + c2, + ) { + Ok(inf_ok) => self.evaluate_predicates_recursively( + previous_stack, + inf_ok.into_obligations(), + ), + Err(_) => Ok(EvaluatedToErr), } - ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), - ty::ConstKind::Param(param_ct) => { - param_ct.find_const_ty_from_env(obligation.param_env) + } + (Err(EvaluateConstErr::InvalidConstParamTy(..)), _) + | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr), + (Err(EvaluateConstErr::EvaluationFailure(..)), _) + | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr), + (Err(EvaluateConstErr::HasGenericsOrInfers), _) + | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => { + if c1.has_non_region_infer() || c2.has_non_region_infer() { + Ok(EvaluatedToAmbig) + } else { + // Two different constants using generic parameters ~> error. + Ok(EvaluatedToErr) } - }; - - match self.infcx.at(&obligation.cause, obligation.param_env).eq( - // Only really exercised by generic_const_exprs - DefineOpaqueTypes::Yes, - ct_ty, - ty, - ) { - Ok(inf_ok) => self.evaluate_predicates_recursively( - previous_stack, - inf_ok.into_obligations(), - ), - Err(_) => Ok(EvaluatedToErr), } } } - }) + ty::PredicateKind::NormalizesTo(..) => { + bug!("NormalizesTo is only used by the new solver") + } + ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + let ct = self.infcx.shallow_resolve_const(ct); + let ct_ty = match ct.kind() { + ty::ConstKind::Infer(_) => { + return Ok(EvaluatedToAmbig); + } + ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), + ty::ConstKind::Value(cv) => cv.ty, + ty::ConstKind::Alias(_, alias_const) => { + alias_const.type_of(self.tcx()).skip_norm_wip() + } + // FIXME(generic_const_exprs): See comment in `fulfill.rs` + ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk), + ty::ConstKind::Placeholder(_) => { + bug!("placeholder const {:?} in old solver", ct) + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Param(param_ct) => { + param_ct.find_const_ty_from_env(obligation.param_env) + } + }; + + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + // Only really exercised by generic_const_exprs + DefineOpaqueTypes::Yes, + ct_ty, + ty, + ) { + Ok(inf_ok) => self + .evaluate_predicates_recursively(previous_stack, inf_ok.into_obligations()), + Err(_) => Ok(EvaluatedToErr), + } + } + } } #[instrument(skip(self, previous_stack), level = "debug", ret)] @@ -1739,15 +1717,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { HigherRankedType, trait_bound, ); - let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| { - normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty::Unnormalized::new_wip(trait_bound), - ) - }); + let Normalized { value: trait_bound, obligations: _ } = normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty::Unnormalized::new_wip(trait_bound), + ); self.infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound) @@ -1799,16 +1775,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let mut infer_projection = infer_predicate.projection_term; if potentially_unnormalized_candidates { - infer_projection = ensure_sufficient_stack(|| { - normalize_with_depth_to( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty::Unnormalized::new_wip(infer_projection), - &mut nested_obligations, - ) - }) + infer_projection = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + ty::Unnormalized::new_wip(infer_projection), + &mut nested_obligations, + ) } let is_match = self @@ -2483,16 +2457,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { types .into_iter() .flat_map(|placeholder_ty| { - let Normalized { value: normalized_ty, mut obligations } = - ensure_sufficient_stack(|| { - normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - Unnormalized::new_wip(placeholder_ty), - ) - }); + let Normalized { value: normalized_ty, mut obligations } = normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + Unnormalized::new_wip(placeholder_ty), + ); let tcx = self.tcx(); let trait_ref = if tcx.generics_of(trait_def_id).own_params.len() == 1 { @@ -2557,16 +2528,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { debug!(?impl_trait_header); let mut nested_obligations = PredicateObligations::new(); - let impl_trait_ref = ensure_sufficient_stack(|| { - normalize_with_depth_to( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_ref, - &mut nested_obligations, - ) - }); + let impl_trait_ref = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_ref, + &mut nested_obligations, + ); debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref); diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index b748611be383f..d677e88220d96 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::stack::ensure_sufficient_stack; use tracing::{debug, instrument, trace}; pub(crate) mod query_context; @@ -160,7 +159,7 @@ where if let Some(answer) = cache.get(&(src_state, dst_state)) { answer.clone() } else { - let answer = ensure_sufficient_stack(|| self.answer_impl(cache, src_state, dst_state)); + let answer = self.answer_impl(cache, src_state, dst_state); if let Some(..) = cache.insert((src_state, dst_state), answer.clone()) { panic!("failed to correctly cache transmutability") } diff --git a/compiler/rustc_type_ir/src/data_structures/mod.rs b/compiler/rustc_type_ir/src/data_structures/mod.rs index c2b629f1d11c4..6ffcead67460b 100644 --- a/compiler/rustc_type_ir/src/data_structures/mod.rs +++ b/compiler/rustc_type_ir/src/data_structures/mod.rs @@ -10,17 +10,11 @@ mod delayed_map; #[cfg(feature = "nightly")] mod impl_ { pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet}; - pub use rustc_data_structures::stack::ensure_sufficient_stack; } #[cfg(not(feature = "nightly"))] mod impl_ { pub use std::collections::{HashMap as SsoHashMap, HashSet as SsoHashSet}; - - #[inline] - pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { - f() - } } pub use delayed_map::{DelayedMap, DelayedSet}; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 734ca79518090..3d2f118de1b93 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -403,7 +403,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "ppv-lite86", "proc-macro-hack", "proc-macro2", - "psm", "pulldown-cmark", "pulldown-cmark-escape", "punycode", @@ -446,7 +445,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "simd-adler32", "smallvec", "stable_deref_trait", - "stacker", "static_assertions", "strsim", "syn", @@ -501,16 +499,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "windows-result", "windows-strings", "windows-sys", - "windows-targets", "windows-threading", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", "wit-bindgen-rt@0.39.0", // pinned to a specific version due to using a binary blob: "writeable", "yoke", diff --git a/tests/crashes/108499.rs b/tests/crashes/108499.rs deleted file mode 100644 index 4a0638cd59ae4..0000000000000 --- a/tests/crashes/108499.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@ known-bug: #108499 - -// at lower recursion limits the recursion limit is reached before the bug happens -#![recursion_limit = "2000"] - -// this will try to calculate 3↑↑3=3^(3^3) -type Test = <() as Op<((), ()), [[[(); 0]; 0]; 0], [[[(); 0]; 0]; 0], - [[[[(); 0]; 0]; 0]; 0]>>::Result; - -use std::default::Default; - -fn main() { - // force the compiler to actually evaluate `Test` - println!("{}", Test::default()); -} - -trait Op { - type Result; -} - -// this recursive function defines the hyperoperation sequence, -// a canonical example of the type of recursion which produces the issue -// the problem seems to be caused by having two recursive calls, the second -// of which depending on the first -impl< - X: Op<(X, Y), A, [B; 0], [C; 0]>, - Y: Op<(X, Y), A, X::Result, C>, - A, B, C, -> Op<(X, Y), A, [[B; 0]; 0], [C; 0]> for () { - type Result = Y::Result; -} - -// base cases -impl Op for () { - type Result = [B; 0]; -} - -impl Op for () { - type Result = [A; 0]; -} - -impl Op for () { - type Result = A; -} diff --git a/tests/crashes/93237.rs b/tests/crashes/93237.rs deleted file mode 100644 index c903e79a2e300..0000000000000 --- a/tests/crashes/93237.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #93237 -trait Trait { - type Assoc; -} -impl Trait for () { - type Assoc = (); -} - -macro_rules! m { - ([#$($t:tt)*] [$($open:tt)*] [$($close:tt)*]) => { - m!{[$($t)*][$($open)*$($open)*][$($close)*$($close)*]} - }; - ([] [$($open:tt)*] [$($close:tt)*]) => { - fn _f() -> $($open)*()$($close)* {} - }; -} - -m! {[###########][impl Trait]} diff --git a/tests/ui/compile-flags/jobs/jobs-pass.rs b/tests/ui/compile-flags/jobs/jobs-pass.rs index 33a300f300051..194ef3380772c 100644 --- a/tests/ui/compile-flags/jobs/jobs-pass.rs +++ b/tests/ui/compile-flags/jobs/jobs-pass.rs @@ -2,6 +2,7 @@ //@ revisions: a b c d e f g //@ ignore-parallel-frontend option conflicts //@ compile-flags: -Z unstable-options +//@ rustc-env:RUST_MIN_STACK=4194304 //@[a] compile-flags: -j 0 //@[b] compile-flags: -j 1 diff --git a/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.rs b/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.rs index 39d22558b15dd..378b5b247db70 100644 --- a/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.rs +++ b/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.rs @@ -1,11 +1,10 @@ //! Regression test for #144719: long reference cycles shouldn't //! overflow the stack. -//@ rustc-env:RUST_MIN_STACK=3000000 #[derive(PartialEq, Copy, Clone)] struct Thing(&'static Thing); -const N: usize = 8000; +const N: usize = 4000; static A: Thing = Thing(&B[0]); static B: [Thing; N] = { let mut x = [Thing(&A); N]; diff --git a/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.stderr b/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.stderr index a549081a26475..495753e238e7a 100644 --- a/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.stderr +++ b/tests/ui/consts/const_in_pattern/cyclic-const-long-chain-issue-144719.stderr @@ -1,5 +1,5 @@ error: constant C cannot be used as pattern - --> $DIR/cyclic-const-long-chain-issue-144719.rs:22:12 + --> $DIR/cyclic-const-long-chain-issue-144719.rs:21:12 | LL | if let C = C {} | ^ diff --git a/tests/ui/parser/survive-peano-lesson-queue.rs b/tests/ui/parser/survive-peano-lesson-queue.rs index 921a83fb1f8b0..84497201b8ac2 100644 --- a/tests/ui/parser/survive-peano-lesson-queue.rs +++ b/tests/ui/parser/survive-peano-lesson-queue.rs @@ -1,4 +1,5 @@ //@ build-pass +//@ rustc-env:RUST_MIN_STACK=33554432 // ignore-tidy-file-filelength // ignore-tidy-file-linelength // some very lightly modified generated code from issue rust-lang/rust#122715