From 33dd288ef1d28eabb15c15e739496014198329ab Mon Sep 17 00:00:00 2001 From: Tamme Dittrich Date: Fri, 26 Jul 2024 13:59:43 +0200 Subject: [PATCH 1/2] Add a test case for `extern "C" unsafe` to the ui tests --- .../issue-87217-keyword-order/wrong-unsafe-abi.rs | 12 ++++++++++++ .../wrong-unsafe-abi.stderr | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.rs create mode 100644 tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr 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 00000000000..c97425d8ade --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.rs @@ -0,0 +1,12 @@ +//@ 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 + +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 00000000000..42c9764cc1e --- /dev/null +++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe-abi.stderr @@ -0,0 +1,8 @@ +error: expected `{`, found keyword `unsafe` + --> $DIR/wrong-unsafe-abi.rs:9:12 + | +LL | extern "C" unsafe fn test() {} + | ^^^^^^ expected `{` + +error: aborting due to 1 previous error + From 3fdc99193e95a29b6fd2228b0acc5f8b4a81feda Mon Sep 17 00:00:00 2001 From: Tamme Dittrich Date: Fri, 26 Jul 2024 15:14:05 +0200 Subject: [PATCH 2/2] Improve error message for `extern "C" unsafe fn()` This was handled correctly already for `extern unsafe fn()`. Co-authored-by: Folkert --- compiler/rustc_parse/src/parser/item.rs | 9 ++++++--- tests/ui/parser/issues/issue-19398.rs | 6 +++++- tests/ui/parser/issues/issue-19398.stderr | 14 +++++++------- .../issue-87217-keyword-order/wrong-unsafe-abi.rs | 6 +++++- .../wrong-unsafe-abi.stderr | 9 +++++++-- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9aaf4b99243..112855e6d1f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2483,12 +2483,15 @@ fn parse_fn_body( /// `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 @@ pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> b || 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 46eb320a172..358f65f1da5 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 236fac673b6..2b97ec50c91 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 index c97425d8ade..794ac635c76 100644 --- 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 @@ -7,6 +7,10 @@ // Visibilities are tested elsewhere. extern "C" unsafe fn test() {} -//~^ ERROR +//~^ 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 index 42c9764cc1e..8ed037869c8 100644 --- 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 @@ -1,8 +1,13 @@ -error: expected `{`, found keyword `unsafe` +error: expected `fn`, found keyword `unsafe` --> $DIR/wrong-unsafe-abi.rs:9:12 | LL | extern "C" unsafe fn test() {} - | ^^^^^^ expected `{` + | -----------^^^^^^ + | | | + | | 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