Rollup merge of #135340 - obeis:explicit-extern-abis, r=traviscross,nadrieril

Add `explicit_extern_abis` Feature and Enforce Explicit ABIs

The unstable `explicit_extern_abis` feature is introduced, requiring explicit ABIs in `extern` blocks. Hard errors will be enforced with this feature enabled in a future edition.

RFC rust-lang/rfcs#3722

Update #134986
This commit is contained in:
Matthias Krüger 2025-04-17 00:16:20 +02:00 committed by GitHub
commit bb3e156f62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 334 additions and 21 deletions

View file

@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
.suggestion = remove the {$remove_descr}
.label = `extern` block begins here
ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
.suggestion = specify an ABI
.help = prior to Rust 2024, a default ABI was inferred
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
.suggestion = remove the attribute
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable

View file

@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> {
self.dcx().emit_err(errors::PatternFnPointer { span });
});
if let Extern::Implicit(extern_span) = bfty.ext {
self.maybe_lint_missing_abi(extern_span, ty.id);
self.handle_missing_abi(extern_span, ty.id);
}
}
TyKind::TraitObject(bounds, ..) => {
@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> {
}
}
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
if self
if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
self.dcx().emit_err(errors::MissingAbi { span });
} else if self
.sess
.source_map()
.span_to_snippet(span)
@ -996,7 +998,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
if abi.is_none() {
self.maybe_lint_missing_abi(*extern_span, item.id);
self.handle_missing_abi(*extern_span, item.id);
}
self.with_in_extern_mod(*safety, |this| {
visit::walk_item(this, item);
@ -1370,7 +1372,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
},
) = fk
{
self.maybe_lint_missing_abi(*extern_span, id);
self.handle_missing_abi(*extern_span, id);
}
// Functions without bodies cannot have patterns.

View file

@ -823,3 +823,12 @@ pub(crate) struct DuplicatePreciseCapturing {
#[label]
pub bound2: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_extern_without_abi)]
#[help]
pub(crate) struct MissingAbi {
#[primary_span]
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
pub span: Span,
}

View file

@ -477,6 +477,8 @@ declare_features! (
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
/// Disallows `extern` without an explicit ABI.
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions

View file

@ -271,7 +271,7 @@ lint_expectation = this lint expectation is unfulfilled
lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
.suggestion = convert it to a `use`
lint_extern_without_abi = extern declarations without an explicit ABI are deprecated
lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated
.label = ABI should be specified here
.suggestion = explicitly specify the {$default_abi} ABI

View file

@ -916,6 +916,7 @@ symbols! {
expf16,
expf32,
expf64,
explicit_extern_abis,
explicit_generic_args_with_impl_trait,
explicit_tail_calls,
export_name,

View file

@ -0,0 +1,23 @@
# `explicit_extern_abis`
The tracking issue for this feature is: #134986
------
Disallow `extern` without an explicit ABI. We should write `extern "C"`
(or another ABI) instead of just `extern`.
By making the ABI explicit, it becomes much clearer that "C" is just one of the
possible choices, rather than the "standard" way for external functions.
Removing the default makes it easier to add a new ABI on equal footing as "C".
```rust,editionfuture,compile_fail
#![feature(explicit_extern_abis)]
extern fn function1() {} // ERROR `extern` declarations without an explicit ABI
// are disallowed
extern "C" fn function2() {} // compiles
extern "aapcs" fn function3() {} // compiles
```

View file

@ -0,0 +1,45 @@
// The purpose of this feature gate is to make something into a hard error in a
// future edition. Consequently, this test differs from most other feature gate
// tests. Instead of verifying that an error occurs when the feature gate is
// missing, it ensures that the hard error is only produced with the feature
// gate is present in the `future` edition -- and otherwise that only a warning
// is emitted.
//@ revisions: current current_feature future future_feature
//@ [current] run-rustfix
//@ [current] check-pass
//@ [current_feature] run-rustfix
//@ [current_feature] check-pass
//@ [future] edition: future
//@ [future] compile-flags: -Z unstable-options
//@ [future] run-rustfix
//@ [future] check-pass
//@ [future_feature] edition: future
//@ [future_feature] compile-flags: -Z unstable-options
#![cfg_attr(future_feature, feature(explicit_extern_abis))]
#![cfg_attr(current_feature, feature(explicit_extern_abis))]
extern "C" fn _foo() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" fn _bar() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
fn main() {}

View file

@ -0,0 +1,22 @@
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:27:1
|
LL | extern fn _foo() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
|
= note: `#[warn(missing_abi)]` on by default
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:33:8
|
LL | unsafe extern fn _bar() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:39:8
|
LL | unsafe extern {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: 3 warnings emitted

View file

@ -0,0 +1,45 @@
// The purpose of this feature gate is to make something into a hard error in a
// future edition. Consequently, this test differs from most other feature gate
// tests. Instead of verifying that an error occurs when the feature gate is
// missing, it ensures that the hard error is only produced with the feature
// gate is present in the `future` edition -- and otherwise that only a warning
// is emitted.
//@ revisions: current current_feature future future_feature
//@ [current] run-rustfix
//@ [current] check-pass
//@ [current_feature] run-rustfix
//@ [current_feature] check-pass
//@ [future] edition: future
//@ [future] compile-flags: -Z unstable-options
//@ [future] run-rustfix
//@ [future] check-pass
//@ [future_feature] edition: future
//@ [future_feature] compile-flags: -Z unstable-options
#![cfg_attr(future_feature, feature(explicit_extern_abis))]
#![cfg_attr(current_feature, feature(explicit_extern_abis))]
extern "C" fn _foo() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" fn _bar() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
fn main() {}

View file

@ -0,0 +1,22 @@
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:27:1
|
LL | extern fn _foo() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
|
= note: `#[warn(missing_abi)]` on by default
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:33:8
|
LL | unsafe extern fn _bar() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:39:8
|
LL | unsafe extern {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: 3 warnings emitted

View file

@ -0,0 +1,45 @@
// The purpose of this feature gate is to make something into a hard error in a
// future edition. Consequently, this test differs from most other feature gate
// tests. Instead of verifying that an error occurs when the feature gate is
// missing, it ensures that the hard error is only produced with the feature
// gate is present in the `future` edition -- and otherwise that only a warning
// is emitted.
//@ revisions: current current_feature future future_feature
//@ [current] run-rustfix
//@ [current] check-pass
//@ [current_feature] run-rustfix
//@ [current_feature] check-pass
//@ [future] edition: future
//@ [future] compile-flags: -Z unstable-options
//@ [future] run-rustfix
//@ [future] check-pass
//@ [future_feature] edition: future
//@ [future_feature] compile-flags: -Z unstable-options
#![cfg_attr(future_feature, feature(explicit_extern_abis))]
#![cfg_attr(current_feature, feature(explicit_extern_abis))]
extern "C" fn _foo() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" fn _bar() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern "C" {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
fn main() {}

View file

@ -0,0 +1,22 @@
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:27:1
|
LL | extern fn _foo() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
|
= note: `#[warn(missing_abi)]` on by default
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:33:8
|
LL | unsafe extern fn _bar() {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/feature-gate-explicit-extern-abis.rs:39:8
|
LL | unsafe extern {}
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
warning: 3 warnings emitted

View file

@ -0,0 +1,26 @@
error: `extern` declarations without an explicit ABI are disallowed
--> $DIR/feature-gate-explicit-extern-abis.rs:27:1
|
LL | extern fn _foo() {}
| ^^^^^^ help: specify an ABI: `extern "<abi>"`
|
= help: prior to Rust 2024, a default ABI was inferred
error: `extern` declarations without an explicit ABI are disallowed
--> $DIR/feature-gate-explicit-extern-abis.rs:33:8
|
LL | unsafe extern fn _bar() {}
| ^^^^^^ help: specify an ABI: `extern "<abi>"`
|
= help: prior to Rust 2024, a default ABI was inferred
error: `extern` declarations without an explicit ABI are disallowed
--> $DIR/feature-gate-explicit-extern-abis.rs:39:8
|
LL | unsafe extern {}
| ^^^^^^ help: specify an ABI: `extern "<abi>"`
|
= help: prior to Rust 2024, a default ABI was inferred
error: aborting due to 3 previous errors

View file

@ -0,0 +1,45 @@
// The purpose of this feature gate is to make something into a hard error in a
// future edition. Consequently, this test differs from most other feature gate
// tests. Instead of verifying that an error occurs when the feature gate is
// missing, it ensures that the hard error is only produced with the feature
// gate is present in the `future` edition -- and otherwise that only a warning
// is emitted.
//@ revisions: current current_feature future future_feature
//@ [current] run-rustfix
//@ [current] check-pass
//@ [current_feature] run-rustfix
//@ [current_feature] check-pass
//@ [future] edition: future
//@ [future] compile-flags: -Z unstable-options
//@ [future] run-rustfix
//@ [future] check-pass
//@ [future_feature] edition: future
//@ [future_feature] compile-flags: -Z unstable-options
#![cfg_attr(future_feature, feature(explicit_extern_abis))]
#![cfg_attr(current_feature, feature(explicit_extern_abis))]
extern fn _foo() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern fn _bar() {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
unsafe extern {}
//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
fn main() {}

View file

@ -2,7 +2,7 @@
//@ compile-flags: --crate-type rlib
#[link(name = "libfoo.a", kind = "static")]
extern { } //~ WARN extern declarations without an explicit ABI are deprecated
extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated
//~| HELP explicitly specify the "C" ABI
pub fn main() { }

View file

@ -1,4 +1,4 @@
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/suggest-libname-only-1.rs:5:1
|
LL | extern { }

View file

@ -2,7 +2,7 @@
//@ compile-flags: --crate-type rlib
#[link(name = "bar.lib", kind = "static")]
extern { } //~ WARN extern declarations without an explicit ABI are deprecated
extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated
//~| HELP explicitly specify the "C" ABI
pub fn main() { }

View file

@ -1,4 +1,4 @@
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/suggest-libname-only-2.rs:5:1
|
LL | extern { }

View file

@ -1,4 +1,4 @@
error: extern declarations without an explicit ABI are deprecated
error: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}

View file

@ -1,4 +1,4 @@
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}

View file

@ -10,8 +10,8 @@
extern fn foo() {}
//[warn_deny]~^ ERROR extern declarations without an explicit ABI are deprecated
//[forbid_warn]~^^ ERROR extern declarations without an explicit ABI are deprecated
//[force_warn_deny]~^^^ WARN extern declarations without an explicit ABI are deprecated
//[warn_deny]~^ ERROR `extern` declarations without an explicit ABI are deprecated
//[forbid_warn]~^^ ERROR `extern` declarations without an explicit ABI are deprecated
//[force_warn_deny]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
fn main() {}

View file

@ -1,4 +1,4 @@
error: extern declarations without an explicit ABI are deprecated
error: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}

View file

@ -51,7 +51,7 @@ LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/bad-lit-suffixes.rs:3:1
|
LL | extern
@ -59,7 +59,7 @@ LL | extern
|
= note: `#[warn(missing_abi)]` on by default
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/bad-lit-suffixes.rs:7:1
|
LL | extern

View file

@ -4,7 +4,7 @@ error: suffixes on string literals are invalid
LL | f!("Foo"__);
| ^^^^^^^ invalid suffix `__`
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/lit-err-in-macro.rs:3:9
|
LL | extern $abi fn f() {}

View file

@ -82,7 +82,7 @@ fn bar() {
}
extern { //~ WARN extern declarations without an explicit ABI are deprecated
extern { //~ WARN `extern` declarations without an explicit ABI are deprecated
fn weird_extern() {
#![print_target_and_args_consume(tenth)]
}

View file

@ -22,7 +22,7 @@ error: expected non-macro inner attribute, found attribute macro `print_attr`
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
warning: extern declarations without an explicit ABI are deprecated
warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/inner-attrs.rs:85:1
|
LL | extern {