diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9aaf4b99243f5..112855e6d1f5a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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] }; @@ -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)))) } diff --git a/tests/ui/parser/issues/issue-19398.rs b/tests/ui/parser/issues/issue-19398.rs index 46eb320a172f2..358f65f1da51b 100644 --- a/tests/ui/parser/issues/issue-19398.rs +++ b/tests/ui/parser/issues/issue-19398.rs @@ -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() {} diff --git a/tests/ui/parser/issues/issue-19398.stderr b/tests/ui/parser/issues/issue-19398.stderr index 236fac673b6b3..2b97ec50c9172 100644 --- a/tests/ui/parser/issues/issue-19398.stderr +++ b/tests/ui/parser/issues/issue-19398.stderr @@ -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 diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.rs new file mode 100644 index 0000000000000..794ac635c7694 --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.rs @@ -0,0 +1,16 @@ +//@ edition:2018 + +// There is an order to respect for keywords before a function: +// `, const, async, unsafe, extern, ""` +// +// 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() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr new file mode 100644 index 0000000000000..8ed037869c829 --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr @@ -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 +