Rollup merge of #121382 - nnethercote:rework-untranslatable_diagnostic-lint, r=davidtwco

Rework `untranslatable_diagnostic` lint

Currently it only checks calls to functions marked with `#[rustc_lint_diagnostics]`. This PR changes it to check calls to any function with an `impl Into<{D,Subd}iagnosticMessage>` parameter. This greatly improves its coverage and doesn't rely on people remembering to add `#[rustc_lint_diagnostics]`. It also lets us add `#[rustc_lint_diagnostics]` to a number of functions that don't have an `impl Into<{D,Subd}iagnosticMessage>`, such as `Diag::span`.

r? ``@davidtwco``
This commit is contained in:
Matthias Krüger 2024-03-06 22:02:46 +01:00 committed by GitHub
commit efe9deace8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 305 additions and 89 deletions

View File

@ -1,6 +1,9 @@
use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::iter;
use std::ops::Bound;
use std::ops::Deref; use std::ops::Deref;
use std::{borrow::Borrow, cmp, iter, ops::Bound};
use rustc_index::Idx; use rustc_index::Idx;
use tracing::debug; use tracing::debug;
@ -32,7 +35,7 @@ where
pub trait LayoutCalculator { pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>; type TargetDataLayoutRef: Borrow<TargetDataLayout>;
fn delayed_bug(&self, txt: String); fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>);
fn current_data_layout(&self) -> Self::TargetDataLayoutRef; fn current_data_layout(&self) -> Self::TargetDataLayoutRef;
fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>( fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(

View File

@ -22,6 +22,7 @@ use std::collections::hash_map::Entry;
use std::fmt::Write; use std::fmt::Write;
impl<'a, 'hir> LoweringContext<'a, 'hir> { impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn lower_inline_asm( pub(crate) fn lower_inline_asm(
&mut self, &mut self,
sp: Span, sp: Span,

View File

@ -1513,6 +1513,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> { fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
let yielded = let yielded =
opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span)); opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));

View File

@ -2272,6 +2272,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.expr_block(block) self.expr_block(block)
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen { fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
match c.value.kind { match c.value.kind {
ExprKind::Underscore => { ExprKind::Underscore => {

View File

@ -17,6 +17,7 @@ use crate::errors;
macro_rules! gate { macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{ ($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit(); feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
} }
}}; }};
@ -34,6 +35,7 @@ macro_rules! gate {
macro_rules! gate_alt { macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{ ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) { if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, $name, $span, $explain).emit(); feature_err(&$visitor.sess, $name, $span, $explain).emit();
} }
}}; }};
@ -73,6 +75,7 @@ struct PostExpansionVisitor<'a> {
} }
impl<'a> PostExpansionVisitor<'a> { impl<'a> PostExpansionVisitor<'a> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) { fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) {
let ast::StrLit { symbol_unescaped, span, .. } = abi; let ast::StrLit { symbol_unescaped, span, .. } = abi;
@ -579,6 +582,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if let Ok(snippet) = sm.span_to_snippet(span) if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!" && snippet == "!"
{ {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental") feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
.emit(); .emit();
} else { } else {

View File

@ -516,6 +516,7 @@ pub struct Condition {
} }
/// Tests if a cfg-pattern matches the cfg set /// Tests if a cfg-pattern matches the cfg set
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn cfg_matches( pub fn cfg_matches(
cfg: &ast::MetaItem, cfg: &ast::MetaItem,
sess: &Session, sess: &Session,
@ -566,6 +567,7 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg; let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) { if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
@ -592,6 +594,7 @@ fn parse_version(s: Symbol) -> Option<RustcVersion> {
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items. /// evaluate individual items.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn eval_condition( pub fn eval_condition(
cfg: &ast::MetaItem, cfg: &ast::MetaItem,
sess: &Session, sess: &Session,

View File

@ -76,6 +76,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// LL | for (key, value) in dict { /// LL | for (key, value) in dict {
/// | ^^^^ /// | ^^^^
/// ``` /// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub(super) fn add_moved_or_invoked_closure_note( pub(super) fn add_moved_or_invoked_closure_note(
&self, &self,
location: Location, location: Location,
@ -585,6 +586,7 @@ impl UseSpans<'_> {
} }
/// Add a span label to the arguments of the closure, if it exists. /// Add a span label to the arguments of the closure, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn args_subdiag( pub(super) fn args_subdiag(
self, self,
dcx: &rustc_errors::DiagCtxt, dcx: &rustc_errors::DiagCtxt,
@ -598,6 +600,7 @@ impl UseSpans<'_> {
/// Add a span label to the use of the captured variable, if it exists. /// Add a span label to the use of the captured variable, if it exists.
/// only adds label to the `path_span` /// only adds label to the `path_span`
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_path_only_subdiag( pub(super) fn var_path_only_subdiag(
self, self,
dcx: &rustc_errors::DiagCtxt, dcx: &rustc_errors::DiagCtxt,
@ -635,6 +638,7 @@ impl UseSpans<'_> {
} }
/// Add a subdiagnostic to the use of the captured variable, if it exists. /// Add a subdiagnostic to the use of the captured variable, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_subdiag( pub(super) fn var_subdiag(
self, self,
dcx: &rustc_errors::DiagCtxt, dcx: &rustc_errors::DiagCtxt,
@ -1008,6 +1012,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.borrow_spans(span, borrow.reserve_location) self.borrow_spans(span, borrow.reserve_location)
} }
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn explain_captures( fn explain_captures(
&mut self, &mut self,
err: &mut Diag<'_>, err: &mut Diag<'_>,

View File

@ -201,6 +201,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// For generic associated types (GATs) which implied 'static requirement // For generic associated types (GATs) which implied 'static requirement
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait // from higher-ranked trait bounds (HRTB). Try to locate span of the trait
// and the span which bounded to the trait for adding 'static lifetime suggestion // and the span which bounded to the trait for adding 'static lifetime suggestion
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn suggest_static_lifetime_for_gat_from_hrtb( fn suggest_static_lifetime_for_gat_from_hrtb(
&self, &self,
diag: &mut Diag<'_>, diag: &mut Diag<'_>,
@ -254,9 +256,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
hrtb_bounds.iter().for_each(|bound| { hrtb_bounds.iter().for_each(|bound| {
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; }; let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_note( diag.span_note(
*trait_span, *trait_span,
"due to current limitations in the borrow checker, this implies a `'static` lifetime" "due to current limitations in the borrow checker, this implies a `'static` lifetime"
@ -580,6 +579,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// executing... /// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure /// = note: ...therefore, returned references to captured variables will escape the closure
/// ``` /// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_fnmut_error( fn report_fnmut_error(
&self, &self,
errci: &ErrorConstraintInfo<'tcx>, errci: &ErrorConstraintInfo<'tcx>,
@ -761,6 +761,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
/// | is returning data with lifetime `'b` /// | is returning data with lifetime `'b`
/// ``` /// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> { fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'tcx> {
let ErrorConstraintInfo { let ErrorConstraintInfo {
fr, fr,
@ -822,6 +823,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a { /// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ``` /// ```
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add_static_impl_trait_suggestion( fn add_static_impl_trait_suggestion(
&self, &self,
diag: &mut Diag<'_>, diag: &mut Diag<'_>,
@ -972,6 +975,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty); self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
} }
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#[instrument(skip(self, err), level = "debug")] #[instrument(skip(self, err), level = "debug")]
fn suggest_constrain_dyn_trait_in_impl( fn suggest_constrain_dyn_trait_in_impl(
&self, &self,
@ -1034,6 +1039,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag); suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag);
} }
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) { fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
let map = self.infcx.tcx.hir(); let map = self.infcx.tcx.hir();
let body_id = map.body_owned_by(self.mir_def_id()); let body_id = map.body_owned_by(self.mir_def_id());

View File

@ -62,6 +62,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err( feature_err(
&ccx.tcx.sess, &ccx.tcx.sess,
@ -556,6 +557,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
Status::Unstable(sym::const_mut_refs) Status::Unstable(sym::const_mut_refs)
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err( feature_err(
&ccx.tcx.sess, &ccx.tcx.sess,
@ -589,6 +591,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
let mut err = feature_err( let mut err = feature_err(
&ccx.tcx.sess, &ccx.tcx.sess,
@ -632,6 +635,7 @@ pub mod ty {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err( feature_err(
&ccx.tcx.sess, &ccx.tcx.sess,

View File

@ -97,6 +97,7 @@ impl Expander {
/// **Note:** This function doesn't interpret argument 0 in any special way. /// **Note:** This function doesn't interpret argument 0 in any special way.
/// If this function is intended to be used with command line arguments, /// If this function is intended to be used with command line arguments,
/// `argv[0]` must be removed prior to calling it manually. /// `argv[0]` must be removed prior to calling it manually.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> { pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> {
let mut expander = Expander::default(); let mut expander = Expander::default();
for arg in at_args { for arg in at_args {

View File

@ -4,6 +4,7 @@
//! //!
//! This API is completely unstable and subject to change. //! This API is completely unstable and subject to change.
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]

View File

@ -598,6 +598,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// ///
/// In the meantime, though, callsites are required to deal with the "bug" /// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense. /// locally in whichever way makes the most sense.
#[rustc_lint_diagnostics]
#[track_caller] #[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) { pub fn downgrade_to_delayed_bug(&mut self) {
assert!( assert!(
@ -631,6 +632,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_labels, with_fn! { with_span_labels,
/// Labels all the given spans with the provided label. /// Labels all the given spans with the provided label.
/// See [`Self::span_label()`] for more information. /// See [`Self::span_label()`] for more information.
#[rustc_lint_diagnostics]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self { pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
for span in spans { for span in spans {
self.span_label(span, label.to_string()); self.span_label(span, label.to_string());
@ -638,6 +640,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self self
} } } }
#[rustc_lint_diagnostics]
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self { pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone(); let before = self.span.clone();
self.span(after); self.span(after);
@ -653,6 +656,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self self
} }
#[rustc_lint_diagnostics]
pub fn note_expected_found( pub fn note_expected_found(
&mut self, &mut self,
expected_label: &dyn fmt::Display, expected_label: &dyn fmt::Display,
@ -663,6 +667,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
} }
#[rustc_lint_diagnostics]
pub fn note_expected_found_extra( pub fn note_expected_found_extra(
&mut self, &mut self,
expected_label: &dyn fmt::Display, expected_label: &dyn fmt::Display,
@ -705,6 +710,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self self
} }
#[rustc_lint_diagnostics]
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![ self.highlighted_note(vec![
StringPart::normal(format!("`{name}` from trait: `")), StringPart::normal(format!("`{name}` from trait: `")),
@ -722,12 +728,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self self
} } } }
#[rustc_lint_diagnostics]
fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self { fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
self self
} }
/// This is like [`Diag::note()`], but it's only printed once. /// This is like [`Diag::note()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self { pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new()); self.sub(Level::OnceNote, msg, MultiSpan::new());
self self
@ -748,6 +756,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints the span with a note above it. /// Prints the span with a note above it.
/// This is like [`Diag::note_once()`], but it gets its own span. /// This is like [`Diag::note_once()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_note_once<S: Into<MultiSpan>>( pub fn span_note_once<S: Into<MultiSpan>>(
&mut self, &mut self,
sp: S, sp: S,
@ -786,12 +795,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} } } }
/// This is like [`Diag::help()`], but it's only printed once. /// This is like [`Diag::help()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self { pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceHelp, msg, MultiSpan::new()); self.sub(Level::OnceHelp, msg, MultiSpan::new());
self self
} }
/// Add a help message attached to this diagnostic with a customizable highlighted message. /// Add a help message attached to this diagnostic with a customizable highlighted message.
#[rustc_lint_diagnostics]
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self { pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Help, msg, MultiSpan::new()); self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
self self
@ -812,12 +823,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Disallow attaching suggestions this diagnostic. /// Disallow attaching suggestions this diagnostic.
/// Any suggestions attached e.g. with the `span_suggestion_*` methods /// Any suggestions attached e.g. with the `span_suggestion_*` methods
/// (before and after the call to `disable_suggestions`) will be ignored. /// (before and after the call to `disable_suggestions`) will be ignored.
#[rustc_lint_diagnostics]
pub fn disable_suggestions(&mut self) -> &mut Self { pub fn disable_suggestions(&mut self) -> &mut Self {
self.suggestions = Err(SuggestionsDisabled); self.suggestions = Err(SuggestionsDisabled);
self self
} }
/// Helper for pushing to `self.suggestions`, if available (not disable). /// Helper for pushing to `self.suggestions`, if available (not disable).
#[rustc_lint_diagnostics]
fn push_suggestion(&mut self, suggestion: CodeSuggestion) { fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions { for subst in &suggestion.substitutions {
for part in &subst.parts { for part in &subst.parts {
@ -838,6 +851,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_multipart_suggestion, with_fn! { with_multipart_suggestion,
/// Show a suggestion that has multiple parts to it. /// Show a suggestion that has multiple parts to it.
/// In other words, multiple changes need to be applied as part of this suggestion. /// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion( pub fn multipart_suggestion(
&mut self, &mut self,
msg: impl Into<SubdiagMessage>, msg: impl Into<SubdiagMessage>,
@ -854,6 +868,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic. /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic.
/// In other words, multiple changes need to be applied as part of this suggestion. /// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_verbose( pub fn multipart_suggestion_verbose(
&mut self, &mut self,
msg: impl Into<SubdiagMessage>, msg: impl Into<SubdiagMessage>,
@ -869,6 +884,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} }
/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. /// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_with_style( pub fn multipart_suggestion_with_style(
&mut self, &mut self,
msg: impl Into<SubdiagMessage>, msg: impl Into<SubdiagMessage>,
@ -911,6 +927,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant /// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability. /// improve understandability.
#[rustc_lint_diagnostics]
pub fn tool_only_multipart_suggestion( pub fn tool_only_multipart_suggestion(
&mut self, &mut self,
msg: impl Into<SubdiagMessage>, msg: impl Into<SubdiagMessage>,
@ -943,6 +960,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// * may contain a name of a function, variable, or type, but not whole expressions /// * may contain a name of a function, variable, or type, but not whole expressions
/// ///
/// See `CodeSuggestion` for more information. /// See `CodeSuggestion` for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion( pub fn span_suggestion(
&mut self, &mut self,
sp: Span, sp: Span,
@ -961,6 +979,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} } } }
/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`]. /// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn span_suggestion_with_style( pub fn span_suggestion_with_style(
&mut self, &mut self,
sp: Span, sp: Span,
@ -986,6 +1005,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestion_verbose, with_fn! { with_span_suggestion_verbose,
/// Always show the suggested change. /// Always show the suggested change.
#[rustc_lint_diagnostics]
pub fn span_suggestion_verbose( pub fn span_suggestion_verbose(
&mut self, &mut self,
sp: Span, sp: Span,
@ -1006,6 +1026,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestions, with_fn! { with_span_suggestions,
/// Prints out a message with multiple suggested edits of the code. /// Prints out a message with multiple suggested edits of the code.
/// See also [`Diag::span_suggestion()`]. /// See also [`Diag::span_suggestion()`].
#[rustc_lint_diagnostics]
pub fn span_suggestions( pub fn span_suggestions(
&mut self, &mut self,
sp: Span, sp: Span,
@ -1022,6 +1043,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
) )
} } } }
#[rustc_lint_diagnostics]
pub fn span_suggestions_with_style( pub fn span_suggestions_with_style(
&mut self, &mut self,
sp: Span, sp: Span,
@ -1052,6 +1074,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints out a message with multiple suggested edits of the code, where each edit consists of /// Prints out a message with multiple suggested edits of the code, where each edit consists of
/// multiple parts. /// multiple parts.
/// See also [`Diag::multipart_suggestion()`]. /// See also [`Diag::multipart_suggestion()`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestions( pub fn multipart_suggestions(
&mut self, &mut self,
msg: impl Into<SubdiagMessage>, msg: impl Into<SubdiagMessage>,
@ -1098,6 +1121,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// inline, it will only show the message and not the suggestion. /// inline, it will only show the message and not the suggestion.
/// ///
/// See `CodeSuggestion` for more information. /// See `CodeSuggestion` for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion_short( pub fn span_suggestion_short(
&mut self, &mut self,
sp: Span, sp: Span,
@ -1121,6 +1145,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant /// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability. /// improve understandability.
#[rustc_lint_diagnostics]
pub fn span_suggestion_hidden( pub fn span_suggestion_hidden(
&mut self, &mut self,
sp: Span, sp: Span,
@ -1165,6 +1190,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
/// interpolated variables). /// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic( pub fn subdiagnostic(
&mut self, &mut self,
dcx: &crate::DiagCtxt, dcx: &crate::DiagCtxt,
@ -1180,6 +1206,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span, with_fn! { with_span,
/// Add a span. /// Add a span.
#[rustc_lint_diagnostics]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self { pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into(); self.span = sp.into();
if let Some(span) = self.span.primary_span() { if let Some(span) = self.span.primary_span() {
@ -1188,6 +1215,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self self
} } } }
#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self { pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage }); self.is_lint = Some(IsLint { name, has_future_breakage });
self self
@ -1195,6 +1223,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_code, with_fn! { with_code,
/// Add an error code. /// Add an error code.
#[rustc_lint_diagnostics]
pub fn code(&mut self, code: ErrCode) -> &mut Self { pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code); self.code = Some(code);
self self
@ -1202,6 +1231,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_primary_message, with_fn! { with_primary_message,
/// Add a primary message. /// Add a primary message.
#[rustc_lint_diagnostics]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self { pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle); self.messages[0] = (msg.into(), Style::NoStyle);
self self
@ -1209,6 +1239,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_arg, with_fn! { with_arg,
/// Add an argument. /// Add an argument.
#[rustc_lint_diagnostics]
pub fn arg( pub fn arg(
&mut self, &mut self,
name: impl Into<DiagArgName>, name: impl Into<DiagArgName>,

View File

@ -1101,32 +1101,36 @@ impl DiagCtxt {
// Functions beginning with `struct_`/`create_` create a diagnostic. Other // Functions beginning with `struct_`/`create_` create a diagnostic. Other
// functions create and emit a diagnostic all in one go. // functions create and emit a diagnostic all in one go.
impl DiagCtxt { impl DiagCtxt {
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn struct_bug(&self, msg: impl Into<DiagMessage>) -> Diag<'_, BugAbort> { pub fn struct_bug(&self, msg: impl Into<Cow<'static, str>>) -> Diag<'_, BugAbort> {
Diag::new(self, Bug, msg) Diag::new(self, Bug, msg.into())
} }
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn bug(&self, msg: impl Into<DiagMessage>) -> ! { pub fn bug(&self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit() self.struct_bug(msg).emit()
} }
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn struct_span_bug( pub fn struct_span_bug(
&self, &self,
span: impl Into<MultiSpan>, span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>, msg: impl Into<Cow<'static, str>>,
) -> Diag<'_, BugAbort> { ) -> Diag<'_, BugAbort> {
self.struct_bug(msg).with_span(span) self.struct_bug(msg).with_span(span)
} }
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! { pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_span_bug(span, msg).emit() self.struct_span_bug(span, msg.into()).emit()
} }
#[track_caller] #[track_caller]
@ -1240,24 +1244,28 @@ impl DiagCtxt {
} }
/// Ensures that an error is printed. See `Level::DelayedBug`. /// Ensures that an error is printed. See `Level::DelayedBug`.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. //
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn delayed_bug(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed { pub fn delayed_bug(&self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit() Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
} }
/// Ensures that an error is printed. See `Level::DelayedBug`. /// Ensures that an error is printed. See `Level::DelayedBug`.
/// ///
/// Note: this function used to be called `delay_span_bug`. It was renamed /// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_err`, `span_warn`, etc. /// to match similar functions like `span_err`, `span_warn`, etc.
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. //
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller] #[track_caller]
pub fn span_delayed_bug( pub fn span_delayed_bug(
&self, &self,
sp: impl Into<MultiSpan>, sp: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>, msg: impl Into<Cow<'static, str>>,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit() Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
} }
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]

View File

@ -1493,6 +1493,8 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
}; };
if crate_matches { if crate_matches {
// FIXME: make this translatable
#[allow(rustc::untranslatable_diagnostic)]
sess.psess.buffer_lint_with_diagnostic( sess.psess.buffer_lint_with_diagnostic(
PROC_MACRO_BACK_COMPAT, PROC_MACRO_BACK_COMPAT,
item.ident.span, item.ident.span,

View File

@ -239,6 +239,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives a compiler warning when the `cfg_attr` contains no attributes and /// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of /// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect. /// the attribute is incorrect.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> { pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
let Some((cfg_predicate, expanded_attrs)) = let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(attr, &self.sess.psess) rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
@ -273,6 +274,7 @@ impl<'a> StripUnconfigured<'a> {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn expand_cfg_attr_item( fn expand_cfg_attr_item(
&self, &self,
attr: &Attribute, attr: &Attribute,
@ -371,6 +373,7 @@ impl<'a> StripUnconfigured<'a> {
} }
/// If attributes are not allowed on expressions, emit an error for `attr` /// If attributes are not allowed on expressions, emit an error for `attr`
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if self.features.is_some_and(|features| !features.stmt_expr_attributes) if self.features.is_some_and(|features| !features.stmt_expr_attributes)
@ -384,7 +387,6 @@ impl<'a> StripUnconfigured<'a> {
); );
if attr.is_doc_comment() { if attr.is_doc_comment() {
#[allow(rustc::untranslatable_diagnostic)]
err.help("`///` is for documentation comments. For a plain comment, use `//`."); err.help("`///` is for documentation comments. For a plain comment, use `//`.");
} }

View File

@ -783,6 +783,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}) })
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
let kind = match item { let kind = match item {
Annotatable::Item(_) Annotatable::Item(_)
@ -825,6 +826,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn visit_item(&mut self, item: &'ast ast::Item) { fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind { match &item.kind {
ItemKind::Mod(_, mod_kind) ItemKind::Mod(_, mod_kind)
@ -1689,6 +1691,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Detect use of feature-gated or invalid attributes on macro invocations // Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion. // since they will not be detected after macro expansion.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) { fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let features = self.cx.ecfg.features; let features = self.cx.ecfg.features;
let mut attrs = attrs.iter().peekable(); let mut attrs = attrs.iter().peekable();

View File

@ -5,6 +5,7 @@
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(macro_metavar_expr)] #![feature(macro_metavar_expr)]
#![feature(map_try_insert)] #![feature(map_try_insert)]
#![feature(proc_macro_diagnostic)] #![feature(proc_macro_diagnostic)]

View File

@ -517,6 +517,9 @@ impl server::FreeFunctions for Rustc<'_, '_> {
Diag::new(&self.psess().dcx, diagnostic.level.to_internal(), message); Diag::new(&self.psess().dcx, diagnostic.level.to_internal(), message);
diag.span(MultiSpan::from_spans(diagnostic.spans)); diag.span(MultiSpan::from_spans(diagnostic.spans));
for child in diagnostic.children { for child in diagnostic.children {
// This message comes from another diagnostic, and we are just reconstructing the
// diagnostic, so there's no need for translation.
#[allow(rustc::untranslatable_diagnostic)]
diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans)); diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans));
} }
diag.emit(); diag.emit();

View File

@ -178,6 +178,7 @@ impl<T: Write> Write for Shared<T> {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) { fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
create_default_session_globals_then(|| { create_default_session_globals_then(|| {
let (handler, source_map, output) = create_test_handler(); let (handler, source_map, output) = create_test_handler();
@ -192,7 +193,6 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
println!("text: {:?}", source_map.span_to_snippet(span)); println!("text: {:?}", source_map.span_to_snippet(span));
} }
#[allow(rustc::untranslatable_diagnostic)]
handler.span_err(msp, "foo"); handler.span_err(msp, "foo");
assert!( assert!(

View File

@ -695,8 +695,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Used by the `rustc::potential_query_instability` lint to warn methods which // Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation. // might not be stable during incremental compilation.
rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
// Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
// to assist in changes to diagnostic APIs. // APIs. Any function with this attribute will be checked by that lint.
rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future). // types (as well as any others in future).

View File

@ -320,6 +320,7 @@ pub struct Config {
// JUSTIFICATION: before session exists, only config // JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)] #[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
trace!("run_compiler"); trace!("run_compiler");

View File

@ -160,6 +160,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
}) })
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn { fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
match unsafe { load_symbol_from_dylib::<MakeBackendFn>(path, "__rustc_codegen_backend") } { match unsafe { load_symbol_from_dylib::<MakeBackendFn>(path, "__rustc_codegen_backend") } {
Ok(backend_sym) => backend_sym, Ok(backend_sym) => backend_sym,
@ -227,6 +228,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
}) })
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn get_codegen_sysroot( fn get_codegen_sysroot(
early_dcx: &EarlyDiagCtxt, early_dcx: &EarlyDiagCtxt,
maybe_sysroot: &Option<PathBuf>, maybe_sysroot: &Option<PathBuf>,
@ -319,6 +321,7 @@ fn get_codegen_sysroot(
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub(crate) fn check_attr_crate_type( pub(crate) fn check_attr_crate_type(
sess: &Session, sess: &Session,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],

View File

@ -621,12 +621,13 @@ pub trait LintContext {
/// Note that this function should only be called for [`LintExpectationId`]s /// Note that this function should only be called for [`LintExpectationId`]s
/// retrieved from the current lint pass. Buffered or manually created ids can /// retrieved from the current lint pass. Buffered or manually created ids can
/// cause ICEs. /// cause ICEs.
#[rustc_lint_diagnostics]
fn fulfill_expectation(&self, expectation: LintExpectationId) { fn fulfill_expectation(&self, expectation: LintExpectationId) {
// We need to make sure that submitted expectation ids are correctly fulfilled suppressed // We need to make sure that submitted expectation ids are correctly fulfilled suppressed
// and stored between compilation sessions. To not manually do these steps, we simply create // and stored between compilation sessions. To not manually do these steps, we simply create
// a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal // a dummy diagnostic and emit it as usual, which will be suppressed and stored like a
// expected lint diagnostic. // normal expected lint diagnostic.
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
self.sess() self.sess()
.dcx() .dcx()
.struct_expect( .struct_expect(

View File

@ -10,7 +10,7 @@ use rustc_ast as ast;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
use rustc_middle::ty; use rustc_middle::ty::{self, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
@ -338,10 +338,11 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
} }
declare_tool_lint! { declare_tool_lint! {
/// The `untranslatable_diagnostic` lint detects diagnostics created /// The `untranslatable_diagnostic` lint detects messages passed to functions with `impl
/// without using translatable Fluent strings. /// 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). /// More details on translatable diagnostics can be found
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
pub rustc::UNTRANSLATABLE_DIAGNOSTIC, pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
Deny, Deny,
"prevent creation of diagnostics which cannot be translated", "prevent creation of diagnostics which cannot be translated",
@ -349,11 +350,13 @@ declare_tool_lint! {
} }
declare_tool_lint! { declare_tool_lint! {
/// The `diagnostic_outside_of_impl` lint detects diagnostics created manually, /// The `diagnostic_outside_of_impl` lint detects calls to functions annotated with
/// and inside an `IntoDiagnostic`/`AddToDiagnostic` implementation, /// `#[rustc_lint_diagnostics]` that are outside an `IntoDiagnostic`, `AddToDiagnostic`, or
/// or a `#[derive(Diagnostic)]`/`#[derive(Subdiagnostic)]` expansion. /// `DecorateLint` impl, or a `#[derive(Diagnostic)]`, `#[derive(Subdiagnostic)]`,
/// `#[derive(DecorateLint)]` expansion.
/// ///
/// More details on diagnostics implementations can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html). /// 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, pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
Deny, Deny,
"prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls", "prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls",
@ -364,54 +367,130 @@ declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE
impl LateLintPass<'_> for Diagnostics { impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; // Only check function calls and method calls.
debug!(?span, ?def_id, ?args); let (span, def_id, fn_gen_args, call_tys) = match expr.kind {
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) ExprKind::Call(callee, args) => {
match cx.typeck_results().node_type(callee.hir_id).kind() {
&ty::FnDef(def_id, fn_gen_args) => {
let call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
(callee.span, def_id, fn_gen_args, call_tys)
}
_ => return, // occurs for fns passed as args
}
}
ExprKind::MethodCall(segment, _recv, args, _span) => {
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
let fn_gen_args = cx.typeck_results().node_args(expr.hir_id);
let mut call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
(segment.ident.span, def_id, fn_gen_args, call_tys)
}
_ => return,
};
// Is the callee marked with `#[rustc_lint_diagnostics]`?
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
.ok() .ok()
.flatten() .flatten()
.is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics)); .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
if !has_attr {
return;
}
let mut found_parent_with_attr = false; // Closure: is the type `{D,Subd}iagMessage`?
let mut found_impl = false; let is_diag_message = |ty: MiddleTy<'_>| {
for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
if let Some(owner_did) = hir_id.as_owner() {
found_parent_with_attr = found_parent_with_attr
|| cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics);
}
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint)
{
found_impl = true;
break;
}
}
debug!(?found_impl);
if !found_parent_with_attr && !found_impl {
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
}
let mut found_diagnostic_message = false;
for ty in args.types() {
debug!(?ty);
if let Some(adt_def) = ty.ty_adt_def() if let Some(adt_def) = ty.ty_adt_def()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage) && matches!(name, sym::DiagMessage | sym::SubdiagMessage)
{ {
found_diagnostic_message = true; true
} else {
false
}
};
// Does the callee have a `impl Into<{D,Subd}iagMessage>` parameter? (There should be at
// most one.)
let mut impl_into_diagnostic_message_param = None;
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, &param_ty) in fn_sig.inputs().iter().enumerate() {
if let ty::Param(p) = 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)
&& is_diag_message(ty1)
{
if impl_into_diagnostic_message_param.is_some() {
cx.tcx.dcx().span_bug(
span,
"can't handle multiple `impl Into<{D,Sub}iagMessage>` params",
);
}
impl_into_diagnostic_message_param = Some((i, p.name));
}
}
}
}
// Is the callee interesting?
if !has_attr && impl_into_diagnostic_message_param.is_none() {
return;
}
// Is the parent method marked with `#[rustc_lint_diagnostics]`?
let mut parent_has_attr = false;
for (hir_id, _parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
if let Some(owner_did) = hir_id.as_owner()
&& cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics)
{
parent_has_attr = true;
break; break;
} }
} }
debug!(?found_diagnostic_message);
if !found_parent_with_attr && !found_diagnostic_message { // Calls to `#[rustc_lint_diagnostics]`-marked functions should only occur:
cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag); // - inside an impl of `IntoDiagnostic`, `AddToDiagnostic`, or `DecorateLint`, or
// - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`.
//
// Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
if has_attr && !parent_has_attr {
let mut is_inside_appropriate_impl = false;
for (_hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(
name,
sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint
)
{
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);
}
}
// 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.
if let Some((param_i, param_i_p_name)) = impl_into_diagnostic_message_param {
// Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
let arg_ty = call_tys[param_i];
let is_translatable = is_diag_message(arg_ty)
|| matches!(arg_ty.kind(), ty::Param(p) if p.name == param_i_p_name);
if !is_translatable {
cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
}
} }
} }
} }
@ -425,7 +504,7 @@ declare_tool_lint! {
report_in_external_macro: true report_in_external_macro: true
} }
declare_lint_pass!(BadOptAccess => [ BAD_OPT_ACCESS ]); declare_lint_pass!(BadOptAccess => [BAD_OPT_ACCESS]);
impl LateLintPass<'_> for BadOptAccess { impl LateLintPass<'_> for BadOptAccess {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {

View File

@ -104,6 +104,7 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
]; ];
impl<'tcx> LateLintPass<'tcx> for LetUnderscore { impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
if matches!(local.source, rustc_hir::LocalSource::AsyncFn) { if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
return; return;

View File

@ -724,6 +724,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
}; };
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) { fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) {
let sess = self.sess; let sess = self.sess;
for (attr_index, attr) in attrs.iter().enumerate() { for (attr_index, attr) in attrs.iter().enumerate() {

View File

@ -947,6 +947,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn report_unused_deps(&mut self, krate: &ast::Crate) { fn report_unused_deps(&mut self, krate: &ast::Crate) {
// Make a point span rather than covering the whole file // Make a point span rather than covering the whole file
let span = krate.spans.inner_span.shrink_to_lo(); let span = krate.spans.inner_span.shrink_to_lo();

View File

@ -93,6 +93,7 @@ struct Collector<'tcx> {
} }
impl<'tcx> Collector<'tcx> { impl<'tcx> Collector<'tcx> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn process_module(&mut self, module: &ForeignModule) { fn process_module(&mut self, module: &ForeignModule) {
let ForeignModule { def_id, abi, ref foreign_items } = *module; let ForeignModule { def_id, abi, ref foreign_items } = *module;
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();

View File

@ -17,6 +17,7 @@ use rustc_target::abi::call::FnAbi;
use rustc_target::abi::*; use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
use std::borrow::Cow;
use std::cmp; use std::cmp;
use std::fmt; use std::fmt;
use std::num::NonZero; use std::num::NonZero;
@ -268,7 +269,7 @@ pub struct LayoutCx<'tcx, C> {
impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
type TargetDataLayoutRef = &'tcx TargetDataLayout; type TargetDataLayoutRef = &'tcx TargetDataLayout;
fn delayed_bug(&self, txt: String) { fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
self.tcx.dcx().delayed_bug(txt); self.tcx.dcx().delayed_bug(txt);
} }

View File

@ -13,7 +13,7 @@ use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use crate::ty::{List, ParamEnv}; use crate::ty::{List, ParamEnv};
use hir::def::DefKind; use hir::def::DefKind;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_errors::{DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan}; use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::LangItem; use rustc_hir::LangItem;
@ -1543,7 +1543,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_error_with_message<S: Into<MultiSpan>>( pub fn new_error_with_message<S: Into<MultiSpan>>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
span: S, span: S,
msg: impl Into<DiagMessage>, msg: impl Into<Cow<'static, str>>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let reported = tcx.dcx().span_delayed_bug(span, msg); let reported = tcx.dcx().span_delayed_bug(span, msg);
Ty::new(tcx, Error(reported)) Ty::new(tcx, Error(reported))

View File

@ -1074,6 +1074,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
/// of one item. Read the documentation of [`check_doc_inline`] for more information. /// of one item. Read the documentation of [`check_doc_inline`] for more information.
/// ///
/// [`check_doc_inline`]: Self::check_doc_inline /// [`check_doc_inline`]: Self::check_doc_inline
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_doc_attrs( fn check_doc_attrs(
&self, &self,
attr: &Attribute, attr: &Attribute,
@ -1756,6 +1757,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
/// Checks if the `#[repr]` attributes on `item` are valid. /// Checks if the `#[repr]` attributes on `item` are valid.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_repr( fn check_repr(
&self, &self,
attrs: &[Attribute], attrs: &[Attribute],
@ -2328,6 +2330,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id); let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
if let Some(hir_sig) = hir_sig { if let Some(hir_sig) = hir_sig {
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
match terr { match terr {
TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => { TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
if let Some(ty) = hir_sig.decl.inputs.get(idx) { if let Some(ty) = hir_sig.decl.inputs.get(idx) {

View File

@ -77,6 +77,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
} }
/// Emits an error when an unsupported expression is found in a const context. /// Emits an error when an unsupported expression is found in a const context.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn const_check_violated(&self, expr: NonConstExpr, span: Span) { fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
let Self { tcx, def_id, const_kind } = *self; let Self { tcx, def_id, const_kind } = *self;

View File

@ -114,6 +114,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
} }
} }
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
if let Some((def_id, _)) = visitor.start_fn { if let Some((def_id, _)) = visitor.start_fn {
Some((def_id.to_def_id(), EntryFnType::Start)) Some((def_id.to_def_id(), EntryFnType::Start))

View File

@ -1,6 +1,8 @@
//! Contains infrastructure for configuring the compiler, including parsing //! Contains infrastructure for configuring the compiler, including parsing
//! command-line options. //! command-line options.
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub use crate::options::*; pub use crate::options::*;
use crate::errors::FileWriteFail; use crate::errors::FileWriteFail;
@ -2468,9 +2470,7 @@ pub fn parse_externs(
)); ));
let adjusted_name = name.replace('-', "_"); let adjusted_name = name.replace('-', "_");
if is_ascii_ident(&adjusted_name) { if is_ascii_ident(&adjusted_name) {
// FIXME: make this translatable #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
error.help(format!( error.help(format!(
"consider replacing the dashes with underscores: `{adjusted_name}`" "consider replacing the dashes with underscores: `{adjusted_name}`"
)); ));

View File

@ -320,6 +320,7 @@ macro_rules! redirect_field {
type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool; type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)]; type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_options<O: Default>( fn build_options<O: Default>(
early_dcx: &EarlyDiagCtxt, early_dcx: &EarlyDiagCtxt,
matches: &getopts::Matches, matches: &getopts::Matches,

View File

@ -168,6 +168,7 @@ pub fn add_feature_diagnostics<G: EmissionGuarantee>(
/// This variant allows you to control whether it is a library or language feature. /// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer /// Almost always, you want to use this for a language feature. If so, prefer
/// `add_feature_diagnostics`. /// `add_feature_diagnostics`.
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
err: &mut Diag<'_, G>, err: &mut Diag<'_, G>,
sess: &Session, sess: &Session,

View File

@ -61,6 +61,7 @@ impl SearchPath {
(PathKind::All, path) (PathKind::All, path)
}; };
if path.is_empty() { if path.is_empty() {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
early_dcx.early_fatal("empty search path given via `-L`"); early_dcx.early_fatal("empty search path given via `-L`");
} }

View File

@ -312,6 +312,7 @@ impl Session {
) -> Diag<'a> { ) -> Diag<'a> {
let mut err = self.dcx().create_err(err); let mut err = self.dcx().create_err(err);
if err.code.is_none() { if err.code.is_none() {
#[allow(rustc::diagnostic_outside_of_impl)]
err.code(E0658); err.code(E0658);
} }
add_feature_diagnostics(&mut err, self, feature); add_feature_diagnostics(&mut err, self, feature);
@ -1022,6 +1023,7 @@ fn default_emitter(
// JUSTIFICATION: literally session construction // JUSTIFICATION: literally session construction
#[allow(rustc::bad_opt_access)] #[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn build_session( pub fn build_session(
early_dcx: EarlyDiagCtxt, early_dcx: EarlyDiagCtxt,
sopts: config::Options, sopts: config::Options,

View File

@ -1,5 +1,6 @@
//! Compute the binary representation of a type //! Compute the binary representation of a type
use std::borrow::Cow;
use std::fmt; use std::fmt;
use base_db::salsa::Cycle; use base_db::salsa::Cycle;
@ -114,8 +115,8 @@ struct LayoutCx<'a> {
impl<'a> LayoutCalculator for LayoutCx<'a> { impl<'a> LayoutCalculator for LayoutCx<'a> {
type TargetDataLayoutRef = &'a TargetDataLayout; type TargetDataLayoutRef = &'a TargetDataLayout;
fn delayed_bug(&self, txt: String) { fn delayed_bug(&self, txt: impl Into<Cow<'static, str>>) {
never!("{}", txt); never!("{}", txt.into());
} }
fn current_data_layout(&self) -> &'a TargetDataLayout { fn current_data_layout(&self) -> &'a TargetDataLayout {

View File

@ -360,6 +360,7 @@ mod tests {
} }
fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> DiagInner { fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> DiagInner {
#[allow(rustc::untranslatable_diagnostic)] // no translation needed for empty string
let mut diag = DiagInner::new(level, ""); let mut diag = DiagInner::new(level, "");
diag.messages.clear(); diag.messages.clear();
if let Some(span) = span { if let Some(span) = span {

View File

@ -14,8 +14,8 @@ extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use rustc_errors::{ use rustc_errors::{
AddToDiagnostic, Diag, EmissionGuarantee, DiagCtxt, IntoDiagnostic, Level, AddToDiagnostic, DecorateLint, Diag, DiagCtxt, DiagInner, DiagMessage, EmissionGuarantee,
SubdiagMessageOp, IntoDiagnostic, Level, SubdiagMessageOp,
}; };
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span; use rustc_span::Span;
@ -78,6 +78,31 @@ impl AddToDiagnostic for TranslatableInAddToDiagnostic {
} }
} }
pub struct UntranslatableInDecorateLint;
impl<'a> DecorateLint<'a, ()> for UntranslatableInDecorateLint {
fn decorate_lint<'b, >(self, diag: &'b mut Diag<'a, ()>) {
diag.note("untranslatable diagnostic");
//~^ ERROR diagnostics should be created using translatable messages
}
fn msg(&self) -> DiagMessage {
unreachable!();
}
}
pub struct TranslatableInDecorateLint;
impl<'a> DecorateLint<'a, ()> for TranslatableInDecorateLint {
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
diag.note(crate::fluent_generated::no_crate_note);
}
fn msg(&self) -> DiagMessage {
unreachable!();
}
}
pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) {
let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
//~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls //~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
@ -87,9 +112,11 @@ pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) {
//~^^ ERROR diagnostics should be created using translatable messages //~^^ ERROR diagnostics should be created using translatable messages
} }
// Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted. // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted for
// `diagnostic_outside_of_impl`.
#[rustc_lint_diagnostics] #[rustc_lint_diagnostics]
pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) { pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) {
#[allow(rustc::untranslatable_diagnostic)]
let _diag = dcx.struct_err("untranslatable diagnostic"); // okay! let _diag = dcx.struct_err("untranslatable diagnostic"); // okay!
} }

View File

@ -16,8 +16,14 @@ error: diagnostics should be created using translatable messages
LL | diag.note("untranslatable diagnostic"); LL | diag.note("untranslatable diagnostic");
| ^^^^ | ^^^^
error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:85:14
|
LL | diag.note("untranslatable diagnostic");
| ^^^^
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
--> $DIR/diagnostics.rs:82:21 --> $DIR/diagnostics.rs:107:21
| |
LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^ | ^^^^^^^^^^
@ -29,16 +35,16 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
--> $DIR/diagnostics.rs:85:21 --> $DIR/diagnostics.rs:110:21
| |
LL | let _diag = dcx.struct_err("untranslatable diagnostic"); LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^ | ^^^^^^^^^^
error: diagnostics should be created using translatable messages error: diagnostics should be created using translatable messages
--> $DIR/diagnostics.rs:85:21 --> $DIR/diagnostics.rs:110:21
| |
LL | let _diag = dcx.struct_err("untranslatable diagnostic"); LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^ | ^^^^^^^^^^
error: aborting due to 5 previous errors error: aborting due to 6 previous errors