From b72b605781514a705cfb6b36ef0164183747409b Mon Sep 17 00:00:00 2001 From: Adwin White Date: Mon, 13 Jul 2026 21:46:59 +0800 Subject: [PATCH] add FCW for next solver overflow --- compiler/rustc_infer/src/infer/context.rs | 4 + compiler/rustc_lint_defs/src/builtin.rs | 63 +++++++++++ compiler/rustc_middle/src/queries.rs | 4 +- compiler/rustc_middle/src/query/keys.rs | 6 + .../src/ty/context/impl_interner.rs | 27 ++++- .../src/solve/eval_ctxt/mod.rs | 106 ++++++++++++++++-- compiler/rustc_trait_selection/src/solve.rs | 5 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 2 + compiler/rustc_type_ir/src/interner.rs | 3 + compiler/rustc_type_ir/src/solve/mod.rs | 14 +++ ...te-instantiation-struct-tail-ice-114484.rs | 2 +- .../overflow/fcw-on-auto-trait.next.stderr | 28 +++++ .../next-solver/overflow/fcw-on-auto-trait.rs | 27 +++++ .../overflow/fcw-on-normalization.next.stderr | 104 +++++++++++++++++ .../overflow/fcw-on-normalization.rs | 63 +++++++++++ .../next-solver/overflow/global-cache.rs | 3 +- .../next-solver/overflow/global-cache.stderr | 6 +- .../ui/traits/next-solver/unsize-overflow.rs | 8 +- .../traits/next-solver/unsize-overflow.stderr | 10 +- 19 files changed, 458 insertions(+), 27 deletions(-) create mode 100644 tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr create mode 100644 tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs create mode 100644 tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr create mode 100644 tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d1a56d5ab073c..07f25001de30c 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -308,6 +308,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.probe(|_| probe()) } + fn commit_if_ok(&self, commit: impl FnOnce() -> Result) -> Result { + self.commit_if_ok(|_| commit()) + } + fn sub_regions( &self, sub: ty::Region<'tcx>, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 75d8d3d129278..959d693d33e26 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -78,6 +78,7 @@ pub mod hardwired { MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, + NEXT_TRAIT_SOLVER_OVERFLOW, NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, OUT_OF_SCOPE_MACRO_CALLS, @@ -5579,3 +5580,65 @@ declare_lint! { report_in_deps: true, }; } + +declare_lint! { + /// The `next_trait_solver_overflow` lint detects situations where the obligation evaluation + /// overflows with the next solver but not with the old solver. + /// + /// ### Example + /// ```text + /// rustc -Znext-solver example.rs + /// ``` + /// + /// ```rust,ignore (requires next solver) + /// #![recursion_limit = "8"] + /// struct Foo { + /// t: T, + /// opt_t: Option, + /// } + /// fn require_sync() {} + /// fn main() { + /// require_sync::>>>>>>(); + /// } + /// ``` + /// + /// This will produces: + /// ```text + /// error[E0275]: overflow evaluating the requirement `Foo>>>>>: Sync` + /// --> example.rs:12:20 + /// | + /// | require_sync::>>>>>>(); + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate + /// note: required by a bound in `require_sync` + /// --> example.rs:9:20 + /// | + /// | fn require_sync() {} + /// | ^^^^ required by this bound in `require_sync` + /// ``` + /// + /// ### Explanation + /// + /// The trait solvers use a recursion limit to avoid hangs from deeply nested obligations. + /// They also use caches to avoid redundant computation. This is a performance optimization and + /// shouldn't affect the final evaluation result. + /// + /// However, the old solver doesn't validate depth requirement when looking up cache. This means + /// evaluation results depend on whether cache entries exists which in turn depends on cache + /// insertion order. + /// + /// The next solver correctly records and validates recursion depth requirements when using + /// the cache. This makes it more prone to overflow compared to the old solver. + /// + /// This is a [future-incompatible] lint to transition this to a hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub NEXT_TRAIT_SOLVER_OVERFLOW, + Warn, + "detects trait solving overflow that only happens with the next solver", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #159228), + report_in_deps: false, + }; +} diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 2fcab301fe763..4080fde3a0693 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2597,10 +2597,10 @@ rustc_queries! { /// Used by `-Znext-solver` to compute proof trees. query evaluate_root_goal_for_proof_tree_raw( - goal: solve::CanonicalInput<'tcx>, + key: (solve::CanonicalInput<'tcx>, usize) ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>) { no_hash - desc { "computing proof tree for `{}`", goal.canonical.value.goal.predicate } + desc { "computing proof tree for `{}` with depth `{}`", key.0.canonical.value.goal.predicate, key.1 } } /// Returns the Rust target features for the current target. These are not always the same as LLVM target features! diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 225618689647d..841efe4793b8e 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -340,6 +340,12 @@ impl<'tcx, T: QueryKeyBounds> QueryKey for (CanonicalQueryInput<'tcx, T>, bool) } } +impl<'tcx, T: QueryKeyBounds> QueryKey for (CanonicalQueryInput<'tcx, T>, usize) { + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> QueryKey for (Ty<'tcx>, rustc_abi::VariantIdx) { fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 3b1a64a7e80bb..c53ff1c706316 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -5,6 +5,7 @@ use std::{debug_assert_matches, fmt}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -786,8 +787,32 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn evaluate_root_goal_for_proof_tree_raw( self, canonical_goal: CanonicalInput<'tcx>, + root_depth: usize, ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>) { - self.evaluate_root_goal_for_proof_tree_raw(canonical_goal) + self.evaluate_root_goal_for_proof_tree_raw((canonical_goal, root_depth)) + } + + fn emit_next_solver_overflow_fcw(self, predicate: ty::Predicate<'tcx>, span: Span) { + self.emit_node_span_lint( + rustc_session::lint::builtin::NEXT_TRAIT_SOLVER_OVERFLOW, + CRATE_HIR_ID, + span, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message(format!( + "reached the recursion limit {} when proving trait bound {}", + self.recursion_limit(), + predicate, + )); + diag.help(format!( + "consider increasing it by adding a `#![recursion_limit = \"{}\"]`", + self.recursion_limit() * 2 + )); + diag.help( + "or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", + ); + diag.note("this lint is attached to the whole crate and can't be disabled on a per-function basis"); + }), + ) } fn item_name(self, id: DefId) -> Symbol { 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 48a421bb5dd9b..387891558851c 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 @@ -246,10 +246,51 @@ where return Ok(res); } - let result = EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| { - // Fast paths handled above - ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal) - }); + let eval_with_recursion_limit = |limit| { + EvalCtxt::enter_root(self, limit, span, |ecx| { + ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal) + }) + }; + let is_overflow_and_has_no_stalled_infers = |eval_result: &Result, _>| { + let predicate = match eval_result { + Err(_) => return false, + Ok(goal_evaluation) if !goal_evaluation.certainty.is_overflow() => return false, + Ok(goal_evaluation) => goal_evaluation.goal.predicate, + }; + + let has_no_stalled_infers = match predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) => { + !projection.projection_term.has_non_region_infer() + } + _ => !predicate.has_non_region_infer(), + }; + has_no_stalled_infers + }; + + // The old solver doesn't check depth requirement when looking up cache + // while the next solver does so. Thus the next solver is more prone to + // overflow. We rerun the overflowed goal with doubled recursion limit + // and emit a FCW for this. See #159228. + let mut result = eval_with_recursion_limit(self.cx().recursion_limit()); + if !self.typing_mode_raw().is_coherence() && is_overflow_and_has_no_stalled_infers(&result) + { + let rerun_result = self.commit_if_ok(|| { + let new_result = eval_with_recursion_limit(self.cx().recursion_limit() * 2); + if let Ok(goal_evaluation) = &new_result + && goal_evaluation.certainty.is_yes() + { + let predicate = goal_evaluation.goal.predicate; + Ok((new_result, predicate)) + } else { + Err(()) + } + }); + if let Ok((new_result, predicate)) = rerun_result { + // Predicates from evaluation results are eagerly resolved. + self.cx().emit_next_solver_overflow_fcw(predicate, span); + result = new_result; + } + } match result { Ok(i) => Ok(i), @@ -302,7 +343,56 @@ where goal: Goal, span: I::Span, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { - evaluate_root_goal_for_proof_tree(self, goal, span) + let is_overflow_and_has_no_stalled_infers = + |goal_evaluation: &inspect::GoalEvaluation| { + match goal_evaluation.result { + Err(_) => return false, + Ok(response) if !response.value.certainty.is_overflow() => return false, + Ok(_) => {} + } + + let predicate: I::Predicate = goal_evaluation.uncanonicalized_goal.predicate; + let has_no_stalled_infers = match predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) => { + !projection.projection_term.has_non_region_infer() + } + _ => !predicate.has_non_region_infer(), + }; + has_no_stalled_infers + }; + + // The old solver doesn't check depth requirement when looking up cache + // while the next solver does so. Thus the next solver is more prone to + // overflow. We rerun the overflowed goal with doubled recursion limit + // and emit a FCW for this. See #159228. + let (mut result, mut goal_evaluation) = + evaluate_root_goal_for_proof_tree(self, goal, span, self.cx().recursion_limit()); + if !self.typing_mode_raw().is_coherence() + && is_overflow_and_has_no_stalled_infers(&goal_evaluation) + { + let rerun_result = self.commit_if_ok(|| { + let (new_result, new_goal_evaluation) = evaluate_root_goal_for_proof_tree( + self, + goal, + span, + self.cx().recursion_limit() * 2, + ); + if let Ok(response) = &new_goal_evaluation.result + && response.value.certainty.is_yes() + { + let predicate = new_goal_evaluation.uncanonicalized_goal.predicate; + Ok((new_result, new_goal_evaluation, predicate)) + } else { + Err(()) + } + }); + if let Ok((new_result, new_goal_evaluation, predicate)) = rerun_result { + self.cx().emit_next_solver_overflow_fcw(predicate, span); + result = new_result; + goal_evaluation = new_goal_evaluation; + } + } + (result, goal_evaluation) } } @@ -1701,11 +1791,12 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider< >( cx: I, canonical_goal: CanonicalInput, + root_depth: usize, ) -> (QueryResult, I::Probe) { let mut inspect = inspect::ProofTreeBuilder::new(); let (canonical_result, accessed_opaques) = SearchGraph::::evaluate_root_goal_for_proof_tree( cx, - cx.recursion_limit(), + root_depth, canonical_goal, &mut inspect, ); @@ -1723,6 +1814,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, delegate: &D, goal: Goal, origin_span: I::Span, + root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(&**delegate, (goal, opaque_types)); @@ -1732,7 +1824,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, canonicalize_goal(delegate, goal, &opaque_types, typing_mode.into()); let (canonical_result, final_revision) = - delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); + delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal, root_depth); let proof_tree = inspect::GoalEvaluation { uncanonicalized_goal: goal, diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 3361780196e26..f6c01b12ae4c0 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -19,11 +19,10 @@ pub use select::InferCtxtSelectExt; fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, - canonical_input: CanonicalInput>, + key: (CanonicalInput>, usize), ) -> (QueryResult>, &'tcx inspect::Probe>) { evaluate_root_goal_for_proof_tree_raw_provider::, TyCtxt<'tcx>>( - tcx, - canonical_input, + tcx, key.0, key.1, ) } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 6a011e82dcbbf..ff52b4b9cca73 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -462,6 +462,8 @@ pub trait InferCtxtLike: Sized { fn probe(&self, probe: impl FnOnce() -> T) -> T; + fn commit_if_ok(&self, commit: impl FnOnce() -> Result) -> Result; + fn sub_regions( &self, sub: ::Region, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 815890c989d93..d4082229268d4 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -460,8 +460,11 @@ pub trait Interner: fn evaluate_root_goal_for_proof_tree_raw( self, canonical_goal: CanonicalInput, + root_depth: usize, ) -> (QueryResult, Self::Probe); + fn emit_next_solver_overflow_fcw(self, predicate: Self::Predicate, span: Self::Span); + fn item_name(self, item_index: Self::DefId) -> Self::Symbol; } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 5c8f1bab46b94..1972154347c38 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -848,6 +848,20 @@ impl Certainty { stalled_on_coroutines: StalledOnCoroutines::No, }) } + + pub fn is_yes(&self) -> bool { + match self { + Certainty::Yes => true, + Certainty::Maybe(_) => false, + } + } + + pub fn is_overflow(&self) -> bool { + match self { + Certainty::Maybe(MaybeInfo { cause: MaybeCause::Overflow { .. }, .. }) => true, + _ => false, + } + } } /// Why we failed to evaluate a goal. diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs index 1abfd88b6bf41..313e0f419c371 100644 --- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs +++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs @@ -13,7 +13,7 @@ //~| ERROR reached the recursion limit while instantiating ` as MyTrait>::virtualize` //@ build-fail -//@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes +//@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes -Awarnings // Regression test for #114484: This used to ICE during monomorphization, because we treated // ` as Pointee>::Metadata` as a rigid projection after reaching the recursion diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr new file mode 100644 index 0000000000000..4fccb121d0bf7 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.next.stderr @@ -0,0 +1,28 @@ +warning: reached the recursion limit 8 when proving trait bound Foo>>>>>: Sync + --> $DIR/fcw-on-auto-trait.rs:22:5 + | +LL | require_sync::>>>>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: `#[warn(next_trait_solver_overflow)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: reached the recursion limit 8 when proving trait bound Foo>>>>>: Sync + --> $DIR/fcw-on-auto-trait.rs:22:5 + | +LL | require_sync::>>>>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs new file mode 100644 index 0000000000000..a7111bcb514a3 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-on-auto-trait.rs @@ -0,0 +1,27 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// The old solver doesn't verify depth when looking up cache. +// To avoid breakage, we evaluate with higher recursion limit in the next solver +// and emit an FCW for this. +// See the `NEXT_TRAIT_SOLVER_OVERFLOW` FCW. + +#![recursion_limit = "8"] + +// The field order matters 😂 +#[allow(dead_code)] +struct Foo { + t: T, + opt_t: Option, +} + +fn require_sync() {} + +fn main() { + require_sync::>>>>>>(); + //[next]~^ WARN: reached the recursion limit 8 when proving trait bound Foo>>>>>: Sync [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound Foo>>>>>: Sync [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr new file mode 100644 index 0000000000000..855187fc1420d --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.next.stderr @@ -0,0 +1,104 @@ +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: `#[warn(next_trait_solver_overflow)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: reached the recursion limit 8 when proving trait bound W>>>>>>>>>: HasAssoc + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed + --> $DIR/fcw-on-normalization.rs:41:12 + | +LL | let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing it by adding a `#![recursion_limit = "16"]` + = help: or consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved + = note: this lint is attached to the whole crate and can't be disabled on a per-function basis + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #159228 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +warning: 8 warnings emitted + diff --git a/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs new file mode 100644 index 0000000000000..e77d69d790c94 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/fcw-on-normalization.rs @@ -0,0 +1,63 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// The old solver doesn't verify depth when looking up cache. +// To avoid breakage, we evaluate with higher recursion limit in the next solver +// and emit an FCW for this. +// See the `NEXT_TRAIT_SOLVER_OVERFLOW` FCW. + +#![recursion_limit = "8"] + +trait Trait { + fn anyone_can_call(&self); +} + +trait HasAssoc { + type Assoc; +} + +struct W(T); + +impl HasAssoc for W { + type Assoc = T::Assoc; +} + +impl HasAssoc for () { + type Assoc = (); +} + +impl Trait for () { + fn anyone_can_call(&self) {} +} + + +fn foo() { + // Insert a cache entry for the old solver. Without this, the old solver + // also overflows. + let a: >>>>>> as HasAssoc>::Assoc = loop {}; + a.anyone_can_call(); + + let b: >>>>>>>>> as HasAssoc>::Assoc = loop {}; + //[next]~^ WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound W>>>>>>>>>: HasAssoc [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc == _ [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //[next]~| WARN: reached the recursion limit 8 when proving trait bound >>>>>>>>> as HasAssoc>::Assoc well-formed [next_trait_solver_overflow] + //[next]~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + + // Force normalization when looking up methods and the self_ty is normalized to infer. + b.anyone_can_call(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/global-cache.rs b/tests/ui/traits/next-solver/overflow/global-cache.rs index 5c5f8e1d1a271..29700ffeb47b0 100644 --- a/tests/ui/traits/next-solver/overflow/global-cache.rs +++ b/tests/ui/traits/next-solver/overflow/global-cache.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Znext-solver +//@ compile-flags: -Znext-solver -Awarnings // Check that we consider the reached depth of global cache // entries when detecting overflow. We would otherwise be unstable @@ -19,5 +19,6 @@ type Four = Inc>>>; fn main() { impls_trait::>>(); impls_trait::>>>>(); + impls_trait::>>>>>>(); //~^ ERROR overflow evaluating the requirement } diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr index de743dc00b891..a96bc2f9f5a67 100644 --- a/tests/ui/traits/next-solver/overflow/global-cache.stderr +++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow evaluating the requirement `Inc>>>>>>: Trait` - --> $DIR/global-cache.rs:21:19 + --> $DIR/global-cache.rs:22:19 | -LL | impls_trait::>>>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impls_trait::>>>>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`) note: required by a bound in `impls_trait` diff --git a/tests/ui/traits/next-solver/unsize-overflow.rs b/tests/ui/traits/next-solver/unsize-overflow.rs index 036be02aaeae3..ee395e55d8c75 100644 --- a/tests/ui/traits/next-solver/unsize-overflow.rs +++ b/tests/ui/traits/next-solver/unsize-overflow.rs @@ -1,7 +1,7 @@ -//@ compile-flags: -Znext-solver -#![recursion_limit = "8"] +//@ compile-flags: -Znext-solver -Awarnings +#![recursion_limit = "6"] fn main() { - let _: Box = Box::new(&&&&&&&1); - //~^ ERROR overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized> + let _: Box = Box::new(&&&&&&&&&&&&1); + //~^ ERROR overflow evaluating the requirement `Box<&&&&&&&&&&&&i32>: CoerceUnsized> } diff --git a/tests/ui/traits/next-solver/unsize-overflow.stderr b/tests/ui/traits/next-solver/unsize-overflow.stderr index ae0f2957243c7..c5a08ca57a11c 100644 --- a/tests/ui/traits/next-solver/unsize-overflow.stderr +++ b/tests/ui/traits/next-solver/unsize-overflow.stderr @@ -1,11 +1,11 @@ -error[E0275]: overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized>` +error[E0275]: overflow evaluating the requirement `Box<&&&&&&&&&&&&i32>: CoerceUnsized>` --> $DIR/unsize-overflow.rs:5:28 | -LL | let _: Box = Box::new(&&&&&&&1); - | ^^^^^^^^^^^^^^^^^^ +LL | let _: Box = Box::new(&&&&&&&&&&&&1); + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`unsize_overflow`) - = note: required for the cast from `Box<&&&&&&&i32>` to `Box` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "12"]` attribute to your crate (`unsize_overflow`) + = note: required for the cast from `Box<&&&&&&&&&&&&i32>` to `Box` error: aborting due to 1 previous error