diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 650525a2f520e..68c22c13dca57 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::{Movability, Mutability, Pinnedness}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::AttrId; @@ -2192,12 +2191,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, - tokens: self.tokens.clone(), - }) + Self { id: self.id, kind: self.kind.clone(), span: self.span, tokens: self.tokens.clone() } } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2c09059fe1904..05e1fce4dcc60 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -11,7 +11,6 @@ use std::ops::DerefMut; use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; use rustc_span::Span; use rustc_span::source_map::Spanned; @@ -1653,7 +1652,7 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::If(cond, tr, fl) => { vis.visit_expr(cond); vis.visit_block(tr); - visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl))); + visit_opt(fl, |fl| vis.visit_expr(fl)); } ExprKind::While(cond, body, label) => { visit_opt(label, |label| vis.visit_label(label)); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index c4bae084a3f8c..ccfb1f1742203 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,6 +1,5 @@ use rustc_ast::ptr::P; use rustc_ast::*; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::Span; @@ -19,117 +18,115 @@ impl<'a, 'hir> LoweringContext<'a, '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::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::Lit(e) => { - break hir::PatKind::Lit(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, - ); - break hir::PatKind::Path(qpath); - } - PatKind::Struct(qself, path, fields, etc) => { - let qpath = self.lower_qpath( - pattern.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); + // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); + let node = loop { + match &pattern.kind { + 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::Lit(e) => { + break hir::PatKind::Lit(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, + ); + break hir::PatKind::Path(qpath); + } + 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); + 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); - 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, *etc == ast::PatFieldsRest::Rest); - } - 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, mutbl) => { - break hir::PatKind::Ref(self.lower_pat(inner), *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()), - ); - } - // FIXME(guard_patterns): lower pattern guards to HIR - PatKind::Guard(inner, _) => pattern = inner, - 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!("{:?} shouldn't exist here", pattern.span), - PatKind::Err(guar) => break hir::PatKind::Err(*guar), + 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, *etc == ast::PatFieldsRest::Rest); } - }; + 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, mutbl) => { + break hir::PatKind::Ref(self.lower_pat(inner), *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()), + ); + } + // FIXME(guard_patterns): lower pattern guards to HIR + PatKind::Guard(inner, _) => pattern = inner, + 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!("{:?} shouldn't exist here", pattern.span), + PatKind::Err(guar) => break hir::PatKind::Err(*guar), + } + }; - self.pat_with_node_id_of(pattern, node, pat_hir_id) - }) + 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 6f51b09323d9b..4d2546fdf7bf5 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,5 +1,4 @@ use rustc_abi::{BackendRepr, VariantIdx}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; @@ -105,7 +104,7 @@ fn const_to_valtree_inner<'tcx>( // Since the returned valtree does not contain the type or layout, we can just // switch to the base type. place.layout = ecx.layout_of(*base).unwrap(); - ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes)) + const_to_valtree_inner(ecx, &place, num_nodes) }, diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 3d6d000348324..35a634ca2d17b 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -1,15 +1,6 @@ // 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 @@ -18,5 +9,5 @@ const STACK_PER_RECURSION: usize = 16 * 1024 * 1024; // 16MB /// 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) + f() } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0e079b037691e..31b7423480b31 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -7,7 +7,6 @@ use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ @@ -246,13 +245,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 21c47967eada9..ce516c9447239 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::infer::unify_key::ConstVariableValue; @@ -445,7 +444,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_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index a68a2a7f98380..2a657962a6dc9 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -7,7 +7,6 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, HasAttrs}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_feature::Features; use rustc_middle::ty::RegisteredTools; use rustc_session::Session; @@ -60,7 +59,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { self.inlined_check_id(id); 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 45b188205d228..e63d5584808b7 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; @@ -278,123 +277,115 @@ fn structurally_same_type_impl<'tcx>( let is_primitive_or_pointer = |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..)); - ensure_sufficient_stack(|| { - match (a.kind(), b.kind()) { - (&Adt(a_def, a_gen_args), &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), - tcx.type_of(b_did).instantiate(tcx, b_gen_args), - ckind, - ) - }, - ) + match (a.kind(), b.kind()) { + (&Adt(a_def, a_gen_args), &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; } - (Array(a_ty, a_len), 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, ckind, - ) - } - (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind) - } - (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => { - a_mutbl == b_mutbl - && structurally_same_type_impl( - seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, - ) + // 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; } - (Ref(_a_region, a_ty, a_mut), 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, ckind, - ) - } - (FnDef(..), 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); + // 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, ckind) - }) - && 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), + tcx.type_of(b_did).instantiate(tcx, b_gen_args), ckind, ) - } - (Tuple(..), 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. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Coroutine(..), Coroutine(..)) - | (CoroutineWitness(..), CoroutineWitness(..)) - | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) - | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) - | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, + }, + ) + } + (Array(a_ty, a_len), 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, ckind) + } + (Slice(a_ty), Slice(b_ty)) => { + structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind) + } + (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => { + a_mutbl == b_mutbl + && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind) + } + (Ref(_a_region, a_ty, a_mut), 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, ckind) + } + (FnDef(..), FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); - // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, 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. - (Adt(..), _) if is_primitive_or_pointer(b) => { - if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { - a_inner == b - } else { - 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, ckind) + }) + && structurally_same_type_impl( + seen_types, + tcx, + typing_env, + a_sig.output(), + b_sig.output(), + ckind, + ) + } + (Tuple(..), 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. + (Dynamic(..), Dynamic(..)) + | (Error(..), Error(..)) + | (Closure(..), Closure(..)) + | (Coroutine(..), Coroutine(..)) + | (CoroutineWitness(..), CoroutineWitness(..)) + | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) + | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) + | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, + + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), + + // An Adt and a primitive or pointer type. This can be FFI-safe if non-null + // enum layout optimisation is being applied. + (Adt(..), _) if is_primitive_or_pointer(b) => { + if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { + a_inner == b + } else { + false } - (_, Adt(..)) if is_primitive_or_pointer(a) => { - if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { - b_inner == a - } else { - false - } + } + (_, Adt(..)) if is_primitive_or_pointer(a) => { + if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { + b_inner == a + } else { + false } - - _ => false, } - }) + + _ => false, + } } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index a4d50c731042b..4fc2ab6990964 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -6,7 +6,6 @@ use std::any::Any; use std::cell::Cell; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; @@ -158,12 +157,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 b9a45ea3c2c5a..a2918724c2766 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,7 +6,6 @@ use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -1105,9 +1104,7 @@ impl<'tcx> TypeFolder> for WeakAliasTypeExpander<'tcx> { } self.depth += 1; - ensure_sufficient_stack(|| { - self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self) - }) + self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self) } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 466f67b1ba4d8..f38ac6e262c71 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/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}; 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/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a3d5376dcd405..2ddd56eb37ae2 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -2,7 +2,6 @@ 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_middle::mir::*; use rustc_middle::span_bug; @@ -43,10 +42,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let block_and = match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, source_info); - ensure_sufficient_stack(|| { - this.in_scope(region_scope, lint_level, |this| { - this.expr_into_dest(destination, block, value) - }) + this.in_scope(region_scope, lint_level, |this| { + this.expr_into_dest(destination, block, value) }) } ExprKind::Block { block: ast_block } => { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5791460a6b1c8..624f275ef8991 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -7,7 +7,6 @@ use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef}; use rustc_middle::bug; use rustc_middle::middle::region; @@ -1667,9 +1666,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/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index d75f01dfba09f..feb042538a48e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,6 +1,5 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::Idx; @@ -28,7 +27,7 @@ use crate::thir::util::UserAnnotatedTyHelpers; impl<'tcx> Cx<'tcx> { 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]> { 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 a13b00e192167..1b9cea3b388c5 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, 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 ed8678de1eb18..50ab7f645d1d2 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::captures::Captures; 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::BitSet; use rustc_middle::mir::tcx::PlaceTy; @@ -529,7 +528,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 a40768300f5d0..90b135d97d41b 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt}; @@ -111,18 +110,16 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( if recursion_limit.value_within_limit(*recursion) { *recursion += 1; stack.push(callee); - let found_recursion = ensure_sufficient_stack(|| { - process( - tcx, - typing_env, - callee, - target, - stack, - seen, - recursion_limiter, - recursion_limit, - ) - }); + let found_recursion = process( + tcx, + typing_env, + callee, + target, + stack, + seen, + recursion_limiter, + recursion_limit, + ); if found_recursion { return true; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 480d82c1a385b..2c51526fdcf02 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -465,11 +465,9 @@ fn collect_items_rec<'tcx>( recursion_limit, )); - rustc_data_structures::stack::ensure_sufficient_stack(|| { - let (used, mentioned) = tcx.items_of_instance((instance, mode)); - used_items.extend(used.into_iter().copied()); - mentioned_items.extend(mentioned.into_iter().copied()); - }); + let (used, mentioned) = tcx.items_of_instance((instance, mode)); + used_items.extend(used.into_iter().copied()); + mentioned_items.extend(mentioned.into_iter().copied()); } MonoItem::GlobalAsm(item_id) => { assert!( @@ -1173,13 +1171,8 @@ 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/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 70ceb22bfea58..7923173ae3f0e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; +use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; @@ -337,26 +337,24 @@ where // Deal with overflow, caching, and coinduction. // // The actual solver logic happens in `ecx.compute_goal`. - let result = ensure_sufficient_stack(|| { - search_graph.with_new_goal( - cx, - canonical_input, - &mut canonical_goal_evaluation, - |search_graph, canonical_goal_evaluation| { - EvalCtxt::enter_canonical( - cx, - search_graph, - canonical_input, - canonical_goal_evaluation, - |ecx, goal| { - let result = ecx.compute_goal(goal); - ecx.inspect.query_result(result); - result - }, - ) - }, - ) - }); + let result = search_graph.with_new_goal( + cx, + canonical_input, + &mut canonical_goal_evaluation, + |search_graph, canonical_goal_evaluation| { + EvalCtxt::enter_canonical( + cx, + search_graph, + canonical_input, + canonical_goal_evaluation, + |ecx, goal| { + let result = ecx.compute_goal(goal); + ecx.inspect.query_result(result); + result + }, + ) + }, + ); canonical_goal_evaluation.query_result(result); goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 0ec151ceb4542..a1b6815139dcd 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}; @@ -346,7 +345,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/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 99261eaa95cc1..5d5f014cdf882 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -709,8 +709,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::BitSet; use smallvec::{SmallVec, smallvec}; @@ -720,7 +718,6 @@ use self::PlaceValidity::*; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; -#[cfg(not(feature = "rustc"))] pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6fb5e37d2d066..b7fa24af59a70 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -11,7 +11,6 @@ use std::mem; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::Sharded; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lock; use rustc_data_structures::{outline, sync}; use rustc_errors::{Diag, FatalError, StashKey}; @@ -803,7 +802,7 @@ where { debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); - ensure_sufficient_stack(|| try_execute_query::(query, qcx, span, key, None).0) + try_execute_query::(query, qcx, span, key, None).0 } #[inline(always)] @@ -830,9 +829,7 @@ where None }; - let (result, dep_node_index) = ensure_sufficient_stack(|| { - try_execute_query::<_, _, true>(query, qcx, span, key, dep_node) - }); + let (result, dep_node_index) = try_execute_query::<_, _, true>(query, qcx, span, key, dep_node); if let Some(dep_node_index) = dep_node_index { qcx.dep_context().dep_graph().read_index(dep_node_index) } @@ -853,7 +850,5 @@ where debug_assert!(!query.anon()); - ensure_sufficient_stack(|| { - try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node)) - }); + try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node)); } 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 94682f501a8c4..1b630970c5920 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -8,7 +8,6 @@ use std::path::PathBuf; 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, @@ -3351,33 +3350,28 @@ 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_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - long_ty_file, - ) - }); + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ) } else { - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_id, - err, - parent_predicate, - param_env, - cause_code.peel_derives(), - obligated_types, - seen_requirements, - long_ty_file, - ) - }); - } + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + cause_code.peel_derives(), + obligated_types, + seen_requirements, + long_ty_file, + ) + }; } ObligationCauseCode::ImplDerived(ref data) => { let mut parent_trait_pred = @@ -3488,50 +3482,44 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )); } // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - long_ty_file, - ) - }); + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ); } 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_id, - err, - parent_predicate, - param_env, - &data.parent_code, - obligated_types, - seen_requirements, - long_ty_file, - ) - }); + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ); } ObligationCauseCode::TypeAlias(ref nested, span, def_id) => { // #74711: avoid a stack overflow - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_id, - err, - predicate, - param_env, - nested, - obligated_types, - seen_requirements, - long_ty_file, - ) - }); + self.note_obligation_cause_code( + body_id, + err, + predicate, + param_env, + nested, + obligated_types, + seen_requirements, + long_ty_file, + ); let mut multispan = MultiSpan::from(span); multispan.push_span_label(span, "required by this bound"); err.span_note( @@ -3551,18 +3539,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate, call_hir_id, ); - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_id, - err, - predicate, - param_env, - parent_code, - obligated_types, - seen_requirements, - long_ty_file, - ) - }); + self.note_obligation_cause_code( + body_id, + err, + predicate, + param_env, + parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ); } // Suppress `compare_type_predicate_entailment` errors for RPITITs, since they // should be implied by the parent method. diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index a724705ffe912..64350d21b0b78 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -2,7 +2,6 @@ use std::assert_matches::assert_matches; use std::fmt::Debug; use std::marker::PhantomData; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::InferCtxt; use rustc_infer::infer::at::At; use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine}; @@ -186,7 +185,7 @@ where if ty.has_escaping_bound_vars() { let (ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); - let result = ensure_sufficient_stack(|| self.normalize_alias_ty(ty))?; + let result = self.normalize_alias_ty(ty)?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -196,7 +195,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_alias_ty(ty)) + self.normalize_alias_ty(ty) } } @@ -216,7 +215,7 @@ where if uv.has_escaping_bound_vars() { let (uv, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?; + let result = self.normalize_unevaluated_const(uv)?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -226,7 +225,7 @@ where result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv)) + self.normalize_unevaluated_const(uv) } } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index ad62b456ad461..3a285d5c0e0ea 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_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ @@ -112,7 +111,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)); + let result = AssocTypeNormalizer::fold(&mut normalizer, value); 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 49c34550f8e03..2a4a12d292dd3 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::def::DefKind; use rustc_hir::lang_items::LangItem; @@ -1925,27 +1924,23 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cache_projection = cache_entry.projection_term; let mut nested_obligations = PredicateObligations::new(); let obligation_projection = obligation.predicate; - let obligation_projection = ensure_sufficient_stack(|| { + let obligation_projection = normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation_projection, + &mut nested_obligations, + ); + let cache_projection = if potentially_unnormalized_candidate { normalize_with_depth_to( selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - obligation_projection, + cache_projection, &mut nested_obligations, ) - }); - let cache_projection = if potentially_unnormalized_candidate { - ensure_sufficient_stack(|| { - normalize_with_depth_to( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - cache_projection, - &mut nested_obligations, - ) - }) } else { cache_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 1d3e8d43af743..4896922c3dc3a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -240,39 +240,28 @@ 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)?; } - Ok::<_, NoSolution>(()) - })?, + Ok::<_, NoSolution>(())? + } - 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)?; } - Ok::<_, NoSolution>(()) - })?, + Ok::<_, NoSolution>(())? + } 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, - )?; - } - Ok::<_, NoSolution>(()) - })? + for ty in args.as_coroutine_closure().upvar_tys() { + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(())? } ty::Coroutine(_, args) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2ef9d5421ba6c..81c0926eab0e8 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_ty` 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; @@ -247,7 +246,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 2fbe2e1e323be..1587660887d48 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,7 +11,6 @@ use std::iter; use std::ops::ControlFlow; use rustc_ast::Mutability; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; use rustc_infer::traits::ObligationCauseCode; @@ -454,36 +453,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: ty::Binder<'tcx, Vec>>, ) -> PredicateObligations<'tcx> { debug!(?nested, "vtable_auto_impl"); - ensure_sufficient_stack(|| { - let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); - let trait_obligations = self.impl_or_trait_obligations( - &cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - trait_ref.args, - obligation.predicate, - ); + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); + let trait_obligations = self.impl_or_trait_obligations( + &cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + trait_ref.args, + obligation.predicate, + ); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It won't have any effect since auto traits are coinductive. + obligations.extend(trait_obligations); - debug!(?obligations, "vtable_auto_impl"); + debug!(?obligations, "vtable_auto_impl"); - obligations - }) + obligations } fn confirm_impl_candidate( @@ -497,16 +494,14 @@ 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( @@ -1004,15 +999,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, - (obligation.predicate.trait_ref, found_trait_ref), - ) - }); + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + (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 d362866cbc38d..c792853c1d142 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -10,7 +10,6 @@ use std::{cmp, iter}; use hir::def::DefKind; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::LangItem; @@ -632,394 +631,378 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - 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(arg)) => { - // 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_arg in previous_stack.cache.wf_args.borrow().iter().rev() { - if stack_arg.0 != arg { - continue; - } - debug!("WellFormed({:?}) on stack", arg); - 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_arg.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_arg.1); - return Ok(EvaluatedToOk); - } else { - return Ok(EvaluatedToAmbigStackDependent); - } - } - return Ok(EvaluatedToOk); + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + // 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_arg in previous_stack.cache.wf_args.borrow().iter().rev() { + if stack_arg.0 != arg { + continue; } - - match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - obligation.recursion_depth + 1, - arg, - obligation.cause.span, - ) { - Some(obligations) => { - cache.wf_args.borrow_mut().push((arg, 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", arg); + 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_arg.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_arg.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_infer() - { - Ok(EvaluatedToOkModuloRegions) - } else { - Ok(EvaluatedToOk) + match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + obligation.recursion_depth + 1, + arg, + obligation.cause.span, + ) { + Some(obligations) => { + cache.wf_args.borrow_mut().push((arg, 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_infer() + { Ok(EvaluatedToOkModuloRegions) + } else { + Ok(EvaluatedToOk) } + } - ty::PredicateKind::DynCompatible(trait_def_id) => { - 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) => { + 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) = + 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, + ) { + if 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 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::ConstEvaluatable(uv)) => { - match const_evaluatable::is_const_evaluatable( - self.infcx, - uv, - 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(uv)) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + uv, + 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 + ); - use rustc_hir::def::DefKind; - match (c1.kind(), c2.kind()) { - (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) - if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => + use rustc_hir::def::DefKind; + match (c1.kind(), c2.kind()) { + (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) + if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst => + { + 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::Unevaluated(_)) - | (ty::ConstKind::Unevaluated(_), _) => (), - (_, _) => { - 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::Unevaluated(_) = 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) + (_, ty::ConstKind::Unevaluated(_)) | (ty::ConstKind::Unevaluated(_), _) => { + () } - }; - - match (evaluate(c1), evaluate(c2)) { - (Ok(c1), Ok(c2)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq( + (_, _) => { + 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::AliasRelate(..) => { - bug!("AliasRelate 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(ty, _) => ty, - ty::ConstKind::Unevaluated(uv) => { - self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) + + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(_) = 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_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::AliasRelate(..) => { + bug!("AliasRelate 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(ty, _) => ty, + ty::ConstKind::Unevaluated(uv) => { + self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) + } + // 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_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)] @@ -1688,15 +1671,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, - trait_bound, - ) - }); + let Normalized { value: trait_bound, obligations: _ } = normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_bound, + ); self.infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, placeholder_trait_ref, trait_bound) @@ -1746,16 +1727,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { env_predicate, ); let infer_projection = if potentially_unnormalized_candidates { - ensure_sufficient_stack(|| { - normalize_with_depth_to( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - infer_predicate.projection_term, - &mut nested_obligations, - ) - }) + normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + infer_predicate.projection_term, + &mut nested_obligations, + ) } else { infer_predicate.projection_term }; @@ -2447,16 +2426,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ let placeholder_ty = self.infcx.enter_forall_and_leak_universe(ty); - let Normalized { value: normalized_ty, mut obligations } = - ensure_sufficient_stack(|| { - normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - placeholder_ty, - ) - }); + let Normalized { value: normalized_ty, mut obligations } = normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + placeholder_ty, + ); let tcx = self.tcx(); let trait_ref = if tcx.generics_of(trait_def_id).own_params.len() == 1 { @@ -2519,15 +2495,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { debug!(?impl_trait_header); let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - ensure_sufficient_stack(|| { - normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_ref, - ) - }); + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_ref, + ); debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref);