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.
This commit is contained in:
bors 2022-03-28 11:08:23 +00:00
commit 0e4524e5b4
11 changed files with 82 additions and 46 deletions

View File

@ -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

View File

@ -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`.

View File

@ -180,7 +180,6 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
use rustc_errors::FatalError;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
@ -560,8 +559,7 @@ fn check_recursion_limit<'tcx>(
if let Some(path) = written_to_path {
err.note(&format!("the full type name has been written to '{}'", path.display()));
}
err.emit();
FatalError.raise();
err.emit()
}
recursion_depths.insert(def_id, recursion_depth + 1);
@ -598,8 +596,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
"consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
type_length
));
diag.emit();
tcx.sess.abort_if_errors();
diag.emit()
}
}

View File

@ -3,9 +3,7 @@ use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream};
use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, PResult,
};
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{
@ -104,7 +102,7 @@ impl<'a> StringReader<'a> {
}
/// Report a fatal lexical error with a given span.
fn fatal_span(&self, sp: Span, m: &str) -> FatalError {
fn fatal_span(&self, sp: Span, m: &str) -> ! {
self.sess.span_diagnostic.span_fatal(sp, m)
}
@ -114,7 +112,7 @@ impl<'a> StringReader<'a> {
}
/// Report a fatal error spanning [`from_pos`, `to_pos`).
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! {
self.fatal_span(self.mk_sp(from_pos, to_pos), m)
}
@ -129,12 +127,24 @@ impl<'a> StringReader<'a> {
to_pos: BytePos,
m: &str,
c: char,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
) -> DiagnosticBuilder<'a, !> {
self.sess
.span_diagnostic
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
fn struct_err_span_char(
&self,
from_pos: BytePos,
to_pos: BytePos,
m: &str,
c: char,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.sess
.span_diagnostic
.struct_span_err(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
/// complain about it.
fn lint_unicode_text_flow(&self, start: BytePos) {
@ -311,7 +321,7 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap();
let mut err =
self.struct_fatal_span_char(start, self.pos, "unknown start of token", c);
self.struct_err_span_char(start, self.pos, "unknown start of token", c);
// FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs,
// instead of keeping a table in `check_for_substitution`into the token. Ideally,
// this should be inside `rustc_lexer`. However, we should first remove compound
@ -503,8 +513,7 @@ impl<'a> StringReader<'a> {
"found invalid character; only `#` is allowed in raw string delimitation",
bad_char,
)
.emit();
FatalError.raise()
.emit()
}
fn report_unterminated_raw_string(
@ -541,8 +550,7 @@ impl<'a> StringReader<'a> {
);
}
err.emit();
FatalError.raise()
err.emit()
}
// RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021,
@ -601,7 +609,6 @@ impl<'a> StringReader<'a> {
found
),
)
.raise();
}
fn validate_literal_escape(

View File

@ -6,6 +6,7 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(never_type)]
#![recursion_limit = "256"]
#[macro_use]

View File

@ -3,6 +3,7 @@
#![feature(let_chains)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
#![feature(option_get_or_insert_default)]
#![recursion_limit = "256"]

View File

@ -341,7 +341,7 @@ impl Session {
&self,
sp: S,
msg: &str,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal(sp, msg)
}
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
@ -349,10 +349,10 @@ impl Session {
sp: S,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
}
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_fatal(msg)
}
@ -1384,7 +1384,7 @@ pub enum IncrCompSession {
InvalidBecauseOfErrors { session_directory: PathBuf },
}
pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
@ -1394,26 +1394,17 @@ pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> Error
Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
}
};
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
let reported = handler.struct_fatal(msg).emit();
reported
rustc_errors::Handler::with_emitter(true, None, emitter)
}
pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
early_error_handler(output).struct_err(msg).emit()
}
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
early_error_no_abort(output, msg);
rustc_errors::FatalError.raise();
early_error_handler(output).struct_fatal(msg).emit()
}
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
}
config::ErrorOutputType::Json { pretty, json_rendered } => {
Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
}
};
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
handler.struct_warn(msg).emit();
early_error_handler(output).struct_warn(msg).emit()
}

View File

@ -19,7 +19,7 @@ impl FatalError {
impl std::fmt::Display for FatalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "parser fatal error")
write!(f, "fatal error")
}
}

View File

@ -168,8 +168,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
"#![feature(generic_const_exprs)]\n".to_string(),
rustc_errors::Applicability::MaybeIncorrect,
)
.emit();
rustc_errors::FatalError.raise();
.emit()
}
debug!(?concrete, "is_const_evaluatable");

View File

@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> {
}
fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = self.sess.struct_span_fatal_with_code(
let mut err = self.sess.struct_span_err_with_code(
self.span,
&format!("can't pass `{}` to variadic function", self.ty),
self.code(),

View File

@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
}
fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = self.sess.struct_span_fatal_with_code(
let mut err = self.sess.struct_span_err_with_code(
self.span,
&format!(
"cannot cast thin pointer `{}` to fat pointer `{}`",