about summary refs log tree commit diff
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-10-27 13:22:10 +0000
committerclubby789 <jamie@hill-daniel.co.uk>2023-10-27 18:29:43 +0000
commitbe0b42fabe4b4abe10e7b6eb5e57ea12b6fa07c9 (patch)
tree6588b04a225c58862a0f91233a901a2704279862
parent54e57e66ffb8ef4f97916d46f40ddcb464fc8be3 (diff)
downloadrust-be0b42fabe4b4abe10e7b6eb5e57ea12b6fa07c9.tar.gz
rust-be0b42fabe4b4abe10e7b6eb5e57ea12b6fa07c9.zip
Recover from incorrectly ordered/duplicated function keywords
-rw-r--r--compiler/rustc_parse/src/parser/item.rs40
-rw-r--r--tests/ui/async-await/no-async-const.rs1
-rw-r--r--tests/ui/async-await/no-async-const.stderr11
-rw-r--r--tests/ui/async-await/no-unsafe-async.rs2
-rw-r--r--tests/ui/async-await/no-unsafe-async.stderr5
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs5
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr11
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/recovery.rs22
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr28
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs5
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr11
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs2
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs2
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs2
14 files changed, 136 insertions, 11 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 982f601c0d5..884ae7be2ef 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2382,22 +2382,39 @@ impl<'a> Parser<'a> {
                         Misplaced(Span),
                     }
 
+                    // We may be able to recover
+                    let mut recover_constness = constness;
+                    let mut recover_asyncness = asyncness;
+                    let mut recover_unsafety = unsafety;
                     // This will allow the machine fix to directly place the keyword in the correct place or to indicate
                     // that the keyword is already present and the second instance should be removed.
                     let wrong_kw = if self.check_keyword(kw::Const) {
                         match constness {
                             Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
-                            Const::No => Some(WrongKw::Misplaced(async_start_sp)),
+                            Const::No => {
+                                recover_constness = Const::Yes(self.token.span);
+                                Some(WrongKw::Misplaced(async_start_sp))
+                            }
                         }
                     } else if self.check_keyword(kw::Async) {
                         match asyncness {
                             Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
-                            Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)),
+                            Async::No => {
+                                recover_asyncness = Async::Yes {
+                                    span: self.token.span,
+                                    closure_id: DUMMY_NODE_ID,
+                                    return_impl_trait_id: DUMMY_NODE_ID,
+                                };
+                                Some(WrongKw::Misplaced(unsafe_start_sp))
+                            }
                         }
                     } else if self.check_keyword(kw::Unsafe) {
                         match unsafety {
                             Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
-                            Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)),
+                            Unsafe::No => {
+                                recover_unsafety = Unsafe::Yes(self.token.span);
+                                Some(WrongKw::Misplaced(ext_start_sp))
+                            }
                         }
                     } else {
                         None
@@ -2467,6 +2484,23 @@ impl<'a> Parser<'a> {
                             }
                         }
                     }
+
+                    if wrong_kw.is_some()
+                        && self.may_recover()
+                        && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
+                    {
+                        // Advance past the misplaced keyword and `fn`
+                        self.bump();
+                        self.bump();
+                        err.emit();
+                        return Ok(FnHeader {
+                            constness: recover_constness,
+                            unsafety: recover_unsafety,
+                            asyncness: recover_asyncness,
+                            ext,
+                        });
+                    }
+
                     return Err(err);
                 }
             }
diff --git a/tests/ui/async-await/no-async-const.rs b/tests/ui/async-await/no-async-const.rs
index 963460c1182..c9941d1c5a0 100644
--- a/tests/ui/async-await/no-async-const.rs
+++ b/tests/ui/async-await/no-async-const.rs
@@ -3,3 +3,4 @@
 
 pub async const fn x() {}
 //~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
+//~| ERROR functions cannot be both `const` and `async`
diff --git a/tests/ui/async-await/no-async-const.stderr b/tests/ui/async-await/no-async-const.stderr
index a51dc88a4ed..524d778c09b 100644
--- a/tests/ui/async-await/no-async-const.stderr
+++ b/tests/ui/async-await/no-async-const.stderr
@@ -9,5 +9,14 @@ LL | pub async const fn x() {}
    |
    = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
-error: aborting due to previous error
+error: functions cannot be both `const` and `async`
+  --> $DIR/no-async-const.rs:4:5
+   |
+LL | pub async const fn x() {}
+   | ----^^^^^-^^^^^----------
+   |     |     |
+   |     |     `const` because of this
+   |     `async` because of this
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/async-await/no-unsafe-async.rs b/tests/ui/async-await/no-unsafe-async.rs
index f40154e16f3..7c6811d81ee 100644
--- a/tests/ui/async-await/no-unsafe-async.rs
+++ b/tests/ui/async-await/no-unsafe-async.rs
@@ -9,3 +9,5 @@ impl S {
 
 #[cfg(FALSE)]
 unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
+
+fn main() {}
diff --git a/tests/ui/async-await/no-unsafe-async.stderr b/tests/ui/async-await/no-unsafe-async.stderr
index f23d17d6bfa..49b112f9313 100644
--- a/tests/ui/async-await/no-unsafe-async.stderr
+++ b/tests/ui/async-await/no-unsafe-async.stderr
@@ -1,16 +1,11 @@
 error: expected one of `extern` or `fn`, found keyword `async`
   --> $DIR/no-unsafe-async.rs:7:12
    |
-LL | impl S {
-   |        - while parsing this item list starting here
-LL |     #[cfg(FALSE)]
 LL |     unsafe async fn g() {}
    |     -------^^^^^
    |     |      |
    |     |      expected one of `extern` or `fn`
    |     help: `async` must come before `unsafe`: `async unsafe`
-LL | }
-   | - the item list ends here
    |
    = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
index df0cd54399a..099178a7d50 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
@@ -7,3 +7,8 @@ const async const fn test() {}
 //~| NOTE expected one of `extern`, `fn`, or `unsafe`
 //~| HELP `const` already used earlier, remove this one
 //~| NOTE `const` first seen here
+//~| ERROR functions cannot be both `const` and `async`
+//~| NOTE `const` because of this
+//~| NOTE `async` because of this
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
index 977c6ebfef3..4c55179ce23 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
@@ -13,5 +13,14 @@ note: `const` first seen here
 LL | const async const fn test() {}
    | ^^^^^
 
-error: aborting due to previous error
+error: functions cannot be both `const` and `async`
+  --> $DIR/const-async-const.rs:5:1
+   |
+LL | const async const fn test() {}
+   | ^^^^^-^^^^^-------------------
+   | |     |
+   | |     `async` because of this
+   | `const` because of this
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/recovery.rs b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.rs
new file mode 100644
index 00000000000..9d7fe43893e
--- /dev/null
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.rs
@@ -0,0 +1,22 @@
+// test for #115714
+
+struct Misplaced;
+
+impl Misplaced {
+    unsafe const fn from_u32(val: u32) {}
+    //~^ ERROR expected one of `extern` or `fn`
+    fn oof(self){}
+}
+
+struct Duplicated;
+
+impl Duplicated {
+    unsafe unsafe fn from_u32(val: u32) {}
+    //~^ ERROR expected one of `extern` or `fn`
+    fn oof(self){}
+}
+
+fn main() {
+    Misplaced.oof();
+    Duplicated.oof();
+}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr
new file mode 100644
index 00000000000..3f504a9ebfc
--- /dev/null
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/recovery.stderr
@@ -0,0 +1,28 @@
+error: expected one of `extern` or `fn`, found keyword `const`
+  --> $DIR/recovery.rs:6:12
+   |
+LL |     unsafe const fn from_u32(val: u32) {}
+   |     -------^^^^^
+   |     |      |
+   |     |      expected one of `extern` or `fn`
+   |     help: `const` must come before `unsafe`: `const unsafe`
+   |
+   = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
+
+error: expected one of `extern` or `fn`, found keyword `unsafe`
+  --> $DIR/recovery.rs:14:12
+   |
+LL |     unsafe unsafe fn from_u32(val: u32) {}
+   |            ^^^^^^
+   |            |
+   |            expected one of `extern` or `fn`
+   |            help: `unsafe` already used earlier, remove this one
+   |
+note: `unsafe` first seen here
+  --> $DIR/recovery.rs:14:5
+   |
+LL |     unsafe unsafe fn from_u32(val: u32) {}
+   |     ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
index bbebc99e94b..47942662685 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs
@@ -12,3 +12,8 @@ async unsafe const fn test() {}
 //~| HELP `const` must come before `async unsafe`
 //~| SUGGESTION const async unsafe
 //~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
+//~| ERROR functions cannot be both `const` and `async`
+//~| NOTE `const` because of this
+//~| NOTE `async` because of this
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr
index f455caba158..489e8eefb05 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr
@@ -9,5 +9,14 @@ LL | async unsafe const fn test() {}
    |
    = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
 
-error: aborting due to previous error
+error: functions cannot be both `const` and `async`
+  --> $DIR/several-kw-jump.rs:9:1
+   |
+LL | async unsafe const fn test() {}
+   | ^^^^^--------^^^^^-------------
+   | |            |
+   | |            `const` because of this
+   | `async` because of this
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs
index 4ff4cf5c8ca..867f71c1204 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs
@@ -12,3 +12,5 @@ unsafe async fn test() {}
 //~| HELP `async` must come before `unsafe`
 //~| SUGGESTION async unsafe
 //~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs
index 2f5fbc513ee..9a7f28210f9 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs
@@ -12,3 +12,5 @@ unsafe const fn test() {}
 //~| HELP `const` must come before `unsafe`
 //~| SUGGESTION const unsafe
 //~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
+
+fn main() {}
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
index df2412e3e9b..8305ff4f623 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
@@ -12,3 +12,5 @@ extern unsafe fn test() {}
 //~| HELP `unsafe` must come before `extern`
 //~| SUGGESTION unsafe extern
 //~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
+
+fn main() {}