Skip to content

Commit 5d429f3

Browse files
authored
Rollup merge of #73803 - Aaron1011:feature/angle-field-recovery, r=matthewjasper
Recover extra trailing angle brackets in struct definition This commit applies the existing 'extra angle bracket recovery' logic when parsing fields in struct definitions. This allows us to continue parsing the struct's fields, avoiding spurious 'missing field' errors in code that tries to use the struct.
2 parents ce49944 + 765bd47 commit 5d429f3

File tree

6 files changed

+66
-8
lines changed

6 files changed

+66
-8
lines changed

src/librustc_parse/parser/diagnostics.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,14 @@ impl<'a> Parser<'a> {
376376
/// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
377377
/// ^^ help: remove extra angle brackets
378378
/// ```
379-
pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
379+
///
380+
/// If `true` is returned, then trailing brackets were recovered, tokens were consumed
381+
/// up until one of the tokens in 'end' was encountered, and an error was emitted.
382+
pub(super) fn check_trailing_angle_brackets(
383+
&mut self,
384+
segment: &PathSegment,
385+
end: &[&TokenKind],
386+
) -> bool {
380387
// This function is intended to be invoked after parsing a path segment where there are two
381388
// cases:
382389
//
@@ -409,7 +416,7 @@ impl<'a> Parser<'a> {
409416
parsed_angle_bracket_args,
410417
);
411418
if !parsed_angle_bracket_args {
412-
return;
419+
return false;
413420
}
414421

415422
// Keep the span at the start so we can highlight the sequence of `>` characters to be
@@ -447,18 +454,18 @@ impl<'a> Parser<'a> {
447454
number_of_gt, number_of_shr,
448455
);
449456
if number_of_gt < 1 && number_of_shr < 1 {
450-
return;
457+
return false;
451458
}
452459

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

464471
let total_num_of_gt = number_of_gt + number_of_shr * 2;
@@ -473,7 +480,9 @@ impl<'a> Parser<'a> {
473480
Applicability::MachineApplicable,
474481
)
475482
.emit();
483+
return true;
476484
}
485+
false
477486
}
478487

479488
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,

src/librustc_parse/parser/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ impl<'a> Parser<'a> {
867867

868868
let fn_span_lo = self.token.span;
869869
let segment = self.parse_path_segment(PathStyle::Expr)?;
870-
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
870+
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
871871

872872
if self.check(&token::OpenDelim(token::Paren)) {
873873
// Method call `expr.f()`

src/librustc_parse/parser/item.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind,
99
use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
1010
use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
1111
use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
12-
use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind};
12+
use rustc_ast::ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
1313
use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter};
1414
use rustc_ast::ptr::P;
1515
use rustc_ast::token::{self, TokenKind};
@@ -1262,6 +1262,25 @@ impl<'a> Parser<'a> {
12621262
sp,
12631263
&format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
12641264
);
1265+
1266+
// Try to recover extra trailing angle brackets
1267+
let mut recovered = false;
1268+
if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
1269+
if let Some(last_segment) = segments.last() {
1270+
recovered = self.check_trailing_angle_brackets(
1271+
last_segment,
1272+
&[&token::Comma, &token::CloseDelim(token::Brace)],
1273+
);
1274+
if recovered {
1275+
// Handle a case like `Vec<u8>>,` where we can continue parsing fields
1276+
// after the comma
1277+
self.eat(&token::Comma);
1278+
// `check_trailing_angle_brackets` already emitted a nicer error
1279+
err.cancel();
1280+
}
1281+
}
1282+
}
1283+
12651284
if self.token.is_ident() {
12661285
// This is likely another field; emit the diagnostic and keep going
12671286
err.span_suggestion(
@@ -1271,6 +1290,14 @@ impl<'a> Parser<'a> {
12711290
Applicability::MachineApplicable,
12721291
);
12731292
err.emit();
1293+
recovered = true;
1294+
}
1295+
1296+
if recovered {
1297+
// Make sure an error was emitted (either by recovering an angle bracket,
1298+
// or by finding an identifier as the next token), since we're
1299+
// going to continue parsing
1300+
assert!(self.sess.span_diagnostic.has_errors());
12741301
} else {
12751302
return Err(err);
12761303
}

src/librustc_parse/parser/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl<'a> Parser<'a> {
169169
// `PathStyle::Expr` is only provided at the root invocation and never in
170170
// `parse_path_segment` to recurse and therefore can be checked to maintain
171171
// this invariant.
172-
self.check_trailing_angle_brackets(&segment, token::ModSep);
172+
self.check_trailing_angle_brackets(&segment, &[&token::ModSep]);
173173
}
174174
segments.push(segment);
175175

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Tests that we recover from extra trailing angle brackets
2+
// in a struct field
3+
4+
struct BadStruct {
5+
first: Vec<u8>>, //~ ERROR unmatched angle bracket
6+
second: bool
7+
}
8+
9+
fn bar(val: BadStruct) {
10+
val.first;
11+
val.second;
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: unmatched angle bracket
2+
--> $DIR/recover-field-extra-angle-brackets.rs:5:19
3+
|
4+
LL | first: Vec<u8>>,
5+
| ^ help: remove extra angle bracket
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)