From 6a6a605a61dfacfa974582484236155ce041a21d Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Fri, 4 Jun 2021 22:46:57 +0200 Subject: [PATCH] Fix handling of unmatched angle brackets in parser --- compiler/rustc_parse/src/parser/path.rs | 84 +++++++++++--------- src/test/ui/parser/issue-84104.rs | 3 + src/test/ui/parser/issue-84104.stderr | 16 ++++ src/test/ui/parser/unmatched-langle-1.rs | 9 +++ src/test/ui/parser/unmatched-langle-1.stderr | 22 +++++ src/test/ui/parser/unmatched-langle-2.rs | 15 ++++ src/test/ui/parser/unmatched-langle-2.stderr | 8 ++ 7 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/parser/issue-84104.rs create mode 100644 src/test/ui/parser/issue-84104.stderr create mode 100644 src/test/ui/parser/unmatched-langle-1.rs create mode 100644 src/test/ui/parser/unmatched-langle-1.stderr create mode 100644 src/test/ui/parser/unmatched-langle-2.rs create mode 100644 src/test/ui/parser/unmatched-langle-2.stderr diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9cc600d9ede..953c6915068 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -352,49 +352,59 @@ 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 => { - // 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(); - + 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()); - 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(); + 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(); + + debug!( + "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ + snapshot.count={:?}", + snapshot.unmatched_angle_bracket_count, + ); + + // Make a span over ${unmatched angle bracket count} characters. + // 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!( + "unmatched angle bracket{}", + pluralize!(snapshot.unmatched_angle_bracket_count) + ), + ) + .span_suggestion( + span, + &format!( + "remove extra angle bracket{}", + pluralize!(snapshot.unmatched_angle_bracket_count) + ), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + + // Try again without unmatched angle bracket characters. + self.parse_angle_args() } - - // Make a span over ${unmatched angle bracket count} characters. - let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); - self.struct_span_err( - span, - &format!( - "unmatched angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - ) - .span_suggestion( - span, - &format!( - "remove extra angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - String::new(), - Applicability::MachineApplicable, - ) - .emit(); - - // Try again without unmatched angle bracket characters. - self.parse_angle_args() } Err(e) => Err(e), } diff --git a/src/test/ui/parser/issue-84104.rs b/src/test/ui/parser/issue-84104.rs new file mode 100644 index 00000000000..998949b94a4 --- /dev/null +++ b/src/test/ui/parser/issue-84104.rs @@ -0,0 +1,3 @@ +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected one of +#[i=i::<ښܖ< diff --git a/src/test/ui/parser/issue-84104.stderr b/src/test/ui/parser/issue-84104.stderr new file mode 100644 index 00000000000..aff31f2c971 --- /dev/null +++ b/src/test/ui/parser/issue-84104.stderr @@ -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 + diff --git a/src/test/ui/parser/unmatched-langle-1.rs b/src/test/ui/parser/unmatched-langle-1.rs new file mode 100644 index 00000000000..fdf2ae39801 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-1.rs @@ -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::<<<>(); + //~^ ERROR: unmatched angle brackets + //~| ERROR: cannot find function `foo` in this scope [E0425] + //~| ERROR: cannot find type `Ty` in this scope [E0412] +} diff --git a/src/test/ui/parser/unmatched-langle-1.stderr b/src/test/ui/parser/unmatched-langle-1.stderr new file mode 100644 index 00000000000..c8072b4c59a --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-1.stderr @@ -0,0 +1,22 @@ +error: unmatched angle brackets + --> $DIR/unmatched-langle-1.rs:5:10 + | +LL | foo::<<<>(); + | ^^^ help: remove extra angle brackets + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/unmatched-langle-1.rs:5:5 + | +LL | foo::<<<>(); + | ^^^ not found in this scope + +error[E0412]: cannot find type `Ty` in this scope + --> $DIR/unmatched-langle-1.rs:5:14 + | +LL | foo::<<<>(); + | ^^ 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`. diff --git a/src/test/ui/parser/unmatched-langle-2.rs b/src/test/ui/parser/unmatched-langle-2.rs new file mode 100644 index 00000000000..8de0d7d89e4 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-2.rs @@ -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::(); +// | ^^^ help: remove extra angle brackets +// +// This test makes sure that this is no longer happening. + +fn main() { + foo::(); + //~^ ERROR: expected `::`, found `(` +} diff --git a/src/test/ui/parser/unmatched-langle-2.stderr b/src/test/ui/parser/unmatched-langle-2.stderr new file mode 100644 index 00000000000..773bb33d8d3 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-2.stderr @@ -0,0 +1,8 @@ +error: expected `::`, found `(` + --> $DIR/unmatched-langle-2.rs:13:20 + | +LL | foo::(); + | ^ expected `::` + +error: aborting due to previous error +