From 14484ec0164228ce23f444c4812a5b52711df620 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 9 Jan 2026 15:51:24 +0100 Subject: [PATCH] Remove the `UNTRANSLATABLE_DIAGNOSTIC` and `DIAGNOSTIC_OUTSIDE_OF_IMPL` lints --- compiler/rustc_lint/messages.ftl | 5 - compiler/rustc_lint/src/internal.rs | 167 +--------------------------- compiler/rustc_lint/src/lib.rs | 2 - compiler/rustc_lint/src/lints.rs | 8 -- 4 files changed, 5 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index e38130aa9a29..507f1abc4900 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -237,9 +237,6 @@ lint_deprecated_where_clause_location = where clause not allowed here .suggestion_move_to_end = move it to the end of the type declaration .suggestion_remove_where = remove this `where` -lint_diag_out_of_impl = - diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls - lint_doc_alias_duplicated = doc alias is duplicated .label = first defined here @@ -992,8 +989,6 @@ lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ -lint_untranslatable_diag = diagnostics should be created using translatable messages - lint_unused_allocation = unnecessary allocation, use `&` instead lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 68885e14f40d..37eb375c7a6c 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,18 +5,17 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, HirId, find_attr}; -use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity, Ty}; +use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::{Span, sym}; -use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ - BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, ImplicitSysrootCrateImportDiag, - LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, - SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, - TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage, UntranslatableDiag, + BadOptAccessDiag, DefaultHashTypesDiag, ImplicitSysrootCrateImportDiag, LintPassByHand, + NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, + SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse, + TypeIrInherentUsage, TypeIrTraitUsage, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -492,162 +491,6 @@ impl EarlyLintPass for LintPassImpl { } } -declare_tool_lint! { - /// The `untranslatable_diagnostic` lint detects messages passed to functions with `impl - /// Into<{D,Subd}iagMessage` parameters without using translatable Fluent strings. - /// - /// More details on translatable diagnostics can be found - /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html). - pub rustc::UNTRANSLATABLE_DIAGNOSTIC, - Allow, - "prevent creation of diagnostics which cannot be translated", - report_in_external_macro: true, - @eval_always = true -} - -declare_tool_lint! { - /// The `diagnostic_outside_of_impl` lint detects calls to functions annotated with - /// `#[rustc_lint_diagnostics]` that are outside an `Diagnostic`, `Subdiagnostic`, or - /// `LintDiagnostic` impl (either hand-written or derived). - /// - /// More details on diagnostics implementations can be found - /// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html). - pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, - Allow, - "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls", - report_in_external_macro: true, - @eval_always = true -} - -declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); - -impl LateLintPass<'_> for Diagnostics { - fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| { - let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra)); - result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span))); - result - }; - // Only check function calls and method calls. - let Some((def_id, span, fn_gen_args, recv, args)) = - get_callee_span_generic_args_and_args(cx, expr) - else { - return; - }; - let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some()); - if let Some(recv) = recv { - arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); // dummy inserted for `self` - } - - Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args); - Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans); - } -} - -impl Diagnostics { - // Is the type `{D,Subd}iagMessage`? - fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool { - if let Some(adt_def) = ty.ty_adt_def() - && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) - && matches!(name, sym::DiagMessage | sym::SubdiagMessage) - { - true - } else { - false - } - } - - fn untranslatable_diagnostic<'cx>( - cx: &LateContext<'cx>, - def_id: DefId, - arg_tys_and_spans: &[(Ty<'cx>, Span)], - ) { - let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); - let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates; - for (i, ¶m_ty) in fn_sig.inputs().iter().enumerate() { - if let ty::Param(sig_param) = param_ty.kind() { - // It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`. - for pred in predicates.iter() { - if let Some(trait_pred) = pred.as_trait_clause() - && let trait_ref = trait_pred.skip_binder().trait_ref - && trait_ref.self_ty() == param_ty // correct predicate for the param? - && cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id) - && let ty1 = trait_ref.args.type_at(1) - && Self::is_diag_message(cx, ty1) - { - // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg - // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an - // `UNTRANSLATABLE_DIAGNOSTIC` lint. - let (arg_ty, arg_span) = arg_tys_and_spans[i]; - - // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`? - let is_translatable = Self::is_diag_message(cx, arg_ty) - || matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name); - if !is_translatable { - cx.emit_span_lint( - UNTRANSLATABLE_DIAGNOSTIC, - arg_span, - UntranslatableDiag, - ); - } - } - } - } - } - } - - fn diagnostic_outside_of_impl<'cx>( - cx: &LateContext<'cx>, - span: Span, - current_id: HirId, - def_id: DefId, - fn_gen_args: GenericArgsRef<'cx>, - ) { - // Is the callee marked with `#[rustc_lint_diagnostics]`? - let Some(inst) = - ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, fn_gen_args).ok().flatten() - else { - return; - }; - - if !find_attr!(cx.tcx.get_all_attrs(inst.def_id()), AttributeKind::RustcLintDiagnostics) { - return; - }; - - for (hir_id, _parent) in cx.tcx.hir_parent_iter(current_id) { - if let Some(owner_did) = hir_id.as_owner() - && find_attr!(cx.tcx.get_all_attrs(owner_did), AttributeKind::RustcLintDiagnostics) - { - // The parent method is marked with `#[rustc_lint_diagnostics]` - return; - } - } - - // Calls to `#[rustc_lint_diagnostics]`-marked functions should only occur: - // - inside an impl of `Diagnostic`, `Subdiagnostic`, or `LintDiagnostic`, or - // - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`. - // - // Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint. - let mut is_inside_appropriate_impl = false; - for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) { - debug!(?parent); - if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent - && let Some(of_trait) = impl_.of_trait - && let Some(def_id) = of_trait.trait_ref.trait_def_id() - && let Some(name) = cx.tcx.get_diagnostic_name(def_id) - && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic) - { - is_inside_appropriate_impl = true; - break; - } - } - debug!(?is_inside_appropriate_impl); - if !is_inside_appropriate_impl { - cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); - } - } -} - declare_tool_lint! { /// The `bad_opt_access` lint detects accessing options by field instead of /// the wrapper function. diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index ae5fbec29e46..0105446b545d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -655,8 +655,6 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(TyTyKind)); store.register_lints(&TypeIr::lint_vec()); store.register_late_mod_pass(|_| Box::new(TypeIr)); - store.register_lints(&Diagnostics::lint_vec()); - store.register_late_mod_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::lint_vec()); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ef11b9884927..db11fdd5ec8f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -943,14 +943,6 @@ pub(crate) struct NonGlobImportTypeIrInherent { #[help] pub(crate) struct LintPassByHand; -#[derive(LintDiagnostic)] -#[diag(lint_diag_out_of_impl)] -pub(crate) struct DiagOutOfImpl; - -#[derive(LintDiagnostic)] -#[diag(lint_untranslatable_diag)] -pub(crate) struct UntranslatableDiag; - #[derive(LintDiagnostic)] #[diag(lint_bad_opt_access)] pub(crate) struct BadOptAccessDiag<'a> {