about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/path.rs84
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs1
-rw-r--r--src/test/ui/parser/issue-84104.rs3
-rw-r--r--src/test/ui/parser/issue-84104.stderr16
-rw-r--r--src/test/ui/parser/issue-84148-1.rs4
-rw-r--r--src/test/ui/parser/issue-84148-1.stderr23
-rw-r--r--src/test/ui/parser/issue-84148-2.rs4
-rw-r--r--src/test/ui/parser/issue-84148-2.stderr31
-rw-r--r--src/test/ui/parser/unmatched-langle-1.rs9
-rw-r--r--src/test/ui/parser/unmatched-langle-1.stderr22
-rw-r--r--src/test/ui/parser/unmatched-langle-2.rs15
-rw-r--r--src/test/ui/parser/unmatched-langle-2.stderr8
12 files changed, 182 insertions, 38 deletions
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();
-                }
-
-                // 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 89cf2d7876e..de5a5632600 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 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/issue-84148-1.rs b/src/test/ui/parser/issue-84148-1.rs
new file mode 100644
index 00000000000..25f7ba4d1f8
--- /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 00000000000..98506568d82
--- /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 `<eof>`
+  --> $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 00000000000..257a3fd6720
--- /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 00000000000..6f314da4360
--- /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 `<eof>`
+  --> $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 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::<<<<Ty<i32>>();
+    //~^ 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::<<<<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`.
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::<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 `(`
+}
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::<Ty<<<i32>();
+   |                    ^ expected `::`
+
+error: aborting due to previous error
+