about summary refs log tree commit diff
path: root/compiler/rustc_errors/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-03-28 11:08:23 +0000
committerbors <bors@rust-lang.org>2022-03-28 11:08:23 +0000
commit0e4524e5b4a9c5656fef69f532f96eb9959a1803 (patch)
treef3b255fe605208ee5eafc4a41541eeada8a9e807 /compiler/rustc_errors/src
parentb3e46a9763d86a1681ddaaf0e60ce537302b9c92 (diff)
parent928388bad20572e9ffa575319bb6d3b636bcdc69 (diff)
downloadrust-0e4524e5b4a9c5656fef69f532f96eb9959a1803.tar.gz
rust-0e4524e5b4a9c5656fef69f532f96eb9959a1803.zip
Auto merge of #94789 - compiler-errors:fatal-never, r=eddyb
Make fatal DiagnosticBuilder yield `!`

Fatal errors should really be fatal, so emitting them should cause us to exit at the same time.

Fine with just throwing away these changes if they're not worthwhile. Also, maybe we want to use an uninhabited enum instead of `!`.

r? `@eddyb` who has been working on `DiagnosticBuilder` stuff, feel free to reassign.
Diffstat (limited to 'compiler/rustc_errors/src')
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs39
-rw-r--r--compiler/rustc_errors/src/lib.rs9
2 files changed, 44 insertions, 4 deletions
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 088f6091528..853243ef3f0 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -198,6 +198,45 @@ impl EmissionGuarantee for () {
     }
 }
 
+impl<'a> DiagnosticBuilder<'a, !> {
+    /// Convenience function for internal use, clients should use one of the
+    /// `struct_*` methods on [`Handler`].
+    crate fn new_fatal(handler: &'a Handler, message: &str) -> Self {
+        let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
+        Self::new_diagnostic_fatal(handler, diagnostic)
+    }
+
+    /// Creates a new `DiagnosticBuilder` with an already constructed
+    /// diagnostic.
+    crate fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+        debug!("Created new diagnostic");
+        Self {
+            inner: DiagnosticBuilderInner {
+                state: DiagnosticBuilderState::Emittable(handler),
+                diagnostic: Box::new(diagnostic),
+            },
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl EmissionGuarantee for ! {
+    fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+        match db.inner.state {
+            // First `.emit()` call, the `&Handler` is still available.
+            DiagnosticBuilderState::Emittable(handler) => {
+                db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+
+                handler.emit_diagnostic(&mut db.inner.diagnostic);
+            }
+            // `.emit()` was previously called, disallowed from repeating it.
+            DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+        }
+        // Then fatally error, returning `!`
+        crate::FatalError.raise()
+    }
+}
+
 /// In general, the `DiagnosticBuilder` uses deref to allow access to
 /// the fields and methods of the embedded `diagnostic` in a
 /// transparent way. *However,* many of the methods are intended to
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2f2f6ed1a5a..ec00910ec8b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(backtrace)]
 #![feature(if_let_guard)]
 #![feature(let_else)]
+#![feature(never_type)]
 #![feature(nll)]
 #![feature(adt_const_params)]
 #![allow(incomplete_features)]
@@ -758,7 +759,7 @@ impl Handler {
         &self,
         span: impl Into<MultiSpan>,
         msg: &str,
-    ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'_, !> {
         let mut result = self.struct_fatal(msg);
         result.set_span(span);
         result
@@ -770,15 +771,15 @@ impl Handler {
         span: impl Into<MultiSpan>,
         msg: &str,
         code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'_, !> {
         let mut result = self.struct_span_fatal(span, msg);
         result.code(code);
         result
     }
 
     /// Construct a builder at the `Error` level with the `msg`.
-    pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        DiagnosticBuilder::new_guaranteeing_error::<{ Level::Fatal }>(self, msg)
+    pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
+        DiagnosticBuilder::new_fatal(self, msg)
     }
 
     /// Construct a builder at the `Help` level with the `msg`.