summaryrefslogtreecommitdiffstats
path: root/tests/ui/parser/recover
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/parser/recover')
-rw-r--r--tests/ui/parser/recover/binding-name-starting-with-number.rs21
-rw-r--r--tests/ui/parser/recover/binding-name-starting-with-number.stderr59
-rw-r--r--tests/ui/parser/recover/recover-assoc-const-constraint.rs9
-rw-r--r--tests/ui/parser/recover/recover-assoc-const-constraint.stderr21
-rw-r--r--tests/ui/parser/recover/recover-assoc-eq-missing-term.rs6
-rw-r--r--tests/ui/parser/recover/recover-assoc-eq-missing-term.stderr18
-rw-r--r--tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs6
-rw-r--r--tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr12
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.rs25
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.stderr155
-rw-r--r--tests/ui/parser/recover/recover-enum.rs11
-rw-r--r--tests/ui/parser/recover/recover-enum.stderr37
-rw-r--r--tests/ui/parser/recover/recover-enum2.rs29
-rw-r--r--tests/ui/parser/recover/recover-enum2.stderr37
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.rs6
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr11
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets.rs14
-rw-r--r--tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr8
-rw-r--r--tests/ui/parser/recover/recover-field-semi.rs16
-rw-r--r--tests/ui/parser/recover/recover-field-semi.stderr35
-rw-r--r--tests/ui/parser/recover/recover-fn-ptr-with-generics.rs31
-rw-r--r--tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr111
-rw-r--r--tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs12
-rw-r--r--tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr48
-rw-r--r--tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed15
-rw-r--r--tests/ui/parser/recover/recover-for-loop-parens-around-head.rs15
-rw-r--r--tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr26
-rw-r--r--tests/ui/parser/recover/recover-from-bad-variant.rs15
-rw-r--r--tests/ui/parser/recover/recover-from-bad-variant.stderr37
-rw-r--r--tests/ui/parser/recover/recover-from-homoglyph.rs4
-rw-r--r--tests/ui/parser/recover/recover-from-homoglyph.stderr22
-rw-r--r--tests/ui/parser/recover/recover-labeled-non-block-expr.fixed26
-rw-r--r--tests/ui/parser/recover/recover-labeled-non-block-expr.rs26
-rw-r--r--tests/ui/parser/recover/recover-labeled-non-block-expr.stderr74
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.fixed61
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.rs61
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.stderr83
-rw-r--r--tests/ui/parser/recover/recover-missing-semi.rs13
-rw-r--r--tests/ui/parser/recover/recover-missing-semi.stderr37
-rw-r--r--tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed12
-rw-r--r--tests/ui/parser/recover/recover-parens-around-match-arm-head.rs12
-rw-r--r--tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr28
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.rs12
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.stderr37
-rw-r--r--tests/ui/parser/recover/recover-range-pats.rs159
-rw-r--r--tests/ui/parser/recover/recover-range-pats.stderr484
-rw-r--r--tests/ui/parser/recover/recover-ref-dyn-mut.rs9
-rw-r--r--tests/ui/parser/recover/recover-ref-dyn-mut.stderr15
-rw-r--r--tests/ui/parser/recover/recover-struct.rs7
-rw-r--r--tests/ui/parser/recover/recover-struct.stderr12
-rw-r--r--tests/ui/parser/recover/recover-tuple-pat.rs12
-rw-r--r--tests/ui/parser/recover/recover-tuple-pat.stderr8
-rw-r--r--tests/ui/parser/recover/recover-tuple.rs11
-rw-r--r--tests/ui/parser/recover/recover-tuple.stderr17
-rw-r--r--tests/ui/parser/recover/recover-unticked-labels.fixed7
-rw-r--r--tests/ui/parser/recover/recover-unticked-labels.rs7
-rw-r--r--tests/ui/parser/recover/recover-unticked-labels.stderr29
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed15
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs17
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr40
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.rs7
-rw-r--r--tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.stderr23
62 files changed, 2233 insertions, 0 deletions
diff --git a/tests/ui/parser/recover/binding-name-starting-with-number.rs b/tests/ui/parser/recover/binding-name-starting-with-number.rs
new file mode 100644
index 000000000..6b279c553
--- /dev/null
+++ b/tests/ui/parser/recover/binding-name-starting-with-number.rs
@@ -0,0 +1,21 @@
+fn 1234test() {
+//~^ ERROR expected identifier, found `1234test`
+ if let 123 = 123 { println!("yes"); }
+
+ if let 2e1 = 123 {
+ //~^ ERROR mismatched types
+ }
+
+ let 23name = 123;
+ //~^ ERROR expected identifier, found `23name`
+}
+fn foo() {
+ let 2x: i32 = 123;
+ //~^ ERROR expected identifier, found `2x`
+}
+fn bar() {
+ let 1x = 123;
+ //~^ ERROR expected identifier, found `1x`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/binding-name-starting-with-number.stderr b/tests/ui/parser/recover/binding-name-starting-with-number.stderr
new file mode 100644
index 000000000..de59a7de0
--- /dev/null
+++ b/tests/ui/parser/recover/binding-name-starting-with-number.stderr
@@ -0,0 +1,59 @@
+error: expected identifier, found `1234test`
+ --> $DIR/binding-name-starting-with-number.rs:1:4
+ |
+LL | fn 1234test() {
+ | ^^^^^^^^ expected identifier
+ |
+help: identifiers cannot start with a number
+ --> $DIR/binding-name-starting-with-number.rs:1:4
+ |
+LL | fn 1234test() {
+ | ^^^^
+
+error: expected identifier, found `23name`
+ --> $DIR/binding-name-starting-with-number.rs:9:9
+ |
+LL | let 23name = 123;
+ | ^^^^^^ expected identifier
+ |
+help: identifiers cannot start with a number
+ --> $DIR/binding-name-starting-with-number.rs:9:9
+ |
+LL | let 23name = 123;
+ | ^^
+
+error: expected identifier, found `2x`
+ --> $DIR/binding-name-starting-with-number.rs:13:9
+ |
+LL | let 2x: i32 = 123;
+ | ^^ expected identifier
+ |
+help: identifiers cannot start with a number
+ --> $DIR/binding-name-starting-with-number.rs:13:9
+ |
+LL | let 2x: i32 = 123;
+ | ^
+
+error: expected identifier, found `1x`
+ --> $DIR/binding-name-starting-with-number.rs:17:9
+ |
+LL | let 1x = 123;
+ | ^^ expected identifier
+ |
+help: identifiers cannot start with a number
+ --> $DIR/binding-name-starting-with-number.rs:17:9
+ |
+LL | let 1x = 123;
+ | ^
+
+error[E0308]: mismatched types
+ --> $DIR/binding-name-starting-with-number.rs:5:12
+ |
+LL | if let 2e1 = 123 {
+ | ^^^ --- this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.rs b/tests/ui/parser/recover/recover-assoc-const-constraint.rs
new file mode 100644
index 000000000..1453e6cb5
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-const-constraint.rs
@@ -0,0 +1,9 @@
+#[cfg(FALSE)]
+fn syntax() {
+ bar::<Item = 42>();
+ //~^ ERROR associated const equality is incomplete
+ bar::<Item = { 42 }>();
+ //~^ ERROR associated const equality is incomplete
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.stderr b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr
new file mode 100644
index 000000000..2d36ce4e9
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr
@@ -0,0 +1,21 @@
+error[E0658]: associated const equality is incomplete
+ --> $DIR/recover-assoc-const-constraint.rs:3:11
+ |
+LL | bar::<Item = 42>();
+ | ^^^^^^^^^
+ |
+ = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+ = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0658]: associated const equality is incomplete
+ --> $DIR/recover-assoc-const-constraint.rs:5:11
+ |
+LL | bar::<Item = { 42 }>();
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+ = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs
new file mode 100644
index 000000000..4b42c44dc
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+ bar::<Item = >(); //~ ERROR missing type to the right of `=`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-assoc-eq-missing-term.stderr b/tests/ui/parser/recover/recover-assoc-eq-missing-term.stderr
new file mode 100644
index 000000000..cf50c0266
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-eq-missing-term.stderr
@@ -0,0 +1,18 @@
+error: missing type to the right of `=`
+ --> $DIR/recover-assoc-eq-missing-term.rs:3:17
+ |
+LL | bar::<Item = >();
+ | ^^^
+ |
+help: to constrain the associated type, add a type after `=`
+ |
+LL | bar::<Item = TheType>();
+ | +++++++
+help: remove the `=` if `Item` is a type
+ |
+LL - bar::<Item = >();
+LL + bar::<Item >();
+ |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs
new file mode 100644
index 000000000..558fcdfe1
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs
@@ -0,0 +1,6 @@
+#[cfg(FALSE)]
+fn syntax() {
+ bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr
new file mode 100644
index 000000000..39a6682fc
--- /dev/null
+++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr
@@ -0,0 +1,12 @@
+error: associated lifetimes are not supported
+ --> $DIR/recover-assoc-lifetime-constraint.rs:3:11
+ |
+LL | bar::<Item = 'a>();
+ | ^^^^^^^--
+ | |
+ | the lifetime is given here
+ |
+ = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
new file mode 100644
index 000000000..25af8772c
--- /dev/null
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
@@ -0,0 +1,25 @@
+// edition:2018
+
+type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T6 = const async unsafe extern "C" fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+//~| ERROR an `fn` pointer type cannot be `async`
+
+type FT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT5 = for<'a> async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT6 = for<'a> const async unsafe extern "C" fn();
+//~^ ERROR an `fn` pointer type cannot be `const`
+//~| ERROR an `fn` pointer type cannot be `async`
+
+fn main() {
+ let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
new file mode 100644
index 000000000..7012096b6
--- /dev/null
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -0,0 +1,155 @@
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:3:11
+ |
+LL | type T0 = const fn();
+ | -----^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:4:11
+ |
+LL | type T1 = const extern "C" fn();
+ | -----^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:5:11
+ |
+LL | type T2 = const unsafe extern fn();
+ | -----^^^^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:6:11
+ |
+LL | type T3 = async fn();
+ | -----^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:7:11
+ |
+LL | type T4 = async extern fn();
+ | -----^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:8:11
+ |
+LL | type T5 = async unsafe extern "C" fn();
+ | -----^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:9:11
+ |
+LL | type T6 = const async unsafe extern "C" fn();
+ | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:9:11
+ |
+LL | type T6 = const async unsafe extern "C" fn();
+ | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:13:12
+ |
+LL | type FT0 = for<'a> const fn();
+ | ^^^^^^^^-----^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:14:12
+ |
+LL | type FT1 = for<'a> const extern "C" fn();
+ | ^^^^^^^^-----^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:15:12
+ |
+LL | type FT2 = for<'a> const unsafe extern fn();
+ | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:16:12
+ |
+LL | type FT3 = for<'a> async fn();
+ | ^^^^^^^^-----^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:17:12
+ |
+LL | type FT4 = for<'a> async extern fn();
+ | ^^^^^^^^-----^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:18:12
+ |
+LL | type FT5 = for<'a> async unsafe extern "C" fn();
+ | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error: an `fn` pointer type cannot be `const`
+ --> $DIR/recover-const-async-fn-ptr.rs:19:12
+ |
+LL | type FT6 = for<'a> const async unsafe extern "C" fn();
+ | ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `const` because of this
+ | help: remove the `const` qualifier
+
+error: an `fn` pointer type cannot be `async`
+ --> $DIR/recover-const-async-fn-ptr.rs:19:12
+ |
+LL | type FT6 = for<'a> const async unsafe extern "C" fn();
+ | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | `async` because of this
+ | help: remove the `async` qualifier
+
+error[E0308]: mismatched types
+ --> $DIR/recover-const-async-fn-ptr.rs:24:33
+ |
+LL | let _recovery_witness: () = 0;
+ | -- ^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 17 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-enum.rs b/tests/ui/parser/recover/recover-enum.rs
new file mode 100644
index 000000000..08dd939e2
--- /dev/null
+++ b/tests/ui/parser/recover/recover-enum.rs
@@ -0,0 +1,11 @@
+fn main() {
+ enum Test {
+ Very //~ HELP missing `,`
+ Bad(usize) //~ HELP missing `,`
+ //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `Bad`
+ Stuff { a: usize } //~ HELP missing `,`
+ //~^ ERROR expected one of `,`, `=`, or `}`, found `Stuff`
+ Here
+ //~^ ERROR expected one of `,`, `=`, or `}`, found `Here`
+ }
+}
diff --git a/tests/ui/parser/recover/recover-enum.stderr b/tests/ui/parser/recover/recover-enum.stderr
new file mode 100644
index 000000000..a2b650e4f
--- /dev/null
+++ b/tests/ui/parser/recover/recover-enum.stderr
@@ -0,0 +1,37 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `Bad`
+ --> $DIR/recover-enum.rs:4:9
+ |
+LL | Very
+ | -
+ | |
+ | expected one of `(`, `,`, `=`, `{`, or `}`
+ | help: missing `,`
+LL | Bad(usize)
+ | ^^^ unexpected token
+
+error: expected one of `,`, `=`, or `}`, found `Stuff`
+ --> $DIR/recover-enum.rs:6:9
+ |
+LL | Bad(usize)
+ | -
+ | |
+ | expected one of `,`, `=`, or `}`
+ | help: missing `,`
+LL |
+LL | Stuff { a: usize }
+ | ^^^^^ unexpected token
+
+error: expected one of `,`, `=`, or `}`, found `Here`
+ --> $DIR/recover-enum.rs:8:9
+ |
+LL | Stuff { a: usize }
+ | -
+ | |
+ | expected one of `,`, `=`, or `}`
+ | help: missing `,`
+LL |
+LL | Here
+ | ^^^^ unexpected token
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/parser/recover/recover-enum2.rs b/tests/ui/parser/recover/recover-enum2.rs
new file mode 100644
index 000000000..56b57f625
--- /dev/null
+++ b/tests/ui/parser/recover/recover-enum2.rs
@@ -0,0 +1,29 @@
+fn main() {
+ enum Test {
+ Var1,
+ Var2(String),
+ Var3 {
+ abc: {}, //~ ERROR: expected type, found `{`
+ },
+ }
+
+ // recover...
+ let () = 1; //~ ERROR mismatched types
+ enum Test2 {
+ Fine,
+ }
+
+ enum Test3 {
+ StillFine {
+ def: i32,
+ },
+ }
+
+ {
+ // fail again
+ enum Test4 {
+ Nope(i32 {}) //~ ERROR: found `{`
+ }
+ let () = 1; //~ ERROR mismatched types
+ }
+}
diff --git a/tests/ui/parser/recover/recover-enum2.stderr b/tests/ui/parser/recover/recover-enum2.stderr
new file mode 100644
index 000000000..132f84cc7
--- /dev/null
+++ b/tests/ui/parser/recover/recover-enum2.stderr
@@ -0,0 +1,37 @@
+error: expected type, found `{`
+ --> $DIR/recover-enum2.rs:6:18
+ |
+LL | Var3 {
+ | ---- while parsing this struct
+LL | abc: {},
+ | ^ expected type
+
+error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
+ --> $DIR/recover-enum2.rs:25:22
+ |
+LL | enum Test4 {
+ | ----- while parsing this enum
+LL | Nope(i32 {})
+ | ^ expected one of 7 possible tokens
+ |
+ = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-enum2.rs:11:9
+ |
+LL | let () = 1;
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found `()`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-enum2.rs:27:13
+ |
+LL | let () = 1;
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found `()`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.rs b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.rs
new file mode 100644
index 000000000..e815c7611
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.rs
@@ -0,0 +1,6 @@
+struct TypedArenaChunk {
+ next: Option<String>>
+ //~^ ERROR unmatched angle bracket
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr
new file mode 100644
index 000000000..2b56498c5
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets-in-struct-with-a-field.stderr
@@ -0,0 +1,11 @@
+error: unmatched angle bracket
+ --> $DIR/recover-field-extra-angle-brackets-in-struct-with-a-field.rs:2:25
+ |
+LL | next: Option<String>>
+ | _________________________^
+LL | |
+LL | | }
+ | |_ help: remove extra angle bracket
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets.rs b/tests/ui/parser/recover/recover-field-extra-angle-brackets.rs
new file mode 100644
index 000000000..5e0e00bcb
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets.rs
@@ -0,0 +1,14 @@
+// Tests that we recover from extra trailing angle brackets
+// in a struct field
+
+struct BadStruct {
+ first: Vec<u8>>, //~ ERROR unmatched angle bracket
+ second: bool
+}
+
+fn bar(val: BadStruct) {
+ val.first;
+ val.second;
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr
new file mode 100644
index 000000000..628626926
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-extra-angle-brackets.stderr
@@ -0,0 +1,8 @@
+error: unmatched angle bracket
+ --> $DIR/recover-field-extra-angle-brackets.rs:5:19
+ |
+LL | first: Vec<u8>>,
+ | ^ help: remove extra angle bracket
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-field-semi.rs b/tests/ui/parser/recover/recover-field-semi.rs
new file mode 100644
index 000000000..b70357886
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-semi.rs
@@ -0,0 +1,16 @@
+struct Foo {
+ foo: i32;
+ //~^ ERROR struct fields are separated by `,`
+}
+
+union Bar { //~ ERROR
+ foo: i32;
+ //~^ ERROR union fields are separated by `,`
+}
+
+enum Baz {
+ Qux { foo: i32; }
+ //~^ ERROR struct fields are separated by `,`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-field-semi.stderr b/tests/ui/parser/recover/recover-field-semi.stderr
new file mode 100644
index 000000000..3cf484748
--- /dev/null
+++ b/tests/ui/parser/recover/recover-field-semi.stderr
@@ -0,0 +1,35 @@
+error: struct fields are separated by `,`
+ --> $DIR/recover-field-semi.rs:2:13
+ |
+LL | struct Foo {
+ | --- while parsing this struct
+LL | foo: i32;
+ | ^ help: replace `;` with `,`
+
+error: union fields are separated by `,`
+ --> $DIR/recover-field-semi.rs:7:13
+ |
+LL | union Bar {
+ | --- while parsing this union
+LL | foo: i32;
+ | ^ help: replace `;` with `,`
+
+error: struct fields are separated by `,`
+ --> $DIR/recover-field-semi.rs:12:19
+ |
+LL | Qux { foo: i32; }
+ | --- ^ help: replace `;` with `,`
+ | |
+ | while parsing this struct
+
+error: unions cannot have zero fields
+ --> $DIR/recover-field-semi.rs:6:1
+ |
+LL | / union Bar {
+LL | | foo: i32;
+LL | |
+LL | | }
+ | |_^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs b/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs
new file mode 100644
index 000000000..31de418be
--- /dev/null
+++ b/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs
@@ -0,0 +1,31 @@
+fn main() {
+ type Predicate = fn<'a>(&'a str) -> bool;
+ //~^ ERROR function pointer types may not have generic parameters
+
+ type Identity = fn<T>(T) -> T;
+ //~^ ERROR function pointer types may not have generic parameters
+ //~| ERROR cannot find type `T` in this scope
+ //~| ERROR cannot find type `T` in this scope
+
+ let _: fn<const N: usize, 'e, Q, 'f>();
+ //~^ ERROR function pointer types may not have generic parameters
+
+ let _: for<'outer> fn<'inner>();
+ //~^ ERROR function pointer types may not have generic parameters
+
+ let _: for<> fn<'r>();
+ //~^ ERROR function pointer types may not have generic parameters
+
+ type Hmm = fn<>();
+ //~^ ERROR function pointer types may not have generic parameters
+
+ let _: extern fn<'a: 'static>();
+ //~^ ERROR function pointer types may not have generic parameters
+ //~| ERROR lifetime bounds cannot be used in this context
+
+ let _: for<'any> extern "C" fn<'u>();
+ //~^ ERROR function pointer types may not have generic parameters
+
+ type QuiteBroken = fn<const>();
+ //~^ ERROR expected identifier, found `>`
+}
diff --git a/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr
new file mode 100644
index 000000000..069fcffe9
--- /dev/null
+++ b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr
@@ -0,0 +1,111 @@
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:2:24
+ |
+LL | type Predicate = fn<'a>(&'a str) -> bool;
+ | ^^^^
+ |
+help: consider moving the lifetime parameter to a `for` parameter list
+ |
+LL - type Predicate = fn<'a>(&'a str) -> bool;
+LL + type Predicate = for<'a> fn(&'a str) -> bool;
+ |
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:5:23
+ |
+LL | type Identity = fn<T>(T) -> T;
+ | ^^^
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:10:14
+ |
+LL | let _: fn<const N: usize, 'e, Q, 'f>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider moving the lifetime parameters to a `for` parameter list
+ |
+LL - let _: fn<const N: usize, 'e, Q, 'f>();
+LL + let _: for<'e, 'f> fn();
+ |
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:13:26
+ |
+LL | let _: for<'outer> fn<'inner>();
+ | ^^^^^^^^
+ |
+help: consider moving the lifetime parameter to the `for` parameter list
+ |
+LL - let _: for<'outer> fn<'inner>();
+LL + let _: for<'outer, 'inner> fn();
+ |
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:16:20
+ |
+LL | let _: for<> fn<'r>();
+ | ^^^^
+ |
+help: consider moving the lifetime parameter to the `for` parameter list
+ |
+LL - let _: for<> fn<'r>();
+LL + let _: for<'r> fn();
+ |
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:19:18
+ |
+LL | type Hmm = fn<>();
+ | ^^
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:22:21
+ |
+LL | let _: extern fn<'a: 'static>();
+ | ^^^^^^^^^^^^^
+ |
+help: consider moving the lifetime parameter to a `for` parameter list
+ |
+LL - let _: extern fn<'a: 'static>();
+LL + let _: for<'a> extern fn();
+ |
+
+error: function pointer types may not have generic parameters
+ --> $DIR/recover-fn-ptr-with-generics.rs:26:35
+ |
+LL | let _: for<'any> extern "C" fn<'u>();
+ | ^^^^
+ |
+help: consider moving the lifetime parameter to the `for` parameter list
+ |
+LL - let _: for<'any> extern "C" fn<'u>();
+LL + let _: for<'any, 'u> extern "C" fn();
+ |
+
+error: expected identifier, found `>`
+ --> $DIR/recover-fn-ptr-with-generics.rs:29:32
+ |
+LL | type QuiteBroken = fn<const>();
+ | ^ expected identifier
+
+error[E0412]: cannot find type `T` in this scope
+ --> $DIR/recover-fn-ptr-with-generics.rs:5:27
+ |
+LL | type Identity = fn<T>(T) -> T;
+ | ^ not found in this scope
+
+error[E0412]: cannot find type `T` in this scope
+ --> $DIR/recover-fn-ptr-with-generics.rs:5:33
+ |
+LL | type Identity = fn<T>(T) -> T;
+ | ^ not found in this scope
+
+error: lifetime bounds cannot be used in this context
+ --> $DIR/recover-fn-ptr-with-generics.rs:22:26
+ |
+LL | let _: extern fn<'a: 'static>();
+ | ^^^^^^^
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs
new file mode 100644
index 000000000..b6611e627
--- /dev/null
+++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.rs
@@ -0,0 +1,12 @@
+fn foo(_: impl fn() -> i32) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn foo2<T: fn(i32)>(_: T) {}
+//~^ ERROR expected identifier, found keyword `fn`
+
+fn main() {
+ foo(|| ());
+ //~^ mismatched types
+ foo2(|_: ()| {});
+ //~^ type mismatch in closure arguments
+}
diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr
new file mode 100644
index 000000000..3681a796c
--- /dev/null
+++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr
@@ -0,0 +1,48 @@
+error: expected identifier, found keyword `fn`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:1:16
+ |
+LL | fn foo(_: impl fn() -> i32) {}
+ | ^^
+ |
+help: use `Fn` to refer to the trait
+ |
+LL | fn foo(_: impl Fn() -> i32) {}
+ | ~~
+
+error: expected identifier, found keyword `fn`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+ |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+ | ^^
+ |
+help: use `Fn` to refer to the trait
+ |
+LL | fn foo2<T: Fn(i32)>(_: T) {}
+ | ~~
+
+error[E0308]: mismatched types
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:8:12
+ |
+LL | foo(|| ());
+ | ^^ expected `i32`, found `()`
+
+error[E0631]: type mismatch in closure arguments
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:10:5
+ |
+LL | foo2(|_: ()| {});
+ | ^^^^ ------- found signature defined here
+ | |
+ | expected due to this
+ |
+ = note: expected closure signature `fn(i32) -> _`
+ found closure signature `fn(()) -> _`
+note: required by a bound in `foo2`
+ --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12
+ |
+LL | fn foo2<T: fn(i32)>(_: T) {}
+ | ^^^^^^^ required by this bound in `foo2`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed
new file mode 100644
index 000000000..6afc2d993
--- /dev/null
+++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+// Here we test that the parser is able to recover in a situation like
+// `for ( $pat in $expr )` since that is familiar syntax in other languages.
+// Instead we suggest that the user writes `for $pat in $expr`.
+
+#![deny(unused)] // Make sure we don't trigger `unused_parens`.
+
+fn main() {
+ let vec = vec![1, 2, 3];
+
+ for _elem in vec {
+ //~^ ERROR unexpected parentheses surrounding `for` loop head
+ const _RECOVERY_WITNESS: u32 = 0u32; //~ ERROR mismatched types
+ }
+}
diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs
new file mode 100644
index 000000000..b1716900c
--- /dev/null
+++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+// Here we test that the parser is able to recover in a situation like
+// `for ( $pat in $expr )` since that is familiar syntax in other languages.
+// Instead we suggest that the user writes `for $pat in $expr`.
+
+#![deny(unused)] // Make sure we don't trigger `unused_parens`.
+
+fn main() {
+ let vec = vec![1, 2, 3];
+
+ for ( _elem in vec ) {
+ //~^ ERROR unexpected parentheses surrounding `for` loop head
+ const _RECOVERY_WITNESS: u32 = 0u8; //~ ERROR mismatched types
+ }
+}
diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr
new file mode 100644
index 000000000..beaa346e7
--- /dev/null
+++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr
@@ -0,0 +1,26 @@
+error: unexpected parentheses surrounding `for` loop head
+ --> $DIR/recover-for-loop-parens-around-head.rs:11:9
+ |
+LL | for ( _elem in vec ) {
+ | ^ ^
+ |
+help: remove parentheses in `for` loop
+ |
+LL - for ( _elem in vec ) {
+LL + for _elem in vec {
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/recover-for-loop-parens-around-head.rs:13:40
+ |
+LL | const _RECOVERY_WITNESS: u32 = 0u8;
+ | ^^^ expected `u32`, found `u8`
+ |
+help: change the type of the numeric literal from `u8` to `u32`
+ |
+LL | const _RECOVERY_WITNESS: u32 = 0u32;
+ | ~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-from-bad-variant.rs b/tests/ui/parser/recover/recover-from-bad-variant.rs
new file mode 100644
index 000000000..e8887147c
--- /dev/null
+++ b/tests/ui/parser/recover/recover-from-bad-variant.rs
@@ -0,0 +1,15 @@
+enum Enum {
+ Foo { a: usize, b: usize },
+ Bar(usize, usize),
+}
+
+fn main() {
+ let x = Enum::Foo(a: 3, b: 4);
+ //~^ ERROR invalid `struct` delimiters or `fn` call arguments
+ match x {
+ Enum::Foo(a, b) => {}
+ //~^ ERROR expected tuple struct or tuple variant, found struct variant `Enum::Foo`
+ Enum::Bar { a, b } => {}
+ //~^ ERROR tuple variant `Enum::Bar` written as struct variant
+ }
+}
diff --git a/tests/ui/parser/recover/recover-from-bad-variant.stderr b/tests/ui/parser/recover/recover-from-bad-variant.stderr
new file mode 100644
index 000000000..04968bbdf
--- /dev/null
+++ b/tests/ui/parser/recover/recover-from-bad-variant.stderr
@@ -0,0 +1,37 @@
+error: invalid `struct` delimiters or `fn` call arguments
+ --> $DIR/recover-from-bad-variant.rs:7:13
+ |
+LL | let x = Enum::Foo(a: 3, b: 4);
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if `Enum::Foo` is a struct, use braces as delimiters
+ |
+LL | let x = Enum::Foo { a: 3, b: 4 };
+ | ~ ~
+help: if `Enum::Foo` is a function, use the arguments directly
+ |
+LL - let x = Enum::Foo(a: 3, b: 4);
+LL + let x = Enum::Foo(3, 4);
+ |
+
+error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum::Foo`
+ --> $DIR/recover-from-bad-variant.rs:10:9
+ |
+LL | Enum::Foo(a, b) => {}
+ | ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+
+error[E0769]: tuple variant `Enum::Bar` written as struct variant
+ --> $DIR/recover-from-bad-variant.rs:12:9
+ |
+LL | Enum::Bar { a, b } => {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: use the tuple variant pattern syntax instead
+ |
+LL | Enum::Bar(a, b) => {}
+ | ~~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0164, E0769.
+For more information about an error, try `rustc --explain E0164`.
diff --git a/tests/ui/parser/recover/recover-from-homoglyph.rs b/tests/ui/parser/recover/recover-from-homoglyph.rs
new file mode 100644
index 000000000..99ce0d1a6
--- /dev/null
+++ b/tests/ui/parser/recover/recover-from-homoglyph.rs
@@ -0,0 +1,4 @@
+fn main() {
+ println!(""); //~ ERROR unknown start of token: \u{37e}
+ let x: usize = (); //~ ERROR mismatched types
+}
diff --git a/tests/ui/parser/recover/recover-from-homoglyph.stderr b/tests/ui/parser/recover/recover-from-homoglyph.stderr
new file mode 100644
index 000000000..f11ca9fd5
--- /dev/null
+++ b/tests/ui/parser/recover/recover-from-homoglyph.stderr
@@ -0,0 +1,22 @@
+error: unknown start of token: \u{37e}
+ --> $DIR/recover-from-homoglyph.rs:2:17
+ |
+LL | println!("");
+ | ^
+ |
+help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
+ |
+LL | println!("");
+ | ~
+
+error[E0308]: mismatched types
+ --> $DIR/recover-from-homoglyph.rs:3:20
+ |
+LL | let x: usize = ();
+ | ----- ^^ expected `usize`, found `()`
+ | |
+ | expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-labeled-non-block-expr.fixed b/tests/ui/parser/recover/recover-labeled-non-block-expr.fixed
new file mode 100644
index 000000000..c2e76444d
--- /dev/null
+++ b/tests/ui/parser/recover/recover-labeled-non-block-expr.fixed
@@ -0,0 +1,26 @@
+// run-rustfix
+fn main() {
+ let _ = 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+ match () { () => {}, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ 'label: { match () { () => break 'label, } }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ #[allow(unused_labels)]
+ 'label: { match () { () => 'lp: loop { break 'lp 0 }, } }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+ let x = 1;
+ let _i = 'label: { match x { //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ 0 => 42,
+ 1 if false => break 'label 17,
+ 1 => {
+ if true {
+ break 'label 13
+ } else {
+ break 'label 0;
+ }
+ }
+ _ => 1,
+ } };
+
+ let other = 3;
+ let _val = 'label: { (1, if other == 3 { break 'label (2, 3) } else { other }) }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+}
diff --git a/tests/ui/parser/recover/recover-labeled-non-block-expr.rs b/tests/ui/parser/recover/recover-labeled-non-block-expr.rs
new file mode 100644
index 000000000..fc11c646a
--- /dev/null
+++ b/tests/ui/parser/recover/recover-labeled-non-block-expr.rs
@@ -0,0 +1,26 @@
+// run-rustfix
+fn main() {
+ let _ = 'label: 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+ 'label: match () { () => {}, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ 'label: match () { () => break 'label, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ #[allow(unused_labels)]
+ 'label: match () { () => 'lp: loop { break 'lp 0 }, }; //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+
+ let x = 1;
+ let _i = 'label: match x { //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+ 0 => 42,
+ 1 if false => break 'label 17,
+ 1 => {
+ if true {
+ break 'label 13
+ } else {
+ break 'label 0;
+ }
+ }
+ _ => 1,
+ };
+
+ let other = 3;
+ let _val = 'label: (1, if other == 3 { break 'label (2, 3) } else { other }); //~ ERROR expected `while`, `for`, `loop` or `{` after a label
+}
diff --git a/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr b/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr
new file mode 100644
index 000000000..d66ce6950
--- /dev/null
+++ b/tests/ui/parser/recover/recover-labeled-non-block-expr.stderr
@@ -0,0 +1,74 @@
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:3:21
+ |
+LL | let _ = 'label: 1 + 1;
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider removing the label
+ |
+LL - let _ = 'label: 1 + 1;
+LL + let _ = 1 + 1;
+ |
+
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:5:13
+ |
+LL | 'label: match () { () => {}, };
+ | ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider removing the label
+ |
+LL - 'label: match () { () => {}, };
+LL + match () { () => {}, };
+ |
+
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:6:13
+ |
+LL | 'label: match () { () => break 'label, };
+ | ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider enclosing expression in a block
+ |
+LL | 'label: { match () { () => break 'label, } };
+ | + +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:8:13
+ |
+LL | 'label: match () { () => 'lp: loop { break 'lp 0 }, };
+ | ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider enclosing expression in a block
+ |
+LL | 'label: { match () { () => 'lp: loop { break 'lp 0 }, } };
+ | + +
+
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:11:22
+ |
+LL | let _i = 'label: match x {
+ | ^^^^^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider enclosing expression in a block
+ |
+LL ~ let _i = 'label: { match x {
+LL | 0 => 42,
+ ...
+LL | _ => 1,
+LL ~ } };
+ |
+
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/recover-labeled-non-block-expr.rs:25:24
+ |
+LL | let _val = 'label: (1, if other == 3 { break 'label (2, 3) } else { other });
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+ |
+help: consider enclosing expression in a block
+ |
+LL | let _val = 'label: { (1, if other == 3 { break 'label (2, 3) } else { other }) };
+ | + +
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.fixed b/tests/ui/parser/recover/recover-missing-semi-before-item.fixed
new file mode 100644
index 000000000..acb846373
--- /dev/null
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.fixed
@@ -0,0 +1,61 @@
+// run-rustfix
+
+#![allow(unused_variables, dead_code, unused_imports)]
+
+fn for_struct() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `struct`
+ struct Foo;
+}
+
+fn for_union() {
+ let foo = 3; //~ ERROR expected `;`, found `union`
+ union Foo {
+ foo: usize,
+ }
+}
+
+fn for_enum() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `enum`
+ enum Foo {
+ Bar,
+ }
+}
+
+fn for_fn() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `fn`
+ fn foo() {}
+}
+
+fn for_extern() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `extern`
+ extern fn foo() {}
+}
+
+fn for_impl() {
+ struct Foo;
+ let foo = 3; //~ ERROR expected `;`, found keyword `impl`
+ impl Foo {}
+}
+
+fn for_use() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `pub`
+ pub use bar::Bar;
+}
+
+fn for_mod() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `mod`
+ mod foo {}
+}
+
+fn for_type() {
+ let foo = 3; //~ ERROR expected `;`, found keyword `type`
+ type Foo = usize;
+}
+
+mod bar {
+ pub struct Bar;
+}
+
+const X: i32 = 123; //~ ERROR expected `;`, found keyword `fn`
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.rs b/tests/ui/parser/recover/recover-missing-semi-before-item.rs
new file mode 100644
index 000000000..ef6cfe3c4
--- /dev/null
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.rs
@@ -0,0 +1,61 @@
+// run-rustfix
+
+#![allow(unused_variables, dead_code, unused_imports)]
+
+fn for_struct() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `struct`
+ struct Foo;
+}
+
+fn for_union() {
+ let foo = 3 //~ ERROR expected `;`, found `union`
+ union Foo {
+ foo: usize,
+ }
+}
+
+fn for_enum() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `enum`
+ enum Foo {
+ Bar,
+ }
+}
+
+fn for_fn() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `fn`
+ fn foo() {}
+}
+
+fn for_extern() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `extern`
+ extern fn foo() {}
+}
+
+fn for_impl() {
+ struct Foo;
+ let foo = 3 //~ ERROR expected `;`, found keyword `impl`
+ impl Foo {}
+}
+
+fn for_use() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `pub`
+ pub use bar::Bar;
+}
+
+fn for_mod() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `mod`
+ mod foo {}
+}
+
+fn for_type() {
+ let foo = 3 //~ ERROR expected `;`, found keyword `type`
+ type Foo = usize;
+}
+
+mod bar {
+ pub struct Bar;
+}
+
+const X: i32 = 123 //~ ERROR expected `;`, found keyword `fn`
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr
new file mode 100644
index 000000000..61c43f2f1
--- /dev/null
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr
@@ -0,0 +1,83 @@
+error: expected `;`, found keyword `struct`
+ --> $DIR/recover-missing-semi-before-item.rs:6:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | struct Foo;
+ | ------ unexpected token
+
+error: expected `;`, found `union`
+ --> $DIR/recover-missing-semi-before-item.rs:11:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | union Foo {
+ | ----- unexpected token
+
+error: expected `;`, found keyword `enum`
+ --> $DIR/recover-missing-semi-before-item.rs:18:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | enum Foo {
+ | ---- unexpected token
+
+error: expected `;`, found keyword `fn`
+ --> $DIR/recover-missing-semi-before-item.rs:25:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | fn foo() {}
+ | -- unexpected token
+
+error: expected `;`, found keyword `extern`
+ --> $DIR/recover-missing-semi-before-item.rs:30:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | extern fn foo() {}
+ | ------ unexpected token
+
+error: expected `;`, found keyword `impl`
+ --> $DIR/recover-missing-semi-before-item.rs:36:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | impl Foo {}
+ | ---- unexpected token
+
+error: expected `;`, found keyword `pub`
+ --> $DIR/recover-missing-semi-before-item.rs:41:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | pub use bar::Bar;
+ | --- unexpected token
+
+error: expected `;`, found keyword `mod`
+ --> $DIR/recover-missing-semi-before-item.rs:46:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | mod foo {}
+ | --- unexpected token
+
+error: expected `;`, found keyword `type`
+ --> $DIR/recover-missing-semi-before-item.rs:51:16
+ |
+LL | let foo = 3
+ | ^ help: add `;` here
+LL | type Foo = usize;
+ | ---- unexpected token
+
+error: expected `;`, found keyword `fn`
+ --> $DIR/recover-missing-semi-before-item.rs:59:19
+ |
+LL | const X: i32 = 123
+ | ^ help: add `;` here
+LL |
+LL | fn main() {}
+ | -- unexpected token
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/parser/recover/recover-missing-semi.rs b/tests/ui/parser/recover/recover-missing-semi.rs
new file mode 100644
index 000000000..f47d5e680
--- /dev/null
+++ b/tests/ui/parser/recover/recover-missing-semi.rs
@@ -0,0 +1,13 @@
+fn main() {
+ let _: usize = ()
+ //~^ ERROR mismatched types
+ //~| ERROR expected `;`
+ let _ = 3;
+}
+
+fn foo() -> usize {
+ let _: usize = ()
+ //~^ ERROR mismatched types
+ //~| ERROR expected `;`
+ return 3;
+}
diff --git a/tests/ui/parser/recover/recover-missing-semi.stderr b/tests/ui/parser/recover/recover-missing-semi.stderr
new file mode 100644
index 000000000..ba4798285
--- /dev/null
+++ b/tests/ui/parser/recover/recover-missing-semi.stderr
@@ -0,0 +1,37 @@
+error: expected `;`, found keyword `let`
+ --> $DIR/recover-missing-semi.rs:2:22
+ |
+LL | let _: usize = ()
+ | ^ help: add `;` here
+...
+LL | let _ = 3;
+ | --- unexpected token
+
+error: expected `;`, found keyword `return`
+ --> $DIR/recover-missing-semi.rs:9:22
+ |
+LL | let _: usize = ()
+ | ^ help: add `;` here
+...
+LL | return 3;
+ | ------ unexpected token
+
+error[E0308]: mismatched types
+ --> $DIR/recover-missing-semi.rs:2:20
+ |
+LL | let _: usize = ()
+ | ----- ^^ expected `usize`, found `()`
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/recover-missing-semi.rs:9:20
+ |
+LL | let _: usize = ()
+ | ----- ^^ expected `usize`, found `()`
+ | |
+ | expected due to this
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed
new file mode 100644
index 000000000..6b9b7fa88
--- /dev/null
+++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+ let val = 42;
+ let x = match val {
+ 0 if true => {
+ //~^ ERROR unexpected parentheses surrounding `match` arm pattern
+ 42u8
+ }
+ _ => 0u8,
+ };
+ let _y: u32 = x.into(); //~ ERROR mismatched types
+}
diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs
new file mode 100644
index 000000000..f523581e2
--- /dev/null
+++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs
@@ -0,0 +1,12 @@
+// run-rustfix
+fn main() {
+ let val = 42;
+ let x = match val {
+ (0 if true) => {
+ //~^ ERROR unexpected parentheses surrounding `match` arm pattern
+ 42u8
+ }
+ _ => 0u8,
+ };
+ let _y: u32 = x; //~ ERROR mismatched types
+}
diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr
new file mode 100644
index 000000000..bad4d7d2f
--- /dev/null
+++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr
@@ -0,0 +1,28 @@
+error: unexpected parentheses surrounding `match` arm pattern
+ --> $DIR/recover-parens-around-match-arm-head.rs:5:9
+ |
+LL | (0 if true) => {
+ | ^ ^
+ |
+help: remove parentheses surrounding the pattern
+ |
+LL - (0 if true) => {
+LL + 0 if true => {
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/recover-parens-around-match-arm-head.rs:11:19
+ |
+LL | let _y: u32 = x;
+ | --- ^ expected `u32`, found `u8`
+ | |
+ | expected due to this
+ |
+help: you can convert a `u8` to a `u32`
+ |
+LL | let _y: u32 = x.into();
+ | +++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs
new file mode 100644
index 000000000..10af39b70
--- /dev/null
+++ b/tests/ui/parser/recover/recover-quantified-closure.rs
@@ -0,0 +1,12 @@
+fn main() {
+ for<'a> |x: &'a u8| *x + 1;
+ //~^ ERROR `for<...>` binders for closures are experimental
+ //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+}
+
+enum Foo { Bar }
+fn foo(x: impl Iterator<Item = Foo>) {
+ for <Foo>::Bar in x {}
+ //~^ ERROR expected one of `move`, `static`, `|`
+ //~^^ ERROR `for<...>` binders for closures are experimental
+}
diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr
new file mode 100644
index 000000000..37e93cbee
--- /dev/null
+++ b/tests/ui/parser/recover/recover-quantified-closure.stderr
@@ -0,0 +1,37 @@
+error: expected one of `move`, `static`, `|`, or `||`, found `::`
+ --> $DIR/recover-quantified-closure.rs:9:14
+ |
+LL | for <Foo>::Bar in x {}
+ | ^^ expected one of `move`, `static`, `|`, or `||`
+
+error[E0658]: `for<...>` binders for closures are experimental
+ --> $DIR/recover-quantified-closure.rs:2:5
+ |
+LL | for<'a> |x: &'a u8| *x + 1;
+ | ^^^^^^^
+ |
+ = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+ = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+ = help: consider removing `for<...>`
+
+error[E0658]: `for<...>` binders for closures are experimental
+ --> $DIR/recover-quantified-closure.rs:9:5
+ |
+LL | for <Foo>::Bar in x {}
+ | ^^^^^^^^^
+ |
+ = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+ = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+ = help: consider removing `for<...>`
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+ --> $DIR/recover-quantified-closure.rs:2:24
+ |
+LL | for<'a> |x: &'a u8| *x + 1;
+ | ------- ^
+ | |
+ | `for<...>` is here
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/parser/recover/recover-range-pats.rs b/tests/ui/parser/recover/recover-range-pats.rs
new file mode 100644
index 000000000..156c7ad94
--- /dev/null
+++ b/tests/ui/parser/recover/recover-range-pats.rs
@@ -0,0 +1,159 @@
+// Here we test all kinds of range patterns in terms of parsing / recovery.
+// We want to ensure that:
+// 1. Things parse as they should.
+// 2. Or at least we have parser recovery if they don't.
+
+#![feature(exclusive_range_pattern)]
+#![deny(ellipsis_inclusive_range_patterns)]
+
+fn main() {}
+
+const X: u8 = 0;
+const Y: u8 = 3;
+
+fn exclusive_from_to() {
+ if let 0..3 = 0 {} // OK.
+ if let 0..Y = 0 {} // OK.
+ if let X..3 = 0 {} // OK.
+ if let X..Y = 0 {} // OK.
+ if let true..Y = 0 {} //~ ERROR only `char` and numeric types
+ if let X..true = 0 {} //~ ERROR only `char` and numeric types
+ if let .0..Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ if let X.. .0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+}
+
+fn inclusive_from_to() {
+ if let 0..=3 = 0 {} // OK.
+ if let 0..=Y = 0 {} // OK.
+ if let X..=3 = 0 {} // OK.
+ if let X..=Y = 0 {} // OK.
+ if let true..=Y = 0 {} //~ ERROR only `char` and numeric types
+ if let X..=true = 0 {} //~ ERROR only `char` and numeric types
+ if let .0..=Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ if let X..=.0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+}
+
+fn inclusive2_from_to() {
+ if let 0...3 = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let 0...Y = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let X...3 = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let X...Y = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let true...Y = 0 {} //~ ERROR only `char` and numeric types
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let X...true = 0 {} //~ ERROR only `char` and numeric types
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ if let .0...Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ //~| WARN this is accepted in the current edition
+ //~| ERROR `...` range patterns are deprecated
+ if let X... .0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+}
+
+fn exclusive_from() {
+ if let 0.. = 0 {}
+ if let X.. = 0 {}
+ if let true.. = 0 {}
+ //~^ ERROR only `char` and numeric types
+ if let .0.. = 0 {}
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive_from() {
+ if let 0..= = 0 {} //~ ERROR inclusive range with no end
+ if let X..= = 0 {} //~ ERROR inclusive range with no end
+ if let true..= = 0 {} //~ ERROR inclusive range with no end
+ //~| ERROR only `char` and numeric types
+ if let .0..= = 0 {} //~ ERROR inclusive range with no end
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive2_from() {
+ if let 0... = 0 {} //~ ERROR inclusive range with no end
+ if let X... = 0 {} //~ ERROR inclusive range with no end
+ if let true... = 0 {} //~ ERROR inclusive range with no end
+ //~| ERROR only `char` and numeric types
+ if let .0... = 0 {} //~ ERROR inclusive range with no end
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn exclusive_to() {
+ if let ..0 = 0 {}
+ if let ..Y = 0 {}
+ if let ..true = 0 {}
+ //~^ ERROR only `char` and numeric types
+ if let .. .0 = 0 {}
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive_to() {
+ if let ..=3 = 0 {}
+ if let ..=Y = 0 {}
+ if let ..=true = 0 {}
+ //~^ ERROR only `char` and numeric types
+ if let ..=.0 = 0 {}
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive2_to() {
+ if let ...3 = 0 {}
+ //~^ ERROR range-to patterns with `...` are not allowed
+ if let ...Y = 0 {}
+ //~^ ERROR range-to patterns with `...` are not allowed
+ if let ...true = 0 {}
+ //~^ ERROR range-to patterns with `...` are not allowed
+ //~| ERROR only `char` and numeric types
+ if let ....3 = 0 {}
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR range-to patterns with `...` are not allowed
+ //~| ERROR mismatched types
+}
+
+fn with_macro_expr_var() {
+ macro_rules! mac2 {
+ ($e1:expr, $e2:expr) => {
+ let $e1..$e2;
+ let $e1...$e2;
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this is accepted in the current edition
+ let $e1..=$e2;
+ }
+ }
+
+ mac2!(0, 1);
+
+ macro_rules! mac {
+ ($e:expr) => {
+ let ..$e;
+ let ...$e;
+ //~^ ERROR range-to patterns with `...` are not allowed
+ let ..=$e;
+ let $e..;
+ let $e...; //~ ERROR inclusive range with no end
+ let $e..=; //~ ERROR inclusive range with no end
+ }
+ }
+
+ mac!(0);
+}
diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr
new file mode 100644
index 000000000..5b69ca5cd
--- /dev/null
+++ b/tests/ui/parser/recover/recover-range-pats.stderr
@@ -0,0 +1,484 @@
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:21:12
+ |
+LL | if let .0..Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:23:16
+ |
+LL | if let X.. .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:34:12
+ |
+LL | if let .0..=Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:36:16
+ |
+LL | if let X..=.0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:59:12
+ |
+LL | if let .0...Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:63:17
+ |
+LL | if let X... .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:74:12
+ |
+LL | if let .0.. = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:80:13
+ |
+LL | if let 0..= = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:81:13
+ |
+LL | if let X..= = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:82:16
+ |
+LL | if let true..= = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:84:12
+ |
+LL | if let .0..= = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:84:14
+ |
+LL | if let .0..= = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:90:13
+ |
+LL | if let 0... = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:91:13
+ |
+LL | if let X... = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:92:16
+ |
+LL | if let true... = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:94:12
+ |
+LL | if let .0... = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:94:14
+ |
+LL | if let .0... = 0 {}
+ | ^^^ help: use `..` instead
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:104:15
+ |
+LL | if let .. .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:114:15
+ |
+LL | if let ..=.0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: range-to patterns with `...` are not allowed
+ --> $DIR/recover-range-pats.rs:120:12
+ |
+LL | if let ...3 = 0 {}
+ | ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+ --> $DIR/recover-range-pats.rs:122:12
+ |
+LL | if let ...Y = 0 {}
+ | ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+ --> $DIR/recover-range-pats.rs:124:12
+ |
+LL | if let ...true = 0 {}
+ | ^^^ help: use `..=` instead
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:127:15
+ |
+LL | if let ....3 = 0 {}
+ | ^^ help: must have an integer part: `0.3`
+
+error: range-to patterns with `...` are not allowed
+ --> $DIR/recover-range-pats.rs:127:12
+ |
+LL | if let ....3 = 0 {}
+ | ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+ --> $DIR/recover-range-pats.rs:149:17
+ |
+LL | let ...$e;
+ | ^^^ help: use `..=` instead
+...
+LL | mac!(0);
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:153:19
+ |
+LL | let $e...;
+ | ^^^ help: use `..` instead
+...
+LL | mac!(0);
+ | ------- in this macro invocation
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+ = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0586]: inclusive range with no end
+ --> $DIR/recover-range-pats.rs:154:19
+ |
+LL | let $e..=;
+ | ^^^ help: use `..` instead
+...
+LL | mac!(0);
+ | ------- in this macro invocation
+ |
+ = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+ = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:41:13
+ |
+LL | if let 0...3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+note: the lint level is defined here
+ --> $DIR/recover-range-pats.rs:7:9
+ |
+LL | #![deny(ellipsis_inclusive_range_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:44:13
+ |
+LL | if let 0...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:47:13
+ |
+LL | if let X...3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:50:13
+ |
+LL | if let X...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:53:16
+ |
+LL | if let true...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:56:13
+ |
+LL | if let X...true = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:59:14
+ |
+LL | if let .0...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:63:13
+ |
+LL | if let X... .0 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:137:20
+ |
+LL | let $e1...$e2;
+ | ^^^ help: use `..=` for an inclusive range
+...
+LL | mac2!(0, 1);
+ | ----------- in this macro invocation
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:19:12
+ |
+LL | if let true..Y = 0 {}
+ | ^^^^ - this is of type `u8`
+ | |
+ | this is of type `bool` but it should be `char` or numeric
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:20:15
+ |
+LL | if let X..true = 0 {}
+ | - ^^^^ this is of type `bool` but it should be `char` or numeric
+ | |
+ | this is of type `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:21:12
+ |
+LL | if let .0..Y = 0 {}
+ | ^^ - - this expression has type `{integer}`
+ | | |
+ | | this is of type `u8`
+ | expected integer, found floating-point number
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:23:16
+ |
+LL | if let X.. .0 = 0 {}
+ | - ^^ - this expression has type `u8`
+ | | |
+ | | expected `u8`, found floating-point number
+ | this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:32:12
+ |
+LL | if let true..=Y = 0 {}
+ | ^^^^ - this is of type `u8`
+ | |
+ | this is of type `bool` but it should be `char` or numeric
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:33:16
+ |
+LL | if let X..=true = 0 {}
+ | - ^^^^ this is of type `bool` but it should be `char` or numeric
+ | |
+ | this is of type `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:34:12
+ |
+LL | if let .0..=Y = 0 {}
+ | ^^ - - this expression has type `{integer}`
+ | | |
+ | | this is of type `u8`
+ | expected integer, found floating-point number
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:36:16
+ |
+LL | if let X..=.0 = 0 {}
+ | - ^^ - this expression has type `u8`
+ | | |
+ | | expected `u8`, found floating-point number
+ | this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:53:12
+ |
+LL | if let true...Y = 0 {}
+ | ^^^^ - this is of type `u8`
+ | |
+ | this is of type `bool` but it should be `char` or numeric
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:56:16
+ |
+LL | if let X...true = 0 {}
+ | - ^^^^ this is of type `bool` but it should be `char` or numeric
+ | |
+ | this is of type `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:59:12
+ |
+LL | if let .0...Y = 0 {}
+ | ^^ - - this expression has type `{integer}`
+ | | |
+ | | this is of type `u8`
+ | expected integer, found floating-point number
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:63:17
+ |
+LL | if let X... .0 = 0 {}
+ | - ^^ - this expression has type `u8`
+ | | |
+ | | expected `u8`, found floating-point number
+ | this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:72:12
+ |
+LL | if let true.. = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:74:12
+ |
+LL | if let .0.. = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:82:12
+ |
+LL | if let true..= = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:84:12
+ |
+LL | if let .0..= = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:92:12
+ |
+LL | if let true... = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:94:12
+ |
+LL | if let .0... = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:102:14
+ |
+LL | if let ..true = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:104:15
+ |
+LL | if let .. .0 = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:112:15
+ |
+LL | if let ..=true = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:114:15
+ |
+LL | if let ..=.0 = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:124:15
+ |
+LL | if let ...true = 0 {}
+ | ^^^^ this is of type `bool` but it should be `char` or numeric
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:127:15
+ |
+LL | if let ....3 = 0 {}
+ | ^^ - this expression has type `{integer}`
+ | |
+ | expected integer, found floating-point number
+
+error: aborting due to 60 previous errors
+
+Some errors have detailed explanations: E0029, E0308, E0586.
+For more information about an error, try `rustc --explain E0029`.
diff --git a/tests/ui/parser/recover/recover-ref-dyn-mut.rs b/tests/ui/parser/recover/recover-ref-dyn-mut.rs
new file mode 100644
index 000000000..3016275cc
--- /dev/null
+++ b/tests/ui/parser/recover/recover-ref-dyn-mut.rs
@@ -0,0 +1,9 @@
+// Test that the parser detects `&dyn mut`, offers a help message, and
+// recovers.
+
+fn main() {
+ let r: &dyn mut Trait;
+ //~^ ERROR: `mut` must precede `dyn`
+ //~| HELP: place `mut` before `dyn`
+ //~| ERROR: cannot find trait `Trait` in this scope [E0405]
+}
diff --git a/tests/ui/parser/recover/recover-ref-dyn-mut.stderr b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr
new file mode 100644
index 000000000..c048c8ea1
--- /dev/null
+++ b/tests/ui/parser/recover/recover-ref-dyn-mut.stderr
@@ -0,0 +1,15 @@
+error: `mut` must precede `dyn`
+ --> $DIR/recover-ref-dyn-mut.rs:5:12
+ |
+LL | let r: &dyn mut Trait;
+ | ^^^^^^^^ help: place `mut` before `dyn`: `&mut dyn`
+
+error[E0405]: cannot find trait `Trait` in this scope
+ --> $DIR/recover-ref-dyn-mut.rs:5:21
+ |
+LL | let r: &dyn mut Trait;
+ | ^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/parser/recover/recover-struct.rs b/tests/ui/parser/recover/recover-struct.rs
new file mode 100644
index 000000000..bfa5b454c
--- /dev/null
+++ b/tests/ui/parser/recover/recover-struct.rs
@@ -0,0 +1,7 @@
+fn main() {
+ struct Test {
+ Very
+ Bad //~ ERROR found `Bad`
+ Stuff
+ }
+}
diff --git a/tests/ui/parser/recover/recover-struct.stderr b/tests/ui/parser/recover/recover-struct.stderr
new file mode 100644
index 000000000..51a9e7077
--- /dev/null
+++ b/tests/ui/parser/recover/recover-struct.stderr
@@ -0,0 +1,12 @@
+error: expected `:`, found `Bad`
+ --> $DIR/recover-struct.rs:4:9
+ |
+LL | struct Test {
+ | ---- while parsing this struct
+LL | Very
+ | - expected `:`
+LL | Bad
+ | ^^^ unexpected token
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-tuple-pat.rs b/tests/ui/parser/recover/recover-tuple-pat.rs
new file mode 100644
index 000000000..7fded752d
--- /dev/null
+++ b/tests/ui/parser/recover/recover-tuple-pat.rs
@@ -0,0 +1,12 @@
+// NOTE: This doesn't recover anymore.
+
+fn main() {
+ let x = (1, 2, 3, 4);
+ match x {
+ (1, .., 4) => {}
+ (1, .=., 4) => { let _: usize = ""; }
+ //~^ ERROR expected pattern, found `.`
+ (.=., 4) => {}
+ (1, 2, 3, 4) => {}
+ }
+}
diff --git a/tests/ui/parser/recover/recover-tuple-pat.stderr b/tests/ui/parser/recover/recover-tuple-pat.stderr
new file mode 100644
index 000000000..e181f0720
--- /dev/null
+++ b/tests/ui/parser/recover/recover-tuple-pat.stderr
@@ -0,0 +1,8 @@
+error: expected pattern, found `.`
+ --> $DIR/recover-tuple-pat.rs:7:13
+ |
+LL | (1, .=., 4) => { let _: usize = ""; }
+ | ^ expected pattern
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/recover/recover-tuple.rs b/tests/ui/parser/recover/recover-tuple.rs
new file mode 100644
index 000000000..59e2695de
--- /dev/null
+++ b/tests/ui/parser/recover/recover-tuple.rs
@@ -0,0 +1,11 @@
+fn main() {
+ // no complaints about the tuple not matching the expected type
+ let x: (usize, usize, usize) = (3, .=.);
+ //~^ ERROR expected expression, found `.`
+ // verify that the parser recovers:
+ let y: usize = ""; //~ ERROR mismatched types
+ // no complaints about the type
+ foo(x);
+}
+
+fn foo(_: (usize, usize, usize)) {}
diff --git a/tests/ui/parser/recover/recover-tuple.stderr b/tests/ui/parser/recover/recover-tuple.stderr
new file mode 100644
index 000000000..88891b54b
--- /dev/null
+++ b/tests/ui/parser/recover/recover-tuple.stderr
@@ -0,0 +1,17 @@
+error: expected expression, found `.`
+ --> $DIR/recover-tuple.rs:3:40
+ |
+LL | let x: (usize, usize, usize) = (3, .=.);
+ | ^ expected expression
+
+error[E0308]: mismatched types
+ --> $DIR/recover-tuple.rs:6:20
+ |
+LL | let y: usize = "";
+ | ----- ^^ expected `usize`, found `&str`
+ | |
+ | expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/recover/recover-unticked-labels.fixed b/tests/ui/parser/recover/recover-unticked-labels.fixed
new file mode 100644
index 000000000..159d995b8
--- /dev/null
+++ b/tests/ui/parser/recover/recover-unticked-labels.fixed
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+ 'label: loop { break 'label }; //~ error: cannot find value `label` in this scope
+ 'label: loop { break 'label 0 }; //~ error: expected a label, found an identifier
+ 'label: loop { continue 'label }; //~ error: expected a label, found an identifier
+}
diff --git a/tests/ui/parser/recover/recover-unticked-labels.rs b/tests/ui/parser/recover/recover-unticked-labels.rs
new file mode 100644
index 000000000..56034de68
--- /dev/null
+++ b/tests/ui/parser/recover/recover-unticked-labels.rs
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+ 'label: loop { break label }; //~ error: cannot find value `label` in this scope
+ 'label: loop { break label 0 }; //~ error: expected a label, found an identifier
+ 'label: loop { continue label }; //~ error: expected a label, found an identifier
+}
diff --git a/tests/ui/parser/recover/recover-unticked-labels.stderr b/tests/ui/parser/recover/recover-unticked-labels.stderr
new file mode 100644
index 000000000..fbd108ca6
--- /dev/null
+++ b/tests/ui/parser/recover/recover-unticked-labels.stderr
@@ -0,0 +1,29 @@
+error: expected a label, found an identifier
+ --> $DIR/recover-unticked-labels.rs:5:26
+ |
+LL | 'label: loop { break label 0 };
+ | -^^^^
+ | |
+ | help: labels start with a tick
+
+error: expected a label, found an identifier
+ --> $DIR/recover-unticked-labels.rs:6:29
+ |
+LL | 'label: loop { continue label };
+ | -^^^^
+ | |
+ | help: labels start with a tick
+
+error[E0425]: cannot find value `label` in this scope
+ --> $DIR/recover-unticked-labels.rs:4:26
+ |
+LL | 'label: loop { break label };
+ | ------ ^^^^^
+ | | |
+ | | not found in this scope
+ | | help: use the similarly named label: `'label`
+ | a label with a similar name exists
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
new file mode 100644
index 000000000..227c40e97
--- /dev/null
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed
@@ -0,0 +1,15 @@
+// Regression test for issues #100790 and #106439.
+// run-rustfix
+
+pub struct Example(usize)
+where
+ (): Sized;
+//~^^^ ERROR where clauses are not allowed before tuple struct bodies
+
+struct _Demo(pub usize, usize)
+where
+ (): Sized,
+ String: Clone;
+//~^^^^ ERROR where clauses are not allowed before tuple struct bodies
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
new file mode 100644
index 000000000..3699e6fe5
--- /dev/null
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs
@@ -0,0 +1,17 @@
+// Regression test for issues #100790 and #106439.
+// run-rustfix
+
+pub struct Example
+where
+ (): Sized,
+(usize);
+//~^^^ ERROR where clauses are not allowed before tuple struct bodies
+
+struct _Demo
+where
+ (): Sized,
+ String: Clone,
+(pub usize, usize);
+//~^^^^ ERROR where clauses are not allowed before tuple struct bodies
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
new file mode 100644
index 000000000..18aa5fadb
--- /dev/null
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr
@@ -0,0 +1,40 @@
+error: where clauses are not allowed before tuple struct bodies
+ --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1
+ |
+LL | pub struct Example
+ | ------- while parsing this tuple struct
+LL | / where
+LL | | (): Sized,
+ | |______________^ unexpected where clause
+LL | (usize);
+ | ------- the struct body
+ |
+help: move the body before the where clause
+ |
+LL ~ pub struct Example(usize)
+LL | where
+LL ~ (): Sized;
+ |
+
+error: where clauses are not allowed before tuple struct bodies
+ --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1
+ |
+LL | struct _Demo
+ | ----- while parsing this tuple struct
+LL | / where
+LL | | (): Sized,
+LL | | String: Clone,
+ | |__________________^ unexpected where clause
+LL | (pub usize, usize);
+ | ------------------ the struct body
+ |
+help: move the body before the where clause
+ |
+LL ~ struct _Demo(pub usize, usize)
+LL | where
+LL | (): Sized,
+LL ~ String: Clone;
+ |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.rs
new file mode 100644
index 000000000..f515ae81e
--- /dev/null
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.rs
@@ -0,0 +1,7 @@
+// Regression test for issues #100790 and #106439.
+
+// Make sure that we still show a helpful error message even if the trailing semicolon is missing.
+
+struct Foo<T> where T: MyTrait, (T)
+//~^ ERROR where clauses are not allowed before tuple struct bodies
+//~| ERROR expected `;`, found `<eof>`
diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.stderr
new file mode 100644
index 000000000..2219c2a73
--- /dev/null
+++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-1.stderr
@@ -0,0 +1,23 @@
+error: where clauses are not allowed before tuple struct bodies
+ --> $DIR/recover-where-clause-before-tuple-struct-body-1.rs:5:15
+ |
+LL | struct Foo<T> where T: MyTrait, (T)
+ | --- ^^^^^^^^^^^^^^^^^ --- the struct body
+ | | |
+ | | unexpected where clause
+ | while parsing this tuple struct
+ |
+help: move the body before the where clause
+ |
+LL - struct Foo<T> where T: MyTrait, (T)
+LL + struct Foo<T>(T) where T: MyTrait
+ |
+
+error: expected `;`, found `<eof>`
+ --> $DIR/recover-where-clause-before-tuple-struct-body-1.rs:5:35
+ |
+LL | struct Foo<T> where T: MyTrait, (T)
+ | ^ expected `;`
+
+error: aborting due to 2 previous errors
+