diff options
| author | bors <bors@rust-lang.org> | 2022-02-25 00:46:04 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-02-25 00:46:04 +0000 |
| commit | d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9 (patch) | |
| tree | 922a1d8bf2850b2f35dda5bc6cc14e9194c375c1 /compiler/rustc_parse/src | |
| parent | 4e82f35492ea5c78e19609bf4468f0a686d9a756 (diff) | |
| parent | b7e95dee65c35db8f8e07046d445b12d92cbae12 (diff) | |
| download | rust-d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9.tar.gz rust-d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9.zip | |
Auto merge of #93368 - eddyb:diagbld-guarantee, r=estebank
rustc_errors: let `DiagnosticBuilder::emit` return a "guarantee of emission".
That is, `DiagnosticBuilder` is now generic over the return type of `.emit()`, so we'll now have:
* `DiagnosticBuilder<ErrorReported>` for error (incl. fatal/bug) diagnostics
* can only be created via a `const L: Level`-generic constructor, that limits allowed variants via a `where` clause, so not even `rustc_errors` can accidentally bypass this limitation
* asserts `diagnostic.is_error()` on emission, just in case the construction restriction was bypassed (e.g. by replacing the whole `Diagnostic` inside `DiagnosticBuilder`)
* `.emit()` returns `ErrorReported`, as a "proof" token that `.emit()` was called
(though note that this isn't a real guarantee until after completing the work on
#69426)
* `DiagnosticBuilder<()>` for everything else (warnings, notes, etc.)
* can also be obtained from other `DiagnosticBuilder`s by calling `.forget_guarantee()`
This PR is a companion to other ongoing work, namely:
* #69426
and it's ongoing implementation:
#93222
the API changes in this PR are needed to get statically-checked "only errors produce `ErrorReported` from `.emit()`", but doesn't itself provide any really strong guarantees without those other `ErrorReported` changes
* #93244
would make the choices of API changes (esp. naming) in this PR fit better overall
In order to be able to let `.emit()` return anything trustable, several changes had to be made:
* `Diagnostic`'s `level` field is now private to `rustc_errors`, to disallow arbitrary "downgrade"s from "some kind of error" to "warning" (or anything else that doesn't cause compilation to fail)
* it's still possible to replace the whole `Diagnostic` inside the `DiagnosticBuilder`, sadly, that's harder to fix, but it's unlikely enough that we can paper over it with asserts on `.emit()`
* `.cancel()` now consumes `DiagnosticBuilder`, preventing `.emit()` calls on a cancelled diagnostic
* it's also now done internally, through `DiagnosticBuilder`-private state, instead of having a `Level::Cancelled` variant that can be read (or worse, written) by the user
* this removes a hazard of calling `.cancel()` on an error then continuing to attach details to it, and even expect to be able to `.emit()` it
* warnings were switched to *only* `can_emit_warnings` on emission (instead of pre-cancelling early)
* `struct_dummy` was removed (as it relied on a pre-`Cancelled` `Diagnostic`)
* since `.emit()` doesn't consume the `DiagnosticBuilder` <sub>(I tried and gave up, it's much more work than this PR)</sub>,
we have to make `.emit()` idempotent wrt the guarantees it returns
* thankfully, `err.emit(); err.emit();` can return `ErrorReported` both times, as the second `.emit()` call has no side-effects *only* because the first one did do the appropriate emission
* `&mut Diagnostic` is now used in a lot of function signatures, which used to take `&mut DiagnosticBuilder` (in the interest of not having to make those functions generic)
* the APIs were already mostly identical, allowing for low-effort porting to this new setup
* only some of the suggestion methods needed some rework, to have the extra `DiagnosticBuilder` functionality on the `Diagnostic` methods themselves (that change is also present in #93259)
* `.emit()`/`.cancel()` aren't available, but IMO calling them from an "error decorator/annotator" function isn't a good practice, and can lead to strange behavior (from the caller's perspective)
* `.downgrade_to_delayed_bug()` was added, letting you convert any `.is_error()` diagnostic into a `delay_span_bug` one (which works because in both cases the guarantees available are the same)
This PR should ideally be reviewed commit-by-commit, since there is a lot of fallout in each.
r? `@estebank` cc `@Manishearth` `@nikomatsakis` `@mark-i-m`
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/unicode_chars.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 81 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 40 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 3 |
13 files changed, 122 insertions, 97 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4cdd83c0acd..3212fc39fb9 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -3,7 +3,9 @@ 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, FatalError, PResult}; +use rustc_errors::{ + error_code, Applicability, DiagnosticBuilder, ErrorReported, FatalError, PResult, +}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::lint::builtin::{ @@ -127,7 +129,7 @@ impl<'a> StringReader<'a> { to_pos: BytePos, m: &str, c: char, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { self.sess .span_diagnostic .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c))) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index a41956c58f0..c7d166319ea 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -144,7 +144,7 @@ pub(crate) fn emit_unescape_error( c.escape_default().to_string(), Applicability::MachineApplicable, ) - .emit() + .emit(); } EscapeError::BareCarriageReturn => { let msg = if mode.in_double_quotes() { @@ -292,16 +292,18 @@ pub(crate) fn emit_unescape_error( .span_label(span, "must have at most 6 hex digits") .emit(); } - EscapeError::UnclosedUnicodeEscape => handler - .struct_span_err(span, "unterminated unicode escape") - .span_label(span, "missing a closing `}`") - .span_suggestion_verbose( - span.shrink_to_hi(), - "terminate the unicode escape", - "}".to_string(), - Applicability::MaybeIncorrect, - ) - .emit(), + EscapeError::UnclosedUnicodeEscape => { + handler + .struct_span_err(span, "unterminated unicode escape") + .span_label(span, "missing a closing `}`") + .span_suggestion_verbose( + span.shrink_to_hi(), + "terminate the unicode escape", + "}".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } EscapeError::NoBraceInUnicodeEscape => { let msg = "incorrect unicode escape sequence"; let mut diag = handler.struct_span_err(span, msg); @@ -347,7 +349,7 @@ pub(crate) fn emit_unescape_error( } EscapeError::ZeroChars => { let msg = "empty character literal"; - handler.struct_span_err(span, msg).span_label(span, msg).emit() + handler.struct_span_err(span, msg).span_label(span, msg).emit(); } EscapeError::LoneSlash => { let msg = "invalid trailing slash in literal"; diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index c2a75d2bc2c..1d63b79adc5 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -3,7 +3,7 @@ use super::StringReader; use crate::token; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks @@ -336,7 +336,7 @@ pub(super) fn check_for_substitution<'a>( reader: &StringReader<'a>, pos: BytePos, ch: char, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, ) -> Option<token::TokenKind> { let Some(&(_u_char, u_name, ascii_char)) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) else { return None; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ca92d6b7fd0..379e47077ea 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; use rustc_ast_pretty::pprust; -use rustc_errors::{error_code, DiagnosticBuilder, PResult}; +use rustc_errors::{error_code, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use std::convert::TryInto; @@ -147,7 +147,7 @@ impl<'a> Parser<'a> { fn annotate_following_item_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, attr_type: OuterAttributeType, ) -> Option<Span> { @@ -165,7 +165,7 @@ impl<'a> Parser<'a> { loop { // skip any other attributes, we want the item if snapshot.token.kind == token::Pound { - if let Err(mut err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) { + if let Err(err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) { err.cancel(); return Some(replacement_span); } @@ -206,7 +206,7 @@ impl<'a> Parser<'a> { ); return None; } - Err(mut item_err) => { + Err(item_err) => { item_err.cancel(); } Ok(None) => {} @@ -412,12 +412,12 @@ impl<'a> Parser<'a> { fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)), - Err(ref mut err) => err.cancel(), + Err(err) => err.cancel(), } match self.parse_meta_item() { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), - Err(ref mut err) => err.cancel(), + Err(err) => err.cancel(), } let found = pprust::token_to_string(&self.token); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index def23005fbe..f1c2dcf10e8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -16,7 +16,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorReported}; use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; @@ -53,7 +53,11 @@ pub enum Error { } impl Error { - fn span_err(self, sp: impl Into<MultiSpan>, handler: &Handler) -> DiagnosticBuilder<'_> { + fn span_err( + self, + sp: impl Into<MultiSpan>, + handler: &Handler, + ) -> DiagnosticBuilder<'_, ErrorReported> { match self { Error::UselessDocComment => { let mut err = struct_span_err!( @@ -151,11 +155,19 @@ impl AttemptLocalParseRecovery { } impl<'a> Parser<'a> { - pub(super) fn span_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + pub(super) fn span_err<S: Into<MultiSpan>>( + &self, + sp: S, + err: Error, + ) -> DiagnosticBuilder<'a, ErrorReported> { err.span_err(sp, self.diagnostic()) } - pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + pub fn struct_span_err<S: Into<MultiSpan>>( + &self, + sp: S, + m: &str, + ) -> DiagnosticBuilder<'a, ErrorReported> { self.sess.span_diagnostic.struct_span_err(sp, m) } @@ -171,7 +183,7 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = self.struct_span_err( self.token.span, &format!("expected identifier, found {}", super::token_descr(&self.token)), @@ -393,7 +405,7 @@ impl<'a> Parser<'a> { Err(err) } - fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool { + fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { match (&self.prev_token.kind, &self.token.kind) { ( TokenKind::Literal(Lit { @@ -461,12 +473,12 @@ impl<'a> Parser<'a> { tail.could_be_bare_literal = true; Ok(tail) } - (Err(mut err), Ok(tail)) => { + (Err(err), Ok(tail)) => { // We have a block tail that contains a somehow valid type ascription expr. err.cancel(); Ok(tail) } - (Err(mut snapshot_err), Err(err)) => { + (Err(snapshot_err), Err(err)) => { // We don't know what went wrong, emit the normal error. snapshot_err.cancel(); self.consume_block(token::Brace, ConsumeClosingDelim::Yes); @@ -483,7 +495,7 @@ impl<'a> Parser<'a> { pub fn maybe_annotate_with_ascription( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, maybe_expected_semicolon: bool, ) { if let Some((sp, likely_path)) = self.last_type_ascription.take() { @@ -537,7 +549,7 @@ impl<'a> Parser<'a> { /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { - if let Err(ref mut err) = + if let Err(err) = self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| { Ok(p.parse_token_tree()) }) @@ -703,7 +715,7 @@ impl<'a> Parser<'a> { *self = snapshot; } } - Err(mut err) => { + Err(err) => { // We couldn't parse generic parameters, unlikely to be a turbofish. Rely on // generic parse error instead. err.cancel(); @@ -717,7 +729,7 @@ impl<'a> Parser<'a> { /// encounter a parse error when encountering the first `,`. pub(super) fn check_mistyped_turbofish_with_multiple_type_params( &mut self, - mut e: DiagnosticBuilder<'a>, + mut e: DiagnosticBuilder<'a, ErrorReported>, expr: &mut P<Expr>, ) -> PResult<'a, ()> { if let ExprKind::Binary(binop, _, _) = &expr.kind { @@ -744,14 +756,14 @@ impl<'a> Parser<'a> { self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } - Err(mut err) => { + Err(err) => { *expr = self.mk_expr_err(expr.span); err.cancel(); } } } } - Err(mut err) => { + Err(err) => { err.cancel(); } _ => {} @@ -767,7 +779,7 @@ impl<'a> Parser<'a> { /// parenthesising the leftmost comparison. fn attempt_chained_comparison_suggestion( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, inner_op: &Expr, outer_op: &Spanned<AssocOp>, ) -> bool /* advanced the cursor */ { @@ -821,7 +833,7 @@ impl<'a> Parser<'a> { enclose(r1.span, r2.span); true } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); *self = snapshot; false @@ -838,7 +850,7 @@ impl<'a> Parser<'a> { enclose(l1.span, r1.span); true } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); *self = snapshot; false @@ -890,7 +902,7 @@ impl<'a> Parser<'a> { "comparison operators cannot be chained", ); - let suggest = |err: &mut DiagnosticBuilder<'_>| { + let suggest = |err: &mut Diagnostic| { err.span_suggestion_verbose( op.span.shrink_to_lo(), TURBOFISH_SUGGESTION_STR, @@ -938,7 +950,7 @@ impl<'a> Parser<'a> { // `ExprKind::Err` placeholder. mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); // Not entirely sure now, but we bubble the error up with the // suggestion. @@ -1439,7 +1451,7 @@ impl<'a> Parser<'a> { pub(super) fn recover_closing_delimiter( &mut self, tokens: &[TokenKind], - mut err: DiagnosticBuilder<'a>, + mut err: DiagnosticBuilder<'a, ErrorReported>, ) -> PResult<'a, bool> { let mut pos = None; // We want to use the last closing delim that would apply. @@ -1637,7 +1649,7 @@ impl<'a> Parser<'a> { pub(super) fn parameter_without_type( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, pat: P<ast::Pat>, require_name: bool, first_param: bool, @@ -1810,7 +1822,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorReported> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { let sp = self.sess.source_map().next_point(self.prev_token.span); @@ -1946,17 +1958,14 @@ impl<'a> Parser<'a> { Ok(expr) } - fn recover_const_param_decl( - &mut self, - ty_generics: Option<&Generics>, - ) -> PResult<'a, Option<GenericArg>> { + fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> { let snapshot = self.clone(); let param = match self.parse_const_param(vec![]) { Ok(param) => param, - Err(mut err) => { + Err(err) => { err.cancel(); *self = snapshot; - return Err(err); + return None; } }; let mut err = @@ -1977,7 +1986,7 @@ impl<'a> Parser<'a> { } let value = self.mk_expr_err(param.span()); err.emit(); - return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))); + Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } pub fn recover_const_param_declaration( @@ -1985,8 +1994,8 @@ impl<'a> Parser<'a> { ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { // We have to check for a few different cases. - if let Ok(arg) = self.recover_const_param_decl(ty_generics) { - return Ok(arg); + if let Some(arg) = self.recover_const_param_decl(ty_generics) { + return Ok(Some(arg)); } // We haven't consumed `const` yet. @@ -2019,7 +2028,7 @@ impl<'a> Parser<'a> { pub fn recover_const_arg( &mut self, start: Span, - mut err: DiagnosticBuilder<'a>, + mut err: DiagnosticBuilder<'a, ErrorReported>, ) -> PResult<'a, GenericArg> { let is_op = AssocOp::from_token(&self.token) .and_then(|op| { @@ -2085,7 +2094,7 @@ impl<'a> Parser<'a> { return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2099,7 +2108,7 @@ impl<'a> Parser<'a> { pub(super) fn incorrect_move_async_order_found( &self, move_async_span: Span, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); err.span_suggestion_verbose( @@ -2139,7 +2148,7 @@ impl<'a> Parser<'a> { Err(mut err) => { self.bump(); // Skip the `:`. match self.parse_pat_no_top_alt(expected) { - Err(mut inner_err) => { + Err(inner_err) => { // Carry on as if we had not done anything, callers will emit a // reasonable error. inner_err.cancel(); @@ -2246,7 +2255,7 @@ impl<'a> Parser<'a> { // suggestion-enhanced error here rather than choking on the comma later. let comma_span = self.token.span; self.bump(); - if let Err(mut err) = self.skip_pat_list() { + if let Err(err) = self.skip_pat_list() { // We didn't expect this to work anyway; we just wanted to advance to the // end of the comma-sequence so we know the span to suggest parenthesizing. err.cancel(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7cb8c35b868..c6919779ffd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -17,7 +17,7 @@ use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, PResult}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edition::LATEST_STABLE_EDITION; @@ -684,7 +684,7 @@ impl<'a> Parser<'a> { let parser_snapshot_before_type = self.clone(); let cast_expr = match self.parse_as_cast_ty() { Ok(rhs) => mk_expr(self, lhs, rhs), - Err(mut type_err) => { + Err(type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse // `usize < y` as a type with generic arguments. @@ -717,7 +717,7 @@ impl<'a> Parser<'a> { .emit(); return Ok(expr); } - Err(mut err) => { + Err(err) => { err.cancel(); *self = snapshot; } @@ -773,7 +773,7 @@ impl<'a> Parser<'a> { expr } - Err(mut path_err) => { + Err(path_err) => { // Couldn't parse as a path, return original error and parser state. path_err.cancel(); *self = parser_snapshot_after_type; @@ -1127,7 +1127,7 @@ impl<'a> Parser<'a> { snapshot: Option<(Self, ExprKind)>, ) -> Option<P<Expr>> { match (seq.as_mut(), snapshot) { - (Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => { + (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { let name = pprust::path_to_string(&path); snapshot.bump(); // `(` match snapshot.parse_struct_fields(path, false, token::Paren) { @@ -1138,11 +1138,12 @@ impl<'a> Parser<'a> { let close_paren = self.prev_token.span; let span = lo.to(self.prev_token.span); if !fields.is_empty() { - err.cancel(); - let mut err = self.struct_span_err( + let replacement_err = self.struct_span_err( span, "invalid `struct` delimiters or `fn` call arguments", ); + mem::replace(err, replacement_err).cancel(); + err.multipart_suggestion( &format!("if `{}` is a struct, use braces as delimiters", name), vec![ @@ -1166,7 +1167,9 @@ impl<'a> Parser<'a> { return Some(self.mk_expr_err(span)); } Ok(_) => {} - Err(mut err) => err.emit(), + Err(mut err) => { + err.emit(); + } } } _ => {} @@ -1622,9 +1625,11 @@ impl<'a> Parser<'a> { }; if let Some(expr) = expr { if matches!(expr.kind, ExprKind::Err) { - self.diagnostic() - .delay_span_bug(self.token.span, &"invalid interpolated expression"); - return self.diagnostic().struct_dummy(); + let mut err = self + .diagnostic() + .struct_span_err(self.token.span, &"invalid interpolated expression"); + err.downgrade_to_delayed_bug(); + return err; } } } @@ -1816,6 +1821,7 @@ impl<'a> Parser<'a> { err } else { self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + .forget_guarantee() }; err.span_label(sp, format!("invalid suffix `{}`", suf)); err.emit(); @@ -1876,7 +1882,7 @@ impl<'a> Parser<'a> { *self = snapshot; Some(self.mk_expr_err(arr.span)) } - Err(mut e) => { + Err(e) => { e.cancel(); None } @@ -2097,9 +2103,9 @@ impl<'a> Parser<'a> { fn error_missing_if_then_block( &self, if_span: Span, - err: Option<DiagnosticBuilder<'a>>, + err: Option<DiagnosticBuilder<'a, ErrorReported>>, binop_span: Option<Span>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let msg = "this `if` expression has a condition, but no block"; let mut err = if let Some(mut err) = err { @@ -2379,7 +2385,7 @@ impl<'a> Parser<'a> { return Some(err(self, stmts)); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2396,7 +2402,7 @@ impl<'a> Parser<'a> { } // We couldn't parse either yet another statement missing it's // enclosing block nor the next arm's pattern or closing brace. - Err(mut stmt_err) => { + Err(stmt_err) => { stmt_err.cancel(); *self = start_snapshot; break; @@ -2653,7 +2659,7 @@ impl<'a> Parser<'a> { let mut base = ast::StructRest::None; let mut recover_async = false; - let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { + let mut async_block_err = |e: &mut Diagnostic, span: Span| { recover_async = true; e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later"); e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 4b57aa1f24a..1b9eeab0298 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -130,7 +130,7 @@ impl<'a> Parser<'a> { // FIXME - try to continue parsing other generics? return Ok((None, TrailingToken::None)); } - Err(mut err) => { + Err(err) => { err.cancel(); // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`? *this = snapshot; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 20ca8a99ab7..bd349e89482 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -13,7 +13,7 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported, PResult, StashKey}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; @@ -801,7 +801,7 @@ impl<'a> Parser<'a> { before_where_clause_span: Span, after_predicates: &[WherePredicate], after_where_clause_span: Span, - ) { + ) -> ErrorReported { let mut err = self.struct_span_err(after_where_clause_span, "where clause not allowed here"); if !after_predicates.is_empty() { @@ -1114,7 +1114,7 @@ impl<'a> Parser<'a> { // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { Ok(impl_info) => impl_info, - Err(mut recovery_error) => { + Err(recovery_error) => { // Recovery failed, raise the "expected identifier" error recovery_error.cancel(); return Err(err); @@ -1476,7 +1476,9 @@ impl<'a> Parser<'a> { // after the comma self.eat(&token::Comma); // `check_trailing_angle_brackets` already emitted a nicer error - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // gets returned, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); } } } @@ -2073,7 +2075,7 @@ impl<'a> Parser<'a> { if let Ok(snippet) = self.span_to_snippet(sp) { let current_vis = match self.parse_visibility(FollowedByType::No) { Ok(v) => v, - Err(mut d) => { + Err(d) => { d.cancel(); return Err(err); } @@ -2216,7 +2218,7 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), // Recover from attempting to parse the argument as a type without pattern. - Err(mut err) => { + Err(err) => { err.cancel(); *this = parser_snapshot_before_ty; this.recover_arg_parse()? @@ -2358,7 +2360,7 @@ impl<'a> Parser<'a> { match self .parse_outer_attributes() .and_then(|_| self.parse_self_param()) - .map_err(|mut e| e.cancel()) + .map_err(|e| e.cancel()) { Ok(Some(_)) => "method", _ => "function", diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6d534bece46..d8e6d5037bb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -32,7 +32,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported, FatalError}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{MultiSpan, Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -849,7 +849,7 @@ impl<'a> Parser<'a> { v.push(t); continue; } - Err(mut e) => { + Err(e) => { // Parsing failed, therefore it must be something more serious // than just a missing separator. expect_err.emit(); @@ -877,7 +877,7 @@ impl<'a> Parser<'a> { fn recover_missing_braces_around_closure_body( &mut self, closure_spans: ClosureSpans, - mut expect_err: DiagnosticBuilder<'_>, + mut expect_err: DiagnosticBuilder<'_, ErrorReported>, ) -> PResult<'a, ()> { let initial_semicolon = self.token.span; @@ -1429,7 +1429,7 @@ impl<'a> Parser<'a> { crate fn make_unclosed_delims_error( unmatched: UnmatchedBrace, sess: &ParseSess, -) -> Option<DiagnosticBuilder<'_>> { +) -> Option<DiagnosticBuilder<'_, ErrorReported>> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to // `unmatched_braces` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ac3123c40e3..d4129871145 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -8,7 +8,7 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -655,7 +655,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, - mut err: DiagnosticBuilder<'a>, + err: DiagnosticBuilder<'a, ErrorReported>, expected: Expected, ) -> PResult<'a, P<Pat>> { err.cancel(); @@ -722,7 +722,7 @@ impl<'a> Parser<'a> { // Ensure the user doesn't receive unhelpful unexpected token errors self.bump(); if self.is_pat_range_end_start(0) { - let _ = self.parse_pat_range_end().map_err(|mut e| e.cancel()); + let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); } self.error_inclusive_range_with_extra_equals(span_with_eq); @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); let mut etc = false; let mut ate_comma = true; - let mut delayed_err: Option<DiagnosticBuilder<'a>> = None; + let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorReported>> = None; let mut etc_span = None; while self.token != token::CloseDelim(token::Brace) { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 48502112e3a..b5857e05970 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -394,7 +394,7 @@ impl<'a> Parser<'a> { debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); match self.parse_angle_args(ty_generics) { Ok(args) => Ok(args), - Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { + Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { // Swap `self` with our backup of the parser state before attempting to parse // generic arguments. let snapshot = mem::replace(self, snapshot.unwrap()); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 965e6a6ca3f..6b195285243 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -18,7 +18,7 @@ use rustc_ast::{ }; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; -use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym}; @@ -296,7 +296,7 @@ impl<'a> Parser<'a> { // extra noise. init } - (Err(mut init_err), Some((snapshot, _, ty_err))) => { + (Err(init_err), Some((snapshot, _, ty_err))) => { // init error, ty error init_err.cancel(); // Couldn't parse the type nor the initializer, only raise the type error and @@ -414,7 +414,10 @@ impl<'a> Parser<'a> { Ok(block) } - fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> { + fn error_block_no_opening_brace_msg( + &mut self, + msg: &str, + ) -> DiagnosticBuilder<'a, ErrorReported> { let sp = self.token.span; let mut e = self.struct_span_err(sp, msg); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; @@ -449,7 +452,7 @@ impl<'a> Parser<'a> { ); } } - Err(mut e) => { + Err(e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); e.cancel(); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 566b77a5e9e..0b01f9e927f 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -345,7 +345,8 @@ impl<'a> Parser<'a> { let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); let bounds = self.parse_generic_bounds_common(allow_plus, None)?; if lt_no_plus { - self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`").emit() + self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`") + .emit(); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } |
