From 928388bad20572e9ffa575319bb6d3b636bcdc69 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Mar 2022 16:11:28 -0800 Subject: [PATCH] Make fatal DiagnosticBuilder yield never --- .../rustc_errors/src/diagnostic_builder.rs | 39 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 9 +++-- compiler/rustc_monomorphize/src/collector.rs | 7 +--- compiler/rustc_parse/src/lexer/mod.rs | 31 +++++++++------ compiler/rustc_parse/src/lib.rs | 1 + compiler/rustc_session/src/lib.rs | 1 + compiler/rustc_session/src/session.rs | 31 ++++++--------- compiler/rustc_span/src/fatal_error.rs | 2 +- .../src/traits/const_evaluatable.rs | 3 +- .../missing_cast_for_variadic_arg.rs | 2 +- .../structured_errors/sized_unsized_cast.rs | 2 +- 11 files changed, 82 insertions(+), 46 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, 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, 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`. diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index a9dcc484b9e..1477bc28cff 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -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() } } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 601a39e69ab..92c5d329f6e 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -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( diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 0ce86a764f4..1118caf5075 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -6,6 +6,7 @@ #![feature(if_let_guard)] #![feature(let_chains)] #![feature(let_else)] +#![feature(never_type)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index bd4e37f1ab7..14273b07ebd 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -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"] diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 4876e2eb851..eed0f1e09ff 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -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>( @@ -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 = 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 = 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() } diff --git a/compiler/rustc_span/src/fatal_error.rs b/compiler/rustc_span/src/fatal_error.rs index 718c0ddbc63..fa84c486df5 100644 --- a/compiler/rustc_span/src/fatal_error.rs +++ b/compiler/rustc_span/src/fatal_error.rs @@ -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") } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 959b644becd..d114515eca1 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -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"); diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs index 79965c1dc28..e2bd018cb20 100644 --- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -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(), diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs index 9b058d32f79..afc5c1fe6cc 100644 --- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs @@ -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 `{}`",