Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recover extra trailing angle brackets in struct definition #73803

Merged
merged 1 commit into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/librustc_parse/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,14 @@ impl<'a> Parser<'a> {
/// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
/// ^^ help: remove extra angle brackets
/// ```
pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
///
/// If `true` is returned, then trailing brackets were recovered, tokens were consumed
/// up until one of the tokens in 'end' was encountered, and an error was emitted.
pub(super) fn check_trailing_angle_brackets(
&mut self,
segment: &PathSegment,
end: &[&TokenKind],
) -> bool {
// This function is intended to be invoked after parsing a path segment where there are two
// cases:
//
Expand Down Expand Up @@ -409,7 +416,7 @@ impl<'a> Parser<'a> {
parsed_angle_bracket_args,
);
if !parsed_angle_bracket_args {
return;
return false;
}

// Keep the span at the start so we can highlight the sequence of `>` characters to be
Expand Down Expand Up @@ -447,18 +454,18 @@ impl<'a> Parser<'a> {
number_of_gt, number_of_shr,
);
if number_of_gt < 1 && number_of_shr < 1 {
return;
return false;
}

// Finally, double check that we have our end token as otherwise this is the
// second case.
if self.look_ahead(position, |t| {
trace!("check_trailing_angle_brackets: t={:?}", t);
*t == end
end.contains(&&t.kind)
}) {
// Eat from where we started until the end token so that parsing can continue
// as if we didn't have those extra angle brackets.
self.eat_to_tokens(&[&end]);
self.eat_to_tokens(end);
let span = lo.until(self.token.span);

let total_num_of_gt = number_of_gt + number_of_shr * 2;
Expand All @@ -473,7 +480,9 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
)
.emit();
return true;
}
false
}

/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ impl<'a> Parser<'a> {

let fn_span_lo = self.token.span;
let segment = self.parse_path_segment(PathStyle::Expr)?;
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);

if self.check(&token::OpenDelim(token::Paren)) {
// Method call `expr.f()`
Expand Down
29 changes: 28 additions & 1 deletion src/librustc_parse/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind,
use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind};
use rustc_ast::ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
Expand Down Expand Up @@ -1262,6 +1262,25 @@ impl<'a> Parser<'a> {
sp,
&format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
);

// Try to recover extra trailing angle brackets
let mut recovered = false;
if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
if let Some(last_segment) = segments.last() {
recovered = self.check_trailing_angle_brackets(
last_segment,
&[&token::Comma, &token::CloseDelim(token::Brace)],
);
if recovered {
// Handle a case like `Vec<u8>>,` where we can continue parsing fields
// after the comma
self.eat(&token::Comma);
// `check_trailing_angle_brackets` already emitted a nicer error
err.cancel();
}
}
}

if self.token.is_ident() {
// This is likely another field; emit the diagnostic and keep going
err.span_suggestion(
Expand All @@ -1271,6 +1290,14 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
);
err.emit();
recovered = true;
}

if recovered {
// Make sure an error was emitted (either by recovering an angle bracket,
// or by finding an identifier as the next token), since we're
// going to continue parsing
assert!(self.sess.span_diagnostic.has_errors());
} else {
return Err(err);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_parse/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl<'a> Parser<'a> {
// `PathStyle::Expr` is only provided at the root invocation and never in
// `parse_path_segment` to recurse and therefore can be checked to maintain
// this invariant.
self.check_trailing_angle_brackets(&segment, token::ModSep);
self.check_trailing_angle_brackets(&segment, &[&token::ModSep]);
}
segments.push(segment);

Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/parser/recover-field-extra-angle-brackets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Tests that we recover from extra trailing angle brackets
// in a struct field

struct BadStruct {
first: Vec<u8>>, //~ ERROR unmatched angle bracket
second: bool
}

fn bar(val: BadStruct) {
val.first;
val.second;
}

fn main() {}
8 changes: 8 additions & 0 deletions src/test/ui/parser/recover-field-extra-angle-brackets.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: unmatched angle bracket
--> $DIR/recover-field-extra-angle-brackets.rs:5:19
|
LL | first: Vec<u8>>,
| ^ help: remove extra angle bracket

error: aborting due to previous error