From 1d41c2c01c9d32b22b1b702cfe04e2f7aae477af Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 13 Jun 2025 10:57:00 +0000 Subject: [PATCH 01/13] Merge unboxed trait object error suggestion into regular dyn incompat error --- .../rustc_hir_analysis/src/check/wfcheck.rs | 66 ------------------- .../rustc_hir_analysis/src/hir_wf_check.rs | 14 +++- compiler/rustc_middle/src/traits/mod.rs | 2 + .../src/error_reporting/traits/suggestions.rs | 7 ++ .../src/traits/dyn_compatibility.rs | 2 +- .../avoid-ice-on-warning-3.old.stderr | 10 +++ .../supertrait-mentions-GAT.rs | 3 +- .../supertrait-mentions-GAT.stderr | 21 ++---- ...-trait-should-use-self-2021-without-dyn.rs | 3 - ...it-should-use-self-2021-without-dyn.stderr | 52 ++------------- ...incompatible-trait-should-use-self-2021.rs | 6 +- ...mpatible-trait-should-use-self-2021.stderr | 38 +++-------- .../dyn-incompatible-trait-should-use-self.rs | 6 +- ...-incompatible-trait-should-use-self.stderr | 38 +++-------- tests/ui/suggestions/issue-116434-2015.rs | 2 + tests/ui/suggestions/issue-116434-2015.stderr | 18 +++-- ...ce-hir-wf-check-anon-const-issue-122199.rs | 1 - ...ir-wf-check-anon-const-issue-122199.stderr | 19 +----- tests/ui/wf/issue-87495.stderr | 5 ++ 19 files changed, 92 insertions(+), 221 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b8dc01cbc03cf..35cdf4c6d1fe7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -382,8 +382,6 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; - check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - // Check that an item definition in a subtrait is shadowing a supertrait item. lint_item_shadowing_supertrait_item(tcx, def_id); @@ -832,70 +830,6 @@ impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { } } -fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { - match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { - [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), - _ => false, - }, - _ => false, - } -} - -/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items. -/// -/// In such cases, suggest using `Self` instead. -fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { - let (trait_ident, trait_def_id) = - match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) { - hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id), - _ => return, - }, - _ => return, - }; - let mut trait_should_be_self = vec![]; - match &item.kind { - hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty)) - if could_be_self(trait_def_id.def_id, ty) => - { - trait_should_be_self.push(ty.span) - } - hir::TraitItemKind::Fn(sig, _) => { - for ty in sig.decl.inputs { - if could_be_self(trait_def_id.def_id, ty) { - trait_should_be_self.push(ty.span); - } - } - match sig.decl.output { - hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => { - trait_should_be_self.push(ty.span); - } - _ => {} - } - } - _ => {} - } - if !trait_should_be_self.is_empty() { - if tcx.is_dyn_compatible(trait_def_id) { - return; - } - let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); - tcx.dcx() - .struct_span_err( - trait_should_be_self, - "associated item referring to unboxed trait object for its own trait", - ) - .with_span_label(trait_ident.span, "in this trait") - .with_multipart_suggestion( - "you might have meant to use `Self` to refer to the implementing type", - sugg, - Applicability::MachineApplicable, - ) - .emit(); - } -} - fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) { let item_name = tcx.item_name(trait_item_def_id.to_def_id()); let trait_def_id = tcx.local_parent(trait_item_def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 4633f3951a784..fef0dbf2ece90 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -1,7 +1,8 @@ +use rustc_hir::def::DefKind; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ObligationCause, WellFormedLoc}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions}; @@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>( // over less-specific types (e.g. `Option>`) if self.depth >= self.cause_depth { self.cause = Some(error.obligation.cause); + if let hir::TyKind::TraitObject(..) = ty.kind { + if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn = + self.tcx.def_kind(self.def_id) + { + self.cause = Some(ObligationCause::new( + ty.span, + self.def_id, + ObligationCauseCode::DynCompatible(ty.span), + )); + } + } self.cause_depth = self.depth } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 27079af06fcd3..d877bd5c626ce 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -397,6 +397,8 @@ pub enum ObligationCauseCode<'tcx> { RustCall, + DynCompatible(Span), + /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than /// the ADT it's being implemented for. AlwaysApplicableImpl, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 68bd9440538fa..505ac5eee25d1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2721,6 +2721,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } + ObligationCauseCode::DynCompatible(span) => { + err.multipart_suggestion( + "you might have meant to use `Self` to refer to the implementing type", + vec![(span, "Self".into())], + Applicability::MachineApplicable, + ); + } ObligationCauseCode::WhereClause(item_def_id, span) | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..) | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..) diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 220a847cc230f..2502a30930e03 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::traits::{ /// /// Currently that is `Self` in supertraits. This is needed /// because `dyn_compatibility_violations` can't be used during -/// type collection. +/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself. #[instrument(level = "debug", skip(tcx), ret)] pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index d8935be560948..8b4f3f52ee934 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr @@ -87,6 +87,11 @@ help: alternatively, consider constraining `g` so it does not apply to trait obj | LL | trait A { fn g(b: B) -> B where Self: Sized; } | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait B { fn f(a: A) -> A; } +LL + trait B { fn f(a: Self) -> A; } + | warning: trait objects without an explicit `dyn` are deprecated --> $DIR/avoid-ice-on-warning-3.rs:14:19 @@ -124,6 +129,11 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | trait B { fn f(a: A) -> A where Self: Sized; } | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait A { fn g(b: B) -> B; } +LL + trait A { fn g(b: Self) -> B; } + | error: aborting due to 2 previous errors; 6 warnings emitted diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs index 9e5c1bfe4160a..b866dab9dba28 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs @@ -8,8 +8,7 @@ trait GatTrait { trait SuperTrait: for<'a> GatTrait = T> { fn c(&self) -> dyn SuperTrait; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `SuperTrait` is not dyn compatible + //~^ ERROR the trait `SuperTrait` is not dyn compatible } fn main() {} diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index 582cf1af05468..ba4ce47539956 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -7,20 +7,6 @@ LL | Self: 'a; | ^^ = help: consider adding an explicit lifetime bound `Self: 'a`... -error: associated item referring to unboxed trait object for its own trait - --> $DIR/supertrait-mentions-GAT.rs:10:20 - | -LL | trait SuperTrait: for<'a> GatTrait = T> { - | ---------- in this trait -LL | fn c(&self) -> dyn SuperTrait; - | ^^^^^^^^^^^^^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn c(&self) -> dyn SuperTrait; -LL + fn c(&self) -> Self; - | - error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/supertrait-mentions-GAT.rs:10:20 | @@ -37,8 +23,13 @@ LL | type Gat<'a> LL | trait SuperTrait: for<'a> GatTrait = T> { | ---------- this trait is not dyn compatible... = help: consider moving `Gat` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn c(&self) -> dyn SuperTrait; +LL + fn c(&self) -> Self; + | -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0311. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs index 10b4781eb0494..97a0e005f86ab 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs @@ -4,19 +4,16 @@ trait A: Sized { fn f(a: A) -> A; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } trait B { fn f(b: B) -> B; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } trait C { fn f(&self, c: C) -> C; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr index e189012d15c94..c4dab4691f492 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr @@ -26,22 +26,8 @@ help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as LL | fn f(a: A) -> impl A; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: A) -> A; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: A) -> A; -LL + fn f(a: Self) -> Self; - | - error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:13 | LL | fn f(b: B) -> B; | ^ @@ -58,7 +44,7 @@ LL | fn f(b: impl B) -> B; | ++++ error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:19 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:19 | LL | fn f(b: B) -> B; | ^ @@ -68,22 +54,8 @@ help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as LL | fn f(b: B) -> impl B; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 - | -LL | trait B { - | - in this trait -LL | fn f(b: B) -> B; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(b: B) -> B; -LL + fn f(b: Self) -> Self; - | - error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:20 | LL | fn f(&self, c: C) -> C; | ^ @@ -100,7 +72,7 @@ LL | fn f(&self, c: impl C) -> C; | ++++ error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:26 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:26 | LL | fn f(&self, c: C) -> C; | ^ @@ -110,20 +82,6 @@ help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as LL | fn f(&self, c: C) -> impl C; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 - | -LL | trait C { - | - in this trait -LL | fn f(&self, c: C) -> C; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(&self, c: C) -> C; -LL + fn f(&self, c: Self) -> Self; - | - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs index 747926c400ae0..a798b1bd5787d 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs @@ -2,13 +2,11 @@ #![allow(bare_trait_objects)] trait A: Sized { fn f(a: dyn A) -> dyn A; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` is not dyn compatible + //~^ ERROR the trait `A` is not dyn compatible } trait B { fn f(a: dyn B) -> dyn B; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` is not dyn compatible + //~^ ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: dyn C) -> dyn C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index 2e3919db1b75f..4ccf65b68bf75 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr @@ -1,17 +1,3 @@ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: dyn A) -> dyn A; - | ^^^^^ ^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: dyn A) -> dyn A; -LL + fn f(a: Self) -> Self; - | - error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 | @@ -26,30 +12,21 @@ LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 - | -LL | trait B { - | - in this trait -LL | fn f(a: dyn B) -> dyn B; - | ^^^^^ ^^^^^ - | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: dyn B) -> dyn B; -LL + fn f(a: Self) -> Self; +LL - fn f(a: dyn A) -> dyn A; +LL + fn f(a: Self) -> dyn A; | error[E0038]: the trait `B` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:13 | LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:8 | LL | trait B { | - this trait is not dyn compatible... @@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | fn f(a: dyn B) -> dyn B where Self: Sized; | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(a: dyn B) -> dyn B; +LL + fn f(a: Self) -> dyn B; + | -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs index 63fe5ebaea499..d8e9d381dbda7 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs @@ -1,12 +1,10 @@ trait A: Sized { fn f(a: dyn A) -> dyn A; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` is not dyn compatible + //~^ ERROR the trait `A` is not dyn compatible } trait B { fn f(a: dyn B) -> dyn B; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` is not dyn compatible + //~^ ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: dyn C) -> dyn C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index e8384afed7a11..bda1d01e23ff9 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -1,17 +1,3 @@ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: dyn A) -> dyn A; - | ^^^^^ ^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: dyn A) -> dyn A; -LL + fn f(a: Self) -> Self; - | - error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 | @@ -26,30 +12,21 @@ LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 - | -LL | trait B { - | - in this trait -LL | fn f(a: dyn B) -> dyn B; - | ^^^^^ ^^^^^ - | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: dyn B) -> dyn B; -LL + fn f(a: Self) -> Self; +LL - fn f(a: dyn A) -> dyn A; +LL + fn f(a: Self) -> dyn A; | error[E0038]: the trait `B` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:6:13 | LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:8 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:6:8 | LL | trait B { | - this trait is not dyn compatible... @@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | fn f(a: dyn B) -> dyn B where Self: Sized; | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(a: dyn B) -> dyn B; +LL + fn f(a: Self) -> dyn B; + | -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs index bad9d02321cf2..e0438cdef253b 100644 --- a/tests/ui/suggestions/issue-116434-2015.rs +++ b/tests/ui/suggestions/issue-116434-2015.rs @@ -11,6 +11,7 @@ trait Foo { //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `Clone` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name + //~| HELP use `Self` to refer to the implementing type } trait DbHandle: Sized {} @@ -26,6 +27,7 @@ trait DbInterface { //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `DbHandle` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name + //~| HELP use `Self` to refer to the implementing type } fn main() {} diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index a0a99cc560dba..cad5812da6632 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -35,13 +35,18 @@ LL | fn foo() -> Clone; = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn foo() -> Clone; +LL + fn foo() -> Self; + | help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; | ++++++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -54,7 +59,7 @@ LL | fn handle() -> dyn DbHandle; | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -68,19 +73,24 @@ LL | fn handle() -> dyn DbHandle; | +++ error[E0038]: the trait `DbHandle` is not dyn compatible - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/issue-116434-2015.rs:16:17 + --> $DIR/issue-116434-2015.rs:17:17 | LL | trait DbHandle: Sized {} | -------- ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn handle() -> DbHandle; +LL + fn handle() -> Self; + | help: there is an associated type with the same name | LL | fn handle() -> Self::DbHandle; diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index 53f07a94fd15e..ad7d972879fff 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -5,7 +5,6 @@ trait Trait { //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters //~| ERROR expected value, found builtin type `u32` //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - //~| ERROR associated item referring to unboxed trait object for its own trait bar //~^ ERROR cannot find value `bar` in this scope } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index a085dd6ac5761..e10bb98c13497 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -20,7 +20,7 @@ LL | fn fnc(&self) -> dyn Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:9:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:8:9 | LL | bar | ^^^ not found in this scope @@ -45,22 +45,7 @@ error: defaults for const parameters are only allowed in `struct`, `enum`, `type LL | fn fnc(&self) -> dyn Trait { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:48 - | -LL | trait Trait { - | ----- in this trait -... -LL | fn fnc(&self) -> dyn Trait { - | ^^^^^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn fnc(&self) -> dyn Trait { -LL + fn fnc(&self) -> Self { - | - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 0c293e3576d64..bf79535df116c 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -13,6 +13,11 @@ LL | trait T { LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains this associated `const` = help: consider moving `CONST` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - const CONST: (bool, dyn T); +LL + const CONST: (bool, Self); + | error: aborting due to 1 previous error From 6d040856df069e0345cc34047c4d21c66021cca9 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 16 Jun 2025 19:41:12 +0200 Subject: [PATCH 02/13] Add a warning to LateContext::get_def_path --- compiler/rustc_lint/src/context.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5679d4566dcd4..c7d59fa283a7a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -710,6 +710,15 @@ impl<'tcx> LateContext<'tcx> { /// Gets the absolute path of `def_id` as a vector of `Symbol`. /// + /// Note that this is kinda expensive because it has to + /// travel the tree and pretty-print. Use sparingly. + /// + /// If you're trying to match for an item given by its path, use a + /// diagnostic item. If you're only interested in given sections, use more + /// specific functions, such as [`TyCtxt::crate_name`] + /// + /// FIXME: It would be great if this could be optimized. + /// /// # Examples /// /// ```rust,ignore (no context or def id available) From 6809ec16482ec72ba46566fe815b2bc89210612f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 20 Jun 2025 12:45:26 -0500 Subject: [PATCH 03/13] Factor out seen_comma variable --- compiler/rustc_parse/src/parser/item.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 658ed4bd41c40..28da287fcc2d3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1916,11 +1916,7 @@ impl<'a> Parser<'a> { safety: Safety, attrs: AttrVec, ) -> PResult<'a, FieldDef> { - let mut seen_comma: bool = false; let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; - if self.token == token::Comma { - seen_comma = true; - } if self.eat(exp!(Semi)) { let sp = self.prev_token.span; let mut err = @@ -1945,19 +1941,11 @@ impl<'a> Parser<'a> { missing_comma: None, }; self.bump(); // consume the doc comment - let comma_after_doc_seen = self.eat(exp!(Comma)); - // `seen_comma` is always false, because we are inside doc block - // condition is here to make code more readable - if !seen_comma && comma_after_doc_seen { - seen_comma = true; - } - if comma_after_doc_seen || self.token == token::CloseBrace { + if self.eat(exp!(Comma)) || self.token == token::CloseBrace { self.dcx().emit_err(err); } else { - if !seen_comma { - let sp = previous_span.shrink_to_hi(); - err.missing_comma = Some(sp); - } + let sp = previous_span.shrink_to_hi(); + err.missing_comma = Some(sp); return Err(self.dcx().create_err(err)); } } From 26a6b557172a7186c140c7aa42bf3873802a39fd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 20 Jun 2025 12:18:37 -0500 Subject: [PATCH 04/13] Recover from semicolon field separator --- compiler/rustc_parse/src/parser/item.rs | 33 ++++++++++--------- tests/ui/parser/recover/recover-field-semi.rs | 6 ++-- .../parser/recover/recover-field-semi.stderr | 12 +++---- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 28da287fcc2d3..5088caa80f88f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1781,7 +1781,7 @@ impl<'a> Parser<'a> { let mut recovered = Recovered::No; if self.eat(exp!(OpenBrace)) { while self.token != token::CloseBrace { - match self.parse_field_def(adt_ty) { + match self.parse_field_def(adt_ty, ident_span) { Ok(field) => { fields.push(field); } @@ -1894,7 +1894,7 @@ impl<'a> Parser<'a> { } /// Parses an element of a struct declaration. - fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> { + fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> { self.recover_vcs_conflict_marker(); let attrs = self.parse_outer_attributes()?; self.recover_vcs_conflict_marker(); @@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; let safety = this.parse_unsafe_field(); - this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs) + this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span) .map(|field| (field, Trailing::No, UsePreAttrPos::No)) }) } @@ -1915,24 +1915,27 @@ impl<'a> Parser<'a> { vis: Visibility, safety: Safety, attrs: AttrVec, + ident_span: Span, ) -> PResult<'a, FieldDef> { let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; - if self.eat(exp!(Semi)) { - let sp = self.prev_token.span; - let mut err = - self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); - err.span_suggestion_short( - sp, - "replace `;` with `,`", - ",", - Applicability::MachineApplicable, - ); - return Err(err); - } match self.token.kind { token::Comma => { self.bump(); } + token::Semi => { + self.bump(); + let sp = self.prev_token.span; + let mut err = + self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); + err.span_suggestion_short( + sp, + "replace `;` with `,`", + ",", + Applicability::MachineApplicable, + ); + err.span_label(ident_span, format!("while parsing this {adt_ty}")); + err.emit(); + } token::CloseBrace => {} token::DocComment(..) => { let previous_span = self.prev_token.span; diff --git a/tests/ui/parser/recover/recover-field-semi.rs b/tests/ui/parser/recover/recover-field-semi.rs index b703578860ec1..b6f235f8ad1c9 100644 --- a/tests/ui/parser/recover/recover-field-semi.rs +++ b/tests/ui/parser/recover/recover-field-semi.rs @@ -3,7 +3,7 @@ struct Foo { //~^ ERROR struct fields are separated by `,` } -union Bar { //~ ERROR +union Bar { foo: i32; //~^ ERROR union fields are separated by `,` } @@ -13,4 +13,6 @@ enum Baz { //~^ ERROR struct fields are separated by `,` } -fn main() {} +fn main() { + let _ = Foo { foo: "" }; //~ ERROR mismatched types +} diff --git a/tests/ui/parser/recover/recover-field-semi.stderr b/tests/ui/parser/recover/recover-field-semi.stderr index 3cf4847488c05..9b1a34e134b6b 100644 --- a/tests/ui/parser/recover/recover-field-semi.stderr +++ b/tests/ui/parser/recover/recover-field-semi.stderr @@ -22,14 +22,12 @@ LL | Qux { foo: i32; } | | | while parsing this struct -error: unions cannot have zero fields - --> $DIR/recover-field-semi.rs:6:1 +error[E0308]: mismatched types + --> $DIR/recover-field-semi.rs:17:24 | -LL | / union Bar { -LL | | foo: i32; -LL | | -LL | | } - | |_^ +LL | let _ = Foo { foo: "" }; + | ^^ expected `i32`, found `&str` error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0308`. From 8e9552a6b5f05b181e9b550880d252d5282f96fe Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jun 2025 23:54:16 +0000 Subject: [PATCH 05/13] Add a few inline directives in rustc_serialize. --- compiler/rustc_serialize/src/int_overflow.rs | 2 ++ compiler/rustc_serialize/src/opaque.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_serialize/src/int_overflow.rs b/compiler/rustc_serialize/src/int_overflow.rs index f2aac2ef711c1..6782fbc33da15 100644 --- a/compiler/rustc_serialize/src/int_overflow.rs +++ b/compiler/rustc_serialize/src/int_overflow.rs @@ -20,6 +20,7 @@ macro_rules! impl_debug_strict_add { ($( $ty:ty )*) => { $( impl DebugStrictAdd for $ty { + #[inline] fn debug_strict_add(self, other: Self) -> Self { if cfg!(debug_assertions) { self + other @@ -42,6 +43,7 @@ macro_rules! impl_debug_strict_sub { ($( $ty:ty )*) => { $( impl DebugStrictSub for $ty { + #[inline] fn debug_strict_sub(self, other: Self) -> Self { if cfg!(debug_assertions) { self - other diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 00bad8e70cf2f..4242642c6643f 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -89,10 +89,12 @@ impl FileEncoder { self.buffered = 0; } + #[inline] pub fn file(&self) -> &File { &self.file } + #[inline] pub fn path(&self) -> &Path { &self.path } From b1d18129d199c095372c39f75a5c3fb31ea166c2 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 16 Jun 2025 17:51:29 +0200 Subject: [PATCH 06/13] Implement DesugaringKind::FormatLiteral --- compiler/rustc_ast/src/format.rs | 8 +++ compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/format.rs | 9 +++- compiler/rustc_builtin_macros/src/format.rs | 1 + compiler/rustc_span/src/hygiene.rs | 16 ++++++ .../src/error_reporting/traits/suggestions.rs | 32 ++++++++--- library/core/src/fmt/mod.rs | 19 ++++--- .../argument-suggestions/issue-100154.stderr | 4 +- .../defaults-unsound-62211-1.current.stderr | 3 +- .../defaults-unsound-62211-1.next.stderr | 3 +- .../defaults-unsound-62211-2.current.stderr | 3 +- .../defaults-unsound-62211-2.next.stderr | 3 +- tests/ui/binop/issue-77910-1.stderr | 3 +- tests/ui/closures/issue-111932.stderr | 4 +- tests/ui/consts/const-eval/format.stderr | 2 +- ...ives-span-Debug-enum-struct-variant.stderr | 3 +- .../ui/derives/derives-span-Debug-enum.stderr | 3 +- .../derives/derives-span-Debug-struct.stderr | 3 +- .../derives-span-Debug-tuple-struct.stderr | 3 +- ...prefix-diagnostics.not-diag-in-deps.stderr | 4 +- ...-diagnostics.only-debuginfo-in-deps.stderr | 4 +- ...refix-diagnostics.only-diag-in-deps.stderr | 4 +- ...efix-diagnostics.only-macro-in-deps.stderr | 4 +- ...-diagnostics.with-debuginfo-in-deps.stderr | 4 +- ...refix-diagnostics.with-diag-in-deps.stderr | 4 +- ...efix-diagnostics.with-macro-in-deps.stderr | 4 +- tests/ui/fmt/format-args-argument-span.stderr | 10 ++-- tests/ui/fmt/ifmt-unimpl.stderr | 4 +- tests/ui/fmt/non-source-literals.rs | 13 +++++ tests/ui/fmt/non-source-literals.stderr | 53 +++++++++++++++++++ .../generic-associated-types-where.stderr | 3 +- .../impl-trait/in-trait/doesnt-satisfy.stderr | 4 +- tests/ui/impl-trait/in-trait/wf-bounds.stderr | 3 +- tests/ui/issues/issue-59488.stderr | 6 +-- ...70724-add_type_neq_err_label-unwrap.stderr | 3 +- .../methods/suggest-convert-ptr-to-ref.stderr | 6 +-- .../method-help-unsatisfied-bound.stderr | 3 +- tests/ui/modules/issue-107649.stderr | 3 +- tests/ui/on-unimplemented/no-debug.stderr | 16 ++++-- .../dbg-macro-requires-debug.stderr | 3 +- tests/ui/span/issue-71363.stderr | 7 +-- tests/ui/suggestions/bound-suggestions.stderr | 24 ++++++--- .../derive-macro-missing-bounds.stderr | 3 +- .../impl-trait-with-missing-bounds.stderr | 18 +++---- tests/ui/suggestions/issue-81098.stderr | 10 +--- tests/ui/suggestions/issue-97760.stderr | 5 +- ...missing-bound-in-derive-copy-impl-3.stderr | 6 +-- .../missing-bound-in-derive-copy-impl.stderr | 6 +-- tests/ui/suggestions/path-display.stderr | 9 +++- .../traits/on_unimplemented_long_types.stderr | 3 +- .../suggest-remove-deref-issue-140166.stderr | 4 +- .../bounds-are-checked3.stderr | 3 +- .../generic_duplicate_param_use2.stderr | 2 +- .../generic_duplicate_param_use4.stderr | 2 +- .../generic_underconstrained2.stderr | 8 +-- tests/ui/type-alias-impl-trait/nested.stderr | 4 +- ...igned-block-without-tail-expression.stderr | 16 ++++-- .../ui/type/pattern_types/derives_fail.stderr | 4 +- .../point-at-type-param-in-path-expr.stderr | 4 +- 59 files changed, 261 insertions(+), 159 deletions(-) create mode 100644 tests/ui/fmt/non-source-literals.rs create mode 100644 tests/ui/fmt/non-source-literals.stderr diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b611ddea1d9f1..28d260419c51b 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -50,6 +50,14 @@ pub struct FormatArgs { /// /// Generally only useful for lints that care about the raw bytes the user wrote. pub uncooked_fmt_str: (LitKind, Symbol), + /// Was the format literal written in the source? + /// - `format!("boo")` => true, + /// - `format!(concat!("b", "o", "o"))` => false, + /// - `format!(include_str!("boo.txt"))` => false, + /// + /// If it wasn't written in the source then we have to be careful with spans pointing into it + /// and suggestions about rewriting it. + pub is_source_literal: bool, } /// A piece of a format template string. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bd2ab34bfc19b..245aa993affe2 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1389,7 +1389,7 @@ macro_rules! common_visitor_and_walkers { // FIXME: visit the template exhaustively. pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result { - let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt; + let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _, is_source_literal: _ } = fmt; let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ; for FormatArgument { kind, expr } in args { match kind { diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 12f0af7548681..943cde90dd20b 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -4,7 +4,7 @@ use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, sym}; use super::LoweringContext; @@ -14,6 +14,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // format_args!() had any arguments _before_ flattening/inlining. let allow_const = fmt.arguments.all_args().is_empty(); let mut fmt = Cow::Borrowed(fmt); + + let sp = self.mark_span_with_reason( + DesugaringKind::FormatLiteral { source: fmt.is_source_literal }, + sp, + sp.ctxt().outer_expn_data().allow_internal_unstable, + ); + if self.tcx.sess.opts.unstable_opts.flatten_format_args { fmt = flatten_format_args(fmt); fmt = self.inline_literals(fmt); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 39f9d5f900514..6785cb6aef5a3 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -606,6 +606,7 @@ fn make_format_args( template, arguments: args, uncooked_fmt_str, + is_source_literal, })) } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 315dedec10758..29be3b73ee99d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1213,6 +1213,17 @@ pub enum DesugaringKind { Contract, /// A pattern type range start/end PatTyRange, + /// A format literal. + FormatLiteral { + /// Was this format literal written in the source? + /// - `format!("boo")` => Yes, + /// - `format!(concat!("b", "o", "o"))` => No, + /// - `format!(include_str!("boo.txt"))` => No, + /// + /// If it wasn't written in the source then we have to be careful with suggestions about + /// rewriting it. + source: bool, + }, } impl DesugaringKind { @@ -1231,6 +1242,10 @@ impl DesugaringKind { DesugaringKind::BoundModifier => "trait bound modifier", DesugaringKind::Contract => "contract check", DesugaringKind::PatTyRange => "pattern type", + DesugaringKind::FormatLiteral { source: true } => "format string literal", + DesugaringKind::FormatLiteral { source: false } => { + "expression that expanded into a format string literal" + } } } @@ -1250,6 +1265,7 @@ impl DesugaringKind { DesugaringKind::BoundModifier => value == "BoundModifier", DesugaringKind::Contract => value == "Contract", DesugaringKind::PatTyRange => value == "PatTyRange", + DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral", } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6d07ae021ae9d..35fce041af4e6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2872,13 +2872,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (), } } - let descr = format!("required by {a} bound in `{item_name}`"); - if span.is_visible(sm) { - let msg = format!("required by {this} in `{short_item_name}`"); - multispan.push_span_label(span, msg); - err.span_note(multispan, descr); + + // If this is from a format string literal desugaring, + // we've already said "required by this formatting parameter" + let is_in_fmt_lit = if let Some(s) = err.span.primary_span() { + matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. })) } else { - err.span_note(tcx.def_span(item_def_id), descr); + false + }; + if !is_in_fmt_lit { + let descr = format!("required by {a} bound in `{item_name}`"); + if span.is_visible(sm) { + let msg = format!("required by {this} in `{short_item_name}`"); + multispan.push_span_label(span, msg); + err.span_note(multispan, descr); + } else { + err.span_note(tcx.def_span(item_def_id), descr); + } } if let Some(note) = note { err.note(note); @@ -3973,7 +3983,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) = expr.kind { if Some(*span) != err.span.primary_span() { - err.span_label(*span, "required by a bound introduced by this call"); + let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true }) + { + "required by this formatting parameter" + } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) { + "required by a formatting parameter in this expression" + } else { + "required by a bound introduced by this call" + }; + err.span_label(*span, msg); } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c20b3d4817f93..2be8d37bbee67 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -855,11 +855,13 @@ impl Display for Arguments<'_> { #[rustc_on_unimplemented( on( crate_local, - label = "`{Self}` cannot be formatted using `{{:?}}`", note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`" ), - message = "`{Self}` doesn't implement `{This}`", - label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" + on( + from_desugaring = "FormatLiteral", + label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" + ), + message = "`{Self}` doesn't implement `{This}`" )] #[doc(alias = "{:?}")] #[rustc_diagnostic_item = "Debug"] @@ -986,11 +988,14 @@ pub use macros::Debug; any(Self = "std::path::Path", Self = "std::path::PathBuf"), label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it", note = "call `.display()` or `.to_string_lossy()` to safely print paths, \ - as they may contain non-Unicode data" + as they may contain non-Unicode data", + ), + on( + from_desugaring = "FormatLiteral", + note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead", + label = "`{Self}` cannot be formatted with the default formatter", ), - message = "`{Self}` doesn't implement `{This}`", - label = "`{Self}` cannot be formatted with the default formatter", - note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" + message = "`{Self}` doesn't implement `{This}`" )] #[doc(alias = "{}")] #[rustc_diagnostic_item = "Display"] diff --git a/tests/ui/argument-suggestions/issue-100154.stderr b/tests/ui/argument-suggestions/issue-100154.stderr index 7eaebcafb5957..9732beac4492f 100644 --- a/tests/ui/argument-suggestions/issue-100154.stderr +++ b/tests/ui/argument-suggestions/issue-100154.stderr @@ -17,10 +17,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-100154.rs:4:11 | LL | foo::<()>(()); - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `foo` --> $DIR/issue-100154.rs:1:16 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr index 8b6f0a47aed98..b17e26b608d93 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-1.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr index 010f51df15ad3..a858c9c1ba04a 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-1.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr index 7552b08913337..facfec85afe38 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-2.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr index 9347894657078..1360843172f96 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-2.rs:24:86 | diff --git a/tests/ui/binop/issue-77910-1.stderr b/tests/ui/binop/issue-77910-1.stderr index 74deac900d424..80c384f39bd1b 100644 --- a/tests/ui/binop/issue-77910-1.stderr +++ b/tests/ui/binop/issue-77910-1.stderr @@ -16,9 +16,8 @@ LL | fn foo(s: &i32) -> &i32 { | --- consider calling this function ... LL | assert_eq!(foo, y); - | ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}` | - = help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}` = help: use parentheses to call this function: `foo(/* &i32 */)` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index 93488ad2011e4..fc3b7b0c6e662 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -14,11 +14,9 @@ error[E0277]: the size for values of type `dyn Foo` cannot be known at compilati LL | println!("{:?}", foo); | ---- ^^^ doesn't have a size known at compile-time | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the trait `Sized` is not implemented for `dyn Foo` -note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 2f202705b7f96..bd50ac0bf4116 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -13,7 +13,7 @@ LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const function `_print` in constant functions --> $DIR/format.rs:7:5 diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr index a7f6d094681a1..147910b715f51 100644 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | x: Error - | ^^^^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr index b3a5847815983..6f97ceb02d3a1 100644 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ b/tests/ui/derives/derives-span-Debug-enum.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | Error - | ^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr index c8ad652716caf..46d69a892f25c 100644 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-struct.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Struct { LL | x: Error - | ^^^^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr index dbece4d2091b2..a3feeff6df377 100644 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Struct( LL | Error - | ^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr index 3ddff11798de3..229bfbe59e50d 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr index 85c781425b16a..a59af3b6a8263 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr index 792ea7925ad56..18fb9afcf390a 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr index d13333d2e4825..9e770f07fba2f 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr index 85c781425b16a..a59af3b6a8263 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr index 08f7fb2c73642..ca6f2b1697a8a 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> remapped/errors/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr index d13333d2e4825..9e770f07fba2f 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/fmt/format-args-argument-span.stderr b/tests/ui/fmt/format-args-argument-span.stderr index 4e2702383d6cb..d46cfb438cf6f 100644 --- a/tests/ui/fmt/format-args-argument-span.stderr +++ b/tests/ui/fmt/format-args-argument-span.stderr @@ -12,7 +12,9 @@ error[E0277]: `Option<{integer}>` doesn't implement `std::fmt::Display` --> $DIR/format-args-argument-span.rs:15:37 | LL | println!("{x:?} {x} {x:?}", x = Some(1)); - | ^^^^^^^ `Option<{integer}>` cannot be formatted with the default formatter + | --- ^^^^^^^ `Option<{integer}>` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Option<{integer}>` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -22,7 +24,7 @@ error[E0277]: `DisplayOnly` doesn't implement `Debug` --> $DIR/format-args-argument-span.rs:18:19 | LL | println!("{x} {x:?} {x}"); - | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `DisplayOnly` = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` @@ -37,7 +39,9 @@ error[E0277]: `DisplayOnly` doesn't implement `Debug` --> $DIR/format-args-argument-span.rs:20:35 | LL | println!("{x} {x:?} {x}", x = DisplayOnly); - | ^^^^^^^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | ----- ^^^^^^^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `DisplayOnly` = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index b8d4425a4a71b..5e80f892dcb5b 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied LL | format!("{:X}", "3"); | ---- ^^^ the trait `UpperHex` is not implemented for `str` | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the following other types implement trait `UpperHex`: &T @@ -17,8 +17,6 @@ LL | format!("{:X}", "3"); i32 and 9 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/fmt/non-source-literals.rs b/tests/ui/fmt/non-source-literals.rs new file mode 100644 index 0000000000000..e3ffdb40a6b78 --- /dev/null +++ b/tests/ui/fmt/non-source-literals.rs @@ -0,0 +1,13 @@ +/// Do not point at the format string if it wasn't written in the source. +//@ forbid-output: required by this formatting parameter + +#[derive(Debug)] +pub struct NonDisplay; +pub struct NonDebug; + +fn main() { + let _ = format!(concat!("{", "}"), NonDisplay); //~ ERROR + let _ = format!(concat!("{", "0", "}"), NonDisplay); //~ ERROR + let _ = format!(concat!("{:", "?}"), NonDebug); //~ ERROR + let _ = format!(concat!("{", "0", ":?}"), NonDebug); //~ ERROR +} diff --git a/tests/ui/fmt/non-source-literals.stderr b/tests/ui/fmt/non-source-literals.stderr new file mode 100644 index 0000000000000..5f8a6200dab7d --- /dev/null +++ b/tests/ui/fmt/non-source-literals.stderr @@ -0,0 +1,53 @@ +error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` + --> $DIR/non-source-literals.rs:9:40 + | +LL | let _ = format!(concat!("{", "}"), NonDisplay); + | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` + --> $DIR/non-source-literals.rs:10:45 + | +LL | let _ = format!(concat!("{", "0", "}"), NonDisplay); + | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `NonDebug` doesn't implement `Debug` + --> $DIR/non-source-literals.rs:11:42 + | +LL | let _ = format!(concat!("{:", "?}"), NonDebug); + | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `NonDebug` + = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NonDebug` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | pub struct NonDebug; + | + +error[E0277]: `NonDebug` doesn't implement `Debug` + --> $DIR/non-source-literals.rs:12:47 + | +LL | let _ = format!(concat!("{", "0", ":?}"), NonDebug); + | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `NonDebug` + = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NonDebug` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | pub struct NonDebug; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-associated-types/generic-associated-types-where.stderr b/tests/ui/generic-associated-types/generic-associated-types-where.stderr index 7dce34650d78c..637f86f7bec28 100644 --- a/tests/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/tests/ui/generic-associated-types/generic-associated-types-where.stderr @@ -2,9 +2,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/generic-associated-types-where.rs:18:22 | LL | type Assoc2 = Vec; - | ^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` with trait `Display` | LL | type Assoc2 = Vec; diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index 119195f17ffc8..df89ed9f3b56d 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -2,10 +2,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/doesnt-satisfy.rs:6:17 | LL | fn bar() -> () {} - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::bar::{anon_assoc#0}` --> $DIR/doesnt-satisfy.rs:2:22 | diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr index 634557094ced9..40a029cdc920b 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -39,9 +39,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/wf-bounds.rs:21:26 | LL | fn nya4() -> impl Wf>; - | ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `NeedsDisplay` --> $DIR/wf-bounds.rs:9:24 | diff --git a/tests/ui/issues/issue-59488.stderr b/tests/ui/issues/issue-59488.stderr index ac8862716c070..b6611ad63a810 100644 --- a/tests/ui/issues/issue-59488.stderr +++ b/tests/ui/issues/issue-59488.stderr @@ -87,18 +87,16 @@ error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` | - = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` | - = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index b30bcfb776c8c..736002c9335a3 100644 --- a/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -26,9 +26,8 @@ LL | fn a() -> i32 { | - consider calling this function ... LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn() -> i32 {a}` | - = help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}` = help: use parentheses to call this function: `a()` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr index 7d52b20121e9b..8cb97ea458bcb 100644 --- a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr +++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr @@ -2,7 +2,7 @@ error[E0599]: `*const u8` doesn't implement `std::fmt::Display` --> $DIR/suggest-convert-ptr-to-ref.rs:5:22 | LL | println!("{}", z.to_string()); - | ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter + | ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds | note: the method `to_string` exists on the type `&u8` --> $SRC_DIR/alloc/src/string.rs:LL:COL @@ -11,13 +11,12 @@ note: the method `to_string` exists on the type `&u8` = note: the following trait bounds were not satisfied: `*const u8: std::fmt::Display` which is required by `*const u8: ToString` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: `*mut u8` doesn't implement `std::fmt::Display` --> $DIR/suggest-convert-ptr-to-ref.rs:8:22 | LL | println!("{}", t.to_string()); - | ^^^^^^^^^ `*mut u8` cannot be formatted with the default formatter + | ^^^^^^^^^ method cannot be called on `*mut u8` due to unsatisfied trait bounds | note: the method `to_string` exists on the type `&&mut u8` --> $SRC_DIR/alloc/src/string.rs:LL:COL @@ -26,7 +25,6 @@ note: the method `to_string` exists on the type `&&mut u8` = note: the following trait bounds were not satisfied: `*mut u8: std::fmt::Display` which is required by `*mut u8: ToString` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope --> $DIR/suggest-convert-ptr-to-ref.rs:9:7 diff --git a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr index be3a3e2abf14c..23bc9dc0f844e 100644 --- a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -2,9 +2,8 @@ error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/method-help-unsatisfied-bound.rs:5:7 | LL | a.unwrap(); - | ^^^^^^ `Foo` cannot be formatted using `{:?}` + | ^^^^^^ the trait `Debug` is not implemented for `Foo` | - = help: the trait `Debug` is not implemented for `Foo` = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` note: required by a bound in `Result::::unwrap` --> $SRC_DIR/core/src/result.rs:LL:COL diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 0d203c1aacba4..f0353282d2850 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -2,10 +2,11 @@ error[E0277]: `Dummy` doesn't implement `Debug` --> $DIR/issue-107649.rs:105:5 | 105 | dbg!(lib::Dummy); - | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` + | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` + = note: required for `&Dummy` to implement `Debug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 diff --git a/tests/ui/on-unimplemented/no-debug.stderr b/tests/ui/on-unimplemented/no-debug.stderr index 97d67dbd82e77..5b0b060d40ef5 100644 --- a/tests/ui/on-unimplemented/no-debug.stderr +++ b/tests/ui/on-unimplemented/no-debug.stderr @@ -2,7 +2,9 @@ error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/no-debug.rs:10:27 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Foo` cannot be formatted using `{:?}` + | ---- ^^^ `Foo` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Foo` = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` @@ -17,7 +19,9 @@ error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/no-debug.rs:10:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Bar` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -26,7 +30,9 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:23 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Foo` cannot be formatted with the default formatter + | -- ^^^ `Foo` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Foo` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -36,7 +42,9 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Bar` cannot be formatted with the default formatter + | -- ^^^ `Bar` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Bar` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 7ec018a95cc72..190db04299438 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -2,10 +2,11 @@ error[E0277]: `NotDebug` doesn't implement `Debug` --> $DIR/dbg-macro-requires-debug.rs:6:23 | LL | let _: NotDebug = dbg!(NotDebug); - | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` + | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` + = note: required for `&NotDebug` to implement `Debug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index 90b623e89cffa..31069914daac6 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -2,10 +2,8 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^ `MyError` cannot be formatted with the default formatter + | ^^^^^^^ the trait `std::fmt::Display` is not implemented for `MyError` | - = help: the trait `std::fmt::Display` is not implemented for `MyError` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL @@ -13,9 +11,8 @@ error[E0277]: `MyError` doesn't implement `Debug` --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^ `MyError` cannot be formatted using `{:?}` + | ^^^^^^^ the trait `Debug` is not implemented for `MyError` | - = help: the trait `Debug` is not implemented for `MyError` = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError` note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index f23e086afe4e7..ec1d23fac458b 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -2,7 +2,9 @@ error[E0277]: `impl Sized` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:9:22 | LL | println!("{:?}", t); - | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting opaque type `impl Sized` with trait `Debug` @@ -14,7 +16,9 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:15:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Debug` @@ -26,7 +30,9 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:21:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `T` with trait `Debug` @@ -38,7 +44,9 @@ error[E0277]: `Y` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:27:30 | LL | println!("{:?} {:?}", x, y); - | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` with trait `Debug` @@ -50,7 +58,9 @@ error[E0277]: `X` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:33:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` @@ -62,7 +72,9 @@ error[E0277]: `X` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:39:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index 68c8204d1e18a..b28f39ced542d 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -4,9 +4,8 @@ error[E0277]: `a::Inner` doesn't implement `Debug` LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ `a::Inner` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `a::Inner` | - = help: the trait `Debug` is not implemented for `a::Inner` = note: add `#[derive(Debug)]` to `a::Inner` or manually `impl Debug for a::Inner` help: consider annotating `a::Inner` with `#[derive(Debug)]` | diff --git a/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr b/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr index d0ce7c9ed4e8a..b3f1865dd3097 100644 --- a/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -2,11 +2,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:6:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -22,11 +21,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -42,11 +40,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:22:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -62,11 +59,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:30:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -82,11 +78,10 @@ error[E0277]: `::Item` doesn't impl --> $DIR/impl-trait-with-missing-bounds.rs:37:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -102,11 +97,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:45:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | diff --git a/tests/ui/suggestions/issue-81098.stderr b/tests/ui/suggestions/issue-81098.stderr index 4dc47a2028243..36948469a3112 100644 --- a/tests/ui/suggestions/issue-81098.stderr +++ b/tests/ui/suggestions/issue-81098.stderr @@ -2,23 +2,17 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-81098.rs:3:13 | LL | fn wat() -> impl core::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `()` error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-81098.rs:9:12 | LL | fn ok() -> impl core::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `()` LL | 1; | -- help: remove this semicolon | | | this expression has type `{integer}`, which implements `std::fmt::Display` - | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index ddd143b967c47..1084ea7c9e0e7 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -2,7 +2,10 @@ error[E0277]: `::Item` doesn't implement `std --> $DIR/issue-97760.rs:4:20 | LL | println!("{x}"); - | ^ `::Item` cannot be formatted with the default formatter + | -^- + | || + | |`::Item` cannot be formatted with the default formatter + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr index 3f8b6f93e1f4a..e3375b67c86dd 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr @@ -21,7 +21,7 @@ error[E0277]: `K` doesn't implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^ the trait `Debug` is not implemented for `K` | note: required by a bound in `Vector2` --> $DIR/missing-bound-in-derive-copy-impl-3.rs:5:23 @@ -40,7 +40,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB{ LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider further restricting type parameter `K` with trait `Debug` | @@ -54,7 +54,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2 - | ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider further restricting type parameter `K` with trait `Debug` | diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr index 3766e3e2c7b54..645d6ebb3961f 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr @@ -21,7 +21,7 @@ error[E0277]: `K` doesn't implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl.rs:11:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^ the trait `Debug` is not implemented for `K` | note: required by a bound in `Vector2` --> $DIR/missing-bound-in-derive-copy-impl.rs:4:23 @@ -78,7 +78,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB { LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider restricting type parameter `K` with trait `Debug` | @@ -111,7 +111,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2, - | ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider restricting type parameter `K` with trait `Debug` | diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index 46d0b35825bca..0c7271b3c1c37 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -2,18 +2,23 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it + | -- ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Path` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data + = note: required for `&Path` to implement `std::fmt::Display` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `PathBuf` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:9:20 | LL | println!("{}", path); - | ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it + | -- ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `PathBuf` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/traits/on_unimplemented_long_types.stderr b/tests/ui/traits/on_unimplemented_long_types.stderr index 1628466e0818f..f32d99a42b12b 100644 --- a/tests/ui/traits/on_unimplemented_long_types.stderr +++ b/tests/ui/traits/on_unimplemented_long_types.stderr @@ -2,7 +2,7 @@ error[E0277]: `Option>>` doesn't implement `std::fmt::Display --> $DIR/on_unimplemented_long_types.rs:3:17 | LL | pub fn foo() -> impl std::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^ `Option>>` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound LL | LL | / Some(Some(Some(Some(Some(Some(Some(Some(Some(S... LL | | Some(Some(Some(Some(Some(Some(Some(Some(So... @@ -14,7 +14,6 @@ LL | | ))))))))))) | |_______________- return type was inferred to be `Option>>` here | = help: the trait `std::fmt::Display` is not implemented for `Option>>` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: the full name for the type has been written to '$TEST_BUILD_DIR/on_unimplemented_long_types.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/traits/suggest-remove-deref-issue-140166.stderr b/tests/ui/traits/suggest-remove-deref-issue-140166.stderr index 90f24d86d53e0..7c61f957fdcc6 100644 --- a/tests/ui/traits/suggest-remove-deref-issue-140166.stderr +++ b/tests/ui/traits/suggest-remove-deref-issue-140166.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `&Chars: Trait` is not satisfied LL | format_args!("{:?}", FlatMap(&Chars)); | ---- ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `&Chars` | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the trait `Trait` is implemented for `Chars` note: required for `FlatMap<&Chars>` to implement `Debug` @@ -14,8 +14,6 @@ LL | impl std::fmt::Debug for FlatMap { | ----- ^^^^^^^^^^^^^^^ ^^^^^^^^^^ | | | unsatisfied trait bound introduced here -note: required by a bound in `core::fmt::rt::Argument::<'_>::new_debug` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr index c0f6d6780976a..01d24cabf48df 100644 --- a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr @@ -2,9 +2,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/bounds-are-checked3.rs:9:35 | LL | type Foo = (impl Debug, Struct); - | ^^^^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Struct` --> $DIR/bounds-are-checked3.rs:5:18 | diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index ef0e73f1481f5..193f0c92c9deb 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -2,7 +2,7 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/generic_duplicate_param_use2.rs:12:5 | LL | t - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^ the trait `Debug` is not implemented for `T` | note: required by a bound in an opaque type --> $DIR/generic_duplicate_param_use2.rs:8:23 diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr index 0932c72ff934f..f0d1e93b0b769 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr @@ -2,7 +2,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_duplicate_param_use4.rs:12:5 | LL | u - | ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^ the trait `Debug` is not implemented for `U` | note: required by a bound in an opaque type --> $DIR/generic_duplicate_param_use4.rs:8:23 diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 429c3b9175a59..1e3c454a5bc20 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -2,7 +2,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:9:33 | LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `U` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -18,7 +18,7 @@ error[E0277]: `V` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:19:43 | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `V` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:15:27 @@ -34,7 +34,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:9:33 | LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `U` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -51,7 +51,7 @@ error[E0277]: `V` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:19:43 | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `V` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:15:27 diff --git a/tests/ui/type-alias-impl-trait/nested.stderr b/tests/ui/type-alias-impl-trait/nested.stderr index 59911f65a2346..f72830b864d12 100644 --- a/tests/ui/type-alias-impl-trait/nested.stderr +++ b/tests/ui/type-alias-impl-trait/nested.stderr @@ -15,7 +15,9 @@ error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/nested.rs:17:22 | LL | println!("{:?}", bar()); - | ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Bar` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr index 3e96d7f317b4a..ff34facf3892f 100644 --- a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr +++ b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr @@ -5,7 +5,9 @@ LL | 42; | - help: remove this semicolon ... LL | println!("{}", x); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -18,7 +20,9 @@ LL | let y = {}; | -- this empty block is missing a tail expression ... LL | println!("{}", y); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -31,7 +35,9 @@ LL | "hi"; | - help: remove this semicolon ... LL | println!("{}", z); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -47,7 +53,9 @@ LL | | }; | |_____- this block is missing a tail expression ... LL | println!("{}", s); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr index 78bef726341d6..6b2e27494f0e7 100644 --- a/tests/ui/type/pattern_types/derives_fail.stderr +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -26,9 +26,7 @@ LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default) | ----- in this derive macro expansion LL | #[repr(transparent)] LL | struct Nanoseconds(NanoI32); - | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | - = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999` + | ^^^^^^^ the trait `Debug` is not implemented for `(i32) is 0..=999999999` error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied --> $DIR/derives_fail.rs:11:20 diff --git a/tests/ui/typeck/point-at-type-param-in-path-expr.stderr b/tests/ui/typeck/point-at-type-param-in-path-expr.stderr index 14642b25c9943..3701b3e379882 100644 --- a/tests/ui/typeck/point-at-type-param-in-path-expr.stderr +++ b/tests/ui/typeck/point-at-type-param-in-path-expr.stderr @@ -2,10 +2,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/point-at-type-param-in-path-expr.rs:4:19 | LL | let x = foo::<()>; - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `foo` --> $DIR/point-at-type-param-in-path-expr.rs:1:11 | From 29ce695cd4e148682b0d439cc47dd36edb494673 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:37:29 +0200 Subject: [PATCH 07/13] Stop dbg! macro yapping about format modifiers --- library/std/src/macros.rs | 9 ++++++++- tests/ui/modules/issue-107649.stderr | 6 ++---- .../rfc-2361-dbg-macro/dbg-macro-ref-impl.rs | 17 +++++++++++++++++ .../dbg-macro-requires-debug.rs | 3 +++ .../dbg-macro-requires-debug.stderr | 8 +++----- 5 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index f008d42804c08..25e2b7ea13703 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -363,7 +363,14 @@ macro_rules! dbg { match $val { tmp => { $crate::eprintln!("[{}:{}:{}] {} = {:#?}", - $crate::file!(), $crate::line!(), $crate::column!(), $crate::stringify!($val), &tmp); + $crate::file!(), + $crate::line!(), + $crate::column!(), + $crate::stringify!($val), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&tmp as &dyn $crate::fmt::Debug, + ); tmp } } diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index f0353282d2850..802ac669a10ea 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -2,12 +2,10 @@ error[E0277]: `Dummy` doesn't implement `Debug` --> $DIR/issue-107649.rs:105:5 | 105 | dbg!(lib::Dummy); - | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy` | - = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` - = note: required for `&Dummy` to implement `Debug` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs new file mode 100644 index 0000000000000..c6e38c0758d71 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs @@ -0,0 +1,17 @@ +/// Check that only `&X: Debug` is required, not `X: Debug` +//@check-pass + +use std::fmt::Debug; +use std::fmt::Formatter; + +struct X; + +impl Debug for &X { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str("X") + } +} + +fn main() { + dbg!(X); +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs index f2fb62d76f3d1..fe71f106fdf96 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs @@ -1,4 +1,7 @@ // Test ensuring that `dbg!(expr)` requires the passed type to implement `Debug`. +// +// `dbg!` shouldn't tell the user about format literal syntax; the user didn't write one. +//@ forbid-output: cannot be formatted using struct NotDebug; diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 190db04299438..4e0ae9184150d 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -1,13 +1,11 @@ error[E0277]: `NotDebug` doesn't implement `Debug` - --> $DIR/dbg-macro-requires-debug.rs:6:23 + --> $DIR/dbg-macro-requires-debug.rs:9:23 | LL | let _: NotDebug = dbg!(NotDebug); - | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug` | - = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` - = note: required for `&NotDebug` to implement `Debug` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] From 2ddbe39bfb2fd906ade40d622c0135c3d4bfbad0 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 22 Jun 2025 13:05:09 +0300 Subject: [PATCH 08/13] remove allow(dead_code) leftovers from serial/parallel compiler --- compiler/rustc_data_structures/src/sync/lock.rs | 2 -- compiler/rustc_data_structures/src/sync/parallel.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 2ccf06ccd4f09..a8161c5151156 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -1,8 +1,6 @@ //! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true. //! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits. -#![allow(dead_code)] - use std::fmt; #[derive(Clone, Copy, PartialEq)] diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index ab65c7f3a6b5f..e5778428d4712 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -1,8 +1,6 @@ //! This module defines parallel operations that are implemented in //! one way for the serial compiler, and another way the parallel compiler. -#![allow(dead_code)] - use std::any::Any; use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; From d092dc9381bd6f09017c4b09777df4537999b952 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 22 Jun 2025 13:24:05 +0300 Subject: [PATCH 09/13] remove few from bootstrap too --- src/bootstrap/src/core/build_steps/setup.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 86b7456d7b4e9..9ce81ff9a229f 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -531,7 +531,7 @@ enum EditorKind { impl EditorKind { // Used in `./tests.rs`. - #[allow(dead_code)] + #[cfg(test)] pub const ALL: &[EditorKind] = &[ EditorKind::Emacs, EditorKind::Helix, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 53a5c6b282fb3..dee4f107ca1a0 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -390,7 +390,6 @@ macro_rules! bootstrap_tool { ; )+) => { #[derive(PartialEq, Eq, Clone)] - #[allow(dead_code)] pub enum Tool { $( $name, From fdb76e2296a0dbc4293b85137b75bd62d23f4008 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 19 Jun 2025 21:24:06 +0200 Subject: [PATCH 10/13] Turn a comment that looks like a docstring into a docstring rewrite using let-chains --- compiler/rustc_hir_typeck/src/demand.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5b55fbe91500b..e5684f8cbe669 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1110,27 +1110,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Returns whether the given expression is a destruct assignment desugaring. - // For example, `(a, b) = (1, &2);` - // Here we try to find the pattern binding of the expression, - // `default_binding_modes` is false only for destruct assignment desugaring. + /// Returns whether the given expression is a destruct assignment desugaring. + /// For example, `(a, b) = (1, &2);` + /// Here we try to find the pattern binding of the expression, + /// `default_binding_modes` is false only for destruct assignment desugaring. pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool { if let hir::ExprKind::Path(hir::QPath::Resolved( _, hir::Path { res: hir::def::Res::Local(bind_hir_id), .. }, )) = expr.kind - { - let bind = self.tcx.hir_node(*bind_hir_id); - let parent = self.tcx.parent_hir_node(*bind_hir_id); - if let hir::Node::Pat(hir::Pat { + && let bind = self.tcx.hir_node(*bind_hir_id) + && let parent = self.tcx.parent_hir_node(*bind_hir_id) + && let hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. }) = bind - && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent - { - return true; - } + && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent + { + true + } else { + false } - false } fn explain_self_literal( From b24df424888d9db3a22d6d52f3f516e29d5be21a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 22 Jun 2025 12:09:14 +0200 Subject: [PATCH 11/13] Port `#[must_use]` to new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 7 ++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/must_use.rs | 40 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 + .../src/session_diagnostics.rs | 9 +++++ compiler/rustc_lint/src/unused.rs | 9 +++-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 11 +++-- src/rustdoc-json-types/lib.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 30 ++++++++------ .../src/return_self_not_must_use.rs | 9 ++++- src/tools/clippy/clippy_utils/src/lib.rs | 5 ++- src/tools/clippy/clippy_utils/src/ty/mod.rs | 16 ++++++-- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/ui/attributes/malformed-must_use.rs | 4 ++ tests/ui/attributes/malformed-must_use.stderr | 8 ++++ ...issue-43106-gating-of-builtin-attrs.stderr | 12 +++--- .../lint/unused/unused-attr-duplicate.stderr | 26 ++++++------ tests/ui/parser/bad-lit-suffixes.rs | 1 - tests/ui/parser/bad-lit-suffixes.stderr | 21 ++-------- 20 files changed, 151 insertions(+), 69 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/must_use.rs create mode 100644 tests/ui/attributes/malformed-must_use.rs create mode 100644 tests/ui/attributes/malformed-must_use.stderr diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index f0f5cc4db07df..ce1d808026230 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -237,6 +237,13 @@ pub enum AttributeKind { /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). MayDangle(Span), + /// Represents `#[must_use]`. + MustUse { + span: Span, + /// must_use can optionally have a reason: `#[must_use = "reason this must be used"]` + reason: Option, + }, + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 1bb5edba326c9..3162c1fc72799 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -33,6 +33,7 @@ pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; pub(crate) mod lint_helpers; +pub(crate) mod must_use; pub(crate) mod repr; pub(crate) mod semantics; pub(crate) mod stability; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs new file mode 100644 index 0000000000000..a672d95612746 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -0,0 +1,40 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_errors::DiagArgValue; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::session_diagnostics; + +pub(crate) struct MustUseParser; + +impl SingleAttributeParser for MustUseParser { + const PATH: &[Symbol] = &[sym::must_use]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + Some(AttributeKind::MustUse { + span: cx.attr_span, + reason: match args { + ArgParser::NoArgs => None, + ArgParser::NameValue(name_value) => name_value.value_as_str(), + ArgParser::List(_) => { + let suggestions = + >::TEMPLATE.suggestions(false, "must_use"); + cx.emit_err(session_diagnostics::MustUseIllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + span: cx.attr_span, + }); + return None; + } + }, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b95ea598e72e7..fbe874d606cc9 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,6 +20,7 @@ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; +use crate::attributes::must_use::MustUseParser; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -112,6 +113,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 29f2e44a98a0b..2a020770e5d3c 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -436,6 +436,15 @@ pub(crate) struct IllFormedAttributeInput { pub suggestions: DiagArgValue, } +#[derive(Diagnostic)] +#[diag(attr_parsing_ill_formed_attribute_input)] +pub(crate) struct MustUseIllFormedAttributeInput { + #[primary_span] + pub span: Span, + pub num_suggestions: usize, + pub suggestions: DiagArgValue, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1620f425794f2..a868c887493c9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -2,6 +2,7 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -368,10 +369,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option { - if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { + if let Some(reason) = find_attr!( + cx.tcx.get_all_attrs(def_id), + AttributeKind::MustUse { reason, .. } => reason + ) { // check for #[must_use = "..."] - let reason = attr.value_str(); - Some(MustUsePath::Def(span, def_id, reason)) + Some(MustUsePath::Def(span, def_id, *reason)) } else { None } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index ed1737bee3306..8e6442353c3e9 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -293,6 +293,7 @@ fn emit_malformed_attribute( | sym::deprecated | sym::optimize | sym::cold + | sym::must_use ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d802bf4df19a0..e11ec2ed47ab9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -171,6 +171,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } + Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { + self.check_must_use(hir_id, *span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -245,7 +248,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) @@ -696,7 +698,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. } | AttributeKind::Align { .. } - | AttributeKind::Cold(..), + | AttributeKind::Cold(..) + | AttributeKind::MustUse { .. }, ) => { continue; } @@ -1576,7 +1579,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Warns against some misuses of `#[must_use]` - fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) { if matches!( target, Target::Fn @@ -1616,7 +1619,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::MustUseNoEffect { article, target }, ); } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index c9b4da183a3ae..e5c246cb69c3e 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: improve handling of generic args -pub const FORMAT_VERSION: u32 = 51; +// Latest feature: Pretty printing of must_use attributes changed +pub const FORMAT_VERSION: u32 = 52; /// The root of the emitted JSON blob. /// diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 70655838b6af0..ea9ed4ddade70 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -15,6 +15,9 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_attr_data_structures::AttributeKind; +use rustc_span::Symbol; +use rustc_attr_data_structures::find_attr; use core::ops::ControlFlow; @@ -22,7 +25,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); if let hir::ItemKind::Fn { ref sig, body: ref body_id, @@ -31,8 +34,8 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, @@ -52,9 +55,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() { check_must_use_candidate( cx, @@ -75,9 +78,9 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir_body(eid); if attr.is_none() && is_public && !is_proc_macro(attrs) { @@ -103,7 +106,8 @@ fn check_needless_must_use( item_id: hir::OwnerId, item_span: Span, fn_header_span: Span, - attr: &Attribute, + attr_span: Span, + reason: Option, attrs: &[Attribute], sig: &FnSig<'_>, ) { @@ -119,7 +123,7 @@ fn check_needless_must_use( "this unit-returning function has a `#[must_use]` attribute", |diag| { diag.span_suggestion( - attr.span(), + attr_span, "remove the attribute", "", Applicability::MachineApplicable, @@ -137,11 +141,11 @@ fn check_needless_must_use( MUST_USE_UNIT, fn_header_span, "this unit-returning function has a `#[must_use]` attribute", - Some(attr.span()), + Some(attr_span), "remove `must_use`", ); } - } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 07ae92fa98439..1b304dc57680b 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -6,7 +6,9 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span}; +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::find_attr; declare_clippy_lint! { /// ### What it does @@ -74,7 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa // We only show this warning for public exported methods. && cx.effective_visibilities.is_exported(fn_def) // We don't want to emit this lint if the `#[must_use]` attribute is already there. - && !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)) + && !find_attr!( + cx.tcx.hir_attrs(owner_id.into()), + AttributeKind::MustUse { .. } + ) && cx.tcx.visibility(fn_def.to_def_id()).is_public() && let ret_ty = return_ty(cx, owner_id) && let self_arg = nth_arg(cx, owner_id, 0) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c7a2375c8df7c..913589319fcce 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1886,7 +1886,10 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use)) + did.is_some_and(|did| find_attr!( + cx.tcx.get_all_attrs(did), + AttributeKind::MustUse { ..} + )) } /// Checks if a function's body represents the identity function. Looks for bodies of the form: diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 32a992ccc2d7b..782b079ce0931 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -31,6 +31,8 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::collections::hash_map::Entry; use std::iter; +use rustc_attr_data_structures::find_attr; +use rustc_attr_data_structures::AttributeKind; use crate::path_res; use crate::paths::{PathNS, lookup_path_str}; @@ -326,8 +328,14 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), - ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), + ty::Adt(adt, _) => find_attr!( + cx.tcx.get_all_attrs(adt.did()), + AttributeKind::MustUse { ..} + ), + ty::Foreign(did) => find_attr!( + cx.tcx.get_all_attrs(*did), + AttributeKind::MustUse { ..} + ), ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays @@ -337,7 +345,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) + && find_attr!(cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), AttributeKind::MustUse { ..}) { return true; } @@ -347,7 +355,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Dynamic(binder, _, _) => { for predicate in *binder { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() - && cx.tcx.has_attr(trait_ref.def_id, sym::must_use) + && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { ..}) { return true; } diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 64df8e5f509ff..3ca6f5a75a5a0 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]' #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/ui/attributes/malformed-must_use.rs b/tests/ui/attributes/malformed-must_use.rs new file mode 100644 index 0000000000000..4b98affa8abd3 --- /dev/null +++ b/tests/ui/attributes/malformed-must_use.rs @@ -0,0 +1,4 @@ +#[must_use()] //~ ERROR valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` +struct Test; + +fn main() {} diff --git a/tests/ui/attributes/malformed-must_use.stderr b/tests/ui/attributes/malformed-must_use.stderr new file mode 100644 index 0000000000000..c948ba677444f --- /dev/null +++ b/tests/ui/attributes/malformed-must_use.stderr @@ -0,0 +1,8 @@ +error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` + --> $DIR/malformed-must_use.rs:1:1 + | +LL | #[must_use()] + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 9280dfdf92e5b..d2b1d71ab87c3 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -403,12 +403,6 @@ LL | #![link_section = "1800"] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 - | -LL | #![must_use] - | ^^^^^^^^^^^^ - warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | @@ -417,6 +411,12 @@ LL | #![cold] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[must_use]` has no effect when applied to a module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 + | +LL | #![must_use] + | ^^^^^^^^^^^^ + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 03ce97570144e..6fdd0adf4cff3 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -65,19 +65,6 @@ LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:60:1 - | -LL | #[must_use = "some message"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:59:1 - | -LL | #[must_use] - | ^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: unused attribute --> $DIR/unused-attr-duplicate.rs:66:1 | @@ -264,6 +251,19 @@ note: attribute also specified here LL | #[macro_export] | ^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:60:1 + | +LL | #[must_use = "some message"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:59:1 + | +LL | #[must_use] + | ^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + error: unused attribute --> $DIR/unused-attr-duplicate.rs:74:1 | diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index f29dc53d322b9..4e8edf4d46eab 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -33,7 +33,6 @@ fn f() {} #[must_use = "string"suffix] //~^ ERROR suffixes on string literals are invalid -//~| ERROR malformed `must_use` attribute input fn g() {} #[link(name = "string"suffix)] diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 86ef35bf7833f..416143e496aff 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -22,29 +22,14 @@ error: suffixes on string literals are invalid LL | #[must_use = "string"suffix] | ^^^^^^^^^^^^^^ invalid suffix `suffix` -error: malformed `must_use` attribute input - --> $DIR/bad-lit-suffixes.rs:34:1 - | -LL | #[must_use = "string"suffix] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[must_use = "string"suffix] -LL + #[must_use = "reason"] - | -LL - #[must_use = "string"suffix] -LL + #[must_use] - | - error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:39:15 + --> $DIR/bad-lit-suffixes.rs:38:15 | LL | #[link(name = "string"suffix)] | ^^^^^^^^^^^^^^ invalid suffix `suffix` error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:43:41 + --> $DIR/bad-lit-suffixes.rs:42:41 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^ invalid suffix `suffix` @@ -165,5 +150,5 @@ LL | 1.0e10suffix; | = help: valid suffixes are `f32` and `f64` -error: aborting due to 21 previous errors; 2 warnings emitted +error: aborting due to 20 previous errors; 2 warnings emitted From 75674e2c2a21986ca07507fc98129e5be164e7ca Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Sun, 22 Jun 2025 16:32:54 +0200 Subject: [PATCH 12/13] cranelift: fix target feature name type: "fxsr" --- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 07ea29f3024ef..8e34436fb5e0a 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -184,7 +184,7 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled - vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")] + vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")] } else if sess.target.arch == "aarch64" { match &*sess.target.os { "none" => vec![], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index da69f6c44927b..684b1781b44ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1080,7 +1080,6 @@ symbols! { fs_create_dir, fsub_algebraic, fsub_fast, - fsxr, full, fundamental, fused_iterator, @@ -1088,6 +1087,7 @@ symbols! { future_drop_poll, future_output, future_trait, + fxsr, gdb_script_file, ge, gen_blocks, From 90524da730f3682ec13da52ef8dc2b26a42e0fb0 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sun, 22 Jun 2025 15:18:58 +0000 Subject: [PATCH 13/13] Document why tidy checks if `eslint` is installed via `npm` --- src/tools/tidy/src/rustdoc_js.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs index 2517e2de12ce5..720f0712ee038 100644 --- a/src/tools/tidy/src/rustdoc_js.rs +++ b/src/tools/tidy/src/rustdoc_js.rs @@ -62,6 +62,9 @@ pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &m return; } }; + // Having the correct `eslint` version installed via `npm` isn't strictly necessary, since we're invoking it via `npx`, + // but this check allows the vast majority that is not working on the rustdoc frontend to avoid the penalty of running + // `eslint` in tidy. See also: https://github.com/rust-lang/rust/pull/142851 match get_eslint_version() { Some(version) => { if version != eslint_version {