From 39628ff5a42d14afc75f57dedcc430c043468836 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 8 Sep 2025 06:12:51 +0200 Subject: [PATCH 01/17] remove untrue/contentious statement One can use unstable features on stable too, like via an env var --- src/doc/rustc-dev-guide/src/contributing.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 347608d305aa9..764452b6e5442 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -52,9 +52,7 @@ channels: stable, beta, and nightly. - **Stable**: this is the latest stable release for general usage. - **Beta**: this is the next release (will be stable within 6 weeks). -- **Nightly**: follows the `master` branch of the repo. This is the only - channel where unstable, incomplete, or experimental features are usable with - feature gates. +- **Nightly**: follows the `master` branch of the repo. See [this chapter on implementing new features](./implementing_new_features.md) for more information. From 1eb80f1d3c9cd30dcba45f4c6b3e49a1a7b50b50 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Oct 2025 21:10:24 +0200 Subject: [PATCH 02/17] restore helpful explanation --- src/doc/rustc-dev-guide/src/contributing.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 764452b6e5442..b927c9a792745 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -53,6 +53,8 @@ channels: stable, beta, and nightly. - **Stable**: this is the latest stable release for general usage. - **Beta**: this is the next release (will be stable within 6 weeks). - **Nightly**: follows the `master` branch of the repo. + This is the only channel where unstable, incomplete, or experimental features + should be used (with feature gates). See [this chapter on implementing new features](./implementing_new_features.md) for more information. From 491554dbc1c4696ceb30629491d99a3b1b6d5c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 2 Oct 2025 15:16:53 +0200 Subject: [PATCH 03/17] add tests for unsizing coercions (both ICE) --- tests/ui/dst/dst-object-from-unsized-type.rs | 3 +++ .../next-solver/unsize-goal-mismatch-2.rs | 18 ++++++++++++++++++ .../next-solver/unsize-goal-mismatch.rs | 19 +++++++++++++++++++ .../ui/traits/next-solver/unsize-overflow.rs | 7 +++++++ 4 files changed, 47 insertions(+) create mode 100644 tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs create mode 100644 tests/ui/traits/next-solver/unsize-goal-mismatch.rs create mode 100644 tests/ui/traits/next-solver/unsize-overflow.rs diff --git a/tests/ui/dst/dst-object-from-unsized-type.rs b/tests/ui/dst/dst-object-from-unsized-type.rs index 3cd5b1ed6f462..5ba6c571a39a6 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.rs +++ b/tests/ui/dst/dst-object-from-unsized-type.rs @@ -1,4 +1,7 @@ // Test that we cannot create objects from unsized types. +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver trait Foo { fn foo(&self) {} } impl Foo for str {} diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs new file mode 100644 index 0000000000000..c651309e01b19 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs @@ -0,0 +1,18 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +// Test from trait-system-refactor-initiative#241: +// Used to ICE in mir typeck because of ambiguity in the new solver. +// The wrong (first) trait bound was selected. +// This is fixed with new logic for unsizing coercions +// that's independent from that of the old solver, which this test verifies. + +trait Super {} +trait Trait: Super + for<'hr> Super<&'hr ()> {} + +fn foo<'a>(x: Box>) -> Box> { + x +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs new file mode 100644 index 0000000000000..c9e2018997248 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +// Test from trait-system-refactor-initiative#241: +// Used to ICE in mir typeck because of ambiguity in the new solver. +// The wrong (first) trait bound was selected. +// This is fixed with new logic for unsizing coercions +// that's independent from that of the old solver, which this test verifies. + +trait Super<'a> {} +trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {} + +fn foo<'a>(x: Box>) -> Box> { + x + //~^ ERROR type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize> +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/unsize-overflow.rs b/tests/ui/traits/next-solver/unsize-overflow.rs new file mode 100644 index 0000000000000..036be02aaeae3 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-overflow.rs @@ -0,0 +1,7 @@ +//@ compile-flags: -Znext-solver +#![recursion_limit = "8"] + +fn main() { + let _: Box = Box::new(&&&&&&&1); + //~^ ERROR overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized> +} From 14a2770c0f13c0adc700a108f27a75eee3292e97 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 2 Jun 2025 17:16:55 +0000 Subject: [PATCH 04/17] Rename nit --- compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs | 2 +- compiler/rustc_trait_selection/src/solve/fulfill.rs | 2 +- .../rustc_trait_selection/src/solve/fulfill/derive_errors.rs | 2 +- compiler/rustc_trait_selection/src/solve/inspect/analyse.rs | 2 +- compiler/rustc_trait_selection/src/solve/select.rs | 2 +- compiler/rustc_trait_selection/src/traits/coherence.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 367e2b6b372ae..33f15409acf77 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::Certainty; use rustc_trait_selection::solve::inspect::{ - InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor, + InspectConfig, InspectGoal, InferCtxtProofTreeExt, ProofTreeVisitor, }; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index ddd79e1dc9405..7b61a653ae31e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -24,7 +24,7 @@ use tracing::instrument; use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; -use super::inspect::{self, ProofTreeInferCtxtExt}; +use super::inspect::{self, InferCtxtProofTreeExt}; use crate::traits::{FulfillmentError, ScrubbedTraitError}; mod derive_errors; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index eef0ddcbf5965..904a0ac45777b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -15,7 +15,7 @@ use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _} use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; -use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; use crate::solve::{Certainty, deeply_normalize_for_diagnostics}; use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf}; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 488315054c6aa..cdbf2b0aeb834 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -463,7 +463,7 @@ pub trait ProofTreeVisitor<'tcx> { fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result; } -#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)] +#[extension(pub trait InferCtxtProofTreeExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { fn visit_proof_tree>( &self, diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index d7e7ffd5d28c6..1feaab2404153 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -12,7 +12,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::Span; use thin_vec::thin_vec; -use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; +use crate::solve::inspect::{self, InferCtxtProofTreeExt}; #[extension(pub trait InferCtxtSelectExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e488fb6802f84..4c8648480bbd6 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -29,7 +29,7 @@ use tracing::{debug, instrument, warn}; use super::ObligationCtxt; use crate::error_reporting::traits::suggest_new_overflow_limit; use crate::infer::InferOk; -use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::inspect::{InspectGoal, InferCtxtProofTreeExt, ProofTreeVisitor}; use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; From 56894773c8f9a72e40e388a25bd6c495998cdcce Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 2 Jun 2025 17:45:06 +0000 Subject: [PATCH 05/17] Rework unsizing coercions in new solver --- compiler/rustc_hir_typeck/src/coercion.rs | 290 +++++++++++------- .../src/fn_ctxt/inspect_obligations.rs | 2 +- .../src/traits/coherence.rs | 2 +- 3 files changed, 177 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1e5fea1db9fcc..7766075bade91 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -35,13 +35,13 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, InferResult, RegionVariableOrigin}; @@ -56,6 +56,8 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; +use rustc_trait_selection::solve::{Certainty, Goal, NoSolution}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, ImplSource, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, @@ -639,131 +641,140 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Adjust::Pointer(PointerCoercion::Unsize), )?; - let mut selcx = traits::SelectionContext::new(self); - // Create an obligation for `Source: CoerceUnsized`. let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + let pred = ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]); + let obligation = Obligation::new(self.tcx, cause, self.fcx.param_env, pred); - // Use a FIFO queue for this custom fulfillment procedure. - // - // A Vec (or SmallVec) is not a natural choice for a queue. However, - // this code path is hot, and this queue usually has a max length of 1 - // and almost never more than 3. By using a SmallVec we avoid an - // allocation, at the (very small) cost of (occasionally) having to - // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( - self.tcx, - cause, - self.fcx.param_env, - ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) - )]; - - // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid - // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where - // inference might unify those two inner type variables later. - let traits = [coerce_unsized_did, unsize_did]; - while !queue.is_empty() { - let obligation = queue.remove(0); - let trait_pred = match obligation.predicate.kind().no_bound_vars() { - Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) - if traits.contains(&trait_pred.def_id()) => - { - self.resolve_vars_if_possible(trait_pred) - } - // Eagerly process alias-relate obligations in new trait solver, - // since these can be emitted in the process of solving trait goals, - // but we need to constrain vars before processing goals mentioning - // them. - Some(ty::PredicateKind::AliasRelate(..)) => { - let ocx = ObligationCtxt::new(self); - ocx.register_obligation(obligation); - if !ocx.try_evaluate_obligations().is_empty() { - return Err(TypeError::Mismatch); + if self.next_trait_solver() { + coercion.obligations.push(obligation); + + if self + .infcx + .visit_proof_tree( + Goal::new(self.tcx, self.param_env, pred), + &mut CoerceVisitor { fcx: self.fcx, span: self.cause.span }, + ) + .is_break() + { + return Err(TypeError::Mismatch); + } + } else { + let mut selcx = traits::SelectionContext::new(self); + // Use a FIFO queue for this custom fulfillment procedure. + // + // A Vec (or SmallVec) is not a natural choice for a queue. However, + // this code path is hot, and this queue usually has a max length of 1 + // and almost never more than 3. By using a SmallVec we avoid an + // allocation, at the (very small) cost of (occasionally) having to + // shift subsequent elements down when removing the front element. + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation]; + + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid + // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where + // inference might unify those two inner type variables later. + let traits = [coerce_unsized_did, unsize_did]; + while !queue.is_empty() { + let obligation = queue.remove(0); + let trait_pred = match obligation.predicate.kind().no_bound_vars() { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) + if traits.contains(&trait_pred.def_id()) => + { + self.resolve_vars_if_possible(trait_pred) } - coercion.obligations.extend(ocx.into_pending_obligations()); - continue; - } - _ => { - coercion.obligations.push(obligation); - continue; - } - }; - debug!("coerce_unsized resolve step: {:?}", trait_pred); - match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { - // Uncertain or unimplemented. - Ok(None) => { - if trait_pred.def_id() == unsize_did { - let self_ty = trait_pred.self_ty(); - let unsize_ty = trait_pred.trait_ref.args[1].expect_ty(); - debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (self_ty.kind(), unsize_ty.kind()) { - (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) - if self.type_var_is_sized(v) => - { - debug!("coerce_unsized: have sized infer {:?}", v); - coercion.obligations.push(obligation); - // `$0: Unsize` where we know that `$0: Sized`, try going - // for unsizing. - } - _ => { - // Some other case for `$0: Unsize`. Note that we - // hit this case even if `Something` is a sized type, so just - // don't do the coercion. - debug!("coerce_unsized: ambiguous unsize"); - return Err(TypeError::Mismatch); + // Eagerly process alias-relate obligations in new trait solver, + // since these can be emitted in the process of solving trait goals, + // but we need to constrain vars before processing goals mentioning + // them. + Some(ty::PredicateKind::AliasRelate(..)) => { + let ocx = ObligationCtxt::new(self); + ocx.register_obligation(obligation); + if !ocx.try_evaluate_obligations().is_empty() { + return Err(TypeError::Mismatch); + } + coercion.obligations.extend(ocx.into_pending_obligations()); + continue; + } + _ => { + coercion.obligations.push(obligation); + continue; + } + }; + debug!("coerce_unsized resolve step: {:?}", trait_pred); + match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { + // Uncertain or unimplemented. + Ok(None) => { + if trait_pred.def_id() == unsize_did { + let self_ty = trait_pred.self_ty(); + let unsize_ty = trait_pred.trait_ref.args[1].expect_ty(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); + match (self_ty.kind(), unsize_ty.kind()) { + (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) + if self.type_var_is_sized(v) => + { + debug!("coerce_unsized: have sized infer {:?}", v); + coercion.obligations.push(obligation); + // `$0: Unsize` where we know that `$0: Sized`, try going + // for unsizing. + } + _ => { + // Some other case for `$0: Unsize`. Note that we + // hit this case even if `Something` is a sized type, so just + // don't do the coercion. + debug!("coerce_unsized: ambiguous unsize"); + return Err(TypeError::Mismatch); + } } + } else { + debug!("coerce_unsized: early return - ambiguous"); + return Err(TypeError::Mismatch); } - } else { - debug!("coerce_unsized: early return - ambiguous"); + } + Err(SelectionError::Unimplemented) => { + debug!("coerce_unsized: early return - can't prove obligation"); return Err(TypeError::Mismatch); } - } - Err(SelectionError::Unimplemented) => { - debug!("coerce_unsized: early return - can't prove obligation"); - return Err(TypeError::Mismatch); - } - Err(SelectionError::TraitDynIncompatible(_)) => { - // Dyn compatibility errors in coercion will *always* be due to the - // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` - // written in source somewhere (otherwise we will never have lowered - // the dyn trait from HIR to middle). - // - // There's no reason to emit yet another dyn compatibility error, - // especially since the span will differ slightly and thus not be - // deduplicated at all! - self.fcx.set_tainted_by_errors( - self.fcx - .dcx() - .span_delayed_bug(self.cause.span, "dyn compatibility during coercion"), - ); - } - Err(err) => { - let guar = self.err_ctxt().report_selection_error( - obligation.clone(), - &obligation, - &err, - ); - self.fcx.set_tainted_by_errors(guar); - // Treat this like an obligation and follow through - // with the unsizing - the lack of a coercion should - // be silent, as it causes a type mismatch later. - } - - Ok(Some(ImplSource::UserDefined(impl_source))) => { - queue.extend(impl_source.nested); - // Certain incoherent `CoerceUnsized` implementations may cause ICEs, - // so check the impl's validity. Taint the body so that we don't try - // to evaluate these invalid coercions in CTFE. We only need to do this - // for local impls, since upstream impls should be valid. - if impl_source.impl_def_id.is_local() - && let Err(guar) = - self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id) - { + Err(SelectionError::TraitDynIncompatible(_)) => { + // Dyn compatibility errors in coercion will *always* be due to the + // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` + // writen in source somewhere (otherwise we will never have lowered + // the dyn trait from HIR to middle). + // + // There's no reason to emit yet another dyn compatibility error, + // especially since the span will differ slightly and thus not be + // deduplicated at all! + self.fcx.set_tainted_by_errors(self.fcx.dcx().span_delayed_bug( + self.cause.span, + "dyn compatibility during coercion", + )); + } + Err(err) => { + let guar = self.err_ctxt().report_selection_error( + obligation.clone(), + &obligation, + &err, + ); self.fcx.set_tainted_by_errors(guar); + // Treat this like an obligation and follow through + // with the unsizing - the lack of a coercion should + // be silent, as it causes a type mismatch later. + } + Ok(Some(ImplSource::UserDefined(impl_source))) => { + queue.extend(impl_source.nested); + // Certain incoherent `CoerceUnsized` implementations may cause ICEs, + // so check the impl's validity. Taint the body so that we don't try + // to evaluate these invalid coercions in CTFE. We only need to do this + // for local impls, since upstream impls should be valid. + if impl_source.impl_def_id.is_local() + && let Err(guar) = + self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id) + { + self.fcx.set_tainted_by_errors(guar); + } } + Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } - Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } } @@ -2005,3 +2016,52 @@ impl AsCoercionSite for hir::Arm<'_> { self.body } } + +/// Recursively visit goals to decide whether an unsizing is possible. +/// `Break`s when it isn't, and an error should be raised. +/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item. +struct CoerceVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, +} + +impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> { + type Result = ControlFlow<()>; + + fn span(&self) -> Span { + self.span + } + + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + let Some(pred) = goal.goal().predicate.as_trait_clause() else { + return ControlFlow::Continue(()); + }; + + if !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) + && !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized) + { + return ControlFlow::Continue(()); + } + + match goal.result() { + Ok(Certainty::Yes) => ControlFlow::Continue(()), + Err(NoSolution) => ControlFlow::Break(()), + Ok(Certainty::Maybe { .. }) => { + // FIXME: structurally normalize? + if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) + && let ty::Dynamic(..) = pred.skip_binder().trait_ref.args.type_at(1).kind() + && let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind() + && self.fcx.type_var_is_sized(vid) + { + ControlFlow::Continue(()) + } else if let Some(cand) = goal.unique_applicable_candidate() + && cand.shallow_certainty() == Certainty::Yes + { + cand.visit_nested_no_probe(self) + } else { + ControlFlow::Break(()) + } + } + } + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 33f15409acf77..ff37cb75a5c53 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::Certainty; use rustc_trait_selection::solve::inspect::{ - InspectConfig, InspectGoal, InferCtxtProofTreeExt, ProofTreeVisitor, + InferCtxtProofTreeExt, InspectConfig, InspectGoal, ProofTreeVisitor, }; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 4c8648480bbd6..1ccda94dc89b2 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -29,7 +29,7 @@ use tracing::{debug, instrument, warn}; use super::ObligationCtxt; use crate::error_reporting::traits::suggest_new_overflow_limit; use crate::infer::InferOk; -use crate::solve::inspect::{InspectGoal, InferCtxtProofTreeExt, ProofTreeVisitor}; +use crate::solve::inspect::{InferCtxtProofTreeExt, InspectGoal, ProofTreeVisitor}; use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; From 5765a82f479bc90d5247215887dda85a9ef14820 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 20 Oct 2025 20:58:30 +0000 Subject: [PATCH 06/17] Prepare for merging from rust-lang/rust This updates the rust-version file to 4068bafedd8ba724e332a5221c06a6fa531a30d2. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 47552aee08f74..a7367c5c88262 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -4fa824bb78318a3cba8c7339d5754b4909922547 +4068bafedd8ba724e332a5221c06a6fa531a30d2 From b0545d660918bce6644cde3273cc78730d62a638 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Oct 2025 23:08:28 +0200 Subject: [PATCH 07/17] how-to-build-and-run.md: remove stray instructions the previous command already builds using in-tree std --- .../rustc-dev-guide/src/building/how-to-build-and-run.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index ace834a55b71f..efb21726e3c6a 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -235,12 +235,6 @@ What this command does is: - Build `library` (the standard libraries) with the stage1 compiler that was just built. - Assemble a working stage1 sysroot, containing the stage1 compiler and stage1 standard libraries. -To build `rustc` with the in-tree `std`, use this command instead: - -```console -./x build library --stage 2 -``` - This final product (stage1 compiler + libs built using that compiler) is what you need to build other Rust programs (unless you use `#![no_std]` or `#![no_core]`). From 8badb14d822b724ab4e63c9b32ff37481204b628 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 24 Oct 2025 03:09:24 +0200 Subject: [PATCH 08/17] Add the gpu version of the kernel which was missing in the docs --- src/doc/rustc-dev-guide/src/offload/usage.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 9f519984d9bcc..7d1a5c9e2e0ed 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -56,6 +56,13 @@ fn main() { unsafe extern "C" { pub fn kernel_1(array_b: *mut [f64; 256]); } + +#[cfg(not(target_os = "linux"))] +#[unsafe(no_mangle)] +#[inline(never)] +pub extern "gpu-kernel" fn kernel_1(x: *mut [f64; 256]) { + unsafe { (*x)[0] = 21.0 }; +} ``` ## Compile instructions From 9503981f32771f28f8ac88d5305261180b58a038 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 15 Oct 2025 14:43:36 +0200 Subject: [PATCH 09/17] add a mailmap entry I accidentally commited some things with my name/email swapped ^^' --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index fc8e83d6493cd..6c168bbbcb554 100644 --- a/.mailmap +++ b/.mailmap @@ -680,6 +680,7 @@ Valerii Lashmanov Vitali Haravy Vitali Haravy Vitaly Shukela Waffle Lapkin +Waffle Lapkin Waffle Lapkin Weihang Lo Weihang Lo From 87c66c93ca71b4d7d326362322584cd2584473bd Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Sun, 26 Oct 2025 14:58:49 +0800 Subject: [PATCH 10/17] ci: loongarch64: use medium code model to avoid relocation overflows The LoongArch C/C++ cross toolchain defaults to the `normal` code model, which can cause relocation overflows when linking LLVM after upgrading to verion 22. This change uses the `medium`code model for `loongarch64-linux-gnu` and `loongarch64-linux-musl` builds to avoid these linking errors. --- src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile | 4 +++- src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile index e3f23149284e5..4b86ed32fd55f 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -21,7 +21,9 @@ ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-gnu/bin ENV CC_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-gcc \ AR_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-ar \ - CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++ + CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++ \ + CFLAGS_loongarch64_unknown_linux_gnu="-mcmodel=medium" \ + CXXFLAGS_loongarch64_unknown_linux_gnu="-mcmodel=medium" # We re-use the Linux toolchain for bare-metal, because upstream bare-metal # target support for LoongArch is only available from GCC 14+. diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile index 2c33b5526eebc..763b29ae1c5e9 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -21,7 +21,9 @@ ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-musl/bin ENV CC_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-gcc \ AR_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-ar \ - CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++ + CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++ \ + CFLAGS_loongarch64_unknown_linux_musl="-mcmodel=medium" \ + CXXFLAGS_loongarch64_unknown_linux_musl="-mcmodel=medium" ENV HOSTS=loongarch64-unknown-linux-musl From b12f71178b101d6423208a28e57816e7220eb831 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 27 Oct 2025 04:14:59 +0000 Subject: [PATCH 11/17] Prepare for merging from rust-lang/rust This updates the rust-version file to b1b464d6f61ec8c4e609c1328106378c066a9729. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index a7367c5c88262..f100e41166860 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -4068bafedd8ba724e332a5221c06a6fa531a30d2 +b1b464d6f61ec8c4e609c1328106378c066a9729 From 349dbecdab77d423118c62046f42aa7cf3c74ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 20 Oct 2025 11:27:43 +0200 Subject: [PATCH 12/17] move old solver coercion code to separate function --- compiler/rustc_hir_typeck/src/coercion.rs | 232 ++++++++++++---------- 1 file changed, 125 insertions(+), 107 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 7766075bade91..a32dd135af763 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -660,125 +660,143 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } } else { - let mut selcx = traits::SelectionContext::new(self); - // Use a FIFO queue for this custom fulfillment procedure. - // - // A Vec (or SmallVec) is not a natural choice for a queue. However, - // this code path is hot, and this queue usually has a max length of 1 - // and almost never more than 3. By using a SmallVec we avoid an - // allocation, at the (very small) cost of (occasionally) having to - // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation]; - - // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid - // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where - // inference might unify those two inner type variables later. - let traits = [coerce_unsized_did, unsize_did]; - while !queue.is_empty() { - let obligation = queue.remove(0); - let trait_pred = match obligation.predicate.kind().no_bound_vars() { - Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) - if traits.contains(&trait_pred.def_id()) => - { - self.resolve_vars_if_possible(trait_pred) - } - // Eagerly process alias-relate obligations in new trait solver, - // since these can be emitted in the process of solving trait goals, - // but we need to constrain vars before processing goals mentioning - // them. - Some(ty::PredicateKind::AliasRelate(..)) => { - let ocx = ObligationCtxt::new(self); - ocx.register_obligation(obligation); - if !ocx.try_evaluate_obligations().is_empty() { - return Err(TypeError::Mismatch); - } - coercion.obligations.extend(ocx.into_pending_obligations()); - continue; - } - _ => { - coercion.obligations.push(obligation); - continue; + self.coerce_unsized_old_solver( + obligation, + &mut coercion, + coerce_unsized_did, + unsize_did, + )?; + } + + Ok(coercion) + } + + fn coerce_unsized_old_solver( + &self, + obligation: Obligation<'tcx, ty::Predicate<'tcx>>, + coercion: &mut InferOk<'tcx, (Vec>, Ty<'tcx>)>, + coerce_unsized_did: DefId, + unsize_did: DefId, + ) -> Result<(), TypeError<'tcx>> { + let mut selcx = traits::SelectionContext::new(self); + // Use a FIFO queue for this custom fulfillment procedure. + // + // A Vec (or SmallVec) is not a natural choice for a queue. However, + // this code path is hot, and this queue usually has a max length of 1 + // and almost never more than 3. By using a SmallVec we avoid an + // allocation, at the (very small) cost of (occasionally) having to + // shift subsequent elements down when removing the front element. + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation]; + + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid + // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where + // inference might unify those two inner type variables later. + let traits = [coerce_unsized_did, unsize_did]; + while !queue.is_empty() { + let obligation = queue.remove(0); + let trait_pred = match obligation.predicate.kind().no_bound_vars() { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) + if traits.contains(&trait_pred.def_id()) => + { + self.resolve_vars_if_possible(trait_pred) + } + // Eagerly process alias-relate obligations in new trait solver, + // since these can be emitted in the process of solving trait goals, + // but we need to constrain vars before processing goals mentioning + // them. + Some(ty::PredicateKind::AliasRelate(..)) => { + let ocx = ObligationCtxt::new(self); + ocx.register_obligation(obligation); + if !ocx.try_evaluate_obligations().is_empty() { + return Err(TypeError::Mismatch); } - }; - debug!("coerce_unsized resolve step: {:?}", trait_pred); - match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { - // Uncertain or unimplemented. - Ok(None) => { - if trait_pred.def_id() == unsize_did { - let self_ty = trait_pred.self_ty(); - let unsize_ty = trait_pred.trait_ref.args[1].expect_ty(); - debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (self_ty.kind(), unsize_ty.kind()) { - (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) - if self.type_var_is_sized(v) => - { - debug!("coerce_unsized: have sized infer {:?}", v); - coercion.obligations.push(obligation); - // `$0: Unsize` where we know that `$0: Sized`, try going - // for unsizing. - } - _ => { - // Some other case for `$0: Unsize`. Note that we - // hit this case even if `Something` is a sized type, so just - // don't do the coercion. - debug!("coerce_unsized: ambiguous unsize"); - return Err(TypeError::Mismatch); - } + coercion.obligations.extend(ocx.into_pending_obligations()); + continue; + } + _ => { + coercion.obligations.push(obligation); + continue; + } + }; + debug!("coerce_unsized resolve step: {:?}", trait_pred); + match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { + // Uncertain or unimplemented. + Ok(None) => { + if trait_pred.def_id() == unsize_did { + let self_ty = trait_pred.self_ty(); + let unsize_ty = trait_pred.trait_ref.args[1].expect_ty(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); + match (self_ty.kind(), unsize_ty.kind()) { + (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) + if self.type_var_is_sized(v) => + { + debug!("coerce_unsized: have sized infer {:?}", v); + coercion.obligations.push(obligation); + // `$0: Unsize` where we know that `$0: Sized`, try going + // for unsizing. + } + _ => { + // Some other case for `$0: Unsize`. Note that we + // hit this case even if `Something` is a sized type, so just + // don't do the coercion. + debug!("coerce_unsized: ambiguous unsize"); + return Err(TypeError::Mismatch); } - } else { - debug!("coerce_unsized: early return - ambiguous"); - return Err(TypeError::Mismatch); } - } - Err(SelectionError::Unimplemented) => { - debug!("coerce_unsized: early return - can't prove obligation"); + } else { + debug!("coerce_unsized: early return - ambiguous"); return Err(TypeError::Mismatch); } + } + Err(SelectionError::Unimplemented) => { + debug!("coerce_unsized: early return - can't prove obligation"); + return Err(TypeError::Mismatch); + } - Err(SelectionError::TraitDynIncompatible(_)) => { - // Dyn compatibility errors in coercion will *always* be due to the - // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` - // writen in source somewhere (otherwise we will never have lowered - // the dyn trait from HIR to middle). - // - // There's no reason to emit yet another dyn compatibility error, - // especially since the span will differ slightly and thus not be - // deduplicated at all! - self.fcx.set_tainted_by_errors(self.fcx.dcx().span_delayed_bug( - self.cause.span, - "dyn compatibility during coercion", - )); - } - Err(err) => { - let guar = self.err_ctxt().report_selection_error( - obligation.clone(), - &obligation, - &err, - ); + Err(SelectionError::TraitDynIncompatible(_)) => { + // Dyn compatibility errors in coercion will *always* be due to the + // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait` + // written in source somewhere (otherwise we will never have lowered + // the dyn trait from HIR to middle). + // + // There's no reason to emit yet another dyn compatibility error, + // especially since the span will differ slightly and thus not be + // deduplicated at all! + self.fcx.set_tainted_by_errors( + self.fcx + .dcx() + .span_delayed_bug(self.cause.span, "dyn compatibility during coercion"), + ); + } + Err(err) => { + let guar = self.err_ctxt().report_selection_error( + obligation.clone(), + &obligation, + &err, + ); + self.fcx.set_tainted_by_errors(guar); + // Treat this like an obligation and follow through + // with the unsizing - the lack of a coercion should + // be silent, as it causes a type mismatch later. + } + Ok(Some(ImplSource::UserDefined(impl_source))) => { + queue.extend(impl_source.nested); + // Certain incoherent `CoerceUnsized` implementations may cause ICEs, + // so check the impl's validity. Taint the body so that we don't try + // to evaluate these invalid coercions in CTFE. We only need to do this + // for local impls, since upstream impls should be valid. + if impl_source.impl_def_id.is_local() + && let Err(guar) = + self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id) + { self.fcx.set_tainted_by_errors(guar); - // Treat this like an obligation and follow through - // with the unsizing - the lack of a coercion should - // be silent, as it causes a type mismatch later. } - Ok(Some(ImplSource::UserDefined(impl_source))) => { - queue.extend(impl_source.nested); - // Certain incoherent `CoerceUnsized` implementations may cause ICEs, - // so check the impl's validity. Taint the body so that we don't try - // to evaluate these invalid coercions in CTFE. We only need to do this - // for local impls, since upstream impls should be valid. - if impl_source.impl_def_id.is_local() - && let Err(guar) = - self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id) - { - self.fcx.set_tainted_by_errors(guar); - } - } - Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } + Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } } - Ok(coercion) + Ok(()) } /// Applies reborrowing for `Pin` From 3d9cb043dd10a1d189ac9bf35ee869c2fd5e3d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 2 Oct 2025 15:29:30 +0200 Subject: [PATCH 13/17] prove both newly added tests are fixed by the changes --- ...t-object-from-unsized-type.current.stderr} | 8 ++-- .../dst-object-from-unsized-type.next.stderr | 41 +++++++++++++++++++ .../unsize-goal-mismatch-2.next.stderr | 13 ++++++ .../next-solver/unsize-goal-mismatch-2.rs | 3 +- .../unsize-goal-mismatch.current.stderr | 17 ++++++++ .../unsize-goal-mismatch.next.stderr | 13 ++++++ .../next-solver/unsize-goal-mismatch.rs | 4 +- .../traits/next-solver/unsize-overflow.stderr | 12 ++++++ 8 files changed, 104 insertions(+), 7 deletions(-) rename tests/ui/dst/{dst-object-from-unsized-type.stderr => dst-object-from-unsized-type.current.stderr} (90%) create mode 100644 tests/ui/dst/dst-object-from-unsized-type.next.stderr create mode 100644 tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr create mode 100644 tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr create mode 100644 tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr create mode 100644 tests/ui/traits/next-solver/unsize-overflow.stderr diff --git a/tests/ui/dst/dst-object-from-unsized-type.stderr b/tests/ui/dst/dst-object-from-unsized-type.current.stderr similarity index 90% rename from tests/ui/dst/dst-object-from-unsized-type.stderr rename to tests/ui/dst/dst-object-from-unsized-type.current.stderr index cbb7dc5e9f421..d5f99eca974e5 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.stderr +++ b/tests/ui/dst/dst-object-from-unsized-type.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:8:23 + --> $DIR/dst-object-from-unsized-type.rs:11:23 | LL | fn test1(t: &T) { | - this type parameter needs to be `Sized` @@ -14,7 +14,7 @@ LL + fn test1(t: &T) { | error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:13:23 + --> $DIR/dst-object-from-unsized-type.rs:16:23 | LL | fn test2(t: &T) { | - this type parameter needs to be `Sized` @@ -29,7 +29,7 @@ LL + fn test2(t: &T) { | error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:18:28 + --> $DIR/dst-object-from-unsized-type.rs:21:28 | LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time @@ -38,7 +38,7 @@ LL | let _: &[&dyn Foo] = &["hi"]; = note: required for the cast from `&'static str` to `&dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:23:23 + --> $DIR/dst-object-from-unsized-type.rs:26:23 | LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time diff --git a/tests/ui/dst/dst-object-from-unsized-type.next.stderr b/tests/ui/dst/dst-object-from-unsized-type.next.stderr new file mode 100644 index 0000000000000..6b4adda5154e6 --- /dev/null +++ b/tests/ui/dst/dst-object-from-unsized-type.next.stderr @@ -0,0 +1,41 @@ +error[E0308]: mismatched types + --> $DIR/dst-object-from-unsized-type.rs:11:23 + | +LL | fn test1(t: &T) { + | - found this type parameter +LL | let u: &dyn Foo = t; + | -------- ^ expected `&dyn Foo`, found `&T` + | | + | expected due to this + | + = note: expected reference `&dyn Foo` + found reference `&T` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0605]: non-primitive cast: `&T` as `&dyn Foo` + --> $DIR/dst-object-from-unsized-type.rs:16:23 + | +LL | let v: &dyn Foo = t as &dyn Foo; + | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error[E0308]: mismatched types + --> $DIR/dst-object-from-unsized-type.rs:21:28 + | +LL | let _: &[&dyn Foo] = &["hi"]; + | ^^^^ expected `&dyn Foo`, found `&str` + | + = note: expected reference `&dyn Foo` + found reference `&'static str` + = help: `str` implements `Foo` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + +error[E0605]: non-primitive cast: `&[u8]` as `&dyn Foo` + --> $DIR/dst-object-from-unsized-type.rs:26:23 + | +LL | let _: &dyn Foo = x as &dyn Foo; + | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0605. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr new file mode 100644 index 0000000000000..b415db33addbf --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr @@ -0,0 +1,13 @@ +error[E0283]: type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize>` + --> $DIR/unsize-goal-mismatch-2.rs:15:5 + | +LL | x + | ^ + | + = note: cannot satisfy `dyn Trait<&()>: Unsize>` + = note: required for `Box>` to implement `CoerceUnsized>>` + = note: required for the cast from `Box<(dyn Trait<&'a ()> + 'static)>` to `Box<(dyn Super<&'a ()> + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs index c651309e01b19..2b174eac5c151 100644 --- a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs @@ -1,7 +1,7 @@ -//@ check-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver +//@[current] check-pass // Test from trait-system-refactor-initiative#241: // Used to ICE in mir typeck because of ambiguity in the new solver. // The wrong (first) trait bound was selected. @@ -13,6 +13,7 @@ trait Trait: Super + for<'hr> Super<&'hr ()> {} fn foo<'a>(x: Box>) -> Box> { x + //[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize>` } fn main() {} diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr new file mode 100644 index 0000000000000..278a68e154714 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr @@ -0,0 +1,17 @@ +error[E0283]: type annotations needed: cannot satisfy `Self: Super<'a>` + --> $DIR/unsize-goal-mismatch.rs:11:18 + | +LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {} + | ^^^^^^^^^ + | +note: multiple `impl`s or `where` clauses satisfying `Self: Super<'a>` found + --> $DIR/unsize-goal-mismatch.rs:10:1 + | +LL | trait Super<'a> {} + | ^^^^^^^^^^^^^^^ +LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {} + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr new file mode 100644 index 0000000000000..cfb978240cbc6 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr @@ -0,0 +1,13 @@ +error[E0283]: type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize>` + --> $DIR/unsize-goal-mismatch.rs:15:5 + | +LL | x + | ^ + | + = note: cannot satisfy `dyn Trait<'_>: Unsize>` + = note: required for `Box>` to implement `CoerceUnsized>>` + = note: required for the cast from `Box<(dyn Trait<'a> + 'static)>` to `Box<(dyn Super<'a> + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs index c9e2018997248..f57cceb4096a0 100644 --- a/tests/ui/traits/next-solver/unsize-goal-mismatch.rs +++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver @@ -10,10 +9,11 @@ trait Super<'a> {} trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {} +//[current]~^ ERROR type annotations needed: cannot satisfy `Self: Super<'a>` fn foo<'a>(x: Box>) -> Box> { x - //~^ ERROR type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize> + //[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize> } fn main() {} diff --git a/tests/ui/traits/next-solver/unsize-overflow.stderr b/tests/ui/traits/next-solver/unsize-overflow.stderr new file mode 100644 index 0000000000000..ae0f2957243c7 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-overflow.stderr @@ -0,0 +1,12 @@ +error[E0275]: overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized>` + --> $DIR/unsize-overflow.rs:5:28 + | +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` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From 17566221f879ba30d3143a0bc40b824ac794029f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 3 Oct 2025 11:32:17 +0200 Subject: [PATCH 14/17] find the right error source when we can't unsize --- compiler/rustc_hir_typeck/src/coercion.rs | 19 +++++- ...st-object-from-unsized-type.current.stderr | 6 +- .../dst-object-from-unsized-type.next.stderr | 64 ++++++++++++------- tests/ui/dst/dst-object-from-unsized-type.rs | 12 ++-- .../higher-ranked-upcasting-ub.next.stderr | 13 ++-- .../higher-ranked-upcasting-ub.rs | 4 +- 6 files changed, 78 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index a32dd135af763..857e4f66489ab 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -2055,6 +2055,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> { return ControlFlow::Continue(()); }; + // Make sure this predicate is referring to either an `Unsize` or `CoerceUnsized` trait, + // Otherwise there's nothing to do. if !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) && !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized) { @@ -2062,8 +2064,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> { } match goal.result() { + // If we prove the `Unsize` or `CoerceUnsized` goal, continue recursing. Ok(Certainty::Yes) => ControlFlow::Continue(()), - Err(NoSolution) => ControlFlow::Break(()), + Err(NoSolution) => { + // Even if we find no solution, continue recursing if we find a single candidate + // for which we're shallowly certain it holds to get the right error source. + if let [only_candidate] = &goal.candidates()[..] + && only_candidate.shallow_certainty() == Certainty::Yes + { + only_candidate.visit_nested_no_probe(self) + } else { + ControlFlow::Break(()) + } + } Ok(Certainty::Maybe { .. }) => { // FIXME: structurally normalize? if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) @@ -2071,6 +2084,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> { && let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind() && self.fcx.type_var_is_sized(vid) { + // We get here when trying to unsize a type variable to a `dyn Trait`, + // knowing that that variable is sized. Unsizing definitely has to happen in that case. + // If the variable weren't sized, we may not need an unsizing coercion. + // In general, we don't want to add coercions too eagerly since it makes error messages much worse. ControlFlow::Continue(()) } else if let Some(cand) = goal.unique_applicable_candidate() && cand.shallow_certainty() == Certainty::Yes diff --git a/tests/ui/dst/dst-object-from-unsized-type.current.stderr b/tests/ui/dst/dst-object-from-unsized-type.current.stderr index d5f99eca974e5..be9966743d4ee 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.current.stderr +++ b/tests/ui/dst/dst-object-from-unsized-type.current.stderr @@ -14,7 +14,7 @@ LL + fn test1(t: &T) { | error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:16:23 + --> $DIR/dst-object-from-unsized-type.rs:17:23 | LL | fn test2(t: &T) { | - this type parameter needs to be `Sized` @@ -29,7 +29,7 @@ LL + fn test2(t: &T) { | error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:21:28 + --> $DIR/dst-object-from-unsized-type.rs:23:28 | LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time @@ -38,7 +38,7 @@ LL | let _: &[&dyn Foo] = &["hi"]; = note: required for the cast from `&'static str` to `&dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/dst-object-from-unsized-type.rs:26:23 + --> $DIR/dst-object-from-unsized-type.rs:29:23 | LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time diff --git a/tests/ui/dst/dst-object-from-unsized-type.next.stderr b/tests/ui/dst/dst-object-from-unsized-type.next.stderr index 6b4adda5154e6..032ba0cb14aeb 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.next.stderr +++ b/tests/ui/dst/dst-object-from-unsized-type.next.stderr @@ -1,41 +1,57 @@ -error[E0308]: mismatched types +error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T` --> $DIR/dst-object-from-unsized-type.rs:11:23 | LL | fn test1(t: &T) { - | - found this type parameter + | - this type parameter needs to be `Sized` LL | let u: &dyn Foo = t; - | -------- ^ expected `&dyn Foo`, found `&T` - | | - | expected due to this - | - = note: expected reference `&dyn Foo` - found reference `&T` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + | ^ within `T`, the trait `Sized` is not implemented for `T` + | + = note: required because it appears within the type `T` + = note: required for `&T` to implement `CoerceUnsized<&dyn Foo>` + = note: required for the cast from `&T` to `&dyn Foo` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn test1(t: &T) { +LL + fn test1(t: &T) { + | -error[E0605]: non-primitive cast: `&T` as `&dyn Foo` - --> $DIR/dst-object-from-unsized-type.rs:16:23 +error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T` + --> $DIR/dst-object-from-unsized-type.rs:17:23 | +LL | fn test2(t: &T) { + | - this type parameter needs to be `Sized` LL | let v: &dyn Foo = t as &dyn Foo; - | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | ^ within `T`, the trait `Sized` is not implemented for `T` + | + = note: required because it appears within the type `T` + = note: required for `&T` to implement `CoerceUnsized<&dyn Foo>` + = note: required for the cast from `&T` to `&dyn Foo` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn test2(t: &T) { +LL + fn test2(t: &T) { + | -error[E0308]: mismatched types - --> $DIR/dst-object-from-unsized-type.rs:21:28 +error[E0277]: the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str` + --> $DIR/dst-object-from-unsized-type.rs:23:28 | LL | let _: &[&dyn Foo] = &["hi"]; - | ^^^^ expected `&dyn Foo`, found `&str` + | ^^^^ within `str`, the trait `Sized` is not implemented for `str` | - = note: expected reference `&dyn Foo` - found reference `&'static str` - = help: `str` implements `Foo` so you could box the found value and coerce it to the trait object `Box`, you will have to change the expected type as well + = note: `str` is considered to contain a `[u8]` slice for auto trait purposes + = note: required for `&str` to implement `CoerceUnsized<&dyn Foo>` + = note: required for the cast from `&'static str` to `&dyn Foo` -error[E0605]: non-primitive cast: `&[u8]` as `&dyn Foo` - --> $DIR/dst-object-from-unsized-type.rs:26:23 +error[E0277]: the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]` + --> $DIR/dst-object-from-unsized-type.rs:29:23 | LL | let _: &dyn Foo = x as &dyn Foo; - | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | ^ within `[u8]`, the trait `Sized` is not implemented for `[u8]` + | + = note: required because it appears within the type `[u8]` + = note: required for `&[u8]` to implement `CoerceUnsized<&dyn Foo>` + = note: required for the cast from `&[u8]` to `&dyn Foo` error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0605. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dst/dst-object-from-unsized-type.rs b/tests/ui/dst/dst-object-from-unsized-type.rs index 5ba6c571a39a6..1e6113b3fc6fb 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.rs +++ b/tests/ui/dst/dst-object-from-unsized-type.rs @@ -9,22 +9,26 @@ impl Foo for [u8] {} fn test1(t: &T) { let u: &dyn Foo = t; - //~^ ERROR the size for values of type + //[current]~^ ERROR the size for values of type + //[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T` } fn test2(t: &T) { let v: &dyn Foo = t as &dyn Foo; - //~^ ERROR the size for values of type + //[current]~^ ERROR the size for values of type + //[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T` } fn test3() { let _: &[&dyn Foo] = &["hi"]; - //~^ ERROR the size for values of type + //[current]~^ ERROR the size for values of type + //[next]~^^ ERROR the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str` } fn test4(x: &[u8]) { let _: &dyn Foo = x as &dyn Foo; - //~^ ERROR the size for values of type + //[current]~^ ERROR the size for values of type + //[next]~^^ ERROR the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]` } fn main() { } diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr index b82f1eef42b5a..392680aa50643 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr @@ -1,14 +1,13 @@ -error[E0308]: mismatched types +error[E0277]: the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied --> $DIR/higher-ranked-upcasting-ub.rs:22:5 | -LL | fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> { - | ----------------------------------- expected `&dyn for<'a, 'b> Supertrait<'a, 'b>` because of return type LL | x - | ^ expected trait `Supertrait`, found trait `Subtrait` + | ^ the trait `Unsize Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>` | - = note: expected reference `&dyn for<'a, 'b> Supertrait<'a, 'b>` - found reference `&dyn for<'a> Subtrait<'a, 'a>` + = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information + = note: required for `&dyn for<'a> Subtrait<'a, 'a>` to implement `CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` + = note: required for the cast from `&dyn for<'a> Subtrait<'a, 'a>` to `&dyn for<'a, 'b> Supertrait<'a, 'b>` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs index af2594b95f3d2..98ca30ca391f7 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs @@ -19,8 +19,10 @@ impl<'a> Supertrait<'a, 'a> for () { } impl<'a> Subtrait<'a, 'a> for () {} fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> { - x //~ ERROR mismatched types + x //[current]~^ ERROR mismatched types + //[current]~| ERROR mismatched types + //[next]~^^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied } fn transmute<'a, 'b>(x: &'a str) -> &'b str { From 94c893ee2ed2d0134a9e0ccb808e40149dbbe186 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 26 Oct 2025 14:04:54 +0100 Subject: [PATCH 15/17] Add `coverage` scope for controlling paths in code coverage --- .../src/coverageinfo/mapgen.rs | 4 ++-- compiler/rustc_session/src/config.rs | 8 +++++--- compiler/rustc_session/src/options.rs | 4 ++-- .../src/compiler-flags/remap-path-scope.md | 3 ++- tests/coverage/remap-path-prefix.rs | 17 +++++++++++++++++ ...map-path-prefix.with_coverage_scope.cov-map | 10 ++++++++++ .../remap-path-prefix.with_macro_scope.cov-map | 10 ++++++++++ ...remap-path-prefix.with_macro_scope.coverage | 18 ++++++++++++++++++ ...remap-path-prefix.with_object_scope.cov-map | 10 ++++++++++ .../remap-path-prefix.with_remap.cov-map | 10 ++++++++++ 10 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 tests/coverage/remap-path-prefix.rs create mode 100644 tests/coverage/remap-path-prefix.with_coverage_scope.cov-map create mode 100644 tests/coverage/remap-path-prefix.with_macro_scope.cov-map create mode 100644 tests/coverage/remap-path-prefix.with_macro_scope.coverage create mode 100644 tests/coverage/remap-path-prefix.with_object_scope.cov-map create mode 100644 tests/coverage/remap-path-prefix.with_remap.cov-map diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 7e873347c82b0..b3a11f8b12bfc 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -128,7 +128,7 @@ impl GlobalFileTable { for file in all_files { raw_file_table.entry(file.stable_id).or_insert_with(|| { file.name - .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) .to_string_lossy() .into_owned() }); @@ -147,7 +147,7 @@ impl GlobalFileTable { .sess .opts .working_dir - .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) .to_string_lossy(); table.push(base_dir.as_ref()); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d1426ff55fbd6..89ae74c902fdd 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1377,10 +1377,12 @@ bitflags::bitflags! { const DIAGNOSTICS = 1 << 1; /// Apply remappings to debug information const DEBUGINFO = 1 << 3; + /// Apply remappings to coverage information + const COVERAGE = 1 << 4; - /// An alias for `macro` and `debuginfo`. This ensures all paths in compiled - /// executables or libraries are remapped but not elsewhere. - const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits(); + /// An alias for `macro`, `debuginfo` and `coverage`. This ensures all paths in compiled + /// executables, libraries and objects are remapped but not elsewhere. + const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits() | Self::COVERAGE.bits(); } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6dd90546de1b0..b89aec7d22a91 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -869,8 +869,7 @@ mod desc { pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; - pub(crate) const parse_remap_path_scope: &str = - "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`"; + pub(crate) const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `coverage`, `object`, `all`"; pub(crate) const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub(crate) const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; @@ -1705,6 +1704,7 @@ pub mod parse { "macro" => RemapPathScopeComponents::MACRO, "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS, "debuginfo" => RemapPathScopeComponents::DEBUGINFO, + "coverage" => RemapPathScopeComponents::COVERAGE, "object" => RemapPathScopeComponents::OBJECT, "all" => RemapPathScopeComponents::all(), _ => return false, diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md index 65219dc68e976..fb1c7d7a68789 100644 --- a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md +++ b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md @@ -10,7 +10,8 @@ This flag accepts a comma-separated list of values and may be specified multiple - `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from - `diagnostics` - apply remappings to printed compiler diagnostics -- `debuginfo` - apply remappings to debug informations +- `debuginfo` - apply remappings to debug information +- `coverage` - apply remappings to coverage information - `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,debuginfo`. - `all` - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`. diff --git a/tests/coverage/remap-path-prefix.rs b/tests/coverage/remap-path-prefix.rs new file mode 100644 index 0000000000000..29c5826989c44 --- /dev/null +++ b/tests/coverage/remap-path-prefix.rs @@ -0,0 +1,17 @@ +// This test makes sure that the files used in the coverage are remapped by +// `--remap-path-prefix` and the `coverage` <- `object` scopes. +// +// We also test the `macro` scope to make sure it does not affect coverage. + +// When coverage paths are remapped, the coverage-run mode can't find source files (because +// it doesn't know about the remapping), so it produces an empty coverage report. The empty +// report (i.e. no `.coverage` files) helps to demonstrate that remapping was indeed performed. + +//@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope +//@ compile-flags: --remap-path-prefix={{src-base}}=remapped +// +//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage +//@[with_object_scope] compile-flags: -Zremap-path-scope=object +//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro + +fn main() {} diff --git a/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map b/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map new file mode 100644 index 0000000000000..35731d71116f7 --- /dev/null +++ b/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map @@ -0,0 +1,10 @@ +Function name: remap_path_prefix::main +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] +Number of files: 1 +- file 0 => remapped/remap-path-prefix.rs +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/remap-path-prefix.with_macro_scope.cov-map b/tests/coverage/remap-path-prefix.with_macro_scope.cov-map new file mode 100644 index 0000000000000..551e286768854 --- /dev/null +++ b/tests/coverage/remap-path-prefix.with_macro_scope.cov-map @@ -0,0 +1,10 @@ +Function name: remap_path_prefix::main +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] +Number of files: 1 +- file 0 => $DIR/remap-path-prefix.rs +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/remap-path-prefix.with_macro_scope.coverage b/tests/coverage/remap-path-prefix.with_macro_scope.coverage new file mode 100644 index 0000000000000..63979d8fe15a5 --- /dev/null +++ b/tests/coverage/remap-path-prefix.with_macro_scope.coverage @@ -0,0 +1,18 @@ + LL| |// This test makes sure that the files used in the coverage are remapped by + LL| |// `--remap-path-prefix` and the `coverage` <- `object` scopes. + LL| |// + LL| |// We also test the `macro` scope to make sure it does not affect coverage. + LL| | + LL| |// When coverage paths are remapped, the coverage-run mode can't find source files (because + LL| |// it doesn't know about the remapping), so it produces an empty coverage report. The empty + LL| |// report (i.e. no `.coverage` files) helps to demonstrate that remapping was indeed performed. + LL| | + LL| |//@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope + LL| |//@ compile-flags: --remap-path-prefix={{src-base}}=remapped + LL| |// + LL| |//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage + LL| |//@[with_object_scope] compile-flags: -Zremap-path-scope=object + LL| |//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro + LL| | + LL| 1|fn main() {} + diff --git a/tests/coverage/remap-path-prefix.with_object_scope.cov-map b/tests/coverage/remap-path-prefix.with_object_scope.cov-map new file mode 100644 index 0000000000000..35731d71116f7 --- /dev/null +++ b/tests/coverage/remap-path-prefix.with_object_scope.cov-map @@ -0,0 +1,10 @@ +Function name: remap_path_prefix::main +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] +Number of files: 1 +- file 0 => remapped/remap-path-prefix.rs +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) +Highest counter ID seen: c0 + diff --git a/tests/coverage/remap-path-prefix.with_remap.cov-map b/tests/coverage/remap-path-prefix.with_remap.cov-map new file mode 100644 index 0000000000000..35731d71116f7 --- /dev/null +++ b/tests/coverage/remap-path-prefix.with_remap.cov-map @@ -0,0 +1,10 @@ +Function name: remap_path_prefix::main +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] +Number of files: 1 +- file 0 => remapped/remap-path-prefix.rs +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) +Highest counter ID seen: c0 + From 943074fd095f66712eeabb0e53bbc78695be7cd8 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 27 Oct 2025 15:35:18 +0200 Subject: [PATCH 16/17] improve and strengthen wording --- src/doc/rustc-dev-guide/src/contributing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index b927c9a792745..dbd04c51593cf 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -53,8 +53,8 @@ channels: stable, beta, and nightly. - **Stable**: this is the latest stable release for general usage. - **Beta**: this is the next release (will be stable within 6 weeks). - **Nightly**: follows the `master` branch of the repo. - This is the only channel where unstable, incomplete, or experimental features - should be used (with feature gates). + This is the only channel where unstable features are intended to be used, + which happens via opt-in feature gates. See [this chapter on implementing new features](./implementing_new_features.md) for more information. From bf6f3035af62a0391249062e47c4455caa69cf9b Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Mon, 27 Oct 2025 18:01:04 +0300 Subject: [PATCH 17/17] Fix typos: duplicate words in comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix 'the the' → 'the' in rustc_const_eval - Fix 'wether' → 'whether' in compiletest - Fix 'is is' → 'is' in rustc_ast_pretty (2 instances) Signed-off-by: Osama Abdelkader --- compiler/rustc_ast_pretty/src/pp.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/util.rs | 2 +- src/tools/compiletest/src/runtest.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 8a0dbadf18cdf..4108671a3629e 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -298,7 +298,7 @@ impl Printer { } } - // This is is where `BoxMarker`s are produced. + // This is where `BoxMarker`s are produced. fn scan_begin(&mut self, token: BeginToken) -> BoxMarker { if self.scan_stack.is_empty() { self.left_total = 1; @@ -310,7 +310,7 @@ impl Printer { BoxMarker } - // This is is where `BoxMarker`s are consumed. + // This is where `BoxMarker`s are consumed. fn scan_end(&mut self, b: BoxMarker) { if self.scan_stack.is_empty() { self.print_end(); diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index b5cf6c4c3723c..1e18a22be81c2 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -121,7 +121,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// ### `tracing_separate_thread` parameter /// /// This macro was introduced to obtain better traces of Miri without impacting release performance. -/// Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized +/// Miri saves traces using the `tracing_chrome` `tracing::Layer` so that they can be visualized /// in . To instruct `tracing_chrome` to put some spans on a separate trace /// thread/line than other spans when viewed in , you can pass /// `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 16b604e9df821..b82a533271c17 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3006,7 +3006,7 @@ impl<'test> TestCx<'test> { self.delete_file(&examined_path); } // If we want them to be the same, but they are different, then error. - // We do this wether we bless or not + // We do this whether we bless or not (_, true, false) => { self.fatal_proc_rec( &format!("`{}` should not have different output from base test!", kind),