From 529fd2da894ff290668d6c1524909ba218d5822b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 8 Mar 2022 17:07:35 +0900 Subject: [PATCH 1/8] suggest adding `{ .. }` around a const function with arguments --- compiler/rustc_parse/src/parser/path.rs | 9 ++++ .../const-generics/const-generic-function.rs | 21 ++++++++ .../const-generic-function.stderr | 54 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/test/ui/const-generics/const-generic-function.rs create mode 100644 src/test/ui/const-generics/const-generic-function.stderr diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 5e537d7b95c4a..0bccf4dc2cef6 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -624,9 +624,18 @@ impl<'a> Parser<'a> { GenericArg::Const(self.parse_const_arg()?) } else if self.check_type() { // Parse type argument. + let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren)); + let mut snapshot = self.clone(); match self.parse_ty() { Ok(ty) => GenericArg::Type(ty), Err(err) => { + if is_const_fn { + if let Ok(expr) = snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { + *self = snapshot; + return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); + } + } + // self.parse_fn_call_expr(); // Try to recover from possible `const` arg without braces. return self.recover_const_arg(start, err).map(Some); } diff --git a/src/test/ui/const-generics/const-generic-function.rs b/src/test/ui/const-generics/const-generic-function.rs new file mode 100644 index 0000000000000..c8d2683e53f47 --- /dev/null +++ b/src/test/ui/const-generics/const-generic-function.rs @@ -0,0 +1,21 @@ +fn foo() -> i32 { + N +} + +const fn bar(n: i32, m: i32) -> i32 { + n +} + +const fn baz() -> i32 { + 1 +} + +const FOO: i32 = 3; + +fn main() { + foo::(); //~ ERROR expected type, found function `baz` + //~| ERROR unresolved item provided when a constant was expected + foo::(); //~ ERROR expected type, found `1` + foo::(); //~ ERROR expected type, found `1` + foo::(); //~ ERROR expected type, found `2` +} diff --git a/src/test/ui/const-generics/const-generic-function.stderr b/src/test/ui/const-generics/const-generic-function.stderr new file mode 100644 index 0000000000000..5ad3f1006c17d --- /dev/null +++ b/src/test/ui/const-generics/const-generic-function.stderr @@ -0,0 +1,54 @@ +error: expected type, found `1` + --> $DIR/const-generic-function.rs:18:19 + | +LL | foo::(); + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | foo::<{ bar(bar(1, 1), bar(1, 1)) }>(); + | + + + +error: expected type, found `1` + --> $DIR/const-generic-function.rs:19:15 + | +LL | foo::(); + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | foo::<{ bar(1, 1) }>(); + | + + + +error: expected type, found `2` + --> $DIR/const-generic-function.rs:20:20 + | +LL | foo::(); + | ^ expected type + | +help: expressions must be enclosed in braces to be used as const generic arguments + | +LL | foo::<{ bar(FOO, 2) }>(); + | + + + +error[E0573]: expected type, found function `baz` + --> $DIR/const-generic-function.rs:16:11 + | +LL | foo::(); + | ^^^^^ not a type + +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/const-generic-function.rs:16:11 + | +LL | foo::(); + | ^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | foo::<{ baz() }>(); + | + + + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0573, E0747. +For more information about an error, try `rustc --explain E0573`. From 527b1f3c2fb478cf30c9b33e945da2adaf29b6e0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 9 Mar 2022 12:59:46 +0900 Subject: [PATCH 2/8] initialize unclosed_delims field --- compiler/rustc_parse/src/parser/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 0bccf4dc2cef6..750d7cce0c0e7 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -626,6 +626,7 @@ impl<'a> Parser<'a> { // Parse type argument. let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren)); let mut snapshot = self.clone(); + snapshot.unclosed_delims = vec![]; match self.parse_ty() { Ok(ty) => GenericArg::Type(ty), Err(err) => { From a34015c0d0c264e98b6753da4c5454433092c02b Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 9 Mar 2022 13:48:40 +0900 Subject: [PATCH 3/8] implement and use `diagnostic_snapshot` --- compiler/rustc_parse/src/parser/diagnostics.rs | 7 +++++++ compiler/rustc_parse/src/parser/path.rs | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 40daf4eb28fc1..94805f4eb8b61 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -179,6 +179,13 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } + pub(super) fn diagnostic_snapshot(&self) -> Self { + let mut snapshot = self.clone(); + // initialize unclosed_delims to avoid duplicate errors. + snapshot.unclosed_delims = vec![]; + snapshot + } + pub(super) fn span_to_snippet(&self, span: Span) -> Result { self.sess.source_map().span_to_snippet(span) } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 750d7cce0c0e7..f300b9c5ae4bd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -625,8 +625,7 @@ impl<'a> Parser<'a> { } else if self.check_type() { // Parse type argument. let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren)); - let mut snapshot = self.clone(); - snapshot.unclosed_delims = vec![]; + let mut snapshot = self.diagnostic_snapshot(); match self.parse_ty() { Ok(ty) => GenericArg::Type(ty), Err(err) => { From 35147413585bb74837aa32448dd9b9ca78219974 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 9 Mar 2022 14:10:34 +0900 Subject: [PATCH 4/8] remove an unnecessary comment --- compiler/rustc_parse/src/parser/path.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index f300b9c5ae4bd..c8ebf707477ac 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -635,7 +635,6 @@ impl<'a> Parser<'a> { return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); } } - // self.parse_fn_call_expr(); // Try to recover from possible `const` arg without braces. return self.recover_const_arg(start, err).map(Some); } From 192acb4b98bb027cb09eaeb8906dbc94a76b9b66 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 9 Mar 2022 16:04:14 +0900 Subject: [PATCH 5/8] take over unclosed_delims --- compiler/rustc_parse/src/parser/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c8ebf707477ac..264174b0ac71d 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -631,6 +631,7 @@ impl<'a> Parser<'a> { Err(err) => { if is_const_fn { if let Ok(expr) = snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { + snapshot.unclosed_delims.extend(self.unclosed_delims.clone()); *self = snapshot; return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); } From 3ded25204b9b91cf4f14977cae81215a60409558 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 9 Mar 2022 23:13:04 +0900 Subject: [PATCH 6/8] implement `SnapshotParser` struct --- .../rustc_parse/src/parser/diagnostics.rs | 33 +++++++++++++++++-- compiler/rustc_parse/src/parser/path.rs | 6 ++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 94805f4eb8b61..4360399d4470c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -5,6 +5,7 @@ use super::{ SemiColonMode, SeqSep, TokenExpectType, TokenType, }; +use crate::lexer::UnmatchedBrace; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Lit, LitKind, TokenKind}; @@ -21,6 +22,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; +use std::ops::{Deref, DerefMut}; use std::mem::take; @@ -154,6 +156,25 @@ impl AttemptLocalParseRecovery { } } +pub(super) struct SnapshotParser<'a> { + parser: Parser<'a>, + unclosed_delims: Vec, +} + +impl<'a> Deref for SnapshotParser<'a> { + type Target = Parser<'a>; + + fn deref(&self) -> &Self::Target { + &self.parser + } +} + +impl<'a> DerefMut for SnapshotParser<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.parser + } +} + impl<'a> Parser<'a> { pub(super) fn span_err>( &self, @@ -179,11 +200,17 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } - pub(super) fn diagnostic_snapshot(&self) -> Self { + pub(super) fn restore(&mut self, snapshot: SnapshotParser<'a>) { + *self = snapshot.parser; + self.unclosed_delims.extend(snapshot.unclosed_delims.clone()); + } + + pub(super) fn diagnostic_snapshot(&self) -> SnapshotParser<'a> { let mut snapshot = self.clone(); + let unclosed_delims = self.unclosed_delims.clone(); // initialize unclosed_delims to avoid duplicate errors. - snapshot.unclosed_delims = vec![]; - snapshot + snapshot.unclosed_delims.clear(); + SnapshotParser { parser: snapshot, unclosed_delims } } pub(super) fn span_to_snippet(&self, span: Span) -> Result { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 264174b0ac71d..12d50fdba10a6 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -630,9 +630,9 @@ impl<'a> Parser<'a> { Ok(ty) => GenericArg::Type(ty), Err(err) => { if is_const_fn { - if let Ok(expr) = snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { - snapshot.unclosed_delims.extend(self.unclosed_delims.clone()); - *self = snapshot; + if let Ok(expr) = (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) + { + self.restore(snapshot); return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); } } From 2db82368574b7b751203418300345a4eb75f1147 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 10 Mar 2022 19:34:42 +0900 Subject: [PATCH 7/8] add doc comments --- compiler/rustc_parse/src/parser/diagnostics.rs | 15 ++++++++++++--- compiler/rustc_parse/src/parser/path.rs | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4360399d4470c..e042df98edf38 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -156,6 +156,9 @@ impl AttemptLocalParseRecovery { } } +// SnapshotParser is used to create a snapshot of the parser +// without causing duplicate errors being emitted when the `Parser` +// is dropped. pub(super) struct SnapshotParser<'a> { parser: Parser<'a>, unclosed_delims: Vec, @@ -200,15 +203,21 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } - pub(super) fn restore(&mut self, snapshot: SnapshotParser<'a>) { + /// Relace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`. + /// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears. + pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) { *self = snapshot.parser; self.unclosed_delims.extend(snapshot.unclosed_delims.clone()); } - pub(super) fn diagnostic_snapshot(&self) -> SnapshotParser<'a> { + /// Create a snapshot of the `Parser`. + pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> { let mut snapshot = self.clone(); let unclosed_delims = self.unclosed_delims.clone(); - // initialize unclosed_delims to avoid duplicate errors. + // Clear `unclosed_delims` in snapshot to avoid + // duplicate errors being emitted when the `Parser` + // is dropped (which may or may not happen, depending + // if the parsing the snapshot is created for is successful) snapshot.unclosed_delims.clear(); SnapshotParser { parser: snapshot, unclosed_delims } } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 12d50fdba10a6..5d41d80833642 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -625,14 +625,14 @@ impl<'a> Parser<'a> { } else if self.check_type() { // Parse type argument. let is_const_fn = self.look_ahead(1, |t| t.kind == token::OpenDelim(token::Paren)); - let mut snapshot = self.diagnostic_snapshot(); + let mut snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(ty) => GenericArg::Type(ty), Err(err) => { if is_const_fn { if let Ok(expr) = (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) { - self.restore(snapshot); + self.restore_snapshot(snapshot); return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); } } From 9a6532276ec45e22695f0a012a0782c97bf39a2d Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 10 Mar 2022 22:11:00 +0900 Subject: [PATCH 8/8] replace `self.clone()` with `self.create_snapshot_for_diagnostic()` --- compiler/rustc_parse/src/parser/attr.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 44 +++++++++---------- compiler/rustc_parse/src/parser/expr.rs | 22 +++++----- compiler/rustc_parse/src/parser/path.rs | 4 +- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 379e47077ea18..a90eff0221082 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { span: Span, attr_type: OuterAttributeType, ) -> Option { - let mut snapshot = self.clone(); + let mut snapshot = self.create_snapshot_for_diagnostic(); let lo = span.lo() + BytePos(match attr_type { OuterAttributeType::Attribute => 1, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e042df98edf38..250050a48f0a9 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -481,7 +481,7 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { // field: value, // } - let mut snapshot = self.clone(); + let mut snapshot = self.create_snapshot_for_diagnostic(); let path = Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None }; let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false); @@ -507,7 +507,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ) .emit(); - *self = snapshot; + self.restore_snapshot(snapshot); let mut tail = self.mk_block( vec![self.mk_stmt_err(expr.span)], s, @@ -721,7 +721,7 @@ impl<'a> Parser<'a> { /// angle brackets. pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) { if token::ModSep == self.token.kind && segment.args.is_none() { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); let lo = self.token.span; match self.parse_angle_args(None) { @@ -755,14 +755,14 @@ impl<'a> Parser<'a> { .emit(); } else { // This doesn't look like an invalid turbofish, can't recover parse state. - *self = snapshot; + self.restore_snapshot(snapshot); } } Err(err) => { // We couldn't parse generic parameters, unlikely to be a turbofish. Rely on // generic parse error instead. err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); } } } @@ -868,7 +868,7 @@ impl<'a> Parser<'a> { // `x == y < z` (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => { // Consume `z`/outer-op-rhs. - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_expr() { Ok(r2) => { // We are sure that outer-op-rhs could be consumed, the suggestion is @@ -878,14 +878,14 @@ impl<'a> Parser<'a> { } Err(expr_err) => { expr_err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); false } } } // `x > y == z` (BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); // At this point it is always valid to enclose the lhs in parentheses, no // further checks are necessary. match self.parse_expr() { @@ -895,7 +895,7 @@ impl<'a> Parser<'a> { } Err(expr_err) => { expr_err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); false } } @@ -960,7 +960,7 @@ impl<'a> Parser<'a> { || outer_op.node == AssocOp::Greater { if outer_op.node == AssocOp::Less { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); // So far we have parsed `foo Parser<'a> { { // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the // parser and bail out. - *self = snapshot.clone(); + self.restore_snapshot(snapshot); } } return if token::ModSep == self.token.kind { @@ -980,7 +980,7 @@ impl<'a> Parser<'a> { // `foo< bar >::` suggest(&mut err); - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); // `::` // Consume the rest of the likely `foo::new()` or return at `foo`. @@ -997,7 +997,7 @@ impl<'a> Parser<'a> { expr_err.cancel(); // Not entirely sure now, but we bubble the error up with the // suggestion. - *self = snapshot; + self.restore_snapshot(snapshot); Err(err) } } @@ -1051,7 +1051,7 @@ impl<'a> Parser<'a> { } fn consume_fn_args(&mut self) -> Result<(), ()> { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); // `(` // Consume the fn call arguments. @@ -1061,7 +1061,7 @@ impl<'a> Parser<'a> { if self.token.kind == token::Eof { // Not entirely sure that what we consumed were fn arguments, rollback. - *self = snapshot; + self.restore_snapshot(snapshot); Err(()) } else { // 99% certain that the suggestion is correct, continue parsing. @@ -2002,12 +2002,12 @@ impl<'a> Parser<'a> { } fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); let param = match self.parse_const_param(vec![]) { Ok(param) => param, Err(err) => { err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); return None; } }; @@ -2099,7 +2099,7 @@ impl<'a> Parser<'a> { // We perform these checks and early return to avoid taking a snapshot unnecessarily. return Err(err); } - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); if is_op_or_dot { self.bump(); } @@ -2131,7 +2131,7 @@ impl<'a> Parser<'a> { err.cancel(); } } - *self = snapshot; + self.restore_snapshot(snapshot); Err(err) } @@ -2191,7 +2191,7 @@ impl<'a> Parser<'a> { let span = self.token.span; // We only emit "unexpected `:`" error here if we can successfully parse the // whole pattern correctly in that case. - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); // Create error for "unexpected `:`". match self.expected_one_of_not_found(&[], &[]) { @@ -2203,7 +2203,7 @@ impl<'a> Parser<'a> { // reasonable error. inner_err.cancel(); err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); } Ok(mut pat) => { // We've parsed the rest of the pattern. @@ -2282,7 +2282,7 @@ impl<'a> Parser<'a> { } _ => { // Carry on as if we had not done anything. This should be unreachable. - *self = snapshot; + self.restore_snapshot(snapshot); } }; first_pat diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index df865d77b9bb4..e160385d3a4be 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -704,7 +704,7 @@ impl<'a> Parser<'a> { ExprKind::Path(None, ast::Path { segments, .. }), TokenKind::Ident(kw::For | kw::Loop | kw::While, false), ) if segments.len() == 1 => { - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); let label = Label { ident: Ident::from_str_and_span( &format!("'{}", segments[0].ident), @@ -726,7 +726,7 @@ impl<'a> Parser<'a> { } Err(err) => { err.cancel(); - *self = snapshot; + self.restore_snapshot(snapshot); } } } @@ -1886,7 +1886,7 @@ impl<'a> Parser<'a> { lo: Span, attrs: AttrVec, ) -> Option> { - let mut snapshot = self.clone(); + let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) { Ok(arr) => { let hi = snapshot.prev_token.span; @@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> { .note("to define an array, one would use square brackets instead of curly braces") .emit(); - *self = snapshot; + self.restore_snapshot(snapshot); Some(self.mk_expr_err(arr.span)) } Err(e) => { @@ -2370,7 +2370,7 @@ impl<'a> Parser<'a> { if self.token.kind != token::Semi { return None; } - let start_snapshot = self.clone(); + let start_snapshot = self.create_snapshot_for_diagnostic(); let semi_sp = self.token.span; self.bump(); // `;` let mut stmts = @@ -2418,15 +2418,15 @@ impl<'a> Parser<'a> { return Some(err(self, stmts)); } if self.token.kind == token::Comma { - *self = start_snapshot; + self.restore_snapshot(start_snapshot); return None; } - let pre_pat_snapshot = self.clone(); + let pre_pat_snapshot = self.create_snapshot_for_diagnostic(); match self.parse_pat_no_top_alt(None) { Ok(_pat) => { if self.token.kind == token::FatArrow { // Reached arm end. - *self = pre_pat_snapshot; + self.restore_snapshot(pre_pat_snapshot); return Some(err(self, stmts)); } } @@ -2435,21 +2435,21 @@ impl<'a> Parser<'a> { } } - *self = pre_pat_snapshot; + self.restore_snapshot(pre_pat_snapshot); match self.parse_stmt_without_recovery(true, ForceCollect::No) { // Consume statements for as long as possible. Ok(Some(stmt)) => { stmts.push(stmt); } Ok(None) => { - *self = start_snapshot; + self.restore_snapshot(start_snapshot); break; } // We couldn't parse either yet another statement missing it's // enclosing block nor the next arm's pattern or closing brace. Err(stmt_err) => { stmt_err.cancel(); - *self = start_snapshot; + self.restore_snapshot(start_snapshot); break; } } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 5d41d80833642..17c57867cf9cf 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -645,7 +645,7 @@ impl<'a> Parser<'a> { } else { // Fall back by trying to parse a const-expr expression. If we successfully do so, // then we should report an error that it needs to be wrapped in braces. - let snapshot = self.clone(); + let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_expr_res(Restrictions::CONST_EXPR, None) { Ok(expr) => { return Ok(Some(self.dummy_const_arg_needs_braces( @@ -654,7 +654,7 @@ impl<'a> Parser<'a> { ))); } Err(err) => { - *self = snapshot; + self.restore_snapshot(snapshot); err.cancel(); return Ok(None); }