From ad5d7f43c95e09f1e0efed8673d8a515d0f2054a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 13 Feb 2024 17:27:24 +1100 Subject: [PATCH] Overhaul `rustc_codegen_ssa::back::write::Diagnostic`. - Make it more closely match `rustc_errors::Diagnostic`, by making the field names match, and adding `children`, which requires adding `rustc_codegen_ssa::back::write::Subdiagnostic`. - Check that we aren't missing important info when converting diagnostics. - Add better comments. - Tweak `rustc_errors::Diagnostic::replace_args` so that we don't need to do any cloning when converting diagnostics. --- compiler/rustc_codegen_ssa/src/back/write.rs | 80 ++++++++++++++------ tests/ui/lto/issue-11154.stderr | 4 +- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0258d1d493d..54831265691 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -17,7 +17,7 @@ use rustc_errors::translation::Translate; use rustc_errors::{ DiagCtxt, DiagnosticArgMap, DiagnosticBuilder, DiagnosticMessage, ErrCode, FatalError, - FluentBundle, Level, Style, + FluentBundle, Level, MultiSpan, Style, }; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -999,11 +999,29 @@ pub(crate) enum Message { /// process another codegen unit. pub struct CguMessage; +// A cut-down version of `rustc_errors::Diagnostic` that impls `Send`, which +// can be used to send diagnostics from codegen threads to the main thread. +// It's missing the following fields from `rustc_errors::Diagnostic`. +// - `span`: it doesn't impl `Send`. +// - `suggestions`: it doesn't impl `Send`, and isn't used for codegen +// diagnostics. +// - `sort_span`: it doesn't impl `Send`. +// - `is_lint`: lints aren't relevant during codegen. +// - `emitted_at`: not used for codegen diagnostics. struct Diagnostic { - msgs: Vec<(DiagnosticMessage, Style)>, - args: DiagnosticArgMap, + level: Level, + messages: Vec<(DiagnosticMessage, Style)>, code: Option, - lvl: Level, + children: Vec, + args: DiagnosticArgMap, +} + +// A cut-down version of `rustc_errors::SubDiagnostic` that impls `Send`. It's +// missing the following fields from `rustc_errors::SubDiagnostic`. +// - `span`: it doesn't impl `Send`. +pub struct Subdiagnostic { + level: Level, + messages: Vec<(DiagnosticMessage, Style)>, } #[derive(PartialEq, Clone, Copy, Debug)] @@ -1812,23 +1830,29 @@ fn fallback_fluent_bundle(&self) -> &FluentBundle { } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) { - let args: DiagnosticArgMap = - diag.args.iter().map(|(name, arg)| (name.clone(), arg.clone())).collect(); - drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msgs: diag.messages.clone(), - args: args.clone(), - code: diag.code, - lvl: diag.level(), - }))); - for child in &diag.children { - drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { - msgs: child.messages.clone(), - args: args.clone(), - code: None, - lvl: child.level, - }))); - } + fn emit_diagnostic(&mut self, mut diag: rustc_errors::Diagnostic) { + // Check that we aren't missing anything interesting when converting to + // the cut-down local `Diagnostic`. + assert_eq!(diag.span, MultiSpan::new()); + assert_eq!(diag.suggestions, Ok(vec![])); + assert_eq!(diag.sort_span, rustc_span::DUMMY_SP); + assert_eq!(diag.is_lint, None); + // No sensible check for `diag.emitted_at`. + + let args = mem::replace(&mut diag.args, DiagnosticArgMap::default()); + drop( + self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { + level: diag.level(), + messages: diag.messages, + code: diag.code, + children: diag + .children + .into_iter() + .map(|child| Subdiagnostic { level: child.level, messages: child.messages }) + .collect(), + args, + })), + ); drop(self.sender.send(SharedEmitterMessage::AbortIfErrors)); } @@ -1854,9 +1878,21 @@ pub fn check(&self, sess: &Session, blocking: bool) { match message { Ok(SharedEmitterMessage::Diagnostic(diag)) => { + // The diagnostic has been received on the main thread. + // Convert it back to a full `Diagnostic` and emit. let dcx = sess.dcx(); - let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msgs); + let mut d = + rustc_errors::Diagnostic::new_with_messages(diag.level, diag.messages); d.code = diag.code; // may be `None`, that's ok + d.children = diag + .children + .into_iter() + .map(|sub| rustc_errors::SubDiagnostic { + level: sub.level, + messages: sub.messages, + span: MultiSpan::new(), + }) + .collect(); d.args = diag.args; dcx.emit_diagnostic(d); } diff --git a/tests/ui/lto/issue-11154.stderr b/tests/ui/lto/issue-11154.stderr index 4d52f6c0f3d..9f5d7518982 100644 --- a/tests/ui/lto/issue-11154.stderr +++ b/tests/ui/lto/issue-11154.stderr @@ -1,6 +1,6 @@ error: cannot prefer dynamic linking when performing LTO - -note: only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO + | + = note: only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO error: aborting due to 1 previous error