diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 719862e67c8..04f446ebcf1 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -379,7 +379,7 @@ fn do_mir_borrowck<'a, 'tcx>( // Convert any reservation warnings into lints. let reservation_warnings = mem::take(&mut mbcx.reservation_warnings); for (_, (place, span, location, bk, borrow)) in reservation_warnings { - let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); + let initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); let scope = mbcx.body.source_info(location).scope; let lint_root = match &mbcx.body.source_scopes[scope].local_data { @@ -2329,7 +2329,7 @@ mod error { move_out_indices: Vec, place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>), ) -> bool { - if let Some((_, mut diag)) = + if let Some((_, diag)) = self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) { // Cancel the old diagnostic so we don't ICE diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 2835afb0208..7d7ab1ed4e5 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -72,8 +72,8 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { Level::Warning => AnnotationType::Warning, Level::Note => AnnotationType::Note, Level::Help => AnnotationType::Help, - // FIXME(#59346): Not sure how to map these two levels - Level::Cancelled | Level::FailureNote => AnnotationType::Error, + // FIXME(#59346): Not sure how to map this level + Level::FailureNote => AnnotationType::Error, Level::Allow => panic!("Should not call with Allow"), } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index f32b11e33c8..6d6ada86428 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -133,7 +133,7 @@ impl Diagnostic { | Level::Error { .. } | Level::FailureNote => true, - Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false, + Level::Warning | Level::Note | Level::Help | Level::Allow => false, } } @@ -151,17 +151,6 @@ impl Diagnostic { } } - /// Cancel the diagnostic (a structured diagnostic must either be emitted or - /// canceled or it will panic when dropped). - pub fn cancel(&mut self) { - self.level = Level::Cancelled; - } - - /// Check if this diagnostic [was cancelled][Self::cancel()]. - pub fn cancelled(&self) -> bool { - self.level == Level::Cancelled - } - /// Delay emission of this diagnostic as a bug. /// /// This can be useful in contexts where an error indicates a bug but @@ -174,17 +163,12 @@ impl Diagnostic { /// locally in whichever way makes the most sense. #[track_caller] pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { - // FIXME(eddyb) this check is only necessary because cancellation exists, - // but hopefully that can be removed in the future, if enough callers - // of `.cancel()` can take `DiagnosticBuilder`, and by-value. - if !self.cancelled() { - assert!( - self.is_error(), - "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", - self.level - ); - self.level = Level::DelayedBug; - } + assert!( + self.is_error(), + "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", + self.level + ); + self.level = Level::DelayedBug; self } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index e0a5e6ef089..7978e1cc162 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -16,7 +16,7 @@ use tracing::debug; #[must_use] #[derive(Clone)] pub struct DiagnosticBuilder<'a> { - handler: &'a Handler, + state: DiagnosticBuilderState<'a>, /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a /// return value, especially within the frequently-used `PResult` type. @@ -25,6 +25,34 @@ pub struct DiagnosticBuilder<'a> { diagnostic: Box, } +#[derive(Clone)] +enum DiagnosticBuilderState<'a> { + /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`. + /// + /// The `Diagnostic` will be emitted through this `Handler`. + Emittable(&'a Handler), + + /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`. + /// + /// The `Diagnostic` will be ignored when calling `.emit()`, and it can be + /// assumed that `.emit()` was previously called, to end up in this state. + /// + /// While this is also used by `.cancel()`, this state is only observed by + /// the `Drop` `impl` of `DiagnosticBuilder`, as `.cancel()` takes `self` + /// by-value specifically to prevent any attempts to `.emit()`. + /// + // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`, + // despite that being potentially lossy, if important information is added + // *after* the original `.emit()` call. + AlreadyEmittedOrDuringCancellation, +} + +// `DiagnosticBuilderState` should be pointer-sized. +rustc_data_structures::static_assert_size!( + DiagnosticBuilderState<'_>, + std::mem::size_of::<&Handler>() +); + /// 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 @@ -78,8 +106,18 @@ impl<'a> DerefMut for DiagnosticBuilder<'a> { impl<'a> DiagnosticBuilder<'a> { /// Emit the diagnostic. pub fn emit(&mut self) { - self.handler.emit_diagnostic(&self); - self.cancel(); + match self.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + handler.emit_diagnostic(&self); + self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { + // FIXME(eddyb) rely on this to return a "proof" that an error + // was/will be emitted, despite doing no emission *here and now*. + } + } } /// Emit the diagnostic unless `delay` is true, @@ -93,6 +131,17 @@ impl<'a> DiagnosticBuilder<'a> { self.emit(); } + /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + /// + /// This method takes `self` by-value to disallow calling `.emit()` on it, + /// which may be expected to *guarantee* the emission of an error, either + /// at the time of the call, or through a prior `.emit()` call. + pub fn cancel(mut self) { + self.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + drop(self); + } + /// Stashes diagnostic for possible later improvement in a different, /// later stage of the compiler. The diagnostic can be accessed with /// the provided `span` and `key` through [`Handler::steal_diagnostic()`]. @@ -105,22 +154,29 @@ impl<'a> DiagnosticBuilder<'a> { } /// Converts the builder to a `Diagnostic` for later emission, - /// unless handler has disabled such buffering. + /// unless handler has disabled such buffering, or `.emit()` was called. pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> { - if self.handler.flags.dont_buffer_diagnostics - || self.handler.flags.treat_err_as_bug.is_some() - { + let handler = match self.state { + // No `.emit()` calls, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => handler, + // `.emit()` was previously called, nothing we can do. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { + return None; + } + }; + + if handler.flags.dont_buffer_diagnostics || handler.flags.treat_err_as_bug.is_some() { self.emit(); return None; } - let handler = self.handler; - - // We must use `Level::Cancelled` for `dummy` to avoid an ICE about an - // unused diagnostic. - let dummy = Diagnostic::new(Level::Cancelled, ""); + // Take the `Diagnostic` by replacing it with a dummy. + let dummy = Diagnostic::new(Level::Allow, ""); let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy); + // Disable the ICE on `Drop`. + self.cancel(); + // Logging here is useful to help track down where in logs an error was // actually emitted. debug!("buffer: diagnostic={:?}", diagnostic); @@ -314,7 +370,10 @@ impl<'a> DiagnosticBuilder<'a> { /// diagnostic. crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> { debug!("Created new diagnostic"); - DiagnosticBuilder { handler, diagnostic: Box::new(diagnostic) } + DiagnosticBuilder { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + } } } @@ -324,19 +383,26 @@ impl<'a> Debug for DiagnosticBuilder<'a> { } } -/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled +/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled /// or we emit a bug. impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { - if !panicking() && !self.cancelled() { - let mut db = DiagnosticBuilder::new( - self.handler, - Level::Bug, - "the following error was constructed but not emitted", - ); - db.emit(); - self.emit(); - panic!(); + match self.state { + // No `.emit()` or `.cancel()` calls. + DiagnosticBuilderState::Emittable(handler) => { + if !panicking() { + let mut db = DiagnosticBuilder::new( + handler, + Level::Bug, + "the following error was constructed but not emitted", + ); + db.emit(); + handler.emit_diagnostic(&self); + panic!(); + } + } + // `.emit()` was previously called, or maybe we're during `.cancel()`. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 34f52d78ec9..b92b1cac2e8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -911,10 +911,6 @@ impl HandlerInner { // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { - if diagnostic.cancelled() { - return; - } - if diagnostic.level == Level::DelayedBug { // FIXME(eddyb) this should check for `has_errors` and stop pushing // once *any* errors were emitted (and truncate `delayed_span_bugs` @@ -1238,7 +1234,6 @@ pub enum Level { Warning, Note, Help, - Cancelled, FailureNote, Allow, } @@ -1266,7 +1261,7 @@ impl Level { spec.set_fg(Some(Color::Cyan)).set_intense(true); } FailureNote => {} - Allow | Cancelled => unreachable!(), + Allow => unreachable!(), } spec } @@ -1279,7 +1274,6 @@ impl Level { Note => "note", Help => "help", FailureNote => "failure-note", - Cancelled => panic!("Shouldn't call on cancelled error"), Allow => panic!("Shouldn't call on allowed error"), } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ee2b5cf85bd..37e9f6adf0d 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -95,7 +95,7 @@ fn emit_frag_parse_err( match kind { // Try a statement if an expression is wanted but failed and suggest adding `;` to call. AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) { - Err(mut err) => err.cancel(), + Err(err) => err.cancel(), Ok(_) => { e.note( "the macro call doesn't expand to an expression, but it can expand to a statement", diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 36c5ce68849..cbf28d48e14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1598,7 +1598,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. - diag.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `diag` + // is borrowed, so we can't fully defuse it. + diag.downgrade_to_delayed_bug(); return; } }; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 609fc4b78c0..e518edcff02 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -102,7 +102,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option match &mut parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { error!("argument key must be an identifier"); @@ -121,7 +121,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option {} Err(err) => err.cancel(), }, - Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + Err(errs) => drop(errs), } // If the user tried to use a key="value" flag, but is missing the quotes, provide @@ -165,7 +165,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { } match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { - Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if let Some(args) = meta_item.meta_item_list() { if meta_item.has_name(sym::names) { @@ -210,7 +210,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { Ok(..) => {} Err(err) => err.cancel(), }, - Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + Err(errs) => drop(errs), } error!( diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a9a0d44c9a6..379e47077ea 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -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 ccd8fa3dbe9..d56d3124a56 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -461,12 +461,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); @@ -537,7 +537,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 +703,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(); @@ -744,14 +744,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(); } _ => {} @@ -821,7 +821,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 +838,7 @@ impl<'a> Parser<'a> { enclose(l1.span, r1.span); true } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); *self = snapshot; false @@ -938,7 +938,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. @@ -1946,17 +1946,14 @@ impl<'a> Parser<'a> { Ok(expr) } - fn recover_const_param_decl( - &mut self, - ty_generics: Option<&Generics>, - ) -> PResult<'a, Option> { + fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { 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 +1974,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 +1982,8 @@ impl<'a> Parser<'a> { ty_generics: Option<&Generics>, ) -> PResult<'a, Option> { // 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. @@ -2085,7 +2082,7 @@ impl<'a> Parser<'a> { return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2139,7 +2136,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 +2243,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 48b2bf8477c..a66307bcbe0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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> { 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![ @@ -1878,7 +1879,7 @@ impl<'a> Parser<'a> { *self = snapshot; Some(self.mk_expr_err(arr.span)) } - Err(mut e) => { + Err(e) => { e.cancel(); None } @@ -2381,7 +2382,7 @@ impl<'a> Parser<'a> { return Some(err(self, stmts)); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2398,7 +2399,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; 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..1fd8472f380 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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..b30705d8d75 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -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(); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ac3123c40e3..986a8c2b47d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -655,7 +655,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, - mut err: DiagnosticBuilder<'a>, + err: DiagnosticBuilder<'a>, expected: Expected, ) -> PResult<'a, P> { 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); 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..bbd24289b15 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -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 @@ -449,7 +449,7 @@ impl<'a> Parser<'a> { ); } } - Err(mut e) => { + Err(e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); e.cancel(); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9ac3e6e22bd..91695257137 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2001,13 +2001,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // into a single one. let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); - parent_err.cancel(); - err.message = take(&mut parent_err.message); err.code = take(&mut parent_err.code); err.children = take(&mut parent_err.children); - drop(parent_err); + parent_err.cancel(); let def_id = this.parent_scope.module.nearest_parent_mod(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 396a7d37ca7..c8d9ddb4a4d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1962,7 +1962,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { // Avoid complaining about other inference issues for expressions like // `42 >> 1`, where the types are still `{integer}`, but we want to // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); return; } let post = if post.len() > 4 { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 0338dd39cf6..293f388ff9c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2114,7 +2114,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); return; } diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index dff370ab750..58ca8869ea9 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -69,9 +69,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option parser, Err(diagnostics) => { - for mut diagnostic in diagnostics { - diagnostic.cancel(); - } + drop(diagnostics); return None; } }; @@ -79,7 +77,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option reparsed_trees, - Err(mut diagnostic) => { + Err(diagnostic) => { diagnostic.cancel(); return None; } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 696397c5f67..96182b0da13 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -551,10 +551,7 @@ crate fn make_test( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source) { Ok(p) => p, Err(errs) => { - for mut err in errs { - err.cancel(); - } - + drop(errs); return (found_main, found_extern_crate, found_macro); } }; @@ -594,7 +591,7 @@ crate fn make_test( } } Ok(None) => break, - Err(mut e) => { + Err(e) => { e.cancel(); break; } diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 8b0cebfa60e..a37d3a32571 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -42,7 +42,7 @@ fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let mut p = new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string); - p.parse_expr().map_err(|mut e| e.cancel()).ok() + p.parse_expr().map_err(|e| e.cancel()).ok() } // Helper functions for building exprs diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index a00361e6062..16173580fd4 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -628,9 +628,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - for mut err in errs { - err.cancel(); - } + drop(errs); return false; }, }; @@ -668,7 +666,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { _ => {}, }, Ok(None) => break, - Err(mut e) => { + Err(e) => { e.cancel(); return false; }, diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 1fa6301ebd7..a328ddda5ae 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -534,7 +534,7 @@ impl Write { match parser .parse_expr() .map(rustc_ast::ptr::P::into_inner) - .map_err(|mut e| e.cancel()) + .map_err(|e| e.cancel()) { // write!(e, ...) Ok(p) if parser.eat(&token::Comma) => Some(p), @@ -563,7 +563,7 @@ impl Write { } let comma_span = parser.prev_token.span; - let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) { + let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|err| err.cancel()) { expr } else { return (Some(fmtstr), None); diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 9c964b274e0..d4bddd95785 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -439,7 +439,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { } } Err(mod_err) if !mods_outside_ast.is_empty() => { - if let ModError::ParserError(mut e) = mod_err { + if let ModError::ParserError(e) = mod_err { e.cancel(); } Ok(Some(SubModKind::MultiExternal(mods_outside_ast))) diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index e10fbe64bcd..306b6bb745e 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -57,7 +57,7 @@ fn parse_cfg_if_inner<'a>( let item = match parser.parse_item(ForceCollect::No) { Ok(Some(item_ptr)) => item_ptr.into_inner(), Ok(None) => continue, - Err(mut err) => { + Err(err) => { err.cancel(); parser.sess.span_diagnostic.reset_err_count(); return Err( diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index 9c8651aa3fa..4c541de04be 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -23,7 +23,7 @@ pub(crate) fn parse_lazy_static( val } } - Err(mut err) => { + Err(err) => { err.cancel(); parser.sess.span_diagnostic.reset_err_count(); return None; diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 2e9ce1d35f4..fd738908170 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -36,7 +36,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { return Some(MacroArg::$macro_arg($f(x)?)); } } - Err(mut e) => { + Err(e) => { e.cancel(); parser.sess.span_diagnostic.reset_err_count(); } diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 657217633f4..f0944a88d2f 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { match parser.parse_mod(&TokenKind::Eof) { Ok(result) => Some(result), Err(mut e) => { - sess.emit_or_cancel_diagnostic(&mut e); + e.emit(); if sess.can_reset_errors() { sess.reset_errors(); } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index d26bb8c2025..40a6d708d8c 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -230,17 +230,6 @@ impl ParseSess { } } - pub(crate) fn emit_or_cancel_diagnostic(&self, diagnostic: &mut Diagnostic) { - self.parse_sess.span_diagnostic.emit_diagnostic(diagnostic); - // The Handler will check whether the diagnostic should be emitted - // based on the user's rustfmt configuration and the originating file - // that caused the parser error. If the Handler determined it should skip - // emission then we need to ensure the diagnostic is cancelled. - if !diagnostic.cancelled() { - diagnostic.cancel(); - } - } - pub(super) fn can_reset_errors(&self) -> bool { self.can_reset_errors.load(Ordering::Acquire) }