Skip to content

Commit 0e4524e

Browse files
committed
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.
2 parents b3e46a9 + 928388b commit 0e4524e

File tree

11 files changed

+82
-46
lines changed

11 files changed

+82
-46
lines changed

compiler/rustc_errors/src/diagnostic_builder.rs

+39
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,45 @@ impl EmissionGuarantee for () {
198198
}
199199
}
200200

201+
impl<'a> DiagnosticBuilder<'a, !> {
202+
/// Convenience function for internal use, clients should use one of the
203+
/// `struct_*` methods on [`Handler`].
204+
crate fn new_fatal(handler: &'a Handler, message: &str) -> Self {
205+
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
206+
Self::new_diagnostic_fatal(handler, diagnostic)
207+
}
208+
209+
/// Creates a new `DiagnosticBuilder` with an already constructed
210+
/// diagnostic.
211+
crate fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
212+
debug!("Created new diagnostic");
213+
Self {
214+
inner: DiagnosticBuilderInner {
215+
state: DiagnosticBuilderState::Emittable(handler),
216+
diagnostic: Box::new(diagnostic),
217+
},
218+
_marker: PhantomData,
219+
}
220+
}
221+
}
222+
223+
impl EmissionGuarantee for ! {
224+
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
225+
match db.inner.state {
226+
// First `.emit()` call, the `&Handler` is still available.
227+
DiagnosticBuilderState::Emittable(handler) => {
228+
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
229+
230+
handler.emit_diagnostic(&mut db.inner.diagnostic);
231+
}
232+
// `.emit()` was previously called, disallowed from repeating it.
233+
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
234+
}
235+
// Then fatally error, returning `!`
236+
crate::FatalError.raise()
237+
}
238+
}
239+
201240
/// In general, the `DiagnosticBuilder` uses deref to allow access to
202241
/// the fields and methods of the embedded `diagnostic` in a
203242
/// transparent way. *However,* many of the methods are intended to

compiler/rustc_errors/src/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#![feature(backtrace)]
99
#![feature(if_let_guard)]
1010
#![feature(let_else)]
11+
#![feature(never_type)]
1112
#![feature(nll)]
1213
#![feature(adt_const_params)]
1314
#![allow(incomplete_features)]
@@ -758,7 +759,7 @@ impl Handler {
758759
&self,
759760
span: impl Into<MultiSpan>,
760761
msg: &str,
761-
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
762+
) -> DiagnosticBuilder<'_, !> {
762763
let mut result = self.struct_fatal(msg);
763764
result.set_span(span);
764765
result
@@ -770,15 +771,15 @@ impl Handler {
770771
span: impl Into<MultiSpan>,
771772
msg: &str,
772773
code: DiagnosticId,
773-
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
774+
) -> DiagnosticBuilder<'_, !> {
774775
let mut result = self.struct_span_fatal(span, msg);
775776
result.code(code);
776777
result
777778
}
778779

779780
/// Construct a builder at the `Error` level with the `msg`.
780-
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
781-
DiagnosticBuilder::new_guaranteeing_error::<{ Level::Fatal }>(self, msg)
781+
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
782+
DiagnosticBuilder::new_fatal(self, msg)
782783
}
783784

784785
/// Construct a builder at the `Help` level with the `msg`.

compiler/rustc_monomorphize/src/collector.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@
180180
181181
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
182182
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
183-
use rustc_errors::FatalError;
184183
use rustc_hir as hir;
185184
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
186185
use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -560,8 +559,7 @@ fn check_recursion_limit<'tcx>(
560559
if let Some(path) = written_to_path {
561560
err.note(&format!("the full type name has been written to '{}'", path.display()));
562561
}
563-
err.emit();
564-
FatalError.raise();
562+
err.emit()
565563
}
566564

567565
recursion_depths.insert(def_id, recursion_depth + 1);
@@ -598,8 +596,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
598596
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
599597
type_length
600598
));
601-
diag.emit();
602-
tcx.sess.abort_if_errors();
599+
diag.emit()
603600
}
604601
}
605602

compiler/rustc_parse/src/lexer/mod.rs

+19-12
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use rustc_ast::ast::{self, AttrStyle};
33
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
44
use rustc_ast::tokenstream::{Spacing, TokenStream};
55
use rustc_ast::util::unicode::contains_text_flow_control_chars;
6-
use rustc_errors::{
7-
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, PResult,
8-
};
6+
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
97
use rustc_lexer::unescape::{self, Mode};
108
use rustc_lexer::{Base, DocStyle, RawStrError};
119
use rustc_session::lint::builtin::{
@@ -104,7 +102,7 @@ impl<'a> StringReader<'a> {
104102
}
105103

106104
/// Report a fatal lexical error with a given span.
107-
fn fatal_span(&self, sp: Span, m: &str) -> FatalError {
105+
fn fatal_span(&self, sp: Span, m: &str) -> ! {
108106
self.sess.span_diagnostic.span_fatal(sp, m)
109107
}
110108

@@ -114,7 +112,7 @@ impl<'a> StringReader<'a> {
114112
}
115113

116114
/// Report a fatal error spanning [`from_pos`, `to_pos`).
117-
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
115+
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! {
118116
self.fatal_span(self.mk_sp(from_pos, to_pos), m)
119117
}
120118

@@ -129,12 +127,24 @@ impl<'a> StringReader<'a> {
129127
to_pos: BytePos,
130128
m: &str,
131129
c: char,
132-
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
130+
) -> DiagnosticBuilder<'a, !> {
133131
self.sess
134132
.span_diagnostic
135133
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
136134
}
137135

136+
fn struct_err_span_char(
137+
&self,
138+
from_pos: BytePos,
139+
to_pos: BytePos,
140+
m: &str,
141+
c: char,
142+
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
143+
self.sess
144+
.span_diagnostic
145+
.struct_span_err(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
146+
}
147+
138148
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
139149
/// complain about it.
140150
fn lint_unicode_text_flow(&self, start: BytePos) {
@@ -311,7 +321,7 @@ impl<'a> StringReader<'a> {
311321
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
312322
let c = self.str_from(start).chars().next().unwrap();
313323
let mut err =
314-
self.struct_fatal_span_char(start, self.pos, "unknown start of token", c);
324+
self.struct_err_span_char(start, self.pos, "unknown start of token", c);
315325
// FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs,
316326
// instead of keeping a table in `check_for_substitution`into the token. Ideally,
317327
// this should be inside `rustc_lexer`. However, we should first remove compound
@@ -503,8 +513,7 @@ impl<'a> StringReader<'a> {
503513
"found invalid character; only `#` is allowed in raw string delimitation",
504514
bad_char,
505515
)
506-
.emit();
507-
FatalError.raise()
516+
.emit()
508517
}
509518

510519
fn report_unterminated_raw_string(
@@ -541,8 +550,7 @@ impl<'a> StringReader<'a> {
541550
);
542551
}
543552

544-
err.emit();
545-
FatalError.raise()
553+
err.emit()
546554
}
547555

548556
// RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021,
@@ -601,7 +609,6 @@ impl<'a> StringReader<'a> {
601609
found
602610
),
603611
)
604-
.raise();
605612
}
606613

607614
fn validate_literal_escape(

compiler/rustc_parse/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(if_let_guard)]
77
#![feature(let_chains)]
88
#![feature(let_else)]
9+
#![feature(never_type)]
910
#![recursion_limit = "256"]
1011

1112
#[macro_use]

compiler/rustc_session/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(let_chains)]
44
#![feature(let_else)]
55
#![feature(min_specialization)]
6+
#![feature(never_type)]
67
#![feature(once_cell)]
78
#![feature(option_get_or_insert_default)]
89
#![recursion_limit = "256"]

compiler/rustc_session/src/session.rs

+11-20
Original file line numberDiff line numberDiff line change
@@ -341,18 +341,18 @@ impl Session {
341341
&self,
342342
sp: S,
343343
msg: &str,
344-
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
344+
) -> DiagnosticBuilder<'_, !> {
345345
self.diagnostic().struct_span_fatal(sp, msg)
346346
}
347347
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
348348
&self,
349349
sp: S,
350350
msg: &str,
351351
code: DiagnosticId,
352-
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
352+
) -> DiagnosticBuilder<'_, !> {
353353
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
354354
}
355-
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
355+
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
356356
self.diagnostic().struct_fatal(msg)
357357
}
358358

@@ -1384,7 +1384,7 @@ pub enum IncrCompSession {
13841384
InvalidBecauseOfErrors { session_directory: PathBuf },
13851385
}
13861386

1387-
pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
1387+
fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
13881388
let emitter: Box<dyn Emitter + sync::Send> = match output {
13891389
config::ErrorOutputType::HumanReadable(kind) => {
13901390
let (short, color_config) = kind.unzip();
@@ -1394,26 +1394,17 @@ pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> Error
13941394
Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
13951395
}
13961396
};
1397-
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
1398-
let reported = handler.struct_fatal(msg).emit();
1399-
reported
1397+
rustc_errors::Handler::with_emitter(true, None, emitter)
1398+
}
1399+
1400+
pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
1401+
early_error_handler(output).struct_err(msg).emit()
14001402
}
14011403

14021404
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
1403-
early_error_no_abort(output, msg);
1404-
rustc_errors::FatalError.raise();
1405+
early_error_handler(output).struct_fatal(msg).emit()
14051406
}
14061407

14071408
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
1408-
let emitter: Box<dyn Emitter + sync::Send> = match output {
1409-
config::ErrorOutputType::HumanReadable(kind) => {
1410-
let (short, color_config) = kind.unzip();
1411-
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
1412-
}
1413-
config::ErrorOutputType::Json { pretty, json_rendered } => {
1414-
Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
1415-
}
1416-
};
1417-
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
1418-
handler.struct_warn(msg).emit();
1409+
early_error_handler(output).struct_warn(msg).emit()
14191410
}

compiler/rustc_span/src/fatal_error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl FatalError {
1919

2020
impl std::fmt::Display for FatalError {
2121
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22-
write!(f, "parser fatal error")
22+
write!(f, "fatal error")
2323
}
2424
}
2525

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
168168
"#![feature(generic_const_exprs)]\n".to_string(),
169169
rustc_errors::Applicability::MaybeIncorrect,
170170
)
171-
.emit();
172-
rustc_errors::FatalError.raise();
171+
.emit()
173172
}
174173

175174
debug!(?concrete, "is_const_evaluatable");

compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> {
2121
}
2222

2323
fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
24-
let mut err = self.sess.struct_span_fatal_with_code(
24+
let mut err = self.sess.struct_span_err_with_code(
2525
self.span,
2626
&format!("can't pass `{}` to variadic function", self.ty),
2727
self.code(),

compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
2121
}
2222

2323
fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
24-
let mut err = self.sess.struct_span_fatal_with_code(
24+
let mut err = self.sess.struct_span_err_with_code(
2525
self.span,
2626
&format!(
2727
"cannot cast thin pointer `{}` to fat pointer `{}`",

0 commit comments

Comments
 (0)