Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions compiler/rustc_ast_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ pub(crate) struct ImplFnConst {
pub parent_constness: Span,
}

#[derive(Diagnostic)]
#[diag("`feature(generic_const_exprs)` is not supported with the next-generation trait solver")]
#[note("`-Znext-solver=globally` is currently enabled by default for testing")]
#[note("reverted the setting to `-Znext-solver=coherence` for this crate")]
#[note("the currently stable trait solver will be used for this crate")]
#[note("see issues #160895 <https://github.com/rust-lang/rust/issues/160895> for more information")]
pub(crate) struct NextSolverDisabledForGenericConstExprs {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("functions in {$in_impl ->
[true] trait impls
Expand Down
19 changes: 7 additions & 12 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_errors::msg;
use rustc_feature::Features;
use rustc_session::Session;
use rustc_session::diagnostics::{feature_err, feature_warn};
use rustc_span::{Span, Spanned, Symbol, sym};
use rustc_span::{Span, Spanned, sym};

use crate::diagnostics;

Expand Down Expand Up @@ -436,7 +436,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
maybe_stage_features(sess, features, krate);
check_incompatible_features(sess, features);
check_dependent_features(sess, features);
check_new_solver_banned_features(sess, features);
warn_next_solver_and_gce(sess, features);
check_features_requiring_new_solver(sess, features);

let mut visitor = PostExpansionVisitor { sess, features };
Expand Down Expand Up @@ -721,26 +721,21 @@ fn check_dependent_features(sess: &Session, features: &Features) {
}
}

fn check_new_solver_banned_features(sess: &Session, features: &Features) {
fn warn_next_solver_and_gce(sess: &Session, features: &Features) {
if !sess.opts.unstable_opts.next_solver.globally {
return;
}

// Ban GCE with the new solver, because it does not implement GCE correctly.
// Warn people who uses GCE and -Znext-solver=globally
// that their trait solver was downgraded to -Znext-solver=no
if let Some(gce_span) = features
.enabled_lang_features()
.iter()
.find(|feat| feat.gate_name == sym::generic_const_exprs)
.map(|feat| feat.attr_sp)
{
// Abort immediately, otherwise GCE can lower to `ConstKind::Expr`,
// which the new solver intentionally does not support.
#[allow(rustc::symbol_intern_string_literal)]
sess.dcx().emit_fatal(diagnostics::IncompatibleFeatures {
spans: vec![gce_span],
f1: Symbol::intern("-Znext-solver=globally"),
f2: sym::generic_const_exprs,
});
sess.dcx()
.emit_warn(diagnostics::NextSolverDisabledForGenericConstExprs { span: gce_span });
}
}

Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,13 @@ fn test_unstable_options_tracking_hash() {
tracked!(mir_opt_level, Some(4));
tracked!(mir_preserve_ub, true);
tracked!(move_size_limit, Some(4096));
tracked!(next_solver, NextSolverConfig { coherence: true, globally: true });

// tidy-alphabetical-end
// FIXME(#160895): We don't test this when the next-solver is enabled by default.
if option_env!("CFG_DEFAULT_NEXT_SOLVER_GLOBALLY").is_none() {
tracked!(next_solver, NextSolverConfig { coherence: true, globally: true });
}
// tidy-alphabetical-start
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
tracked!(no_profiler_runtime, true);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2686,7 +2686,7 @@ impl<'tcx> TyCtxt<'tcx> {
}

pub fn next_trait_solver_globally(self) -> bool {
self.sess.opts.unstable_opts.next_solver.globally
self.sess.opts.unstable_opts.next_solver.globally && !self.features().generic_const_exprs()
}

pub fn next_trait_solver_in_coherence(self) -> bool {
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ impl ExternEntry {
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct NextSolverConfig {
/// Whether the new trait solver should be enabled in coherence.
pub coherence: bool = true,
Expand All @@ -1020,6 +1020,18 @@ pub struct NextSolverConfig {
pub globally: bool = false,
}

@lcnr lcnr Aug 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not part of this PR, but we allow coherence: bool = true even without derive(Default) that's surprising to me 🤔

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also surprised :) If you read the RFC, it can be used when constructing values of the struct manually (you can skip fields with a default value).


// FIXME(#160895): Using -Znext-solver as default on nightly
// See https://github.com/rust-lang/compiler-team/issues/1014
impl Default for NextSolverConfig {
fn default() -> Self {
if option_env!("CFG_DEFAULT_NEXT_SOLVER_GLOBALLY").is_some() {
Self { coherence: true, globally: true }
} else {
Self { coherence: true, globally: false }
}
}
}

#[derive(Clone)]
pub enum Input {
/// Load source code from a file.
Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1371,8 +1371,9 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS

let nightly = builder.config.channel == "nightly" || builder.config.channel == "dev";
if nightly {
// We want to enable Polonius Alpha by default on nighty
// We want to enable Polonius Alpha and Next Trait Solver by default on nighty
cargo.env("CFG_DEFAULT_POLONIUS_NEXT", "1");
cargo.env("CFG_DEFAULT_NEXT_SOLVER_GLOBALLY", "1");
}

// These conditionals represent a tension between three forces:
Expand Down
9 changes: 8 additions & 1 deletion src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3228,6 +3228,9 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
let mut cmd = builder.rustdoc_cmd(compiler);
builder.add_rust_test_threads(&mut cmd);
// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
cmd.arg("-Znext-solver=coherence");
// allow for unstable options such as new editions
cmd.arg("-Z");
cmd.arg("unstable-options");
Expand Down Expand Up @@ -3300,7 +3303,7 @@ impl CommandLineStep for CrateLibrustc {
///
/// Returns whether the test succeeded.
fn run_cargo_test<'a>(
cargo: builder::Cargo,
mut cargo: builder::Cargo,
libtest_args: &[&str],
crates: &[String],
description: impl Into<Option<&'a str>>,
Expand All @@ -3314,6 +3317,10 @@ fn run_cargo_test<'a>(
_ => compiler.stage + 1,
};

// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
cargo.rustdocflag("-Znext-solver=coherence");

@lcnr lcnr Aug 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we only set rustdocflag and not rustflag here. Do we only test rustdoc stuff here?

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cargo.rustdocflag("-Znext-solver=coherence");
cargo.rustflag("-Znext-solver=coherence");
cargo.rustdocflag("-Znext-solver=coherence");

seems safer to do that?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do run ordinary tests with this helper as well, so this feels necessary

@lcnr lcnr Aug 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, used an LLM to help me debug this.

So afaict this function fn run_cargo_test is used to effectively run cargo test for the compiler and std, but doesn't just do that to handle bootstrap stuff.

This means by setting rustdocflag and not rustflag, normal #[test] tests are compiled with -Znext-solver=globally now, while testing code examples from doc comment goes through rustdoc and uses -Znext-solver=coherence.

We need to use the old solver to compile doc comments for stuff like

//! ```compile_fail,E0072
//! # enum List<T> {
//! Cons(T, List<T>),
//! # }
//! ```

The old and new solver may not agree on the error code after all!

As there are no "expect compile fail" tests in the crate source itself (as that would cause compiling the crate to fail, preventing all other tests), compiling normal tests using the new solver is totally fine. These are only runtime tests and whether the program has been compiled using the old or new solver would only matter if they encounter an edge-case where the old and new solver result in different runtime behavior/or the code isn't accepted by one of the two. That is far less of an issue

@lcnr lcnr Aug 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
let _time = helpers::timeit(builder);

Expand Down
7 changes: 6 additions & 1 deletion src/tools/clippy/tests/compile-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ impl TestContext {
"-Ainternal_features",
"-Zui-testing",
"-Zdeduplicate-diagnostics=no",
// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
"-Znext-solver=coherence",
"-Dwarnings",
]
.map(OsString::from),
Expand Down Expand Up @@ -334,7 +337,9 @@ fn run_ui_cargo(cx: &TestContext) {
config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag;
config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()];
config.program.envs.extend([
("RUSTFLAGS".into(), Some("-Dwarnings".into())),
// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
("RUSTFLAGS".into(), Some("-Dwarnings -Znext-solver=coherence".into())),
("CARGO_INCREMENTAL".into(), Some("0".into())),
]);
// We need to do this while we still have a rustc in the `program` field.
Expand Down
7 changes: 7 additions & 0 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,9 @@ impl<'test> TestCx<'test> {
.arg(file_to_doc)
.arg("-A")
.arg("internal_features")
// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
.arg("-Znext-solver=coherence")
.args(&self.props.compile_flags)
.args(&self.props.doc_flags);

Expand Down Expand Up @@ -1848,6 +1851,10 @@ impl<'test> TestCx<'test> {
},
}

// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
compiler.args(["-Znext-solver=coherence"]);

match self.config.compare_mode {
Some(CompareMode::Polonius) => {
compiler.args(&["-Zpolonius=next"]);
Expand Down
3 changes: 3 additions & 0 deletions src/tools/lint-docs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@ impl<'a> LintExtractor<'a> {
cmd.arg(format!("--edition={edition}"));
// Just in case this is an unstable edition.
cmd.arg("-Zunstable-options");
// FIXME(#160895): While the new solver is enabled by default on nightly,
// we don't want to use it in our tests for now.
cmd.arg("-Znext-solver=coherence");
cmd.arg("--error-format=json");
cmd.arg("--target").arg(self.rustc_target);
if let Some(target_linker) = self.rustc_linker {
Expand Down
3 changes: 3 additions & 0 deletions src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[
// Deduplicating diagnostics means we miss events when tracking what happens during an
// execution. Let's not do that.
"-Zdeduplicate-diagnostics=no",
// FIXME(#160895): the new solver is enabled by default on nightly, but we
// don't want to use it in Miri for now. Remove once that's reverted.
"-Znext-solver=coherence",
];
1 change: 1 addition & 0 deletions src/tools/miri/tests/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ fn run_tests(
)
.into(),
);

if let Ok(extra_flags) = env::var("MIRIFLAGS") {
for flag in extra_flags.split_whitespace() {
config.program.args.push(flag.into());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
//@ run-pass
//@ compile-flags: -Znext-solver=globally

#![feature(min_generic_const_args)]
#![feature(generic_const_args)]
#![feature(generic_const_exprs)]
//~^ ERROR `-Znext-solver=globally` and `generic_const_exprs` are incompatible
//~^ WARN: `feature(generic_const_exprs)` is not supported with the next-generation trait solver
//@ normalize-stderr: "(--> ).*/tests/ui/const-generics/generic_const_exprs" -> "$1$$DIR"

use std::mem::size_of;

union AsBytes<T> {
as_bytes: [u8; const { size_of::<T>() }],
//~^ WARN: union `AsBytes` is never used
as_bytes: [u8; { size_of::<T>() }],
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
--> $DIR/next-solver-gce-incompatible-issue-158428.rs:5:12
warning: `feature(generic_const_exprs)` is not supported with the next-generation trait solver
--> $DIR/next-solver-gce-incompatible-issue-158428.rs:6:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= help: remove one of these features
= note: `-Znext-solver=globally` is currently enabled by default for testing
= note: reverted the setting to `-Znext-solver=coherence` for this crate
= note: the currently stable trait solver will be used for this crate
= note: see issues #160895 <https://github.com/rust-lang/rust/issues/160895> for more information

error: aborting due to 1 previous error
warning: union `AsBytes` is never used
--> $DIR/next-solver-gce-incompatible-issue-158428.rs:12:7
|
LL | union AsBytes<T> {
| ^^^^^^^
|
= note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: 2 warnings emitted

10 changes: 7 additions & 3 deletions tests/ui/traits/const-traits/unsatisfied-const-trait-bound.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//@ known-bug: unknown
// This used to ensure that the next solver prints unsatisfied always-const trait bounds as
// `const Trait`, but no longer does because GCE is incompatible with the next solver.
//@ compile-flags: -Znext-solver

#![feature(const_trait_impl, generic_const_exprs)]
#![allow(incomplete_features)]
//~^ WARN: `feature(generic_const_exprs)` is not supported with the next-generation trait solver

fn require<T: const Trait>() {}

Expand All @@ -15,19 +14,24 @@ const trait Trait {
struct Ty;

impl Trait for Ty {
fn make() -> u32 { 0 }
fn make() -> u32 {
0
}
}

fn main() {
require::<Ty>();
//~^ ERROR: the trait bound `Ty: const Trait` is not satisfied
}

struct Container<const N: u32>;

// FIXME(const_trait_impl): Somehow emit `the trait bound `T: const Trait`
// is not satisfied` here instead and suggest changing `Trait` to `const Trait`.
fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
//~^ ERROR: the trait bound `T: const Trait` is not satisfied

// FIXME(const_trait_impl): Instead of suggesting `+ const Trait`, suggest
// changing `[const] Trait` to `const Trait`.
const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
//~^ ERROR: the trait bound `T: const Trait` is not satisfied
40 changes: 36 additions & 4 deletions tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
--> $DIR/unsatisfied-const-trait-bound.rs:6:30
warning: `feature(generic_const_exprs)` is not supported with the next-generation trait solver
--> $DIR/unsatisfied-const-trait-bound.rs:5:30
|
LL | #![feature(const_trait_impl, generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= help: remove one of these features
= note: `-Znext-solver=globally` is currently enabled by default for testing
= note: reverted the setting to `-Znext-solver=coherence` for this crate
= note: the currently stable trait solver will be used for this crate
= note: see issues #160895 <https://github.com/rust-lang/rust/issues/160895> for more information

error: aborting due to 1 previous error
error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:31:37
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^

error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:36:51
|
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
| ^

error[E0277]: the trait bound `Ty: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:23:15
|
LL | require::<Ty>();
| ^^
|
note: required by a bound in `require`
--> $DIR/unsatisfied-const-trait-bound.rs:8:15
|
LL | fn require<T: const Trait>() {}
| ^^^^^^^^^^^ required by this bound in `require`
help: make the `impl` of trait `Trait` `const`
|
LL | const impl Trait for Ty {
| +++++

error: aborting due to 3 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0277`.
Loading