Skip to content

Commit

Permalink
Fix diagnostic for qualifier in extern block
Browse files Browse the repository at this point in the history
  • Loading branch information
krtab committed Apr 3, 2024
1 parent 45796d1 commit 9835a35
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 33 deletions.
8 changes: 8 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 { .. })
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 44 additions & 8 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
});
}
}
}

Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/extern/extern-headerless.rs
Original file line number Diff line number Diff line change
@@ -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() {}
46 changes: 46 additions & 0 deletions tests/ui/extern/extern-headerless.stderr
Original file line number Diff line number Diff line change
@@ -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

9 changes: 2 additions & 7 deletions tests/ui/extern/issue-95829.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

27 changes: 13 additions & 14 deletions tests/ui/parser/no-const-fn-in-extern-block.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 9835a35

Please sign in to comment.