about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-04-17 00:16:20 +0200
committerGitHub <noreply@github.com>2025-04-17 00:16:20 +0200
commitbb3e156f62c8a7f2f88ff70d513f35e9c1ddc40f (patch)
treea20e5870572e82c1d870be7a858f19d187138636
parent78f2104e334068d5a892a170d50193c0025c690e (diff)
parentd17c04e4a220d6f7bf170eeb0f90498e215555fa (diff)
downloadrust-bb3e156f62c8a7f2f88ff70d513f35e9c1ddc40f.tar.gz
rust-bb3e156f62c8a7f2f88ff70d513f35e9c1ddc40f.zip
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
-rw-r--r--compiler/rustc_ast_passes/messages.ftl4
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs12
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs9
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/doc/unstable-book/src/language-features/explicit-extern-abis.md23
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed45
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed45
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed45
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr26
-rw-r--r--tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs45
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-1.rs2
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-1.stderr2
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-2.rs2
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-2.stderr2
-rw-r--r--tests/ui/lint/cli-lint-override.forbid_warn.stderr2
-rw-r--r--tests/ui/lint/cli-lint-override.force_warn_deny.stderr2
-rw-r--r--tests/ui/lint/cli-lint-override.rs6
-rw-r--r--tests/ui/lint/cli-lint-override.warn_deny.stderr2
-rw-r--r--tests/ui/parser/bad-lit-suffixes.stderr4
-rw-r--r--tests/ui/parser/lit-err-in-macro.stderr2
-rw-r--r--tests/ui/proc-macro/inner-attrs.rs2
-rw-r--r--tests/ui/proc-macro/inner-attrs.stderr2
27 files changed, 334 insertions, 21 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 25944392a52..80754a8f65a 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -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
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index dc77e7b2834..9a7b7daabbf 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -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.
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 8e53e600f7a..2373a7d223e 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -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,
+}
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 36e375c778d..d0ac822ba26 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -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
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 782d328a951..60c183bd56b 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -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
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2af567f2ec5..cc817d99cfa 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -916,6 +916,7 @@ symbols! {
         expf16,
         expf32,
         expf64,
+        explicit_extern_abis,
         explicit_generic_args_with_impl_trait,
         explicit_tail_calls,
         export_name,
diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
new file mode 100644
index 00000000000..ba622466ba7
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
@@ -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
+```
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed
new file mode 100644
index 00000000000..525f78d162f
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed
@@ -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() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr
new file mode 100644
index 00000000000..cf927807c7c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr
@@ -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
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed
new file mode 100644
index 00000000000..525f78d162f
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed
@@ -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() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr
new file mode 100644
index 00000000000..cf927807c7c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr
@@ -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
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed
new file mode 100644
index 00000000000..525f78d162f
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed
@@ -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() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr
new file mode 100644
index 00000000000..cf927807c7c
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr
@@ -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
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr
new file mode 100644
index 00000000000..096a6f43416
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr
@@ -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
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs
new file mode 100644
index 00000000000..379c45f5899
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs
@@ -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() {}
diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs
index c69949d1fdb..8699e4819e6 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-1.rs
+++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs
@@ -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() { }
diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
index 0320294a800..59bd99f619a 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
@@ -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 { }
diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs
index d5150c327cd..87373f563d0 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-2.rs
+++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs
@@ -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() { }
diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
index e492aea27b4..298a9ced170 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
@@ -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 { }
diff --git a/tests/ui/lint/cli-lint-override.forbid_warn.stderr b/tests/ui/lint/cli-lint-override.forbid_warn.stderr
index fb8779ad4f1..fe3437ae3d7 100644
--- a/tests/ui/lint/cli-lint-override.forbid_warn.stderr
+++ b/tests/ui/lint/cli-lint-override.forbid_warn.stderr
@@ -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() {}
diff --git a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
index 10fc13e3f52..f48fca4bd9f 100644
--- a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
+++ b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
@@ -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() {}
diff --git a/tests/ui/lint/cli-lint-override.rs b/tests/ui/lint/cli-lint-override.rs
index 4b3fd0d9c01..b733872166a 100644
--- a/tests/ui/lint/cli-lint-override.rs
+++ b/tests/ui/lint/cli-lint-override.rs
@@ -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() {}
diff --git a/tests/ui/lint/cli-lint-override.warn_deny.stderr b/tests/ui/lint/cli-lint-override.warn_deny.stderr
index 979ca22324f..91baad1f9f8 100644
--- a/tests/ui/lint/cli-lint-override.warn_deny.stderr
+++ b/tests/ui/lint/cli-lint-override.warn_deny.stderr
@@ -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() {}
diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr
index d6b50b0e0d1..86ef35bf783 100644
--- a/tests/ui/parser/bad-lit-suffixes.stderr
+++ b/tests/ui/parser/bad-lit-suffixes.stderr
@@ -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
diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/lit-err-in-macro.stderr
index 9422f22f9c8..08fe58643d4 100644
--- a/tests/ui/parser/lit-err-in-macro.stderr
+++ b/tests/ui/parser/lit-err-in-macro.stderr
@@ -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() {}
diff --git a/tests/ui/proc-macro/inner-attrs.rs b/tests/ui/proc-macro/inner-attrs.rs
index c541e93f904..ca4b2029a33 100644
--- a/tests/ui/proc-macro/inner-attrs.rs
+++ b/tests/ui/proc-macro/inner-attrs.rs
@@ -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)]
     }
diff --git a/tests/ui/proc-macro/inner-attrs.stderr b/tests/ui/proc-macro/inner-attrs.stderr
index 4e7825c0d00..54cccae8da0 100644
--- a/tests/ui/proc-macro/inner-attrs.stderr
+++ b/tests/ui/proc-macro/inner-attrs.stderr
@@ -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 {