Fix handling of unmatched angle brackets in parser

This commit is contained in:
Fabian Wolff 2021-06-04 22:46:57 +02:00
parent 4e219e6335
commit 6a6a605a61
7 changed files with 120 additions and 37 deletions

View File

@ -352,29 +352,38 @@ impl<'a> Parser<'a> {
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
match self.parse_angle_args() {
Ok(args) => Ok(args),
Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
Err(mut 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());
// Eat the unmatched angle brackets.
let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
.fold(true, |a, _| a && self.eat_lt());
if !all_angle_brackets {
// If there are other tokens in between the extraneous `<`s, we cannot simply
// suggest to remove them. This check also prevents us from accidentally ending
// up in the middle of a multibyte character (issue #84104).
let _ = mem::replace(self, snapshot);
Err(e)
} else {
// Cancel error from being unable to find `>`. We know the error
// must have been this due to a non-zero unmatched angle bracket
// count.
e.cancel();
// Swap `self` with our backup of the parser state before attempting to parse
// generic arguments.
let snapshot = mem::replace(self, snapshot.unwrap());
debug!(
"parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
snapshot.count={:?}",
snapshot.unmatched_angle_bracket_count,
);
// Eat the unmatched angle brackets.
for _ in 0..snapshot.unmatched_angle_bracket_count {
self.eat_lt();
}
// Make a span over ${unmatched angle bracket count} characters.
let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
// This is safe because `all_angle_brackets` ensures that there are only `<`s,
// i.e. no multibyte characters, in this range.
let span =
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
self.struct_span_err(
span,
&format!(
@ -396,6 +405,7 @@ impl<'a> Parser<'a> {
// Try again without unmatched angle bracket characters.
self.parse_angle_args()
}
}
Err(e) => Err(e),
}
}

View File

@ -0,0 +1,3 @@
// error-pattern: this file contains an unclosed delimiter
// error-pattern: expected one of
#[i=i::<ښܖ<

View File

@ -0,0 +1,16 @@
error: this file contains an unclosed delimiter
--> $DIR/issue-84104.rs:3:13
|
LL | #[i=i::<ښܖ<
| - ^
| |
| unclosed delimiter
error: expected one of `>`, a const expression, lifetime, or type, found `]`
--> $DIR/issue-84104.rs:3:13
|
LL | #[i=i::<ښܖ<
| ^ expected one of `>`, a const expression, lifetime, or type
error: aborting due to 2 previous errors

View File

@ -0,0 +1,9 @@
// Check that a suggestion is issued if there are too many `<`s in a
// generic argument list, and that the parser recovers properly.
fn main() {
foo::<<<<Ty<i32>>();
//~^ ERROR: unmatched angle brackets
//~| ERROR: cannot find function `foo` in this scope [E0425]
//~| ERROR: cannot find type `Ty` in this scope [E0412]
}

View File

@ -0,0 +1,22 @@
error: unmatched angle brackets
--> $DIR/unmatched-langle-1.rs:5:10
|
LL | foo::<<<<Ty<i32>>();
| ^^^ help: remove extra angle brackets
error[E0425]: cannot find function `foo` in this scope
--> $DIR/unmatched-langle-1.rs:5:5
|
LL | foo::<<<<Ty<i32>>();
| ^^^ not found in this scope
error[E0412]: cannot find type `Ty` in this scope
--> $DIR/unmatched-langle-1.rs:5:14
|
LL | foo::<<<<Ty<i32>>();
| ^^ not found in this scope
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0412, E0425.
For more information about an error, try `rustc --explain E0412`.

View File

@ -0,0 +1,15 @@
// When there are too many opening `<`s, the compiler would previously
// suggest nonsense if the `<`s were interspersed with other tokens:
//
// error: unmatched angle brackets
// --> unmatched-langle.rs:2:10
// |
// 2 | foo::<Ty<<<i32>();
// | ^^^ help: remove extra angle brackets
//
// This test makes sure that this is no longer happening.
fn main() {
foo::<Ty<<<i32>();
//~^ ERROR: expected `::`, found `(`
}

View File

@ -0,0 +1,8 @@
error: expected `::`, found `(`
--> $DIR/unmatched-langle-2.rs:13:20
|
LL | foo::<Ty<<<i32>();
| ^ expected `::`
error: aborting due to previous error