about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-22 08:01:37 +0000
committerbors <bors@rust-lang.org>2024-02-22 08:01:37 +0000
commitf70f19fef41cfdda75c92f163434c29ad046cf09 (patch)
treef781338fb3f2e285e13f5cdb5478e8cacaebd093 /compiler/rustc_codegen_ssa/src
parent026b3b8e955e0571db39aa96fc9d7aba25cc4d66 (diff)
parent6efffd723bc87f3a577f4f52fcffb6335406e9cb (diff)
downloadrust-f70f19fef41cfdda75c92f163434c29ad046cf09.tar.gz
rust-f70f19fef41cfdda75c92f163434c29ad046cf09.zip
Auto merge of #121129 - nnethercote:codegen-Diags, r=estebank
Improve codegen diagnostic handling

Clarify the workings of the temporary `Diagnostic` type used to send diagnostics from codegen threads to the main thread.

r? `@estebank`
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs90
1 files changed, 61 insertions, 29 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 7a981217b52..c2fc32130ea 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -16,8 +16,8 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
 use rustc_errors::translation::Translate;
 use rustc_errors::{
-    DiagCtxt, DiagnosticArgName, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrCode,
-    FatalError, FluentBundle, Level, Style,
+    DiagCtxt, DiagnosticArgMap, DiagnosticBuilder, DiagnosticMessage, ErrCode, FatalError,
+    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<B: WriteBackendMethods> {
 /// 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: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>,
+    level: Level,
+    messages: Vec<(DiagnosticMessage, Style)>,
     code: Option<ErrCode>,
-    lvl: Level,
+    children: Vec<Subdiagnostic>,
+    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)]
@@ -1766,7 +1784,6 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
 enum SharedEmitterMessage {
     Diagnostic(Diagnostic),
     InlineAsmError(u32, String, Level, Option<(String, Vec<InnerSpan>)>),
-    AbortIfErrors,
     Fatal(String),
 }
 
@@ -1812,24 +1829,29 @@ impl Translate for SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) {
-        let args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue> =
-            diag.args().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,
-            })));
-        }
-        drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
+    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,
+            })),
+        );
     }
 
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
@@ -1854,11 +1876,24 @@ impl SharedEmitterMain {
 
             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.replace_args(diag.args);
+                    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);
+                    sess.dcx().abort_if_errors();
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
                     assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
@@ -1891,9 +1926,6 @@ impl SharedEmitterMain {
 
                     err.emit();
                 }
-                Ok(SharedEmitterMessage::AbortIfErrors) => {
-                    sess.dcx().abort_if_errors();
-                }
                 Ok(SharedEmitterMessage::Fatal(msg)) => {
                     sess.dcx().fatal(msg);
                 }