From 2f6b0618b2076a9445480fbde4f1fb98986c826d Mon Sep 17 00:00:00 2001 From: Giang Dao Date: Fri, 20 Sep 2024 21:49:37 +0800 Subject: [PATCH 1/8] dont regenerate new links for rexports --- compiler/rustc_hir/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c1a4a4497c7a9..381062b142971 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -33,6 +33,7 @@ pub mod weak_lang_items; #[cfg(test)] mod tests; +#[doc(no_inline)] pub use hir::*; pub use hir_id::*; pub use lang_items::{LangItem, LanguageItems}; From ff86fa50fbb71073ec828e82fbfa431a3bdac2b1 Mon Sep 17 00:00:00 2001 From: Giang Dao Date: Fri, 20 Sep 2024 23:30:31 +0800 Subject: [PATCH 2/8] no_inline for index vec --- compiler/rustc_index/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 52f354b8ecaff..cae55230b0679 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -17,6 +17,7 @@ mod vec; pub use idx::Idx; pub use rustc_index_macros::newtype_index; pub use slice::IndexSlice; +#[doc(no_inline)] pub use vec::IndexVec; /// Type size assertion. The first argument is a type and the second argument is its expected size. From 287eb03838d5ff211706c8df8f5357034219472f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Oct 2024 12:25:26 +0200 Subject: [PATCH 3/8] fix/update teach_note from 'escaping mutable ref/ptr' const-check --- compiler/rustc_const_eval/messages.ftl | 51 ++++++++++--------- .../src/check_consts/check.rs | 1 + .../rustc_const_eval/src/check_consts/ops.rs | 6 +-- compiler/rustc_const_eval/src/errors.rs | 12 ++--- tests/ui/error-codes/E0010-teach.stderr | 2 +- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 73a9a1569f64e..24dbe688f363b 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -134,14 +134,16 @@ const_eval_incompatible_return_types = const_eval_incompatible_types = calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} -const_eval_interior_mutable_data_refer = +const_eval_interior_mutable_ref_escaping = {const_eval_const_context}s cannot refer to interior mutable data .label = this borrow of an interior mutable value may end up in the final value .help = to fix this, the value can be extracted to a separate `static` item and then referenced .teach_note = - A constant containing interior mutable data behind a reference can allow you to modify that data. - This would make multiple uses of a constant to be able to see different values and allow circumventing - the `Send` and `Sync` requirements for shared mutable data, which is unsound. + References that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. const_eval_intern_kind = {$kind -> [static] static @@ -229,6 +231,24 @@ const_eval_modified_global = const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} +const_eval_mutable_raw_escaping = + raw mutable pointers are not allowed in the final value of {const_eval_const_context}s + .teach_note = + Pointers that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. + +const_eval_mutable_ref_escaping = + mutable references are not allowed in the final value of {const_eval_const_context}s + .teach_note = + References that escape into the final value of a constant or static must be immutable. + This is to avoid accidentally creating shared mutable state. + + + If you really want global mutable state, try using an interior mutable `static` or a `static mut`. + const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead const_eval_non_const_fmt_macro_call = cannot call non-const formatting macro in {const_eval_const_context}s @@ -364,30 +384,11 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in const_eval_unallowed_heap_allocations = allocations are not allowed in {const_eval_const_context}s .label = allocation not allowed in {const_eval_const_context}s - .teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + .teach_note = + The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s -const_eval_unallowed_mutable_raw = - raw mutable pointers are not allowed in the final value of {const_eval_const_context}s - .teach_note = - References in statics and constants may only refer to immutable values. - - - Statics are shared everywhere, and if they refer to mutable data one might violate memory - safety since holding multiple mutable references to shared data is not allowed. - - - If you really want global mutable state, try using static mut or a global UnsafeCell. - -const_eval_unallowed_mutable_refs = - mutable references are not allowed in the final value of {const_eval_const_context}s - .teach_note = - Statics are shared everywhere, and if they refer to mutable data one might violate memory - safety since holding multiple mutable references to shared data is not allowed. - - - If you really want global mutable state, try using static mut or a global UnsafeCell. const_eval_unallowed_op_in_const_context = {$msg} diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 2cbf242fcf28d..463a66d4e2e46 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -666,6 +666,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } + // This can be called on stable via the `vec!` macro. if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); return; diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 6eb33c29e1d89..5c4a899f28a14 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -402,7 +402,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow { DiagImportance::Secondary } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { + ccx.dcx().create_err(errors::InteriorMutableRefEscaping { span, opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)), kind: ccx.const_kind(), @@ -430,12 +430,12 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { match self.0 { - hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { + hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping { span, kind: ccx.const_kind(), teach: ccx.tcx.sess.teach(E0764), }), - hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { + hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping { span, kind: ccx.const_kind(), teach: ccx.tcx.sess.teach(E0764), diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index c60bacb85067f..c943236affc56 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -118,8 +118,8 @@ pub(crate) struct UnstableConstFn { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_refs, code = E0764)] -pub(crate) struct UnallowedMutableRefs { +#[diag(const_eval_mutable_ref_escaping, code = E0764)] +pub(crate) struct MutableRefEscaping { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -128,8 +128,8 @@ pub(crate) struct UnallowedMutableRefs { } #[derive(Diagnostic)] -#[diag(const_eval_unallowed_mutable_raw, code = E0764)] -pub(crate) struct UnallowedMutableRaw { +#[diag(const_eval_mutable_raw_escaping, code = E0764)] +pub(crate) struct MutableRawEscaping { #[primary_span] pub span: Span, pub kind: ConstContext, @@ -181,8 +181,8 @@ pub(crate) struct UnallowedInlineAsm { } #[derive(Diagnostic)] -#[diag(const_eval_interior_mutable_data_refer, code = E0492)] -pub(crate) struct InteriorMutableDataRefer { +#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)] +pub(crate) struct InteriorMutableRefEscaping { #[primary_span] #[label] pub span: Span, diff --git a/tests/ui/error-codes/E0010-teach.stderr b/tests/ui/error-codes/E0010-teach.stderr index 7634970f36e2e..37a9892ccbf49 100644 --- a/tests/ui/error-codes/E0010-teach.stderr +++ b/tests/ui/error-codes/E0010-teach.stderr @@ -4,7 +4,7 @@ error[E0010]: allocations are not allowed in constants LL | const CON: Vec = vec![1, 2, 3]; | ^^^^^^^^^^^^^ allocation not allowed in constants | - = note: The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + = note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const fn `slice::::into_vec::` in constants From d6aaf7b036868c29e74ec380493f81ecbd1a4503 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 10 Oct 2024 03:38:10 +0200 Subject: [PATCH 4/8] Avoid redundant -Wl,-dylib flag when linking --- compiler/rustc_codegen_ssa/src/back/linker.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 3f3d305da0142..c4bb82d0dd7b1 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -404,12 +404,14 @@ impl<'a> GccLinker<'a> { fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { - if !self.is_ld { + if self.is_cc() { + // `-dynamiclib` makes `cc` pass `-dylib` to the linker. self.cc_arg("-dynamiclib"); + } else { + self.link_arg("-dylib"); + // Clang also sets `-dynamic`, but that's implied by `-dylib`, so unnecessary. } - self.link_arg("-dylib"); - // Note that the `osx_rpath_install_name` option here is a hack // purely to support bootstrap right now, we should get a more // principled solution at some point to force the compiler to pass From 09b634a4ba72336f1de2e3f5dccadd6e5bc3a011 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 10 Oct 2024 04:03:48 +0200 Subject: [PATCH 5/8] Fix hardcoded strip path when cross-compiling from Linux to Darwin --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e7b1c63a82251..34dc599e4fddd 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1087,7 +1087,9 @@ fn link_natively( let strip = sess.opts.cg.strip; if sess.target.is_like_osx { - let stripcmd = "/usr/bin/strip"; + // Use system `strip` when running on host macOS. + // + let stripcmd = if cfg!(target_os = "macos") { "/usr/bin/strip" } else { "strip" }; match (strip, crate_type) { (Strip::Debuginfo, _) => { strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S")) From 2a8f08083f32ed64fb367282b4896ee792f0c4a8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 10 Oct 2024 00:20:37 -0400 Subject: [PATCH 6/8] Structurallyresolve adts and tuples expectations too --- compiler/rustc_hir_typeck/src/expr.rs | 4 +-- .../traits/next-solver/typeck/guide-ctors.rs | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/typeck/guide-ctors.rs diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 95ca3e6647272..c5b7fc1eabd7c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1783,7 +1783,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let flds = expected.only_has_type(self).and_then(|ty| { - let ty = self.resolve_vars_with_obligations(ty); + let ty = self.try_structurally_resolve_type(expr.span, ty); match ty.kind() { ty::Tuple(flds) => Some(&flds[..]), _ => None, @@ -1861,7 +1861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - let adt_ty = self.resolve_vars_with_obligations(adt_ty); + let adt_ty = self.try_structurally_resolve_type(span, adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); diff --git a/tests/ui/traits/next-solver/typeck/guide-ctors.rs b/tests/ui/traits/next-solver/typeck/guide-ctors.rs new file mode 100644 index 0000000000000..7432ea78a56a0 --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/guide-ctors.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Makes sure we structurally normalize before trying to use expectation to guide +// coercion in adt and tuples. + +use std::any::Any; + +trait Coerce { + type Assoc; +} + +struct TupleGuidance; +impl Coerce for TupleGuidance { + type Assoc = (&'static dyn Any,); +} + +struct AdtGuidance; +impl Coerce for AdtGuidance { + type Assoc = Adt<&'static dyn Any>; +} + +struct Adt { + f: T, +} + +fn foo<'a, T: Coerce>(_: T::Assoc) {} + +fn main() { + foo::((&0u32,)); + foo::(Adt { f: &0u32 }); +} From e48159953692320c4866c960e144f7af5551c998 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 10 Oct 2024 01:09:13 -0400 Subject: [PATCH 7/8] Add myself back to review rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index d3e4af9b71899..231a7bba1f7c9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -923,7 +923,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "BoxyUwU", "fmease", - "jhpratt", "jyn514", "oli-obk", ] From d6fd45c2e3ee24bedbc1b7643b622ab97f29537f Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 10 Oct 2024 09:26:49 +0000 Subject: [PATCH 8/8] impossible obligations check fast path --- .../src/solve/eval_ctxt/mod.rs | 72 ++++++++++++++----- .../rustc_next_trait_solver/src/solve/mod.rs | 8 +++ .../src/solve/search_graph.rs | 3 - compiler/rustc_trait_selection/src/solve.rs | 1 + .../src/solve/fulfill.rs | 15 ++-- .../src/traits/coherence.rs | 13 +++- .../rustc_type_ir/src/search_graph/mod.rs | 12 ++-- tests/crashes/124894.rs | 11 --- 8 files changed, 90 insertions(+), 45 deletions(-) delete mode 100644 tests/crashes/124894.rs 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 ffa800348f2ce..bc324dcbf51f4 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 @@ -18,8 +18,8 @@ use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, - GoalSource, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, - SolverMode, + GoalSource, HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, + QueryResult, SolverMode, }; pub(super) mod canonical; @@ -126,11 +126,31 @@ pub enum GenerateProofTree { } pub trait SolverDelegateEvalExt: SolverDelegate { + /// Evaluates a goal from **outside** of the trait solver. + /// + /// Using this while inside of the solver is wrong as it uses a new + /// search graph which would break cycle detection. fn evaluate_root_goal( &self, goal: Goal::Predicate>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>); + ) -> ( + Result<(HasChanged, Certainty), NoSolution>, + Option>, + ); + + /// Check whether evaluating `goal` with a depth of `root_depth` may + /// succeed. This only returns `false` if the goal is guaranteed to + /// not hold. In case evaluation overflows and fails with ambiguity this + /// returns `true`. + /// + /// This is only intended to be used as a performance optimization + /// in coherence checking. + fn root_goal_may_hold_with_depth( + &self, + root_depth: usize, + goal: Goal::Predicate>, + ) -> bool; // FIXME: This is only exposed because we need to use it in `analyse.rs` // which is not yet uplifted. Once that's done, we should remove this. @@ -139,7 +159,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate { goal: Goal::Predicate>, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, Option>, ); } @@ -149,31 +169,41 @@ where D: SolverDelegate, I: Interner, { - /// Evaluates a goal from **outside** of the trait solver. - /// - /// Using this while inside of the solver is wrong as it uses a new - /// search graph which would break cycle detection. #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, goal: Goal, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>) { - EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ) -> (Result<(HasChanged, Certainty), NoSolution>, Option>) { + EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } + fn root_goal_may_hold_with_depth( + &self, + root_depth: usize, + goal: Goal::Predicate>, + ) -> bool { + self.probe(|| { + EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, |ecx| { + ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + .0 + }) + .is_ok() + } + #[instrument(level = "debug", skip(self))] fn evaluate_root_goal_raw( &self, goal: Goal, generate_proof_tree: GenerateProofTree, ) -> ( - Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution>, Option>, ) { - EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, |ecx| { ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } @@ -197,10 +227,11 @@ where /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root( delegate: &D, + root_depth: usize, generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - let mut search_graph = SearchGraph::new(delegate.solver_mode()); + let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth); let mut ecx = EvalCtxt { delegate, @@ -339,7 +370,7 @@ where goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal, - ) -> Result<(bool, Certainty), NoSolution> { + ) -> Result<(HasChanged, Certainty), NoSolution> { let (normalization_nested_goals, has_changed, certainty) = self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; assert!(normalization_nested_goals.is_empty()); @@ -360,7 +391,7 @@ where goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, goal: Goal, - ) -> Result<(NestedNormalizationGoals, bool, Certainty), NoSolution> { + ) -> Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -378,8 +409,13 @@ where Ok(response) => response, }; - let has_changed = !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty(); + let has_changed = if !response.value.var_values.is_identity_modulo_regions() + || !response.value.external_constraints.opaque_types.is_empty() + { + HasChanged::Yes + } else { + HasChanged::No + }; let (normalization_nested_goals, certainty) = self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); @@ -552,7 +588,7 @@ where for (source, goal) in goals.goals { let (has_changed, certainty) = self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; - if has_changed { + if has_changed == HasChanged::Yes { unchanged_certainty = None; } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 309ab7f28d154..97f7c71f3fccc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -48,6 +48,14 @@ enum GoalEvaluationKind { Nested, } +/// Whether evaluating this goal ended up changing the +/// inference state. +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] +pub enum HasChanged { + Yes, + No, +} + // FIXME(trait-system-refactor-initiative#117): we don't detect whether a response // ended up pulling down any universes. fn has_no_inference_or_external_constraints( diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index e47cc03f5adf9..0e3f179b0c846 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -40,9 +40,6 @@ where } const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize = 4; - fn recursion_limit(cx: I) -> usize { - cx.recursion_limit() - } fn initial_provisional_result( cx: I, diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index e47f5389cd180..d425ab50ae0fd 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -6,6 +6,7 @@ pub mod inspect; mod normalize; mod select; +pub(crate) use delegate::SolverDelegate; pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c6e3ba3c95735..081d7a6a769a1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; +use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; use tracing::instrument; use super::Certainty; @@ -86,10 +86,7 @@ impl<'tcx> ObligationStorage<'tcx> { let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No) .0; - match result { - Ok((has_changed, _)) => has_changed, - _ => false, - } + matches!(result, Ok((HasChanged::Yes, _))) })); }) } @@ -113,7 +110,7 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { &self, infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - result: &Result<(bool, Certainty), NoSolution>, + result: &Result<(HasChanged, Certainty), NoSolution>, ) { if let Some(inspector) = infcx.obligation_inspector.get() { let result = match result { @@ -181,7 +178,11 @@ where continue; } }; - has_changed |= changed; + + if changed == HasChanged::Yes { + has_changed = true; + } + match certainty { Certainty::Yes => {} Certainty::Maybe(_) => self.obligations.register(obligation), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 27d2a3c15b9ac..b29e41beab551 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; pub use rustc_next_trait_solver::coherence::*; +use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, warn}; @@ -28,7 +29,7 @@ use crate::error_reporting::traits::suggest_new_overflow_limit; use crate::infer::InferOk; use crate::infer::outlives::env::OutlivesEnvironment; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use crate::solve::{deeply_normalize_for_diagnostics, inspect}; +use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{ @@ -333,6 +334,16 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; if infcx.next_trait_solver() { + // A fast path optimization, try evaluating all goals with + // a very low recursion depth and bail if any of them don't + // hold. + if !obligations.iter().all(|o| { + <&SolverDelegate<'tcx>>::from(infcx) + .root_goal_may_hold_with_depth(8, Goal::new(infcx.tcx, o.param_env, o.predicate)) + }) { + return IntersectionHasImpossibleObligations::Yes; + } + let ocx = ObligationCtxt::new_with_diagnostics(infcx); ocx.register_obligations(obligations.iter().cloned()); let errors_and_ambiguities = ocx.select_all_or_error(); diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index ac4d0795a92e8..f4fb03562de9c 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -81,7 +81,6 @@ pub trait Delegate { fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool; const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize; - fn recursion_limit(cx: Self::Cx) -> usize; fn initial_provisional_result( cx: Self::Cx, @@ -156,7 +155,7 @@ impl AvailableDepth { /// the remaining depth of all nested goals to prevent hangs /// in case there is exponential blowup. fn allowed_depth_for_nested( - cx: D::Cx, + root_depth: AvailableDepth, stack: &IndexVec>, ) -> Option { if let Some(last) = stack.raw.last() { @@ -170,7 +169,7 @@ impl AvailableDepth { AvailableDepth(last.available_depth.0 - 1) }) } else { - Some(AvailableDepth(D::recursion_limit(cx))) + Some(root_depth) } } @@ -360,6 +359,7 @@ struct ProvisionalCacheEntry { pub struct SearchGraph, X: Cx = ::Cx> { mode: SolverMode, + root_depth: AvailableDepth, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -374,9 +374,10 @@ pub struct SearchGraph, X: Cx = ::Cx> { } impl, X: Cx> SearchGraph { - pub fn new(mode: SolverMode) -> SearchGraph { + pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph { Self { mode, + root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), _marker: PhantomData, @@ -460,7 +461,8 @@ impl, X: Cx> SearchGraph { inspect: &mut D::ProofTreeBuilder, mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, ) -> X::Result { - let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::(cx, &self.stack) + let Some(available_depth) = + AvailableDepth::allowed_depth_for_nested::(self.root_depth, &self.stack) else { return self.handle_overflow(cx, input, inspect); }; diff --git a/tests/crashes/124894.rs b/tests/crashes/124894.rs deleted file mode 100644 index 230cf4a89c151..0000000000000 --- a/tests/crashes/124894.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#124894 -//@ compile-flags: -Znext-solver=coherence - -#![feature(generic_const_exprs)] - -pub trait IsTrue {} -impl IsZST for T where (): IsTrue<{ std::mem::size_of::() == 0 }> {} - -pub trait IsZST {} - -impl IsZST for IsZST {}