diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9cc600d9ede02..953c6915068af 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(); - } - - // 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(); + 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() + // Try again without unmatched angle bracket characters. + self.parse_angle_args() + } } Err(e) => Err(e), } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 89cf2d7876e1d..de5a5632600e4 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -334,7 +334,6 @@ impl<'a> Parser<'a> { mut bounds: GenericBounds, plus: bool, ) -> PResult<'a, TyKind> { - assert_ne!(self.token, token::Question); if plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?); diff --git a/src/test/ui/parser/issue-84104.rs b/src/test/ui/parser/issue-84104.rs new file mode 100644 index 0000000000000..998949b94a4ba --- /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 0000000000000..aff31f2c97149 --- /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/issue-84148-1.rs b/src/test/ui/parser/issue-84148-1.rs new file mode 100644 index 0000000000000..25f7ba4d1f88e --- /dev/null +++ b/src/test/ui/parser/issue-84148-1.rs @@ -0,0 +1,4 @@ +fn f(t:for<>t?) +//~^ ERROR: expected parameter name +//~| ERROR: expected one of +//~| ERROR: expected one of diff --git a/src/test/ui/parser/issue-84148-1.stderr b/src/test/ui/parser/issue-84148-1.stderr new file mode 100644 index 0000000000000..98506568d82c2 --- /dev/null +++ b/src/test/ui/parser/issue-84148-1.stderr @@ -0,0 +1,23 @@ +error: expected parameter name, found `?` + --> $DIR/issue-84148-1.rs:1:14 + | +LL | fn f(t:for<>t?) + | ^ expected parameter name + +error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` + --> $DIR/issue-84148-1.rs:1:14 + | +LL | fn f(t:for<>t?) + | ^ + | | + | expected one of `(`, `)`, `+`, `,`, `::`, or `<` + | help: missing `,` + +error: expected one of `->`, `;`, `where`, or `{`, found `` + --> $DIR/issue-84148-1.rs:1:15 + | +LL | fn f(t:for<>t?) + | ^ expected one of `->`, `;`, `where`, or `{` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/issue-84148-2.rs b/src/test/ui/parser/issue-84148-2.rs new file mode 100644 index 0000000000000..257a3fd67207e --- /dev/null +++ b/src/test/ui/parser/issue-84148-2.rs @@ -0,0 +1,4 @@ +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected parameter name +// error-pattern: expected one of +fn f(t:for<>t? diff --git a/src/test/ui/parser/issue-84148-2.stderr b/src/test/ui/parser/issue-84148-2.stderr new file mode 100644 index 0000000000000..6f314da436070 --- /dev/null +++ b/src/test/ui/parser/issue-84148-2.stderr @@ -0,0 +1,31 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-84148-2.rs:4:16 + | +LL | fn f(t:for<>t? + | - ^ + | | + | unclosed delimiter + +error: expected parameter name, found `?` + --> $DIR/issue-84148-2.rs:4:14 + | +LL | fn f(t:for<>t? + | ^ expected parameter name + +error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` + --> $DIR/issue-84148-2.rs:4:14 + | +LL | fn f(t:for<>t? + | ^ + | | + | expected one of `(`, `)`, `+`, `,`, `::`, or `<` + | help: missing `,` + +error: expected one of `->`, `;`, `where`, or `{`, found `` + --> $DIR/issue-84148-2.rs:4:16 + | +LL | fn f(t:for<>t? + | ^ expected one of `->`, `;`, `where`, or `{` + +error: aborting due to 4 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 0000000000000..fdf2ae398014b --- /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 0000000000000..c8072b4c59ad2 --- /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 0000000000000..8de0d7d89e4e7 --- /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 0000000000000..773bb33d8d3f3 --- /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 +