diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index aba94f4d817d7..46f052da3eb7b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2483,6 +2483,14 @@ pub enum CoroutineKind { } impl CoroutineKind { + pub fn span(self) -> Span { + match self { + CoroutineKind::Async { span, .. } => span, + CoroutineKind::Gen { span, .. } => span, + CoroutineKind::AsyncGen { span, .. } => span, + } + } + pub fn is_async(self) -> bool { matches!(self, CoroutineKind::Async { .. }) } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 28a13d275a559..ac3799e7a0565 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -68,7 +68,7 @@ ast_passes_extern_block_suggestion = if you meant to declare an externally defin ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers .label = in this `extern` block - .suggestion = remove the qualifiers + .suggestion = remove this qualifier ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers .label = in this `extern` block diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3edb832b9a09b..384f9ef79e61b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -514,13 +514,49 @@ impl<'a> AstValidator<'a> { } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. - fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { - if header.has_qualifiers() { - self.dcx().emit_err(errors::FnQualifierInExtern { - span: ident.span, - block: self.current_extern_span(), - sugg_span: span.until(ident.span.shrink_to_lo()), - }); + fn check_foreign_fn_headerless(&self, header: FnHeader) { + let FnHeader { unsafety, coroutine_kind, constness, ext } = header; + match unsafety { + Unsafe::Yes(span) => { + self.dcx().emit_err(errors::FnQualifierInExtern { + span: span, + block: self.current_extern_span(), + }); + } + Unsafe::No => (), + } + match coroutine_kind { + Some(knd) => { + self.dcx().emit_err(errors::FnQualifierInExtern { + span: knd.span(), + block: self.current_extern_span(), + }); + } + None => (), + } + match constness { + Const::Yes(span) => { + self.dcx().emit_err(errors::FnQualifierInExtern { + span, + block: self.current_extern_span(), + }); + } + Const::No => (), + } + match ext { + Extern::None => (), + Extern::Implicit(span) => { + self.dcx().emit_err(errors::FnQualifierInExtern { + span, + block: self.current_extern_span(), + }); + } + Extern::Explicit(_, span) => { + self.dcx().emit_err(errors::FnQualifierInExtern { + span, + block: self.current_extern_span(), + }); + } } } @@ -1145,7 +1181,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); - self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); + self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(fi.ident); } ForeignItemKind::TyAlias(box TyAlias { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9e8c1d7f5fd19..218a7bdee73f7 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -266,15 +266,14 @@ pub struct FnBodyInExtern { pub block: Span, } -#[derive(Diagnostic)] +#[derive(Diagnostic, Debug)] #[diag(ast_passes_extern_fn_qualifiers)] pub struct FnQualifierInExtern { #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] pub span: Span, #[label] pub block: Span, - #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")] - pub sugg_span: Span, } #[derive(Diagnostic)] diff --git a/tests/ui/extern/extern-headerless.rs b/tests/ui/extern/extern-headerless.rs new file mode 100644 index 0000000000000..e6f06da014b1a --- /dev/null +++ b/tests/ui/extern/extern-headerless.rs @@ -0,0 +1,20 @@ +//@ edition:2018 + +extern "C" { + const fn a(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers + + unsafe fn b(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers + + async fn c(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers + + extern fn d(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers + + extern "C" fn e(); + //~^ ERROR functions in `extern` blocks cannot have qualifiers +} + +pub fn main() {} diff --git a/tests/ui/extern/extern-headerless.stderr b/tests/ui/extern/extern-headerless.stderr new file mode 100644 index 0000000000000..d527b1a9972e0 --- /dev/null +++ b/tests/ui/extern/extern-headerless.stderr @@ -0,0 +1,46 @@ +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/extern-headerless.rs:4:5 + | +LL | extern "C" { + | ---------- in this `extern` block +LL | const fn a(); + | ^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/extern-headerless.rs:7:5 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | unsafe fn b(); + | ^^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/extern-headerless.rs:10:5 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | async fn c(); + | ^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/extern-headerless.rs:13:5 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | extern fn d(); + | ^^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/extern-headerless.rs:16:5 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | extern "C" fn e(); + | ^^^^^^^^^^ help: remove this qualifier + +error: aborting due to 5 previous errors + diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr index b902f0ef8f5c0..16504d1f0c9d0 100644 --- a/tests/ui/extern/issue-95829.stderr +++ b/tests/ui/extern/issue-95829.stderr @@ -16,17 +16,12 @@ LL | | } = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: functions in `extern` blocks cannot have qualifiers - --> $DIR/issue-95829.rs:4:14 + --> $DIR/issue-95829.rs:4:5 | LL | extern { | ------ in this `extern` block LL | async fn L() { - | ^ - | -help: remove the qualifiers - | -LL | fn L() { - | ~~ + | ^^^^^ help: remove this qualifier error: aborting due to 2 previous errors diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 4ac0e265501f2..948ce669112c3 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -1,29 +1,28 @@ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:2:14 + --> $DIR/no-const-fn-in-extern-block.rs:2:5 | LL | extern "C" { | ---------- in this `extern` block LL | const fn foo(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn foo(); - | ~~ + | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:4:21 + --> $DIR/no-const-fn-in-extern-block.rs:4:11 | LL | extern "C" { | ---------- in this `extern` block ... LL | const unsafe fn bar(); - | ^^^ - | -help: remove the qualifiers + | ^^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:5 | -LL | fn bar(); - | ~~ +LL | extern "C" { + | ---------- in this `extern` block +... +LL | const unsafe fn bar(); + | ^^^^^ help: remove this qualifier -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors