From 7442ae735d528a438f3cd209e5adf74aaf40b79c Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Sun, 17 May 2026 16:12:19 -0400 Subject: [PATCH 1/2] add red test --- .../as_expression.current.stderr | 22 ++++++++- .../as_expression.next.stderr | 22 ++++++++- .../do_not_recommend/as_expression.rs | 45 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr index 46dd21ceb00a..dc14838f591a 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr @@ -12,6 +12,26 @@ LL | impl AsExpression for &'_ str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `Text`, found `Integer` -error: aborting due to 1 previous error +error[E0277]: the trait bound `X: A` is not satisfied + --> $DIR/as_expression.rs:60:5 + | +LL | X.start().foo().finish(); + | ^^^^^^^^^ unsatisfied trait bound + | +help: the trait `A` is not implemented for `X` + --> $DIR/as_expression.rs:70:1 + | +LL | struct X; + | ^^^^^^^^ +note: required by a bound in `Ext::foo` + --> $DIR/as_expression.rs:79:23 + | +LL | fn foo(self) -> Self + | --- required by a bound in this associated function +LL | where +LL | Self: Sized + A; + | ^ required by this bound in `Ext::foo` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index c43b4cd8defe..d47424abcf10 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -22,6 +22,26 @@ LL | where LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error: aborting due to 1 previous error +error[E0277]: the trait bound `X: A` is not satisfied + --> $DIR/as_expression.rs:60:15 + | +LL | X.start().foo().finish(); + | ^^^ unsatisfied trait bound + | +help: the trait `A` is not implemented for `X` + --> $DIR/as_expression.rs:70:1 + | +LL | struct X; + | ^^^^^^^^ +note: required by a bound in `Ext::foo` + --> $DIR/as_expression.rs:79:23 + | +LL | fn foo(self) -> Self + | --- required by a bound in this associated function +LL | where +LL | Self: Sized + A; + | ^ required by this bound in `Ext::foo` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index ca8b95f79bbe..c92c78f91ea4 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -55,4 +55,49 @@ impl Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); //~^ ERROR the trait bound `&str: AsExpression` is not satisfied + + // Regression test for https://github.com/rust-lang/rust/issues/156475. + X.start().foo().finish(); + //~^ ERROR the trait bound `X: A` is not satisfied +} + +trait A {} +trait B {} + +#[diagnostic::do_not_recommend] +impl A for T {} + +struct X; + +trait Start { + fn start(self) -> Self; +} + +trait Ext { + fn foo(self) -> Self + where + Self: Sized + A; +} + +trait Finish { + fn finish(self); +} + +impl Start for T { + fn start(self) -> Self { + self + } +} + +impl Ext for T { + fn foo(self) -> Self + where + Self: Sized + A, + { + self + } +} + +impl Finish for T { + fn finish(self) {} } From 7aa831f47a4320ec80367ff9fd6edd34915703d5 Mon Sep 17 00:00:00 2001 From: qaijuang <237468078+qaijuang@users.noreply.github.com> Date: Sun, 17 May 2026 16:12:40 -0400 Subject: [PATCH 2/2] preserve spans when hiding do_not_recommend impls --- .../src/error_reporting/traits/fulfillment_errors.rs | 8 ++++++++ .../src/error_reporting/traits/mod.rs | 2 +- .../do_not_recommend/as_expression.current.stderr | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index bf881feb6015..51a4186658c6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -816,6 +816,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn apply_do_not_recommend( &self, obligation: &mut PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, ) -> bool { let mut base_cause = obligation.cause.code().clone(); let mut applied_do_not_recommend = false; @@ -823,6 +824,13 @@ pub(super) fn apply_do_not_recommend( if let ObligationCauseCode::ImplDerived(ref c) = base_cause { if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) { let code = (*c.derived.parent_code).clone(); + // Keep more precise spans that still point within the parent obligation, + // but do not let hidden impl details move the span outside of it. + if code == *root_obligation.cause.code() + && !root_obligation.cause.span.contains(obligation.cause.span) + { + obligation.cause.span = root_obligation.cause.span; + } obligation.cause.map_code(|_| code); obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx); applied_do_not_recommend = true; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 990a703409d1..e38ac4c447fc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -298,7 +298,7 @@ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuara error.code, FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented) | FulfillmentErrorCode::Project(_) - ) && self.apply_do_not_recommend(&mut error.obligation) + ) && self.apply_do_not_recommend(&mut error.obligation, &error.root_obligation) { error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented); } diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr index dc14838f591a..0cb117d3fc4c 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr @@ -13,10 +13,10 @@ LL | impl AsExpression for &'_ str { = help: for that trait implementation, expected `Text`, found `Integer` error[E0277]: the trait bound `X: A` is not satisfied - --> $DIR/as_expression.rs:60:5 + --> $DIR/as_expression.rs:60:15 | LL | X.start().foo().finish(); - | ^^^^^^^^^ unsatisfied trait bound + | ^^^ unsatisfied trait bound | help: the trait `A` is not implemented for `X` --> $DIR/as_expression.rs:70:1