Skip to content

Commit

Permalink
Rollup merge of #128229 - tdittr:unsafe-extern-abi-error, r=compiler-…
Browse files Browse the repository at this point in the history
…errors

Improve `extern "<abi>" unsafe fn()` error message

These errors were already reported in #87217, and fixed by #87235 but missed the case of an explicit ABI.

This PR does not cover multiple keywords like `extern "C" pub const unsafe fn()`, but I don't know what a good way to cover this  would be. It also seems rarer than `extern "C" unsafe` which I saw happen a few times in workshops.
  • Loading branch information
tgross35 authored Jul 26, 2024
2 parents f9209ae + 3fdc991 commit 7eaf747
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 11 deletions.
9 changes: 6 additions & 3 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2483,12 +2483,15 @@ impl<'a> Parser<'a> {
/// `check_pub` adds additional `pub` to the checks in case users place it
/// wrongly, can be used to ensure `pub` never comes after `default`.
pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
const ALL_QUALS: &[Symbol] =
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern];

// We use an over-approximation here.
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
// `pub` is added in case users got confused with the ordering like `async pub fn`,
// only if it wasn't preceded by `default` as `default pub` is invalid.
let quals: &[Symbol] = if check_pub {
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]
ALL_QUALS
} else {
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]
};
Expand Down Expand Up @@ -2518,9 +2521,9 @@ impl<'a> Parser<'a> {
|| self.check_keyword_case(kw::Extern, case)
&& self.look_ahead(1, |t| t.can_begin_string_literal())
&& (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) ||
// this branch is only for better diagnostic in later, `pub` is not allowed here
// this branch is only for better diagnostics; `pub`, `unsafe`, etc. are not allowed here
(self.may_recover()
&& self.look_ahead(2, |t| t.is_keyword(kw::Pub))
&& self.look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw)))
&& self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case))))
}

Expand Down
6 changes: 5 additions & 1 deletion tests/ui/parser/issues/issue-19398.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
trait T {
extern "Rust" unsafe fn foo();
//~^ ERROR expected `{`, found keyword `unsafe`
//~^ ERROR expected `fn`, found keyword `unsafe`
//~| NOTE expected `fn`
//~| HELP `unsafe` must come before `extern "Rust"`
//~| SUGGESTION unsafe extern "Rust"
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
}

fn main() {}
14 changes: 7 additions & 7 deletions tests/ui/parser/issues/issue-19398.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: expected `{`, found keyword `unsafe`
error: expected `fn`, found keyword `unsafe`
--> $DIR/issue-19398.rs:2:19
|
LL | trait T {
| - while parsing this item list starting here
LL | extern "Rust" unsafe fn foo();
| ^^^^^^ expected `{`
LL |
LL | }
| - the item list ends here
| --------------^^^^^^
| | |
| | expected `fn`
| help: `unsafe` must come before `extern "Rust"`: `unsafe extern "Rust"`
|
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ edition:2018

// There is an order to respect for keywords before a function:
// `<visibility>, const, async, unsafe, extern, "<ABI>"`
//
// This test ensures the compiler is helpful about them being misplaced.
// Visibilities are tested elsewhere.

extern "C" unsafe fn test() {}
//~^ ERROR expected `fn`, found keyword `unsafe`
//~| NOTE expected `fn`
//~| HELP `unsafe` must come before `extern "C"`
//~| SUGGESTION unsafe extern "C"
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: expected `fn`, found keyword `unsafe`
--> $DIR/wrong-unsafe-abi.rs:9:12
|
LL | extern "C" unsafe fn test() {}
| -----------^^^^^^
| | |
| | expected `fn`
| help: `unsafe` must come before `extern "C"`: `unsafe extern "C"`
|
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to 1 previous error

0 comments on commit 7eaf747

Please sign in to comment.