Convert to inline diagnostics in rustc_errors

This commit is contained in:
Jonathan Brouwer 2026-02-04 16:27:09 +01:00
parent 0a13b43612
commit e55eb45661
No known key found for this signature in database
GPG key ID: F13E55D38C971DEF
8 changed files with 45 additions and 79 deletions

View file

@ -3846,7 +3846,6 @@ dependencies = [
"rustc_data_structures", "rustc_data_structures",
"rustc_error_codes", "rustc_error_codes",
"rustc_error_messages", "rustc_error_messages",
"rustc_fluent_macro",
"rustc_hashes", "rustc_hashes",
"rustc_index", "rustc_index",
"rustc_lint_defs", "rustc_lint_defs",

View file

@ -118,7 +118,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
rustc_borrowck::DEFAULT_LOCALE_RESOURCE, rustc_borrowck::DEFAULT_LOCALE_RESOURCE,
rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE, rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE,
rustc_const_eval::DEFAULT_LOCALE_RESOURCE, rustc_const_eval::DEFAULT_LOCALE_RESOURCE,
rustc_errors::DEFAULT_LOCALE_RESOURCE,
rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE, rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE,
rustc_lint::DEFAULT_LOCALE_RESOURCE, rustc_lint::DEFAULT_LOCALE_RESOURCE,
rustc_middle::DEFAULT_LOCALE_RESOURCE, rustc_middle::DEFAULT_LOCALE_RESOURCE,

View file

@ -14,7 +14,6 @@ rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" }
rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_codes = { path = "../rustc_error_codes" }
rustc_error_messages = { path = "../rustc_error_messages" } rustc_error_messages = { path = "../rustc_error_messages" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hashes = { path = "../rustc_hashes" } rustc_hashes = { path = "../rustc_hashes" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_lint_defs = { path = "../rustc_lint_defs" }

View file

@ -1,48 +0,0 @@
errors_delayed_at_with_newline =
delayed at {$emitted_at}
{$note}
errors_delayed_at_without_newline =
delayed at {$emitted_at} - {$note}
errors_expected_lifetime_parameter =
expected lifetime {$count ->
[1] parameter
*[other] parameters
}
errors_indicate_anonymous_lifetime =
indicate the anonymous {$count ->
[1] lifetime
*[other] lifetimes
}
errors_invalid_flushed_delayed_diagnostic_level =
`flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug`
errors_target_inconsistent_architecture =
inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
errors_target_inconsistent_pointer_width =
inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
errors_target_invalid_address_space =
invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
errors_target_invalid_alignment =
invalid alignment for `{$cause}` in "data-layout": `{$align}` is {$err_kind ->
[not_power_of_two] not a power of 2
[too_large] too large
*[other] {""}
}
errors_target_invalid_bits =
invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
errors_target_invalid_bits_size = {$err}
errors_target_invalid_datalayout_pointer_spec =
unknown pointer specification `{$err}` in datalayout string
errors_target_missing_alignment =
missing alignment for `{$cause}` in "data-layout"

View file

@ -7,8 +7,7 @@ use rustc_span::{Span, Symbol};
use crate::diagnostic::DiagLocation; use crate::diagnostic::DiagLocation;
use crate::{ use crate::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, inline_fluent,
fluent_generated as fluent,
}; };
impl IntoDiagArg for DiagLocation { impl IntoDiagArg for DiagLocation {
@ -44,43 +43,48 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
match self { match self {
TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
Diag::new(dcx, level, fluent::errors_target_invalid_address_space) Diag::new(dcx, level, inline_fluent!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("addr_space", addr_space) .with_arg("addr_space", addr_space)
.with_arg("cause", cause) .with_arg("cause", cause)
.with_arg("err", err) .with_arg("err", err)
} }
TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
Diag::new(dcx, level, fluent::errors_target_invalid_bits) Diag::new(dcx, level, inline_fluent!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("kind", kind) .with_arg("kind", kind)
.with_arg("bit", bit) .with_arg("bit", bit)
.with_arg("cause", cause) .with_arg("cause", cause)
.with_arg("err", err) .with_arg("err", err)
} }
TargetDataLayoutErrors::MissingAlignment { cause } => { TargetDataLayoutErrors::MissingAlignment { cause } => {
Diag::new(dcx, level, fluent::errors_target_missing_alignment) Diag::new(dcx, level, inline_fluent!("missing alignment for `{$cause}` in \"data-layout\""))
.with_arg("cause", cause) .with_arg("cause", cause)
} }
TargetDataLayoutErrors::InvalidAlignment { cause, err } => { TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
Diag::new(dcx, level, fluent::errors_target_invalid_alignment) Diag::new(dcx, level, inline_fluent!("invalid alignment for `{$cause}` in \"data-layout\": `{$align}` is {$err_kind ->
.with_arg("cause", cause) [not_power_of_two] not a power of 2
.with_arg("err_kind", err.diag_ident()) [too_large] too large
.with_arg("align", err.align()) *[other] {\"\"}
}"))
.with_arg("cause", cause)
.with_arg("err_kind", err.diag_ident())
.with_arg("align", err.align())
} }
TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
Diag::new(dcx, level, fluent::errors_target_inconsistent_architecture) Diag::new(dcx, level, inline_fluent!(
.with_arg("dl", dl) "inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"
.with_arg("target", target) ))
.with_arg("dl", dl).with_arg("target", target)
} }
TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
Diag::new(dcx, level, fluent::errors_target_inconsistent_pointer_width) Diag::new(dcx, level, inline_fluent!(
.with_arg("pointer_size", pointer_size) "inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"
.with_arg("target", target) )).with_arg("pointer_size", pointer_size).with_arg("target", target)
} }
TargetDataLayoutErrors::InvalidBitsSize { err } => { TargetDataLayoutErrors::InvalidBitsSize { err } => {
Diag::new(dcx, level, fluent::errors_target_invalid_bits_size).with_arg("err", err) Diag::new(dcx, level, inline_fluent!("{$err}")).with_arg("err", err)
} }
TargetDataLayoutErrors::UnknownPointerSpecification { err } => { TargetDataLayoutErrors::UnknownPointerSpecification { err } => {
Diag::new(dcx, level, fluent::errors_target_invalid_datalayout_pointer_spec) Diag::new(dcx, level, inline_fluent!("unknown pointer specification `{$err}` in datalayout string"))
.with_arg("err", err) .with_arg("err", err)
} }
} }
@ -99,7 +103,12 @@ impl Subdiagnostic for SingleLabelManySpans {
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[label(errors_expected_lifetime_parameter)] #[label(
"expected lifetime {$count ->
[1] parameter
*[other] parameters
}"
)]
pub struct ExpectedLifetimeParameter { pub struct ExpectedLifetimeParameter {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
@ -107,7 +116,14 @@ pub struct ExpectedLifetimeParameter {
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")] #[suggestion(
"indicate the anonymous {$count ->
[1] lifetime
*[other] lifetimes
}",
code = "{suggestion}",
style = "verbose"
)]
pub struct IndicateAnonymousLifetime { pub struct IndicateAnonymousLifetime {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,

View file

@ -45,8 +45,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
rustc_span::create_default_session_globals_then(|| { rustc_span::create_default_session_globals_then(|| {
let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
sm.new_source_file(filename(&sm, "test.rs"), code.to_owned()); sm.new_source_file(filename(&sm, "test.rs"), code.to_owned());
let translator = let translator = Translator::with_fallback_bundle(vec![], false);
Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
let output = Arc::new(Mutex::new(Vec::new())); let output = Arc::new(Mutex::new(Vec::new()));
let je = JsonEmitter::new( let je = JsonEmitter::new(

View file

@ -92,8 +92,6 @@ pub mod translation;
pub type PResult<'a, T> = Result<T, Diag<'a>>; pub type PResult<'a, T> = Result<T, Diag<'a>>;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24); rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
@ -1531,7 +1529,9 @@ impl DiagCtxtInner {
// the usual `Diag`/`DiagCtxt` level, so we must augment `bug` // the usual `Diag`/`DiagCtxt` level, so we must augment `bug`
// in a lower-level fashion. // in a lower-level fashion.
bug.arg("level", bug.level); bug.arg("level", bug.level);
let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level; let msg = inline_fluent!(
"`flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug`"
);
let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call
bug.sub(Note, msg, bug.span.primary_span().unwrap().into()); bug.sub(Note, msg, bug.span.primary_span().unwrap().into());
} }
@ -1573,10 +1573,13 @@ impl DelayedDiagInner {
// lower-level fashion. // lower-level fashion.
let mut diag = self.inner; let mut diag = self.inner;
let msg = match self.note.status() { let msg = match self.note.status() {
BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline, BacktraceStatus::Captured => inline_fluent!(
"delayed at {$emitted_at}
{$note}"
),
// Avoid the needless newline when no backtrace has been captured, // Avoid the needless newline when no backtrace has been captured,
// the display impl should just be a single line. // the display impl should just be a single line.
_ => crate::fluent_generated::errors_delayed_at_without_newline, _ => inline_fluent!("delayed at {$emitted_at} - {$note}"),
}; };
diag.arg("emitted_at", diag.emitted_at.clone()); diag.arg("emitted_at", diag.emitted_at.clone());
diag.arg("note", self.note); diag.arg("note", self.note);

View file

@ -1432,8 +1432,7 @@ impl EarlyDiagCtxt {
fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> { fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
// FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
// need to reference every crate that might emit an early error for translation to work. // need to reference every crate that might emit an early error for translation to work.
let translator = let translator = Translator::with_fallback_bundle(vec![], false);
Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
let emitter: Box<DynEmitter> = match output { let emitter: Box<DynEmitter> = match output {
config::ErrorOutputType::HumanReadable { kind, color_config } => match kind { config::ErrorOutputType::HumanReadable { kind, color_config } => match kind {
HumanReadableErrorType { short, unicode } => Box::new( HumanReadableErrorType { short, unicode } => Box::new(