1
Fork 0

Make fatal DiagnosticBuilder yield never

This commit is contained in:
Michael Goulet 2022-03-09 16:11:28 -08:00
parent 93313d108f
commit 928388bad2
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 /// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a /// the fields and methods of the embedded `diagnostic` in a
/// transparent way. *However,* many of the methods are intended to /// transparent way. *However,* many of the methods are intended to

View file

@ -8,6 +8,7 @@
#![feature(backtrace)] #![feature(backtrace)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(let_else)] #![feature(let_else)]
#![feature(never_type)]
#![feature(nll)] #![feature(nll)]
#![feature(adt_const_params)] #![feature(adt_const_params)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
@ -758,7 +759,7 @@ impl Handler {
&self, &self,
span: impl Into<MultiSpan>, span: impl Into<MultiSpan>,
msg: &str, msg: &str,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> { ) -> DiagnosticBuilder<'_, !> {
let mut result = self.struct_fatal(msg); let mut result = self.struct_fatal(msg);
result.set_span(span); result.set_span(span);
result result
@ -770,15 +771,15 @@ impl Handler {
span: impl Into<MultiSpan>, span: impl Into<MultiSpan>,
msg: &str, msg: &str,
code: DiagnosticId, code: DiagnosticId,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> { ) -> DiagnosticBuilder<'_, !> {
let mut result = self.struct_span_fatal(span, msg); let mut result = self.struct_span_fatal(span, msg);
result.code(code); result.code(code);
result result
} }
/// Construct a builder at the `Error` level with the `msg`. /// Construct a builder at the `Error` level with the `msg`.
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorGuaranteed> { pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new_guaranteeing_error::<{ Level::Fatal }>(self, msg) DiagnosticBuilder::new_fatal(self, msg)
} }
/// Construct a builder at the `Help` level with the `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::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
use rustc_errors::FatalError;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::itemlikevisit::ItemLikeVisitor;
@ -560,8 +559,7 @@ fn check_recursion_limit<'tcx>(
if let Some(path) = written_to_path { if let Some(path) = written_to_path {
err.note(&format!("the full type name has been written to '{}'", path.display())); err.note(&format!("the full type name has been written to '{}'", path.display()));
} }
err.emit(); err.emit()
FatalError.raise();
} }
recursion_depths.insert(def_id, recursion_depth + 1); 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", "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
type_length type_length
)); ));
diag.emit(); diag.emit()
tcx.sess.abort_if_errors();
} }
} }

View file

@ -3,9 +3,7 @@ use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream}; use rustc_ast::tokenstream::{Spacing, TokenStream};
use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, PResult,
};
use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{ use rustc_session::lint::builtin::{
@ -104,7 +102,7 @@ impl<'a> StringReader<'a> {
} }
/// Report a fatal lexical error with a given span. /// 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) 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`). /// 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) self.fatal_span(self.mk_sp(from_pos, to_pos), m)
} }
@ -129,12 +127,24 @@ impl<'a> StringReader<'a> {
to_pos: BytePos, to_pos: BytePos,
m: &str, m: &str,
c: char, c: char,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> { ) -> DiagnosticBuilder<'a, !> {
self.sess self.sess
.span_diagnostic .span_diagnostic
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c))) .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 /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
/// complain about it. /// complain about it.
fn lint_unicode_text_flow(&self, start: BytePos) { fn lint_unicode_text_flow(&self, start: BytePos) {
@ -311,7 +321,7 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => { rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap(); let c = self.str_from(start).chars().next().unwrap();
let mut err = 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, // 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, // 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 // 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", "found invalid character; only `#` is allowed in raw string delimitation",
bad_char, bad_char,
) )
.emit(); .emit()
FatalError.raise()
} }
fn report_unterminated_raw_string( fn report_unterminated_raw_string(
@ -541,8 +550,7 @@ impl<'a> StringReader<'a> {
); );
} }
err.emit(); err.emit()
FatalError.raise()
} }
// RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021, // RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021,
@ -601,7 +609,6 @@ impl<'a> StringReader<'a> {
found found
), ),
) )
.raise();
} }
fn validate_literal_escape( fn validate_literal_escape(

View file

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

View file

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

View file

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

View file

@ -19,7 +19,7 @@ impl FatalError {
impl std::fmt::Display for FatalError { impl std::fmt::Display for FatalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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(), "#![feature(generic_const_exprs)]\n".to_string(),
rustc_errors::Applicability::MaybeIncorrect, rustc_errors::Applicability::MaybeIncorrect,
) )
.emit(); .emit()
rustc_errors::FatalError.raise();
} }
debug!(?concrete, "is_const_evaluatable"); 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> { 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, self.span,
&format!("can't pass `{}` to variadic function", self.ty), &format!("can't pass `{}` to variadic function", self.ty),
self.code(), self.code(),

View file

@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
} }
fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 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, self.span,
&format!( &format!(
"cannot cast thin pointer `{}` to fat pointer `{}`", "cannot cast thin pointer `{}` to fat pointer `{}`",