From 96f2261db1cc7367962a0c82599fe26edd82b414 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 11:46:49 +0100 Subject: [PATCH 01/11] Remove unused `LintContext::lint` method --- compiler/rustc_lint/src/context.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5cd5c95f1ec14..d47f6ec1d7e0e 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -565,13 +565,6 @@ pub trait LintContext { self.opt_span_diag_lint(lint, None as Option, decorator); } - /// Emit a lint at the appropriate level, with no associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) { - self.opt_span_lint(lint, None as Option, decorate); - } - /// This returns the lint level for the given lint at the current location. fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource; From 25c779800409ee5066e0a7cfb6a112a2f737b154 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 12:11:56 +0100 Subject: [PATCH 02/11] Create new `Diagnostic` type for panic calls without literals --- compiler/rustc_lint/src/non_fmt_panic.rs | 105 +++++++++++------- .../const_panic_stability.e2018.stderr | 2 +- .../imports/ambiguous-panic-pick-core.stderr | 2 +- .../imports/ambiguous-panic-pick-std.stderr | 2 +- tests/ui/macros/non-fmt-panic.stderr | 52 ++++----- 5 files changed, 92 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index bb04da96140a6..7f137d5bf0603 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,5 +1,6 @@ use rustc_ast as ast; -use rustc_errors::{Applicability, msg}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, msg}; +use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::{bug, ty}; @@ -85,49 +86,26 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { } } -fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Lit(lit) = &arg.kind { - if let ast::LitKind::Str(sym, _) = lit.node { - // The argument is a string literal. - check_panic_str(cx, f, arg, sym.as_str()); - return; - } - } - - // The argument is *not* a string literal. - - let (span, panic, symbol) = panic_call(cx, f); - - if span.in_external_macro(cx.sess().source_map()) { - // Nothing that can be done about it in the current crate. - return; - } - - // Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the - // case of `panic!(some_macro!())` or `unreachable!(some_macro!())`. - // We don't use source_callsite(), because this `panic!(..)` might itself - // be expanded from another macro, in which case we want to stop at that - // expansion. - let mut arg_span = arg.span; - let mut arg_macro = None; - while !span.contains(arg_span) { - let ctxt = arg_span.ctxt(); - if ctxt.is_root() { - break; - } - let expn = ctxt.outer_expn_data(); - arg_macro = expn.macro_def_id; - arg_span = expn.call_site; - } +struct PanicMessageNotLiteral<'a, 'tcx> { + arg_span: Span, + symbol: Symbol, + span: Span, + arg_macro: Option, + cx: &'a LateContext<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + panic: Option, +} - cx.span_lint(NON_FMT_PANICS, arg_span, |lint| { - lint.primary_message(msg!("panic message is not a string literal")); - lint.arg("name", symbol); - lint.note(msg!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021")); - lint.note(msg!("for more information, see ")); +impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for PanicMessageNotLiteral<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { arg_span, symbol, span, arg_macro, cx, arg, panic } = self; + let mut lint = Diag::new(dcx, level, "panic message is not a string literal") + .with_arg("name", symbol) + .with_note(msg!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021")) + .with_note("for more information, see "); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. - return; + return lint; } if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. @@ -215,7 +193,50 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } } } - }); + lint + } +} + +fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Lit(lit) = &arg.kind { + if let ast::LitKind::Str(sym, _) = lit.node { + // The argument is a string literal. + check_panic_str(cx, f, arg, sym.as_str()); + return; + } + } + + // The argument is *not* a string literal. + + let (span, panic, symbol) = panic_call(cx, f); + + if span.in_external_macro(cx.sess().source_map()) { + // Nothing that can be done about it in the current crate. + return; + } + + // Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the + // case of `panic!(some_macro!())` or `unreachable!(some_macro!())`. + // We don't use source_callsite(), because this `panic!(..)` might itself + // be expanded from another macro, in which case we want to stop at that + // expansion. + let mut arg_span = arg.span; + let mut arg_macro = None; + while !span.contains(arg_span) { + let ctxt = arg_span.ctxt(); + if ctxt.is_root() { + break; + } + let expn = ctxt.outer_expn_data(); + arg_macro = expn.macro_def_id; + arg_span = expn.call_site; + } + + cx.emit_span_lint( + NON_FMT_PANICS, + arg_span, + PanicMessageNotLiteral { arg_span, symbol, span, arg_macro, cx, arg, panic }, + ); } fn check_panic_str<'tcx>( diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr index c33d5b003042e..e8fdfc3d6136e 100644 --- a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr +++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -4,9 +4,9 @@ warning: panic message is not a string literal LL | panic!({ "foo" }); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/imports/ambiguous-panic-pick-core.stderr b/tests/ui/imports/ambiguous-panic-pick-core.stderr index 0a43c83934acc..5c4c881f6bc73 100644 --- a/tests/ui/imports/ambiguous-panic-pick-core.stderr +++ b/tests/ui/imports/ambiguous-panic-pick-core.stderr @@ -24,9 +24,9 @@ warning: panic message is not a string literal LL | panic!(&std::string::String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/imports/ambiguous-panic-pick-std.stderr b/tests/ui/imports/ambiguous-panic-pick-std.stderr index 53e51afe051c2..8938450d1c579 100644 --- a/tests/ui/imports/ambiguous-panic-pick-std.stderr +++ b/tests/ui/imports/ambiguous-panic-pick-std.stderr @@ -24,9 +24,9 @@ warning: panic message is not a string literal LL | panic!(std::string::String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/macros/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr index 9cadaf3fbe388..959fcf6bfcf61 100644 --- a/tests/ui/macros/non-fmt-panic.stderr +++ b/tests/ui/macros/non-fmt-panic.stderr @@ -78,9 +78,9 @@ warning: panic message is not a string literal LL | assert!(false, S); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", S); @@ -92,9 +92,9 @@ warning: panic message is not a string literal LL | assert!(false, 123); | ^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", 123); @@ -106,9 +106,9 @@ warning: panic message is not a string literal LL | assert!(false, Some(123)); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | assert!(false, "{:?}", Some(123)); @@ -133,9 +133,9 @@ warning: panic message is not a string literal LL | panic!(C); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", C); @@ -147,9 +147,9 @@ warning: panic message is not a string literal LL | panic!(S); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", S); @@ -161,9 +161,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); @@ -175,9 +175,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); @@ -189,9 +189,9 @@ warning: panic message is not a string literal LL | std::panic!(123); | ^^^ | - = note: for more information, see = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | std::panic!("{}", 123); @@ -208,9 +208,9 @@ warning: panic message is not a string literal LL | core::panic!(&*"abc"); | ^^^^^^^ | - = note: for more information, see = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | core::panic!("{}", &*"abc"); @@ -222,9 +222,9 @@ warning: panic message is not a string literal LL | panic!(Some(123)); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | panic!("{:?}", Some(123)); @@ -280,9 +280,9 @@ warning: panic message is not a string literal LL | panic!(a!()); | ^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", a!()); @@ -299,9 +299,9 @@ warning: panic message is not a string literal LL | unreachable!(a!()); | ^^^^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", a!()); @@ -313,10 +313,10 @@ warning: panic message is not a string literal LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - panic!(format!("{}", 1)); @@ -329,10 +329,10 @@ warning: panic message is not a string literal LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - unreachable!(format!("{}", 1)); @@ -345,10 +345,10 @@ warning: panic message is not a string literal LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - assert!(false, format!("{}", 1)); @@ -361,10 +361,10 @@ warning: panic message is not a string literal LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - debug_assert!(false, format!("{}", 1)); @@ -377,9 +377,9 @@ warning: panic message is not a string literal LL | panic![123]; | ^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!["{}", 123]; @@ -396,9 +396,9 @@ warning: panic message is not a string literal LL | panic!{123}; | ^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!{"{}", 123}; @@ -415,9 +415,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: use std::panic::panic_any instead | LL - panic!(v); @@ -430,9 +430,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:84:12 @@ -440,9 +440,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | panic!("{:?}", v); @@ -459,9 +459,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | assert!(false, "{:?}", v); @@ -473,9 +473,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); @@ -492,9 +492,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); @@ -506,9 +506,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); @@ -525,9 +525,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); From 9dc456a3662f7885775cab9d2b7b35c2a08760cc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 19:55:51 +0100 Subject: [PATCH 03/11] Remove usage of `LintContext::span_lint` in clippy --- compiler/rustc_errors/src/diagnostic.rs | 1 + compiler/rustc_lint/src/context.rs | 1 + src/tools/clippy/clippy_utils/src/diagnostics.rs | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index cfc697b521fc5..f7fdbfa0cd57e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -106,6 +106,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] + #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>; } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d47f6ec1d7e0e..ad764bf76799f 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -537,6 +537,7 @@ pub trait LintContext { /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`, /// typically generated by `#[derive(Diagnostic)]`). + #[track_caller] fn emit_span_lint>( &self, lint: &'static Lint, diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 81b06ea0c539b..65c962826900d 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan}; +use rustc_errors::{Applicability, Diag, Diagnostic, DiagCtxtHandle, DiagMessage, Level, MultiSpan}; #[cfg(debug_assertions)] use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; use rustc_hir::HirId; @@ -240,15 +240,25 @@ where M: Into, F: FnOnce(&mut Diag<'_, ()>), { + struct ClippyDiag)>(F); + + impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for ClippyDiag { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut lint = Diag::new(dcx, level, ""); + (self.0)(&mut lint); + lint + } + } + #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, sp, |diag| { + cx.emit_span_lint(lint, sp, ClippyDiag(|diag: &mut Diag<'_, ()>| { diag.primary_message(msg); f(diag); docs_link(diag, lint); #[cfg(debug_assertions)] validate_diag(diag); - }); + })); } /// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`. From 1f62cd294290b537d5d0914c248d3a720c92da1a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 12:19:05 +0100 Subject: [PATCH 04/11] Remove unused `LintContext::span_lint` method --- compiler/rustc_lint/src/context.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index ad764bf76799f..d51fa7f276fc5 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -547,19 +547,6 @@ pub trait LintContext { self.opt_span_diag_lint(lint, Some(span), decorator); } - /// Emit a lint at the appropriate level, with an associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - fn span_lint>( - &self, - lint: &'static Lint, - span: S, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - self.opt_span_lint(lint, Some(span), decorate); - } - /// Emit a lint from a lint struct (some type that implements `Diagnostic`, typically /// generated by `#[derive(Diagnostic)]`). fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) { From a0b24e39b9c240891674513191debc1a7d60ffae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 12:23:20 +0100 Subject: [PATCH 05/11] Remove unused `LintContext::opt_span_lint` method --- compiler/rustc_lint/src/context.rs | 38 +----------------------------- compiler/rustc_lint/src/levels.rs | 15 +----------- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d51fa7f276fc5..98f087892a398 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Diag, Diagnostic, LintBuffer, MultiSpan}; +use rustc_errors::{Diagnostic, LintBuffer, MultiSpan}; use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -509,19 +509,6 @@ pub struct EarlyContext<'a> { pub trait LintContext { fn sess(&self) -> &Session; - // FIXME: These methods should not take an Into -- instead, callers should need to - // set the span in their `decorate` function (preferably using set_span). - /// Emit a lint at the appropriate level, with an optional associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ); - // FIXME: These methods should not take an Into -- instead, callers should need to // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. @@ -606,20 +593,6 @@ impl<'tcx> LintContext for LateContext<'tcx> { self.tcx.sess } - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let hir_id = self.last_node_with_lint_attrs; - - match span { - Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate), - None => self.tcx.node_lint(lint, hir_id, decorate), - } - } - fn opt_span_diag_lint>( &self, lint: &'static Lint, @@ -645,15 +618,6 @@ impl LintContext for EarlyContext<'_> { self.builder.sess() } - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate) - } - fn opt_span_diag_lint>( &self, lint: &'static Lint, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a134b623d7bd4..1dd59e5d6d7cb 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,7 +2,7 @@ use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Diag, Diagnostic, MultiSpan, msg}; +use rustc_errors::{Diagnostic, MultiSpan, msg}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; @@ -974,19 +974,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.provider.get_lint_level(lint, self.sess) } - /// Used to emit a lint-related diagnostic based on the current state of - /// this lint context. - #[track_caller] - pub(crate) fn opt_span_lint( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let level = self.lint_level(lint); - lint_level(self.sess, lint, level, span, decorate) - } - /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. #[track_caller] From 6e47be7ad96b784fd351eb925022e2a53f3b6e07 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 12:38:41 +0100 Subject: [PATCH 06/11] Remove last use of `rustc_middle::lint_level` function in `rustc_lint` --- compiler/rustc_lint/src/levels.rs | 47 +++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 1dd59e5d6d7cb..8b7a8c9ed5d87 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,7 +2,7 @@ use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Diagnostic, MultiSpan, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; @@ -11,7 +11,7 @@ use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, diag_lint_level, - lint_level, reveal_actual_level, + reveal_actual_level, }; use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -948,22 +948,45 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { return true; }; - if self.lint_added_lints { - let lint = builtin::UNKNOWN_LINTS; - let level = self.lint_level(builtin::UNKNOWN_LINTS); - lint_level(self.sess, lint, level, Some(span.into()), |lint| { - lint.primary_message(msg!("unknown lint: `{$name}`")); - lint.arg("name", lint_id.lint.name_lower()); - lint.note(msg!("the `{$name}` lint is unstable")); + struct UnknownLint<'a> { + sess: &'a Session, + lint_id: LintId, + feature: Symbol, + lint_from_cli: bool, + } + + impl<'a, 'b> Diagnostic<'a, ()> for UnknownLint<'b> { + fn into_diag( + self, + dcx: DiagCtxtHandle<'a>, + level: rustc_errors::Level, + ) -> Diag<'a, ()> { + let Self { sess, lint_id, feature, lint_from_cli } = self; + let mut lint = Diag::new(dcx, level, msg!("unknown lint: `{$name}`")) + .with_arg("name", lint_id.lint.name_lower()) + .with_note(msg!("the `{$name}` lint is unstable")); rustc_session::parse::add_feature_diagnostics_for_issue( - lint, - &self.sess, + &mut lint, + sess, feature, GateIssue::Language, lint_from_cli, None, ); - }); + lint + } + } + + if self.lint_added_lints { + let lint = builtin::UNKNOWN_LINTS; + let level = self.lint_level(builtin::UNKNOWN_LINTS); + diag_lint_level( + self.sess, + lint, + level, + Some(span.into()), + UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli }, + ); } false From 140ad033e76c31fb138a49e1324832f1714509a6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 12:49:20 +0100 Subject: [PATCH 07/11] Remove `TyCtxt::node_span_lint` usage from `rustc_codegen_ssa` --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 1ceb01337b118..b8a8bb3ad419d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -5,6 +5,7 @@ use rustc_hir::attrs::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{self as hir, Attribute, find_attr}; +use rustc_macros::Diagnostic; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs, }; @@ -385,6 +386,17 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code } } +#[derive(Diagnostic)] +#[diag("non-default `sanitize` will have no effect after inlining")] +struct SanitizeOnInline { + #[note("inlining requested here")] + inline_span: Span, +} + +#[derive(Diagnostic)] +#[diag("the async executor can run blocking code, without realtime sanitizer catching it")] +struct AsyncBlocking; + fn check_result( tcx: TyCtxt<'_>, did: LocalDefId, @@ -425,10 +437,12 @@ fn check_result( (interesting_spans.sanitize, interesting_spans.inline) { let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| { - lint.primary_message("non-default `sanitize` will have no effect after inlining"); - lint.span_note(inline_span, "inlining requested here"); - }) + tcx.emit_node_span_lint( + lint::builtin::INLINE_NO_SANITIZE, + hir_id, + sanitize_span, + SanitizeOnInline { inline_span }, + ) } // warn for nonblocking async functions, blocks and closures. @@ -445,13 +459,11 @@ fn check_result( != rustc_hir::ClosureKind::Closure)) { let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::RTSAN_NONBLOCKING_ASYNC, hir_id, sanitize_span, - |lint| { - lint.primary_message(r#"the async executor can run blocking code, without realtime sanitizer catching it"#); - } + AsyncBlocking, ); } From e1ee66935e0f1b7606e5d1dfa850cf730fd85000 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 16:22:25 +0100 Subject: [PATCH 08/11] Remove `TyCtxt::node_span_lint` usage from `rustc_hir_analysis` --- .../rustc_hir_analysis/src/check/check.rs | 99 ++++++++++++------- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check_unused.rs | 31 ++++-- compiler/rustc_hir_analysis/src/collect.rs | 25 +++-- .../src/collect/generics_of.rs | 18 +++- .../src/hir_ty_lowering/dyn_trait.rs | 46 ++++++--- .../src/hir_ty_lowering/generics.rs | 22 ++++- .../src/hir_ty_lowering/mod.rs | 91 ++++++++++++----- tests/ui/abi/unsupported.aarch64.stderr | 8 +- tests/ui/abi/unsupported.arm.stderr | 8 +- tests/ui/abi/unsupported.riscv32.stderr | 8 +- tests/ui/abi/unsupported.riscv64.stderr | 8 +- tests/ui/abi/unsupported.x64.stderr | 8 +- tests/ui/abi/unsupported.x64_win.stderr | 18 ++-- .../repr-c-big-discriminant1.ptr64.stderr | 20 ++-- .../repr-c-big-discriminant2.ptr64.stderr | 4 +- .../raw-dylib/windows/unsupported-abi.stderr | 2 +- .../future-incompatible-lint-group.stderr | 4 +- .../lint/improper-ctypes/lint-ctypes.stderr | 2 +- tests/ui/lint/improper-ctypes/lint-fn.stderr | 2 +- .../repr-transparent-non-exhaustive.stderr | 68 ++++++------- tests/ui/repr/repr-transparent-repr-c.stderr | 12 +-- tests/ui/statics/uninhabited-static.stderr | 8 +- ...ity-lint-ambiguous_associated_items.stderr | 4 +- 24 files changed, 329 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 94988f3c92750..f3d234afef05e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::{ExternAbi, FieldIdx, ScalableElt}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; -use rustc_errors::{EmissionGuarantee, MultiSpan}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan}; use rustc_hir as hir; use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::def::{CtorKind, DefKind}; @@ -12,6 +12,7 @@ use rustc_hir::{LangItem, Node, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS}; +use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; @@ -53,6 +54,22 @@ fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, T } pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { + struct UnsupportedCallingConventions { + abi: ExternAbi, + } + + impl<'a> Diagnostic<'a, ()> for UnsupportedCallingConventions { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { abi } = self; + let mut lint = Diag::new( + dcx, + level, + format!("{abi} is not a supported ABI for the current target"), + ); + add_abi_diag_help(abi, &mut lint); + lint + } + } // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this // currently only guards function imports, function definitions, and function pointer types. // Functions in trait declarations can still use "deprecated" ABIs without any warning. @@ -64,12 +81,12 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering")); } AbiMapping::Deprecated(..) => { - tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message(format!( - "{abi} is not a supported ABI for the current target" - )); - add_abi_diag_help(abi, lint); - }); + tcx.emit_node_span_lint( + UNSUPPORTED_CALLING_CONVENTIONS, + hir_id, + span, + UnsupportedCallingConventions { abi }, + ); } } } @@ -174,6 +191,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b /// Check that a `static` is inhabited. fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { + #[derive(Diagnostic)] + #[diag("static of uninhabited type")] + #[note("uninhabited statics cannot be initialized, and any access would be an immediate error")] + struct StaticOfUninhabitedType; + // Make sure statics are inhabited. // Other parts of the compiler assume that there are no uninhabited places. In principle it // would be enough to check this for `extern` statics, as statics with an initializer will @@ -204,15 +226,11 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { } }; if layout.is_uninhabited() { - tcx.node_span_lint( + tcx.emit_node_span_lint( UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), span, - |lint| { - lint.primary_message("static of uninhabited type"); - lint - .note("uninhabited statics cannot be initialized, and any access would be an immediate error"); - }, + StaticOfUninhabitedType, ); } } @@ -1637,6 +1655,39 @@ pub(super) fn check_packed_inner( } pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { + struct ZeroSizedFieldReprTransparentIncompatibility<'tcx> { + unsuited: UnsuitedInfo<'tcx>, + } + + impl<'a, 'tcx> Diagnostic<'a, ()> for ZeroSizedFieldReprTransparentIncompatibility<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { unsuited } = self; + let (title, note) = match unsuited.reason { + UnsuitedReason::NonExhaustive => ( + "external non-exhaustive types", + "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.", + ), + UnsuitedReason::PrivateField => ( + "external types with private fields", + "contains private fields, so it could become non-zero-sized in the future.", + ), + UnsuitedReason::ReprC => ( + "`repr(C)` types", + "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", + ), + }; + Diag::new( + dcx, + level, + format!("zero-sized fields in `repr(transparent)` cannot contain {title}"), + ) + .with_note(format!( + "this field contains `{field_ty}`, which {note}", + field_ty = unsuited.ty, + )) + } + } + if !adt.repr().transparent() { return; } @@ -1747,29 +1798,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. if non_trivial_count > 0 || prev_unsuited_1zst { - tcx.node_span_lint( + tcx.emit_node_span_lint( REPR_TRANSPARENT_NON_ZST_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), field.span, - |lint| { - let title = match unsuited.reason { - UnsuitedReason::NonExhaustive => "external non-exhaustive types", - UnsuitedReason::PrivateField => "external types with private fields", - UnsuitedReason::ReprC => "`repr(C)` types", - }; - lint.primary_message( - format!("zero-sized fields in `repr(transparent)` cannot contain {title}"), - ); - let note = match unsuited.reason { - UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.", - UnsuitedReason::PrivateField => "contains private fields, so it could become non-zero-sized in the future.", - UnsuitedReason::ReprC => "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", - }; - lint.note(format!( - "this field contains `{field_ty}`, which {note}", - field_ty = unsuited.ty, - )); - }, + ZeroSizedFieldReprTransparentIncompatibility { unsuited }, ); } else { prev_unsuited_1zst = true; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 61e6133306066..458bb6ddd2117 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -77,7 +77,7 @@ use std::num::NonZero; pub use check::{check_abi, check_custom_abi}; use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 3fb33c741c9dc..7302913cc1ae7 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -1,10 +1,28 @@ use rustc_data_structures::unord::{ExtendUnord, UnordSet}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; use rustc_session::lint; +use rustc_span::Span; use tracing::debug; +struct UnusedImport<'tcx> { + tcx: TyCtxt<'tcx>, + span: Span, +} + +impl<'a, 'tcx> Diagnostic<'a, ()> for UnusedImport<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { tcx, span } = self; + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + Diag::new(dcx, level, format!("unused import: `{snippet}`")) + } else { + Diag::new(dcx, level, "unused import") + } + } +} + pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { let mut used_trait_imports = UnordSet::::default(); @@ -31,12 +49,11 @@ pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { continue; } let (path, _) = item.expect_use(); - tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { - lint.primary_message(format!("unused import: `{snippet}`")); - } else { - lint.primary_message("unused import"); - } - }); + tcx.emit_node_span_lint( + lint::builtin::UNUSED_IMPORTS, + item.hir_id(), + path.span, + UnusedImport { tcx, span: path.span }, + ); } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f4c7234cd8f83..6850e67aff1a7 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -22,7 +22,9 @@ use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, E0228, ErrorGuaranteed, Level, StashKey, +}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; @@ -610,6 +612,19 @@ pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { } pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) { + struct ReprCIssue { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for ReprCIssue { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + .with_note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C") + .with_help("use `repr($int_ty)` instead to explicitly set the size of this enum") + } + } + let def = tcx.adt_def(def_id); let repr_type = def.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); @@ -659,15 +674,11 @@ pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) { } else { "`repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`" }; - tcx.node_span_lint( + tcx.emit_node_span_lint( rustc_session::lint::builtin::REPR_C_ENUMS_LARGER_THAN_INT, tcx.local_def_id_to_hir_id(def_id), span, - |d| { - d.primary_message(msg) - .note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C") - .help("use `repr($int_ty)` instead to explicitly set the size of this enum"); - } + ReprCIssue { msg }, ); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index b4c264c3a2364..e1ec57aea9217 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,6 +1,7 @@ use std::ops::ControlFlow; use rustc_data_structures::assert_matches; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; @@ -17,6 +18,17 @@ use crate::middle::resolve_bound_vars as rbv; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; + struct GenericParametersForbiddenHere { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for GenericParametersForbiddenHere { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + } + } + // For an RPITIT, synthesize generics which are equal to the opaque's generics // and parent fn's generics compressed into one list. if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = @@ -269,13 +281,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { match param_default_policy.expect("no policy for generic param default") { ParamDefaultPolicy::Allowed => {} ParamDefaultPolicy::FutureCompatForbidden => { - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, - |lint| { - lint.primary_message(MESSAGE); - }, + GenericParametersForbiddenHere { msg: MESSAGE }, ); } ParamDefaultPolicy::Forbidden => { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 7b8e09943df71..8397ff61a3b3c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -2,11 +2,12 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey, + Suggestions, struct_span_code_err, }; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, HirId, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ @@ -523,6 +524,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: hir::HirId, hir_bounds: &[hir::PolyTraitRef<'tcx>], ) -> Option { + struct TraitObjectWithoutDyn<'a, 'tcx> { + span: Span, + hir_id: HirId, + sugg: Vec<(Span, String)>, + this: &'a dyn HirTyLowerer<'tcx>, + } + + impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for TraitObjectWithoutDyn<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { span, hir_id, sugg, this } = self; + let mut lint = + Diag::new(dcx, level, "trait objects without an explicit `dyn` are deprecated"); + if span.can_be_used_for_suggestions() { + lint.multipart_suggestion( + "if this is a dyn-compatible trait, use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + } + this.maybe_suggest_blanket_trait_impl(span, hir_id, &mut lint); + lint + } + } + let tcx = self.tcx(); let [poly_trait_ref, ..] = hir_bounds else { return None }; @@ -606,17 +631,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(diag.emit()) } else { - tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| { - lint.primary_message("trait objects without an explicit `dyn` are deprecated"); - if span.can_be_used_for_suggestions() { - lint.multipart_suggestion( - "if this is a dyn-compatible trait, use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - } - self.maybe_suggest_blanket_trait_impl(span, hir_id, lint); - }); + tcx.emit_node_span_lint( + BARE_TRAIT_OBJECTS, + hir_id, + span, + TraitObjectWithoutDyn { span, hir_id, sugg, this: self }, + ); None } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index ff0a5a8df0faf..0ca57cb50cf25 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -1,6 +1,9 @@ use rustc_ast::ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, + struct_span_code_err, +}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; @@ -625,6 +628,17 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( args: &hir::GenericArgs<'_>, position: GenericArgPosition, ) -> ExplicitLateBound { + struct LifetimeArgsIssue { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for LifetimeArgsIssue { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + } + } + let param_counts = def.own_counts(); if let Some(span_late) = def.has_late_bound_regions @@ -644,13 +658,11 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); - cx.tcx().node_span_lint( + cx.tcx().emit_node_span_lint( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, - |lint| { - lint.primary_message(msg); - }, + LifetimeArgsIssue { msg }, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 25911d3e9e462..3a41ef47ac526 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -27,7 +27,8 @@ use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -1481,6 +1482,54 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, mode: LowerTypeRelativePathMode, ) -> Result, ErrorGuaranteed> { + struct AmbiguousAssocItem<'tcx> { + variant_def_id: DefId, + item_def_id: DefId, + span: Span, + segment_ident: Ident, + bound_def_id: DefId, + self_ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, + mode: LowerTypeRelativePathMode, + } + + impl<'a, 'tcx> Diagnostic<'a, ()> for AmbiguousAssocItem<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { + variant_def_id, + item_def_id, + span, + segment_ident, + bound_def_id, + self_ty, + tcx, + mode, + } = self; + let mut lint = Diag::new(dcx, level, "ambiguous associated item"); + + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + segment_ident, + also, + tcx.def_kind_descr(kind, def_id) + ); + lint.span_note(tcx.def_span(def_id), note_msg); + }; + + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also"); + + lint.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", self_ty, tcx.item_name(bound_def_id), segment_ident), + Applicability::MachineApplicable, + ); + lint + } + } + debug!(%self_ty, ?segment.ident); let tcx = self.tcx(); @@ -1556,33 +1605,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?; if let Some(variant_def_id) = variant_def_id { - tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| { - lint.primary_message("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - segment.ident, - also, - tcx.def_kind_descr(kind, def_id) - ); - lint.span_note(tcx.def_span(def_id), note_msg); - }; - - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also"); - - lint.span_suggestion( + tcx.emit_node_span_lint( + AMBIGUOUS_ASSOCIATED_ITEMS, + qpath_hir_id, + span, + AmbiguousAssocItem { + variant_def_id, + item_def_id, span, - "use fully-qualified syntax", - format!( - "<{} as {}>::{}", - self_ty, - tcx.item_name(bound.def_id()), - segment.ident - ), - Applicability::MachineApplicable, - ); - }); + segment_ident: segment.ident, + bound_def_id: bound.def_id(), + self_ty, + tcx, + mode, + }, + ); } Ok(TypeRelativePath::AssocItem(item_def_id, args)) diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 00cc31170b74f..6add008aa60fa 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -162,9 +162,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -173,9 +173,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -183,9 +183,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -193,9 +193,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 25 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 23bdcc2272950..ab345f9e42e96 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -144,9 +144,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -155,9 +155,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -165,9 +165,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -175,9 +175,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 22 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index ef1f1b53cdc56..e2ca35d6a50e2 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -156,9 +156,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -177,9 +177,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 24 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index ef1f1b53cdc56..e2ca35d6a50e2 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -156,9 +156,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -177,9 +177,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 24 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 0c338849ae9d8..41842eecbd020 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -138,9 +138,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -149,9 +149,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -159,9 +159,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -169,9 +169,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 21 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 07c4eb691fe97..79938f04c5996 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -106,9 +106,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "stdcall" is not a supported ABI for the current target @@ -117,9 +117,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "stdcall-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:92:1 @@ -127,9 +127,9 @@ warning: "stdcall-unwind" is not a supported ABI for the current target LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:100:17 @@ -137,9 +137,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:105:1 @@ -147,9 +147,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -157,9 +157,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:137:1 @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "stdcall" is not a supported ABI for the current target --> $DIR/unsupported.rs:78:1 @@ -177,9 +177,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 17 previous errors; 9 warnings emitted diff --git a/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr b/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr index e2517ab342f45..2b8326018bc93 100644 --- a/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr +++ b/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr @@ -4,10 +4,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = 9223372036854775807, // i64::MAX | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 note: the lint level is defined here --> $DIR/repr-c-big-discriminant1.rs:8:9 | @@ -20,10 +20,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = -2147483649, // i32::MIN-1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `unsigned int`, and a previous discriminant does not fit into C `int` --> $DIR/repr-c-big-discriminant1.rs:36:5 @@ -31,10 +31,10 @@ error: `repr(C)` enum discriminant does not fit into C `unsigned int`, and a pre LL | B = -1, | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int` --> $DIR/repr-c-big-discriminant1.rs:43:5 @@ -42,10 +42,10 @@ error: `repr(C)` enum discriminant does not fit into C `int`, and a previous dis LL | A = 2147483648, // i32::MAX+1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int` --> $DIR/repr-c-big-discriminant1.rs:53:5 @@ -53,10 +53,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = I64_MAX as isize, | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: aborting due to 5 previous errors diff --git a/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr b/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr index 8cd978ccb2fb1..ebf14059b314d 100644 --- a/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr +++ b/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr @@ -4,10 +4,10 @@ error: `repr(C)` enum discriminant does not fit into C `int`, and a previous dis LL | B, // +1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 note: the lint level is defined here --> $DIR/repr-c-big-discriminant2.rs:8:9 | diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index 5a574636245d3..9d945eb23491c 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr @@ -9,9 +9,9 @@ LL | | LL | | } | |_^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index ff1e54f5dea30..8f234c6216065 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -14,8 +14,6 @@ error: ambiguous associated item LL | fn foo() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57644 note: `V` could refer to the variant defined here --> $DIR/future-incompatible-lint-group.rs:8:10 | @@ -26,6 +24,8 @@ note: `V` could also refer to the associated type defined here | LL | type V; | ^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57644 note: the lint level is defined here --> $DIR/future-incompatible-lint-group.rs:6:9 | diff --git a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr index ef23f3ca6c919..82eacf901d25d 100644 --- a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr +++ b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr @@ -218,7 +218,7 @@ warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct TransparentCustomZst(i32, ZeroSize); | ^^^^^^^^ | + = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. diff --git a/tests/ui/lint/improper-ctypes/lint-fn.stderr b/tests/ui/lint/improper-ctypes/lint-fn.stderr index a0d1ab232c6ad..45681cc9f1122 100644 --- a/tests/ui/lint/improper-ctypes/lint-fn.stderr +++ b/tests/ui/lint/improper-ctypes/lint-fn.stderr @@ -169,7 +169,7 @@ warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct TransparentCustomZst(i32, ZeroSize); | ^^^^^^^^ | + = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr index ac5493bf7e59c..0a575e5f5829d 100644 --- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr +++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr @@ -4,9 +4,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T5(Sized, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -19,9 +19,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:54:23 @@ -29,9 +29,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` | ^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:59:22 @@ -39,9 +39,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T7(Sized, NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:64:22 @@ -49,9 +49,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T8(Sized, NonExhaustiveVariant); | ^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:69:22 @@ -59,9 +59,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:74:23 @@ -69,9 +69,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T10(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:79:23 @@ -79,9 +79,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T11(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:84:23 @@ -89,9 +89,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T12(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:89:23 @@ -99,9 +99,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T13(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:94:23 @@ -109,9 +109,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:99:23 @@ -119,9 +119,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T15(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:104:23 @@ -129,9 +129,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T16(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:109:16 @@ -139,9 +139,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T17(NonExhaustive, Sized); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:114:31 @@ -149,9 +149,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T18(NonExhaustive, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:119:31 @@ -159,9 +159,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T19(NonExhaustive, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:124:32 @@ -169,9 +169,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T19Flipped(Private, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: aborting due to 17 previous errors @@ -182,9 +182,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T5(Sized, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -198,9 +198,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -214,9 +214,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` | ^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -230,9 +230,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T7(Sized, NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -246,9 +246,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T8(Sized, NonExhaustiveVariant); | ^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -262,9 +262,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -278,9 +278,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T10(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -294,9 +294,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T11(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -310,9 +310,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T12(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -326,9 +326,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T13(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -342,9 +342,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -358,9 +358,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T15(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -374,9 +374,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T16(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -390,9 +390,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T17(NonExhaustive, Sized); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -406,9 +406,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T18(NonExhaustive, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -422,9 +422,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T19(NonExhaustive, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -438,9 +438,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T19Flipped(Private, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | diff --git a/tests/ui/repr/repr-transparent-repr-c.stderr b/tests/ui/repr/repr-transparent-repr-c.stderr index 5724845afdc1e..2a670fed80704 100644 --- a/tests/ui/repr/repr-transparent-repr-c.stderr +++ b/tests/ui/repr/repr-transparent-repr-c.stderr @@ -4,9 +4,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T5(Sized, ReprC1Zst); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -19,9 +19,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T6(ReprC1Zst, Sized); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types --> $DIR/repr-transparent-repr-c.rs:28:15 @@ -29,9 +29,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type | ^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. error: aborting due to 3 previous errors @@ -42,9 +42,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T5(Sized, ReprC1Zst); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -58,9 +58,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T6(ReprC1Zst, Sized); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -74,9 +74,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type | ^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index a0f9ad6772de5..4762784574dc7 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -4,9 +4,9 @@ error: static of uninhabited type LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error note: the lint level is defined here --> $DIR/uninhabited-static.rs:2:9 | @@ -19,9 +19,9 @@ error: static of uninhabited type LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type --> $DIR/uninhabited-static.rs:6:5 @@ -29,9 +29,9 @@ error: static of uninhabited type LL | static VOID: Void; | ^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type --> $DIR/uninhabited-static.rs:8:5 @@ -39,9 +39,9 @@ error: static of uninhabited type LL | static NEVER: !; | ^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:12:31 diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr index 79bd1f2adc17b..918d05b5d6781 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr @@ -4,8 +4,6 @@ error: ambiguous associated item LL | fn f() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57644 note: `V` could refer to the variant defined here --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5 | @@ -16,6 +14,8 @@ note: `V` could also refer to the associated type defined here | LL | type V; | ^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57644 = note: `#[deny(ambiguous_associated_items)]` (part of `#[deny(future_incompatible)]`) on by default error: aborting due to 1 previous error From c98094bd32e70f8a6f583262217f273b9e90a4c1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 Mar 2026 18:34:49 +0100 Subject: [PATCH 09/11] Remove `TyCtxt::node_span_lint` usage from `rustc_hir_typeck` --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 38 +- compiler/rustc_hir_typeck/src/inline_asm.rs | 55 ++- .../src/method/prelude_edition_lints.rs | 432 ++++++++++-------- compiler/rustc_hir_typeck/src/method/probe.rs | 110 +++-- compiler/rustc_hir_typeck/src/pat.rs | 40 +- compiler/rustc_hir_typeck/src/upvar.rs | 321 +++++++------ tests/ui/inference/inference_unstable.stderr | 8 +- tests/ui/resolve/slice-as-slice.stderr | 2 +- 8 files changed, 614 insertions(+), 392 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d2152b763a8e2..c24d1127d5a62 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -3,7 +3,9 @@ use std::slice; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, +}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; @@ -80,6 +82,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { + struct UnreachableItem<'a, 'b> { + kind: &'a str, + span: Span, + orig_span: Span, + custom_note: Option<&'b str>, + } + + impl<'a, 'b, 'c> Diagnostic<'a, ()> for UnreachableItem<'b, 'c> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { kind, span, orig_span, custom_note } = self; + let msg = format!("unreachable {kind}"); + Diag::new(dcx, level, msg.clone()).with_span_label(span, msg).with_span_label( + orig_span, + custom_note.map(|c| c.to_owned()).unwrap_or_else(|| { + "any code following this expression is unreachable".to_owned() + }), + ) + } + } + let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else { return; }; @@ -102,14 +124,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - let msg = format!("unreachable {kind}"); - self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - lint.primary_message(msg.clone()); - lint.span_label(span, msg).span_label( - orig_span, - custom_note.unwrap_or("any code following this expression is unreachable"), - ); - }) + self.tcx().emit_node_span_lint( + lint::builtin::UNREACHABLE_CODE, + id, + span, + UnreachableItem { kind, span, orig_span, custom_note }, + ); } /// Resolves type and const variables in `t` if possible. Unlike the infcx diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 7c1655f8201d7..f2b746ac96b10 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -1,6 +1,7 @@ use rustc_abi::FieldIdx; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; @@ -168,6 +169,40 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { is_input: bool, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option)>, ) -> Option { + struct FormattingSubRegisterArg<'a> { + expr_span: Span, + idx: usize, + suggested_modifier: char, + suggested_result: &'a str, + suggested_size: u16, + default_modifier: char, + default_result: &'a str, + default_size: u16, + } + + impl<'a, 'b> Diagnostic<'a, ()> for FormattingSubRegisterArg<'b> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { + expr_span, + idx, + suggested_modifier, + suggested_result, + suggested_size, + default_modifier, + default_result, + default_size, + } = self; + Diag::new(dcx, level, "formatting may not be suitable for sub-register argument") + .with_span_label(expr_span, "for this argument") + .with_help(format!( + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", + )) + .with_help(format!( + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", + )) + } + } + let ty = self.expr_ty(expr); if ty.has_non_region_infer() { bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); @@ -362,19 +397,19 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { result: default_result, size: default_size, } = reg_class.default_modifier(asm_arch).unwrap(); - self.tcx().node_span_lint( + self.tcx().emit_node_span_lint( lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, - |lint| { - lint.primary_message("formatting may not be suitable for sub-register argument"); - lint.span_label(expr.span, "for this argument"); - lint.help(format!( - "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", - )); - lint.help(format!( - "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", - )); + FormattingSubRegisterArg { + expr_span: expr.span, + idx, + suggested_modifier, + suggested_result, + suggested_size, + default_modifier, + default_result, + default_size, }, ); } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 38413cca633c9..d846f4433dc70 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -3,19 +3,157 @@ use std::fmt::Write; use hir::def_id::DefId; use hir::{HirId, ItemKind}; use rustc_ast::join_path_idents; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir as hir; use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; -use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, kw, sym}; +use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, Symbol, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::FnCtxt; use crate::method::probe::{self, Pick}; +struct AmbiguousTraitMethodCall<'a, 'b, 'tcx> { + segment_name: Symbol, + self_expr_span: Span, + pick: &'a Pick<'tcx>, + tcx: TyCtxt<'tcx>, + edition: &'b str, +} + +impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitMethodCall<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { segment_name, self_expr_span, pick, tcx, edition } = self; + let mut lint = Diag::new( + dcx, + level, + format!("trait method `{}` will become ambiguous in Rust {edition}", segment_name), + ); + let derefs = "*".repeat(pick.autoderefs); + + let autoref = match pick.autoref_or_ptr_adjustment { + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), + Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, + }; + if let Ok(self_expr) = tcx.sess.source_map().span_to_snippet(self_expr_span) { + let mut self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}{self_expr} as *const _") + } else { + format!("{autoref}{derefs}{self_expr}") + }; + + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = + pick.autoref_or_ptr_adjustment + { + self_adjusted.push('>'); + } + + lint.span_suggestion( + self_expr_span, + "disambiguate the method call", + format!("({self_adjusted})"), + Applicability::MachineApplicable, + ); + } else { + let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}(...) as *const _") + } else { + format!("{autoref}{derefs}...") + }; + lint.span_help( + self_expr_span, + format!("disambiguate the method call with `({self_adjusted})`",), + ); + } + lint + } +} + +struct AmbiguousTraitMethod<'a, 'b, 'tcx, 'pcx, 'fnctx> { + segment: &'a hir::PathSegment<'pcx>, + call_expr: &'tcx hir::Expr<'tcx>, + self_expr: &'tcx hir::Expr<'tcx>, + pick: &'a Pick<'tcx>, + args: &'tcx [hir::Expr<'tcx>], + edition: &'b str, + span: Span, + this: &'a FnCtxt<'fnctx, 'tcx>, +} + +impl<'a, 'b, 'c, 'tcx, 'pcx, 'fnctx> Diagnostic<'a, ()> + for AmbiguousTraitMethod<'b, 'c, 'tcx, 'pcx, 'fnctx> +{ + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { segment, call_expr, self_expr, pick, args, edition, span, this } = self; + let mut lint = Diag::new( + dcx, + level, + format!( + "trait method `{}` will become ambiguous in Rust {edition}", + segment.ident.name + ), + ); + + let sp = call_expr.span; + let trait_name = + this.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container_id(this.tcx)); + + let (self_adjusted, precise) = this.adjust_expr(pick, self_expr, sp); + if precise { + let args = args.iter().fold(String::new(), |mut string, arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); + write!(string, ", {}", this.sess().source_map().span_to_snippet(span).unwrap()) + .unwrap(); + string + }); + + lint.span_suggestion( + sp, + "disambiguate the associated function", + format!( + "{}::{}{}({}{})", + trait_name, + segment.ident.name, + if let Some(args) = segment.args.as_ref().and_then(|args| this + .sess() + .source_map() + .span_to_snippet(args.span_ext) + .ok()) + { + // Keep turbofish. + format!("::{args}") + } else { + String::new() + }, + self_adjusted, + args, + ), + Applicability::MachineApplicable, + ); + } else { + lint.span_help( + sp, + format!( + "disambiguate the associated function with `{}::{}(...)`", + trait_name, segment.ident, + ), + ); + } + lint + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_edition_dependent_dot_call( &self, @@ -101,133 +239,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Inherent impls only require not relying on autoref and autoderef in order to // ensure that the trait implementation won't be used - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( prelude_or_array_lint, self_expr.hir_id, self_expr.span, - |lint| { - lint.primary_message(format!( - "trait method `{}` will become ambiguous in Rust {edition}", - segment.ident.name - )); - - let sp = self_expr.span; - - let derefs = "*".repeat(pick.autoderefs); - - let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => { - mutbl.ref_prefix_str() - } - Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", - Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { - hir::Mutability::Mut => "Pin<&mut ", - hir::Mutability::Not => "Pin<&", - }, - }; - if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) - { - let mut self_adjusted = - if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = - pick.autoref_or_ptr_adjustment - { - format!("{derefs}{self_expr} as *const _") - } else { - format!("{autoref}{derefs}{self_expr}") - }; - - if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = - pick.autoref_or_ptr_adjustment - { - self_adjusted.push('>'); - } - - lint.span_suggestion( - sp, - "disambiguate the method call", - format!("({self_adjusted})"), - Applicability::MachineApplicable, - ); - } else { - let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = - pick.autoref_or_ptr_adjustment - { - format!("{derefs}(...) as *const _") - } else { - format!("{autoref}{derefs}...") - }; - lint.span_help( - sp, - format!("disambiguate the method call with `({self_adjusted})`",), - ); - } + AmbiguousTraitMethodCall { + segment_name: segment.ident.name, + self_expr_span: self_expr.span, + pick, + tcx: self.tcx, + edition, }, ); } else { // trait implementations require full disambiguation to not clash with the new prelude // additions (i.e. convert from dot-call to fully-qualified call) - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( prelude_or_array_lint, call_expr.hir_id, call_expr.span, - |lint| { - lint.primary_message(format!( - "trait method `{}` will become ambiguous in Rust {edition}", - segment.ident.name - )); - - let sp = call_expr.span; - let trait_name = self.trait_path_or_bare_name( - span, - call_expr.hir_id, - pick.item.container_id(self.tcx), - ); - - let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); - if precise { - let args = args.iter().fold(String::new(), |mut string, arg| { - let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); - write!( - string, - ", {}", - self.sess().source_map().span_to_snippet(span).unwrap() - ) - .unwrap(); - string - }); - - lint.span_suggestion( - sp, - "disambiguate the associated function", - format!( - "{}::{}{}({}{})", - trait_name, - segment.ident.name, - if let Some(args) = segment.args.as_ref().and_then(|args| self - .sess() - .source_map() - .span_to_snippet(args.span_ext) - .ok()) - { - // Keep turbofish. - format!("::{args}") - } else { - String::new() - }, - self_adjusted, - args, - ), - Applicability::MachineApplicable, - ); - } else { - lint.span_help( - sp, - format!( - "disambiguate the associated function with `{}::{}(...)`", - trait_name, segment.ident, - ), - ); - } + AmbiguousTraitMethod { + segment, + call_expr, + self_expr, + pick, + args, + edition, + span, + this: self, }, ); } @@ -242,6 +281,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_id: hir::HirId, pick: &Pick<'tcx>, ) { + struct AmbiguousTraitAssocFunc<'a, 'fnctx, 'tcx> { + method_name: Symbol, + this: &'a FnCtxt<'fnctx, 'tcx>, + pick: &'a Pick<'tcx>, + span: Span, + expr_id: hir::HirId, + self_ty_span: Span, + self_ty: Ty<'tcx>, + } + + impl<'a, 'b, 'fnctx, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitAssocFunc<'b, 'fnctx, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { method_name, this, pick, span, expr_id, self_ty_span, self_ty } = self; + let mut lint = Diag::new( + dcx, + level, + format!( + "trait-associated function `{}` will become ambiguous in Rust 2021", + method_name + ), + ); + + // "type" refers to either a type or, more likely, a trait from which + // the associated function or method is from. + let container_id = pick.item.container_id(this.tcx); + let trait_path = this.trait_path_or_bare_name(span, expr_id, container_id); + let trait_generics = this.tcx.generics_of(container_id); + + let trait_name = + if trait_generics.own_params.len() <= trait_generics.has_self as usize { + trait_path + } else { + let counts = trait_generics.own_counts(); + format!( + "{}<{}>", + trait_path, + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain(std::iter::repeat("_").take( + counts.types + counts.consts - trait_generics.has_self as usize + )) + .collect::>() + .join(", ") + ) + }; + + let mut self_ty_name = self_ty_span + .find_ancestor_inside(span) + .and_then(|span| this.sess().source_map().span_to_snippet(span).ok()) + .unwrap_or_else(|| self_ty.to_string()); + + // Get the number of generics the self type has (if an Adt) unless we can determine that + // the user has written the self type with generics already which we (naively) do by looking + // for a "<" in `self_ty_name`. + if !self_ty_name.contains('<') { + if let ty::Adt(def, _) = self_ty.kind() { + let generics = this.tcx.generics_of(def.did()); + if !generics.is_own_empty() { + let counts = generics.own_counts(); + self_ty_name += &format!( + "<{}>", + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain( + std::iter::repeat("_").take(counts.types + counts.consts) + ) + .collect::>() + .join(", ") + ); + } + } + } + lint.span_suggestion( + span, + "disambiguate the associated function", + format!("<{} as {}>::{}", self_ty_name, trait_name, method_name), + Applicability::MachineApplicable, + ); + lint + } + } + // Rust 2021 and later is already using the new prelude if span.at_least_rust_2021() { return; @@ -278,67 +399,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - self.tcx.node_span_lint(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| { - lint.primary_message(format!( - "trait-associated function `{}` will become ambiguous in Rust 2021", - method_name.name - )); - - // "type" refers to either a type or, more likely, a trait from which - // the associated function or method is from. - let container_id = pick.item.container_id(self.tcx); - let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); - let trait_generics = self.tcx.generics_of(container_id); - - let trait_name = - if trait_generics.own_params.len() <= trait_generics.has_self as usize { - trait_path - } else { - let counts = trait_generics.own_counts(); - format!( - "{}<{}>", - trait_path, - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take( - counts.types + counts.consts - trait_generics.has_self as usize - )) - .collect::>() - .join(", ") - ) - }; - - let mut self_ty_name = self_ty_span - .find_ancestor_inside(span) - .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) - .unwrap_or_else(|| self_ty.to_string()); - - // Get the number of generics the self type has (if an Adt) unless we can determine that - // the user has written the self type with generics already which we (naively) do by looking - // for a "<" in `self_ty_name`. - if !self_ty_name.contains('<') { - if let ty::Adt(def, _) = self_ty.kind() { - let generics = self.tcx.generics_of(def.did()); - if !generics.is_own_empty() { - let counts = generics.own_counts(); - self_ty_name += &format!( - "<{}>", - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take(counts.types + counts.consts)) - .collect::>() - .join(", ") - ); - } - } - } - lint.span_suggestion( + self.tcx.emit_node_span_lint( + RUST_2021_PRELUDE_COLLISIONS, + expr_id, + span, + AmbiguousTraitAssocFunc { + method_name: method_name.name, + this: self, + pick, span, - "disambiguate the associated function", - format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), - Applicability::MachineApplicable, - ); - }); + expr_id, + self_ty_span, + self_ty, + }, + ); } fn trait_path_or_bare_name( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b6162f2556d36..8d92ee03ff472 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -5,13 +5,14 @@ use std::ops::Deref; use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::{self as hir, ExprKind, HirId, Node, find_attr}; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query}; +use rustc_macros::Diagnostic; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -389,6 +390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result>, { + #[derive(Diagnostic)] + #[diag("type annotations needed")] + struct MissingTypeAnnot; + let mut orig_values = OriginalQueryValues::default(); let predefined_opaques_in_body = if self.next_trait_solver() { self.tcx.mk_predefined_opaques_in_body_from_iter( @@ -471,13 +476,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::TYVAR_BEHIND_RAW_POINTER, scope_expr_id, span, - |lint| { - lint.primary_message("type annotations needed"); - }, + MissingTypeAnnot, ); } else { // Ended up encountering a type variable when doing autoderef, @@ -1823,47 +1826,68 @@ impl<'tcx> Pick<'tcx> { span: Span, scope_expr_id: HirId, ) { - if self.unstable_candidates.is_empty() { - return; + struct ItemMaybeBeAddedToStd<'a, 'tcx> { + this: &'a Pick<'tcx>, + tcx: TyCtxt<'tcx>, + span: Span, } - let def_kind = self.item.as_def_kind(); - tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| { - lint.primary_message(format!( - "{} {} with this name may be added to the standard library in the future", - tcx.def_kind_descr_article(def_kind, self.item.def_id), - tcx.def_kind_descr(def_kind, self.item.def_id), - )); - - match (self.item.kind, self.item.container) { - (ty::AssocKind::Fn { .. }, _) => { - // FIXME: This should be a `span_suggestion` instead of `help` - // However `self.span` only - // highlights the method name, so we can't use it. Also consider reusing - // the code from `report_method_error()`. - lint.help(format!( - "call with fully qualified syntax `{}(...)` to keep using the current \ - method", - tcx.def_path_str(self.item.def_id), - )); - } - (ty::AssocKind::Const { name, .. }, ty::AssocContainer::Trait) => { - let def_id = self.item.container_id(tcx); - lint.span_suggestion( - span, - "use the fully qualified path to the associated const", - format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name), - Applicability::MachineApplicable, - ); + + impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for ItemMaybeBeAddedToStd<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { this, tcx, span } = self; + let def_kind = this.item.as_def_kind(); + let mut lint = Diag::new( + dcx, + level, + format!( + "{} {} with this name may be added to the standard library in the future", + tcx.def_kind_descr_article(def_kind, this.item.def_id), + tcx.def_kind_descr(def_kind, this.item.def_id), + ), + ); + + match (this.item.kind, this.item.container) { + (ty::AssocKind::Fn { .. }, _) => { + // FIXME: This should be a `span_suggestion` instead of `help` + // However `this.span` only + // highlights the method name, so we can't use it. Also consider reusing + // the code from `report_method_error()`. + lint.help(format!( + "call with fully qualified syntax `{}(...)` to keep using the current \ + method", + tcx.def_path_str(this.item.def_id), + )); + } + (ty::AssocKind::Const { name, .. }, ty::AssocContainer::Trait) => { + let def_id = this.item.container_id(tcx); + lint.span_suggestion( + span, + "use the fully qualified path to the associated const", + format!("<{} as {}>::{}", this.self_ty, tcx.def_path_str(def_id), name), + Applicability::MachineApplicable, + ); + } + _ => {} } - _ => {} + tcx.disabled_nightly_features( + &mut lint, + this.unstable_candidates.iter().map(|(candidate, feature)| { + (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) + }), + ); + lint } - tcx.disabled_nightly_features( - lint, - self.unstable_candidates.iter().map(|(candidate, feature)| { - (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) - }), - ); - }); + } + + if self.unstable_candidates.is_empty() { + return; + } + tcx.emit_node_span_lint( + lint::builtin::UNSTABLE_NAME_COLLISIONS, + scope_expr_id, + span, + ItemMaybeBeAddedToStd { this: self, tcx, span }, + ); } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index ea4edb3ccf3cd..8f50228d86896 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -7,7 +7,8 @@ use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, pluralize, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -2471,6 +2472,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &[(&ty::FieldDef, Ident)], ty: Ty<'tcx>, ) { + struct FieldsNotListed<'a, 'b, 'tcx> { + pat_span: Span, + unmentioned_fields: &'a [(&'b ty::FieldDef, Ident)], + joined_patterns: String, + ty: Ty<'tcx>, + } + + impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for FieldsNotListed<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { pat_span, unmentioned_fields, joined_patterns, ty } = self; + Diag::new(dcx, level, "some fields are not explicitly listed") + .with_span_label(pat_span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)) + .with_help( + "ensure that all fields are mentioned explicitly by adding the suggested fields", + ) + .with_note(format!( + "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", + )) + } + } + fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String { const LIMIT: usize = 3; match witnesses { @@ -2495,16 +2517,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &unmentioned_fields.iter().map(|(_, i)| i).collect::>(), ); - self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| { - lint.primary_message("some fields are not explicitly listed"); - lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); - lint.help( - "ensure that all fields are mentioned explicitly by adding the suggested fields", - ); - lint.note(format!( - "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", - )); - }); + self.tcx.emit_node_span_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + pat.hir_id, + pat.span, + FieldsNotListed { pat_span: pat.span, unmentioned_fields, joined_patterns, ty }, + ); } /// Returns a diagnostic reporting a struct pattern which does not mention some fields. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 1f680ca5b09a7..df02974d2fb2d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -35,7 +35,7 @@ use std::iter; use rustc_abi::FIRST_VARIANT; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::{ExtendUnord, UnordSet}; -use rustc_errors::{Applicability, MultiSpan}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, HirId, find_attr}; @@ -964,165 +964,216 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_clause: hir::CaptureBy, span: Span, ) { - let (need_migrations, reasons) = self.compute_2229_migrations( - closure_def_id, - span, - capture_clause, - self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), - ); + struct MigrationLint<'a, 'b, 'tcx> { + closure_def_id: LocalDefId, + this: &'a FnCtxt<'b, 'tcx>, + body_id: hir::BodyId, + need_migrations: Vec, + migration_message: String, + } - if !need_migrations.is_empty() { - let (migration_string, migrated_variables_concat) = - migration_suggestion_for_2229(self.tcx, &need_migrations); + impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for MigrationLint<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { closure_def_id, this, body_id, need_migrations, migration_message } = + self; + let mut lint = Diag::new(dcx, level, migration_message); + + let (migration_string, migrated_variables_concat) = + migration_suggestion_for_2229(this.tcx, &need_migrations); + + let closure_hir_id = this.tcx.local_def_id_to_hir_id(closure_def_id); + let closure_head_span = this.tcx.def_span(closure_def_id); + + for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { + // Labels all the usage of the captured variable and why they are responsible + // for migration being needed + for lint_note in diagnostics_info.iter() { + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { + source_expr: Some(capture_expr_id), + var_name: captured_name, + } => { + let cause_span = this.tcx.hir_span(*capture_expr_id); + lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + this.tcx.hir_name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span } => { + lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + this.tcx.hir_name(*var_hir_id), + )); + } + + _ => {} + } + + // Add a label pointing to where a captured variable affected by drop order + // is dropped + if lint_note.reason.drop_order { + let drop_location_span = drop_location_span(this.tcx, closure_hir_id); - let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); - let closure_head_span = self.tcx.def_span(closure_def_id); - self.tcx.node_span_lint( - lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, - closure_hir_id, - closure_head_span, - |lint| { - lint.primary_message(reasons.migration_message()); - - for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { - // Labels all the usage of the captured variable and why they are responsible - // for migration being needed - for lint_note in diagnostics_info.iter() { match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { - let cause_span = self.tcx.hir_span(*capture_expr_id); - lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir_name(*var_hir_id), + UpvarMigrationInfo::CapturingPrecise { + var_name: captured_name, + .. + } => { + lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", + this.tcx.hir_name(*var_hir_id), captured_name, )); } - UpvarMigrationInfo::CapturingNothing { use_span } => { - lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", - self.tcx.hir_name(*var_hir_id), + UpvarMigrationInfo::CapturingNothing { use_span: _ } => { + lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + v = this.tcx.hir_name(*var_hir_id), )); } - - _ => { } } + } - // Add a label pointing to where a captured variable affected by drop order - // is dropped - if lint_note.reason.drop_order { - let drop_location_span = drop_location_span(self.tcx, closure_hir_id); - - match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir_name(*var_hir_id), - captured_name, - )); - } - UpvarMigrationInfo::CapturingNothing { use_span: _ } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", - v = self.tcx.hir_name(*var_hir_id), - )); - } + // Add a label explaining why a closure no longer implements a trait + for &missing_trait in &lint_note.reason.auto_traits { + // not capturing something anymore cannot cause a trait to fail to be implemented: + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { + var_name: captured_name, + .. + } => { + let var_name = this.tcx.hir_name(*var_hir_id); + lint.span_label( + closure_head_span, + format!( + "\ + in Rust 2018, this closure implements {missing_trait} \ + as `{var_name}` implements {missing_trait}, but in Rust 2021, \ + this closure will no longer implement {missing_trait} \ + because `{var_name}` is not fully captured \ + and `{captured_name}` does not implement {missing_trait}" + ), + ); } - } - // Add a label explaining why a closure no longer implements a trait - for &missing_trait in &lint_note.reason.auto_traits { - // not capturing something anymore cannot cause a trait to fail to be implemented: - match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - let var_name = self.tcx.hir_name(*var_hir_id); - lint.span_label(closure_head_span, format!("\ - in Rust 2018, this closure implements {missing_trait} \ - as `{var_name}` implements {missing_trait}, but in Rust 2021, \ - this closure will no longer implement {missing_trait} \ - because `{var_name}` is not fully captured \ - and `{captured_name}` does not implement {missing_trait}")); - } - - // Cannot happen: if we don't capture a variable, we impl strictly more traits - UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), - } + // Cannot happen: if we don't capture a variable, we impl strictly more traits + UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!( + *use_span, + "missing trait from not capturing something" + ), } } } + } - let diagnostic_msg = format!( - "add a dummy let to cause {migrated_variables_concat} to be fully captured" - ); + let diagnostic_msg = format!( + "add a dummy let to cause {migrated_variables_concat} to be fully captured" + ); - let closure_span = self.tcx.hir_span_with_body(closure_hir_id); - let mut closure_body_span = { - // If the body was entirely expanded from a macro - // invocation, i.e. the body is not contained inside the - // closure span, then we walk up the expansion until we - // find the span before the expansion. - let s = self.tcx.hir_span_with_body(body_id.hir_id); - s.find_ancestor_inside(closure_span).unwrap_or(s) - }; + let closure_span = this.tcx.hir_span_with_body(closure_hir_id); + let mut closure_body_span = { + // If the body was entirely expanded from a macro + // invocation, i.e. the body is not contained inside the + // closure span, then we walk up the expansion until we + // find the span before the expansion. + let s = this.tcx.hir_span_with_body(body_id.hir_id); + s.find_ancestor_inside(closure_span).unwrap_or(s) + }; - if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { - if s.starts_with('$') { - // Looks like a macro fragment. Try to find the real block. - if let hir::Node::Expr(&hir::Expr { - kind: hir::ExprKind::Block(block, ..), .. - }) = self.tcx.hir_node(body_id.hir_id) { - // If the body is a block (with `{..}`), we use the span of that block. - // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. - // Since we know it's a block, we know we can insert the `let _ = ..` without - // breaking the macro syntax. - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) { - closure_body_span = block.span; - s = snippet; - } + if let Ok(mut s) = this.tcx.sess.source_map().span_to_snippet(closure_body_span) { + if s.starts_with('$') { + // Looks like a macro fragment. Try to find the real block. + if let hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Block(block, ..), + .. + }) = this.tcx.hir_node(body_id.hir_id) + { + // If the body is a block (with `{..}`), we use the span of that block. + // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. + // Since we know it's a block, we know we can insert the `let _ = ..` without + // breaking the macro syntax. + if let Ok(snippet) = + this.tcx.sess.source_map().span_to_snippet(block.span) + { + closure_body_span = block.span; + s = snippet; } } + } - let mut lines = s.lines(); - let line1 = lines.next().unwrap_or_default(); - - if line1.trim_end() == "{" { - // This is a multi-line closure with just a `{` on the first line, - // so we put the `let` on its own line. - // We take the indentation from the next non-empty line. - let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); - let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; - lint.span_suggestion( - closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(), - diagnostic_msg, - format!("\n{indent}{migration_string};"), - Applicability::MachineApplicable, - ); - } else if line1.starts_with('{') { - // This is a closure with its body wrapped in - // braces, but with more than just the opening - // brace on the first line. We put the `let` - // directly after the `{`. - lint.span_suggestion( - closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(), - diagnostic_msg, - format!(" {migration_string};"), - Applicability::MachineApplicable, - ); - } else { - // This is a closure without braces around the body. - // We add braces to add the `let` before the body. - lint.multipart_suggestion( - diagnostic_msg, - vec![ - (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")), - (closure_body_span.shrink_to_hi(), " }".to_string()), - ], - Applicability::MachineApplicable - ); - } - } else { + let mut lines = s.lines(); + let line1 = lines.next().unwrap_or_default(); + + if line1.trim_end() == "{" { + // This is a multi-line closure with just a `{` on the first line, + // so we put the `let` on its own line. + // We take the indentation from the next non-empty line. + let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); + let indent = + line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; lint.span_suggestion( - closure_span, + closure_body_span + .with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())) + .shrink_to_lo(), diagnostic_msg, - migration_string, - Applicability::HasPlaceholders + format!("\n{indent}{migration_string};"), + Applicability::MachineApplicable, + ); + } else if line1.starts_with('{') { + // This is a closure with its body wrapped in + // braces, but with more than just the opening + // brace on the first line. We put the `let` + // directly after the `{`. + lint.span_suggestion( + closure_body_span + .with_lo(closure_body_span.lo() + BytePos(1)) + .shrink_to_lo(), + diagnostic_msg, + format!(" {migration_string};"), + Applicability::MachineApplicable, + ); + } else { + // This is a closure without braces around the body. + // We add braces to add the `let` before the body. + lint.multipart_suggestion( + diagnostic_msg, + vec![ + ( + closure_body_span.shrink_to_lo(), + format!("{{ {migration_string}; "), + ), + (closure_body_span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, ); } + } else { + lint.span_suggestion( + closure_span, + diagnostic_msg, + migration_string, + Applicability::HasPlaceholders, + ); + } + lint + } + } + + let (need_migrations, reasons) = self.compute_2229_migrations( + closure_def_id, + span, + capture_clause, + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), + ); + + if !need_migrations.is_empty() { + self.tcx.emit_node_span_lint( + lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, + self.tcx.local_def_id_to_hir_id(closure_def_id), + self.tcx.def_span(closure_def_id), + MigrationLint { + this: self, + migration_message: reasons.migration_message(), + closure_def_id, + body_id, + need_migrations, }, ); } diff --git a/tests/ui/inference/inference_unstable.stderr b/tests/ui/inference/inference_unstable.stderr index 0072175d51403..b547293052a2a 100644 --- a/tests/ui/inference/inference_unstable.stderr +++ b/tests/ui/inference/inference_unstable.stderr @@ -4,9 +4,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_flatten(), 1); | ^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten` | @@ -19,9 +19,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_by_value_vs_by_ref(), 1); | ^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_value_vs_by_ref(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_value_vs_by_ref(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_value_vs_by_ref` | LL + #![feature(ipu_flatten)] @@ -33,9 +33,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_by_ref_vs_by_ref_mut(), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_ref_vs_by_ref_mut(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_ref_vs_by_ref_mut(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_ref_vs_by_ref_mut` | LL + #![feature(ipu_flatten)] @@ -47,9 +47,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!((&mut 'x' as *mut char).ipu_by_mut_ptr_vs_by_const_ptr(), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_mut_ptr_vs_by_const_ptr(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_mut_ptr_vs_by_const_ptr(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_mut_ptr_vs_by_const_ptr` | LL + #![feature(ipu_flatten)] diff --git a/tests/ui/resolve/slice-as-slice.stderr b/tests/ui/resolve/slice-as-slice.stderr index c93363431c595..f22a0dd6ac58e 100644 --- a/tests/ui/resolve/slice-as-slice.stderr +++ b/tests/ui/resolve/slice-as-slice.stderr @@ -4,9 +4,9 @@ warning: a method with this name may be added to the standard library in the fut LL | b(data.as_slice()); | ^^^^^^^^ | + = help: call with fully qualified syntax `ComponentSlice::as_slice(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `ComponentSlice::as_slice(...)` to keep using the current method = note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default help: add `#![feature(str_as_str)]` to the crate attributes to enable `core::slice::::as_slice` | From 8d96e603b1c3e65bba9e944616de6260e7e40781 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 6 Mar 2026 15:15:43 +0100 Subject: [PATCH 10/11] Preserve the `DiagLocation` in `diag_lint_level` --- compiler/rustc_errors/src/diagnostic.rs | 6 +++--- compiler/rustc_errors/src/lib.rs | 4 ++-- compiler/rustc_middle/src/lint.rs | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index f7fdbfa0cd57e..a093fede8c198 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -140,7 +140,7 @@ where } #[derive(Clone, Debug, Encodable, Decodable)] -pub(crate) struct DiagLocation { +pub struct DiagLocation { file: Cow<'static, str>, line: u32, col: u32, @@ -148,7 +148,7 @@ pub(crate) struct DiagLocation { impl DiagLocation { #[track_caller] - fn caller() -> Self { + pub fn caller() -> Self { let loc = panic::Location::caller(); DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } } @@ -249,7 +249,7 @@ pub struct DiagInner { pub long_ty_path: Option, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. - pub(crate) emitted_at: DiagLocation, + pub emitted_at: DiagLocation, } impl DiagInner { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7fc3e4a45d0ab..c881339564570 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -37,8 +37,8 @@ pub use anstyle::{ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ - BugAbort, Diag, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, - StringPart, Subdiag, Subdiagnostic, + BugAbort, Diag, DiagInner, DiagLocation, DiagStyledString, Diagnostic, EmissionGuarantee, + FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 223b47c9044be..eb1628762ffe8 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,7 +2,7 @@ use std::cmp; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::{Diag, Diagnostic, MultiSpan}; +use rustc_errors::{Diag, DiagLocation, Diagnostic, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; use rustc_lint_defs::EditionFcw; use rustc_macros::{Decodable, Encodable, HashStable}; @@ -602,6 +602,9 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( } else { Diag::new(sess.dcx(), err_level, "") }; + // FIXME: Find a nicer way to expose the `DiagLocation` + err.emitted_at = DiagLocation::caller(); + if let Some(span) = span && err.span.primary_span().is_none() { From e01a7e7ba1a8adb7bb3477838d6f1b4b57d9761a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Mar 2026 16:38:53 +0100 Subject: [PATCH 11/11] Fix panic by setting the span before it is actually needed --- src/tools/clippy/clippy_utils/src/diagnostics.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 65c962826900d..c0d02aaa6ee88 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -250,9 +250,11 @@ where } } + let sp = sp.into(); #[expect(clippy::disallowed_methods)] - cx.emit_span_lint(lint, sp, ClippyDiag(|diag: &mut Diag<'_, ()>| { + cx.emit_span_lint(lint, sp.clone(), ClippyDiag(|diag: &mut Diag<'_, ()>| { diag.primary_message(msg); + diag.span(sp); f(diag); docs_link(diag, lint);