From a19d2deb92dbdd2af499a054d5514b1d72fe76b6 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 3 Aug 2026 22:07:35 +0300 Subject: [PATCH 1/9] Fix a couple of links in AVR target documentation - Update a link to MCU list in the code and make it an actual link - Make avr-tester link point to the crate page (which is more expected and informative) instead of a repository (which has also moved) --- src/doc/rustc/src/platform-support/avr-none.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/platform-support/avr-none.md b/src/doc/rustc/src/platform-support/avr-none.md index 1862890ca43f3..58144d058db1b 100644 --- a/src/doc/rustc/src/platform-support/avr-none.md +++ b/src/doc/rustc/src/platform-support/avr-none.md @@ -66,7 +66,7 @@ recommended to always use `--release` to avoid running out of space. Also, please note that specifying `-C target-cpu`[^1] is required - here's a list of the possible variants: -https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32 +[https://github.com/llvm/llvm-project/blob/d5a6124259b55789bc49489632efa7c168a4f6cb/clang/lib/Basic/Targets/AVR.cpp#L48](https://github.com/llvm/llvm-project/blob/d5a6124259b55789bc49489632efa7c168a4f6cb/clang/lib/Basic/Targets/AVR.cpp#L48) Note that devices that have no SRAM are not supported, same as when compiling C/C++ programs with avr-gcc or Clang. @@ -86,4 +86,4 @@ $ simavr -m atmega328p ./target/avr-none/release/your-project.elf ``` Alternatively, if you want to write a couple of actual `#[test]`s, you can use -[`avr-tester`](https://github.com/Patryk27/avr-tester). +[`avr-tester`](https://crates.io/crates/avr-tester). From 8c4b74197d648cea1ea594a418bb3180c139b353 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2026 09:20:31 +0200 Subject: [PATCH 2/9] Revert "Rollup merge of #161006 - GuillaumeGomez:gcc-binutils, r=Kobzol" This reverts commit 5d4e11e1b5e4032c42323fc8466d0e3062f9079f, reversing changes made to 71b938ce4e29ea63b8fd49624564639545c24e88. --- .../host-x86_64/dist-x86_64-linux/dist.sh | 12 ---------- src/ci/docker/scripts/build-gcc.sh | 22 ------------------- 2 files changed, 34 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index ba1ed57491070..f2f78b04d7787 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -19,16 +19,4 @@ if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist \ gcc-dev \ gcc - # We confirm that the built GCC has support for the `retain` attribute. - # FIXME: Maybe get the path from `.x.py` instead? - gcc_path="./build/$HOSTS/gcc/$HOSTS/install/bin/gcc" - c_code='int x __attribute__((used, retain));' - if echo "$c_code" | "$gcc_path" -S -x c -o - - | grep -i '"a.*R"'; then - echo "retain attribute is supported" - else - echo "retain attribute is not supported" - # We display the generated asm just in case... - echo "$c_code" | "$gcc_path" -S -x c -o - - - exit 1 - fi fi diff --git a/src/ci/docker/scripts/build-gcc.sh b/src/ci/docker/scripts/build-gcc.sh index c1c94a89d17e7..6a96b82d3f924 100755 --- a/src/ci/docker/scripts/build-gcc.sh +++ b/src/ci/docker/scripts/build-gcc.sh @@ -4,27 +4,6 @@ set -eux source shared.sh -# We have to build our own binutils for the GCC build, because the default CentOS 7 binutils are -# too old, and they do not support `SHF_GNU_RETAIN`. -BINUTILS="2.47" -curl https://ci-mirrors.rust-lang.org/rustc/gcc/binutils-$BINUTILS.tar.xz | xzcat | tar xf - -mkdir binutils-build -cd binutils-build -hide_output ../binutils-$BINUTILS/configure --prefix=/rustroot -hide_output make -j$(nproc) -hide_output make install - -cd .. -rm -rf binutils-build binutils-$BINUTILS - -if echo '.section .test,"awR",@progbits' | as - -o /dev/null 2>/dev/null; then - echo "binutils assembler supports SHF_GNU_RETAIN" -else - echo "binutils assembler DOES NOT support SHF_GNU_RETAIN" - exit 1 -fi - - # Note: in the future when bumping to version 10.1.0, also take care of the sed block below. # This version is specified in the Dockerfile GCC=$GCC_VERSION @@ -57,7 +36,6 @@ sed -i'' 's|ftp://gcc\.gnu\.org/pub/gcc/infrastructure|https://ci-mirrors.rust-l mkdir ../gcc-build cd ../gcc-build -export PATH=/rustroot/bin:$PATH # '-fno-reorder-blocks-and-partition' is required to # enable BOLT optimization of the C++ standard library, # which is included in librustc_driver.so From 2d60e51ec79e27786ae23bf55c896ad519bcb5d2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 13 Aug 2026 06:30:43 +0000 Subject: [PATCH 3/9] Add a normalize_ty callback to try_evaluate_const --- .../src/solve/delegate.rs | 4 ++- .../src/traits/auto_trait.rs | 8 ++++-- .../src/traits/const_evaluatable.rs | 8 ++++-- .../src/traits/fulfill.rs | 1 + .../rustc_trait_selection/src/traits/mod.rs | 28 ++++++++++++++----- .../src/traits/select/mod.rs | 8 ++++-- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 071c62d0b5ee0..98d0cd35ed45a 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -326,7 +326,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> Option> { let ct = ty::Const::new_alias(self.tcx, ty::IsRigid::No, alias_const); - match crate::traits::try_evaluate_const(&self.0, ct, param_env) { + match crate::traits::try_evaluate_const(&self.0, ct, param_env, |ty| { + Ok::<_, !>(ty.skip_norm_wip()) + }) { Ok(ct) => Some(ct), Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)), Err( diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index c885406f6dcfb..798bca8483b0a 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -853,8 +853,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Alias(_, alias_const) = c.kind() { - let ct = - super::try_evaluate_const(selcx.infcx, c, obligation.param_env); + let ct = super::try_evaluate_const( + selcx.infcx, + c, + obligation.param_env, + |ty| Ok::<_, !>(ty.skip_norm_wip()), + ); if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct { let span = alias_const.kind.def_span(self.tcx); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 74413d430b1cd..2a1cb4c7ad5d3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -67,7 +67,9 @@ pub fn is_const_evaluatable<'tcx>( tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); } ty::ConstKind::Alias(_, _) => { - match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env, |ty| { + Ok::<_, !>(ty.skip_norm_wip()) + }) { Err(EvaluateConstErr::HasGenericsOrInfers) => { Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug( span, @@ -98,7 +100,9 @@ pub fn is_const_evaluatable<'tcx>( _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), }; - match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env, |ty| { + Ok::<_, !>(ty.skip_norm_wip()) + }) { // If we're evaluating a generic foreign constant, under a nightly compiler while // the current crate does not enable `feature(generic_const_exprs)`, abort // compilation with a useful error. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d0452052f10f6..941d80db4bbc4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -764,6 +764,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { self.selcx.infcx, c, obligation.param_env, + |ty| Ok::<_, !>(ty.skip_norm_wip()), ) { Ok(val) => Ok(val), e @ Err(EvaluateConstErr::HasGenericsOrInfers) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index eda63e09b1189..8b9b21b3d58b2 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -572,8 +572,7 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&clauses)) } -#[derive(Debug)] -pub enum EvaluateConstErr { +pub enum EvaluateConstErr { /// The constant being evaluated was either a generic parameter or inference variable, *or*, /// some alias const with either generic parameters or inference variables in its /// generic arguments. @@ -585,6 +584,18 @@ pub enum EvaluateConstErr { /// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`). /// This is also used when the constant was already tainted by error. EvaluationFailure(ErrorGuaranteed), + FailedNormalization(E), +} + +impl std::fmt::Debug for EvaluateConstErr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::HasGenericsOrInfers => f.write_str("HasGenericsOrInfers"), + Self::InvalidConstParamTy(e) => f.debug_tuple("InvalidConstParamTy").field(e).finish(), + Self::EvaluationFailure(e) => f.debug_tuple("EvaluationFailure").field(e).finish(), + Self::FailedNormalization(_) => f.write_str("FailedNormalization(..)"), + } + } } // FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine @@ -601,7 +612,7 @@ pub fn evaluate_const<'tcx>( ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> ty::Const<'tcx> { - match try_evaluate_const(infcx, ct, param_env) { + match try_evaluate_const(infcx, ct, param_env, |v| Ok::<_, !>(v.skip_norm_wip())) { Ok(ct) => ct, Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => { ty::Const::new_error(infcx.tcx, e) @@ -618,12 +629,13 @@ pub fn evaluate_const<'tcx>( /// /// You should not call this function unless you are implementing normalization itself. Prefer to use /// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`. -#[instrument(level = "debug", skip(infcx), ret)] -pub fn try_evaluate_const<'tcx>( +#[instrument(level = "debug", skip(infcx, normalize_ty), ret)] +pub fn try_evaluate_const<'tcx, E>( infcx: &InferCtxt<'tcx>, ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> Result, EvaluateConstErr> { + normalize_ty: impl FnOnce(Unnormalized<'tcx, Ty<'tcx>>) -> Result, E>, +) -> Result, EvaluateConstErr> { let tcx = infcx.tcx; let ct = infcx.resolve_vars_if_possible(ct); debug!(?ct); @@ -762,7 +774,9 @@ pub fn try_evaluate_const<'tcx>( let span = alias_const.kind.def_span(tcx); match tcx.const_eval_resolve_for_typeck(typing_env, erased_alias_const, span) { Ok(Ok(val)) => { - Ok(ty::Const::new_value(tcx, val, alias_const.type_of(tcx).skip_norm_wip())) + let ty = normalize_ty(alias_const.type_of(tcx)) + .map_err(EvaluateConstErr::FailedNormalization)?; + Ok(ty::Const::new_value(tcx, val, ty)) } Ok(Err(_)) => { let e = tcx.dcx().delayed_bug( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9b4ee13bf1b63..038b0ae141751 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -921,8 +921,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Alias(_, _) = c.kind() { - match crate::traits::try_evaluate_const(self.infcx, c, obligation.param_env) - { + match crate::traits::try_evaluate_const( + self.infcx, + c, + obligation.param_env, + |v| Ok::<_, !>(v.skip_norm_wip()), + ) { Ok(val) => Ok(val), Err(e) => Err(e), } From 50ea65bdcd7c7ca64a34659cf60150e61e19921a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 13 Aug 2026 06:31:12 +0000 Subject: [PATCH 4/9] Normalize the type of evaluated consts in the new solver --- .../rustc_next_trait_solver/src/delegate.rs | 10 ++++++++-- .../src/solve/eval_ctxt/mod.rs | 15 +++++++++++---- .../src/solve/delegate.rs | 18 ++++++++++-------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 1212f422f76e8..2af89789f93f5 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -36,11 +36,17 @@ pub trait SolverDelegate: Deref + Sized { // FIXME: Uplift the leak check into this crate. fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; - fn evaluate_const( + /// Evaluate a const, normalizing the type of the resulting value with `normalize_ty`. + /// Returns `Ok(None)` if the const is too generic, and `Err(_)` only if `normalize_ty` + /// failed. + fn evaluate_const( &self, param_env: ::ParamEnv, alias_const: ty::AliasConst, - ) -> Option<::Const>; + normalize_ty: impl FnOnce( + ty::Unnormalized::Ty>, + ) -> Result<::Ty, E>, + ) -> Result::Const>, E>; // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! fn well_formed_goals( 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 559ca0a98c58e..c78887527dd1e 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 @@ -1403,9 +1403,9 @@ where Ok(()) } - // Try to evaluate a const, or return `None` if the const is too generic. - // This doesn't mean the const isn't evaluatable, though, and should be treated - // as an ambiguity rather than no-solution. + // Try to evaluate a const and normalize the type of the resulting value, or return `None` if + // the const is too generic. This doesn't mean the const isn't evaluatable, though, and should + // be treated as an ambiguity rather than no-solution. pub(super) fn evaluate_const( &mut self, param_env: I::ParamEnv, @@ -1415,7 +1415,14 @@ where match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - Ok(self.delegate.evaluate_const(param_env, alias_const)) + let delegate = self.delegate; + match delegate.evaluate_const(param_env, alias_const, |ty| { + self.normalize(GoalSource::Misc, param_env, ty) + }) { + Ok(ct) => Ok(ct), + Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Ok(None), + Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => Err(e), + } } pub(super) fn evaluate_const_and_instantiate_projection_term( diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 98d0cd35ed45a..ad0af281abaa9 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -319,21 +319,23 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } - fn evaluate_const( + fn evaluate_const( &self, param_env: ty::ParamEnv<'tcx>, alias_const: ty::AliasConst<'tcx>, - ) -> Option> { + normalize_ty: impl FnOnce(ty::Unnormalized<'tcx, Ty<'tcx>>) -> Result, E>, + ) -> Result>, E> { let ct = ty::Const::new_alias(self.tcx, ty::IsRigid::No, alias_const); - match crate::traits::try_evaluate_const(&self.0, ct, param_env, |ty| { - Ok::<_, !>(ty.skip_norm_wip()) - }) { - Ok(ct) => Some(ct), - Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)), + match crate::traits::try_evaluate_const(&self.0, ct, param_env, normalize_ty) { + Ok(ct) => Ok(Some(ct)), + Err(EvaluateConstErr::EvaluationFailure(e)) => { + Ok(Some(ty::Const::new_error(self.tcx, e))) + } Err( EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers, - ) => None, + ) => Ok(None), + Err(EvaluateConstErr::FailedNormalization(e)) => Err(e), } } From 89472f4093e2a671fe14bda91a2ff771a62edacf Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 13 Aug 2026 06:31:12 +0000 Subject: [PATCH 5/9] Add regression test for evaluated const with alias type --- .../next-solver/adt-const-param-projection.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/ui/traits/next-solver/adt-const-param-projection.rs diff --git a/tests/ui/traits/next-solver/adt-const-param-projection.rs b/tests/ui/traits/next-solver/adt-const-param-projection.rs new file mode 100644 index 0000000000000..926451bae2c3d --- /dev/null +++ b/tests/ui/traits/next-solver/adt-const-param-projection.rs @@ -0,0 +1,26 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ edition: 2015 + +// Regression test for https://github.com/rust-lang/rust/issues/156294. +// We used to not normalize the type we get back from const evaluation, so the value of +// `EMPTY_MATRIX` had the type `::Matrix` instead of `[usize; 1]`. Nobody +// normalized it later on either, so we ended up ICEing when mangling the symbol name of +// `Walk::::new`. + +#![feature(adt_const_params)] + +pub const EMPTY_MATRIX: ::Matrix = [1]; +pub struct Walk::Matrix>; +impl Walk { + pub fn new() {} +} +pub enum Type {} +pub trait Trait { + type Matrix; +} +impl Trait for Type { + type Matrix = [usize; 1]; +} From 1c7f148de428321b2e7b1e4e07116eed83eb3e31 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 13 Aug 2026 14:47:13 +0000 Subject: [PATCH 6/9] Remove explicit debug impl and other misc --- compiler/rustc_next_trait_solver/src/delegate.rs | 3 ++- .../rustc_trait_selection/src/solve/delegate.rs | 3 ++- compiler/rustc_trait_selection/src/traits/mod.rs | 14 ++------------ .../rustc_trait_selection/src/traits/select/mod.rs | 7 ++----- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 2af89789f93f5..93e97b53f7720 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::ops::Deref; use rustc_type_ir::solve::{ @@ -39,7 +40,7 @@ pub trait SolverDelegate: Deref + Sized { /// Evaluate a const, normalizing the type of the resulting value with `normalize_ty`. /// Returns `Ok(None)` if the const is too generic, and `Err(_)` only if `normalize_ty` /// failed. - fn evaluate_const( + fn evaluate_const( &self, param_env: ::ParamEnv, alias_const: ty::AliasConst, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index ad0af281abaa9..d93e3fdf853fc 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,4 +1,5 @@ use std::collections::hash_map::Entry; +use std::fmt::Debug; use std::mem; use std::ops::Deref; @@ -319,7 +320,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } - fn evaluate_const( + fn evaluate_const( &self, param_env: ty::ParamEnv<'tcx>, alias_const: ty::AliasConst<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8b9b21b3d58b2..e0c93a7d3af63 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -572,6 +572,7 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&clauses)) } +#[derive(Debug)] pub enum EvaluateConstErr { /// The constant being evaluated was either a generic parameter or inference variable, *or*, /// some alias const with either generic parameters or inference variables in its @@ -587,17 +588,6 @@ pub enum EvaluateConstErr { FailedNormalization(E), } -impl std::fmt::Debug for EvaluateConstErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::HasGenericsOrInfers => f.write_str("HasGenericsOrInfers"), - Self::InvalidConstParamTy(e) => f.debug_tuple("InvalidConstParamTy").field(e).finish(), - Self::EvaluationFailure(e) => f.debug_tuple("EvaluationFailure").field(e).finish(), - Self::FailedNormalization(_) => f.write_str("FailedNormalization(..)"), - } - } -} - // FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine // FIXME(generic_const_exprs): Consider accepting a `ty::AliasConst` when we are not rolling our own // normalization scheme @@ -630,7 +620,7 @@ pub fn evaluate_const<'tcx>( /// You should not call this function unless you are implementing normalization itself. Prefer to use /// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`. #[instrument(level = "debug", skip(infcx, normalize_ty), ret)] -pub fn try_evaluate_const<'tcx, E>( +pub fn try_evaluate_const<'tcx, E: Debug>( infcx: &InferCtxt<'tcx>, ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 038b0ae141751..d1c579d922287 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -921,15 +921,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Alias(_, _) = c.kind() { - match crate::traits::try_evaluate_const( + crate::traits::try_evaluate_const( self.infcx, c, obligation.param_env, |v| Ok::<_, !>(v.skip_norm_wip()), - ) { - Ok(val) => Ok(val), - Err(e) => Err(e), - } + ) } else { Ok(c) } From 60ec532a0115871660fa0c28a9b7d01238cbf72e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 18 Aug 2026 10:52:59 +0000 Subject: [PATCH 7/9] make sure to propagate even the NoSolution from ty normalization in current parent goal context --- .../src/solve/eval_ctxt/mod.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) 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 c78887527dd1e..78d3ab86cc250 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 @@ -1410,19 +1410,14 @@ where &mut self, param_env: I::ParamEnv, alias_const: ty::AliasConst, - ) -> Result, RerunNonErased> { + ) -> Result, NoSolutionOrRerunNonErased> { if self.typing_mode().is_erased_not_coherence() { match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - let delegate = self.delegate; - match delegate.evaluate_const(param_env, alias_const, |ty| { + self.delegate.evaluate_const(param_env, alias_const, |ty| { self.normalize(GoalSource::Misc, param_env, ty) - }) { - Ok(ct) => Ok(ct), - Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Ok(None), - Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => Err(e), - } + }) } pub(super) fn evaluate_const_and_instantiate_projection_term( From 40616472975b7e07f3c44a14719700950f9f4ce8 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Tue, 18 Aug 2026 10:53:37 +0000 Subject: [PATCH 8/9] Add test to observer where CTFE succeeds but normalization of type fails with NoSolution in parent goal context --- .../next-solver/normalize-const-item-type.rs | 34 +++++++++++++++++++ .../normalize-const-item-type.stderr | 23 +++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/ui/traits/next-solver/normalize-const-item-type.rs create mode 100644 tests/ui/traits/next-solver/normalize-const-item-type.stderr diff --git a/tests/ui/traits/next-solver/normalize-const-item-type.rs b/tests/ui/traits/next-solver/normalize-const-item-type.rs new file mode 100644 index 0000000000000..873b0bb690e4c --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-const-item-type.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Znext-solver +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] + +use std::marker::PhantomData; + +trait Project1<'a> { + type Assoc1; +} + +impl<'a, T> Project1<'a> for T { + type Assoc1 = (); +} + +trait Project2 { + type Assoc2; +} + +impl> Project2 for PhantomData { + type Assoc2 = usize; +} + +const N: as Project2>::Assoc2 = 2_usize; + +fn func(_: [(); core::direct_const_arg!(N::)]) +//~^ ERROR: type mismatch resolving `N == _` [E0271] +//~| ERROR: the type `[(); N::]` is not well-formed +//~| ERROR: type mismatch resolving `N == _` [E0271] +where + for<'a> u32: Project1<'a>, +{} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-const-item-type.stderr b/tests/ui/traits/next-solver/normalize-const-item-type.stderr new file mode 100644 index 0000000000000..67f4f596f40bf --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-const-item-type.stderr @@ -0,0 +1,23 @@ +error[E0271]: type mismatch resolving `N == _` + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: the type `[(); N::]` is not well-formed + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `N == _` + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0271`. From b245c07db8df0f960d7f1431513294a21b3329aa Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Tue, 18 Aug 2026 23:03:13 +0000 Subject: [PATCH 9/9] compiler: Account for default_sanitizers when comparing target modifiers Prior to this PR, rustc would complain about mismatched ABIs if crates built with -Zsanitizer=shadow-call-stack were mixed with crates not built with -Zsanitizer=shadow-call-stack for the exact same target where SCS is one of the default_sanitizers. Rustc should also take into account default_sanitizers before doing the target modifiers checks. AI: Gemini was used to initially help write tests for this PR. I edited some of it and reviewed it to the best of my ability before submitting. --- compiler/rustc_session/src/options.rs | 12 ++++--- .../auxiliary/sanitizer_default_explicit.rs | 10 ++++++ .../auxiliary/sanitizer_default_implicit.rs | 11 ++++++ .../auxiliary/sanitizer_non_default.rs | 11 ++++++ ...sanitizer_default.explicit_mismatch.stderr | 9 +++++ ...sanitizer_default.implicit_mismatch.stderr | 9 +++++ .../ui/target_modifiers/sanitizer_default.rs | 36 +++++++++++++++++++ 7 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs create mode 100644 tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs create mode 100644 tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs create mode 100644 tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr create mode 100644 tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr create mode 100644 tests/ui/target_modifiers/sanitizer_default.rs diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 18bee1b1ba7f1..9ed3975043966 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -90,12 +90,16 @@ pub mod mitigation_coverage; mod target_modifier_consistency_check { use super::*; - pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool { - let mut lparsed: SanitizerSet = Default::default(); + pub(super) fn sanitizer( + sess: &Session, + l: &TargetModifier, + r: Option<&TargetModifier>, + ) -> bool { + let mut lparsed: SanitizerSet = sess.target.options.default_sanitizers; let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) }; parse::parse_sanitizers(&mut lparsed, lval); - let mut rparsed: SanitizerSet = Default::default(); + let mut rparsed: SanitizerSet = sess.target.options.default_sanitizers; let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str()); parse::parse_sanitizers(&mut rparsed, rval); @@ -166,7 +170,7 @@ impl TargetModifier { match self.opt { OptionsTargetModifiers::UnstableOptions(unstable) => match unstable { UnstableOptionsTargetModifiers::Sanitizer => { - return target_modifier_consistency_check::sanitizer(self, other); + return target_modifier_consistency_check::sanitizer(sess, self, other); } UnstableOptionsTargetModifiers::SanitizerCfiNormalizeIntegers => { return target_modifier_consistency_check::sanitizer_cfi_normalize_integers( diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs new file mode 100644 index 0000000000000..831c681179b9a --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs @@ -0,0 +1,10 @@ +// This represents an rlib where SCS is explicitly provided as a -Zsanitizer flag. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia -Zsanitizer=shadow-call-stack +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs new file mode 100644 index 0000000000000..6aac2294283f8 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs @@ -0,0 +1,11 @@ +// This represents an rlib where SCS is not explicitly provided as a -Zsanitizer flag. +// SCS is a default_sanitizer on riscv64gc-unknown-fuchsia. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs new file mode 100644 index 0000000000000..c04ab13b310ff --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs @@ -0,0 +1,11 @@ +// This represents an rlib where CFI is explicitly provided as a -Zsanitizer flag. +// CFI is not a default_sanitizer for riscv64gc-unknown-fuchsia. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia -Zsanitizer=cfi -Clinker-plugin-lto +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr b/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr new file mode 100644 index 0000000000000..aa194b329b684 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr @@ -0,0 +1,9 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer=shadow-call-stack` in this crate is incompatible with `-Zsanitizer=cfi` in dependency `sanitizer_non_default` + = help: set `-Zsanitizer=cfi` in this crate or `-Zsanitizer=shadow-call-stack` in `sanitizer_non_default` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr b/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr new file mode 100644 index 0000000000000..cb3ebf06d892f --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr @@ -0,0 +1,9 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer` is unset in this crate which is incompatible with `-Zsanitizer=cfi` in dependency `sanitizer_non_default` + = help: set `-Zsanitizer=cfi` in this crate or unset `-Zsanitizer` in `sanitizer_non_default` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizer_default.rs b/tests/ui/target_modifiers/sanitizer_default.rs new file mode 100644 index 0000000000000..5b3b1f4d7b6e5 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.rs @@ -0,0 +1,36 @@ +// Test that we do not get an ABI mismatch error when a default sanitizer is not +// explicitly provided via a -Zsanitizer flag. +// +// riscv64gc-unknown-fuchsia has shadow-call-stack as a default sanitizer. +// Compiling one crate without `-Zsanitizer` and another crate with the target's +// default sanitizer explicitly specified (-Zsanitizer=shadow-call-stack) +// must be accepted. + +//@ aux-build:sanitizer_default_implicit.rs +//@ aux-build:sanitizer_default_explicit.rs +//@ aux-build:sanitizer_non_default.rs +//@ compile-flags: --target riscv64gc-unknown-fuchsia +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +//@ revisions: implicit_default explicit_default implicit_mismatch explicit_mismatch +//@[implicit_default] check-pass +//@[explicit_default] compile-flags: -Zsanitizer=shadow-call-stack +//@[explicit_default] check-pass +//@[explicit_mismatch] compile-flags: -Zsanitizer=shadow-call-stack + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] + +#[cfg(any(implicit_default, explicit_default))] +extern crate sanitizer_default_implicit; + +#[cfg(any(implicit_default, explicit_default))] +extern crate sanitizer_default_explicit; + +// We still expect the normal mismatch error with a non-default sanitizer. +#[cfg(any(implicit_mismatch, explicit_mismatch))] +extern crate sanitizer_non_default; +//[implicit_mismatch]~? ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` +//[explicit_mismatch]~? ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default`