about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-01-15 09:20:25 +0000
committerbors <bors@rust-lang.org>2025-01-15 09:20:25 +0000
commit2776bdfe423c9fdfcd6313d678f0852ea26f1309 (patch)
tree3db4eb13790bbab54261f589cfebc0a002494e44
parent00ded39014a4a9cab60d1819a832c2888415e5f9 (diff)
parent8e91327e7128d9315782750f7914657d2053ff58 (diff)
downloadrust-2776bdfe423c9fdfcd6313d678f0852ea26f1309.tar.gz
rust-2776bdfe423c9fdfcd6313d678f0852ea26f1309.zip
Auto merge of #135525 - jhpratt:rollup-4gu2wpm, r=jhpratt
Rollup of 7 pull requests

Successful merges:

 - #132397 (Make missing_abi lint warn-by-default.)
 - #133807 (ci: Enable opt-dist for dist-aarch64-linux builds)
 - #134143 (Convert `struct FromBytesWithNulError` into enum)
 - #134338 (Use a C-safe return type for `__rust_[ui]128_*` overflowing intrinsics)
 - #134678 (Update `ReadDir::next` in `std::sys::pal::unix::fs` to use `&raw const (*p).field` instead of `p.byte_offset().cast()`)
 - #135424 (Detect unstable lint docs that dont enable their feature)
 - #135520 (Make sure we actually use the right trivial lifetime substs when eagerly monomorphizing drop for ADTs)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch4
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/compiler_builtins.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs4
-rw-r--r--compiler/rustc_codegen_gcc/example/mod_bench.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/std_example.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/int.rs123
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs6
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs22
-rw-r--r--compiler/rustc_type_ir/src/binder.rs2
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/alloc/Cargo.toml2
-rw-r--r--library/core/src/ffi/c_str.rs52
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/sys/pal/unix/fs.rs36
-rw-r--r--src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile5
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.rs1
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.stderr4
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed1
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs1
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr16
-rw-r--r--src/tools/lint-docs/src/lib.rs75
-rw-r--r--src/tools/opt-dist/src/bolt.rs13
-rw-r--r--src/tools/opt-dist/src/main.rs28
-rw-r--r--tests/codegen-units/item-collection/drop-glue-eager.rs13
-rw-r--r--tests/ui/associated-types/issue-91231.rs2
-rw-r--r--tests/ui/attributes/key-value-expansion.rs2
-rw-r--r--tests/ui/borrowck/issue-92157.rs2
-rw-r--r--tests/ui/coherence/coherence-negative-impls-copy.rs2
-rw-r--r--tests/ui/conditional-compilation/cfg_accessible-not_sure.rs2
-rw-r--r--tests/ui/consts/const-eval/validation-ice-extern-type-field.rs2
-rw-r--r--tests/ui/delegation/glob-non-impl.rs2
-rw-r--r--tests/ui/extern/extern-type-diag-not-similar.rs4
-rw-r--r--tests/ui/extern/issue-10025.rs2
-rw-r--r--tests/ui/extern/issue-95829.rs2
-rw-r--r--tests/ui/extern/issue-95829.stderr8
-rw-r--r--tests/ui/extern/not-in-block.rs1
-rw-r--r--tests/ui/extern/not-in-block.stderr4
-rw-r--r--tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs2
-rw-r--r--tests/ui/foreign/issue-91370-foreign-fn-block-impl.stderr4
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs2
-rw-r--r--tests/ui/link-native-libs/issue-109144.rs2
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-1.stderr10
-rw-r--r--tests/ui/link-native-libs/suggest-libname-only-2.stderr10
-rw-r--r--tests/ui/lint/function-item-references.rs2
-rw-r--r--tests/ui/lint/lint-ctypes.rs2
-rw-r--r--tests/ui/lint/lint-ctypes.stderr4
-rw-r--r--tests/ui/offset-of/offset-of-dst-field.rs2
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.fixed8
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.rs8
-rw-r--r--tests/ui/parser/bad-fn-ptr-qualifier.stderr32
-rw-r--r--tests/ui/parser/bad-lit-suffixes.rs4
-rw-r--r--tests/ui/parser/bad-lit-suffixes.stderr16
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs1
-rw-r--r--tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr2
-rw-r--r--tests/ui/parser/item-kw-case-mismatch.fixed2
-rw-r--r--tests/ui/parser/item-kw-case-mismatch.rs2
-rw-r--r--tests/ui/parser/item-kw-case-mismatch.stderr8
-rw-r--r--tests/ui/parser/lit-err-in-macro.rs2
-rw-r--r--tests/ui/parser/lit-err-in-macro.stderr14
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.rs8
-rw-r--r--tests/ui/parser/recover/recover-const-async-fn-ptr.stderr32
-rw-r--r--tests/ui/parser/recover/recover-fn-ptr-with-generics.rs2
-rw-r--r--tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr16
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.fixed2
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.rs2
-rw-r--r--tests/ui/parser/recover/recover-missing-semi-before-item.stderr2
-rw-r--r--tests/ui/proc-macro/inner-attrs.stderr10
-rw-r--r--tests/ui/proc-macro/issue-66286.rs2
-rw-r--r--tests/ui/proc-macro/issue-66286.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs2
-rw-r--r--tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed10
-rw-r--r--tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs10
-rw-r--r--tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs2
-rw-r--r--tests/ui/statics/uninhabited-static.rs2
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.rs8
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.stdout8
81 files changed, 431 insertions, 317 deletions
diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
index b2eeb526336..bf58e485158 100644
--- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch
@@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644
  
  [dependencies]
  core = { path = "../core" }
--compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std', 'no-f16-f128'] }
+-compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] }
++compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std', 'no-f16-f128'] }
  
  [dev-dependencies]
  rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 025667e66b2..dcfd7ddabbc 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -76,20 +76,22 @@ pub(crate) fn maybe_codegen_mul_checked<'tcx>(
     }
 
     let is_signed = type_sign(lhs.layout().ty);
-
-    let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
-    let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
+    let oflow_out_place = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
     let param_types = vec![
-        AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
         AbiParam::new(types::I128),
         AbiParam::new(types::I128),
+        AbiParam::special(fx.pointer_type, ArgumentPurpose::Normal),
     ];
-    let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
-    fx.lib_call(
+    let args = [lhs.load_scalar(fx), rhs.load_scalar(fx), oflow_out_place.to_ptr().get_addr(fx)];
+    let ret = fx.lib_call(
         if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
         param_types,
-        vec![],
+        vec![AbiParam::new(types::I128)],
         &args,
     );
-    Some(out_place.to_cvalue(fx))
+    let mul = ret[0];
+    let oflow = oflow_out_place.to_cvalue(fx).load_scalar(fx);
+    let oflow = clif_intcast(fx, oflow, types::I8, false);
+    let layout = fx.layout_of(Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]));
+    Some(CValue::by_val_pair(mul, oflow, layout))
 }
diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
index f8e3a034421..2484c10848e 100644
--- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
+++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
@@ -43,7 +43,7 @@ builtin_functions! {
     fn __divti3(n: i128, d: i128) -> i128;
     fn __umodti3(n: u128, d: u128) -> u128;
     fn __modti3(n: i128, d: i128) -> i128;
-    fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool);
+    fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128;
 
     // floats
     fn __floattisf(i: i128) -> f32;
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index bd7a4612a92..5a4ee0a198c 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -689,7 +689,7 @@ impl<T> Index<usize> for [T] {
     }
 }
 
-extern {
+extern "C" {
     type VaListImpl;
 }
 
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index dcfa34cb729..1d51e0a1856 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -258,13 +258,13 @@ fn main() {
 
     assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
 
-    extern {
+    extern "C" {
         #[linkage = "weak"]
         static ABC: *const u8;
     }
 
     {
-        extern {
+        extern "C" {
             #[linkage = "weak"]
             static ABC: *const u8;
         }
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
index cae911c1073..e8a9cade747 100644
--- a/compiler/rustc_codegen_gcc/example/mod_bench.rs
+++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs
@@ -3,7 +3,7 @@
 #![allow(internal_features)]
 
 #[link(name = "c")]
-extern {}
+extern "C" {}
 
 #[panic_handler]
 fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs
index 9e43b4635f0..5fa1e0afb06 100644
--- a/compiler/rustc_codegen_gcc/example/std_example.rs
+++ b/compiler/rustc_codegen_gcc/example/std_example.rs
@@ -7,7 +7,7 @@ use std::arch::x86_64::*;
 use std::io::Write;
 use std::ops::Coroutine;
 
-extern {
+extern "C" {
     pub fn printf(format: *const i8, ...) -> i32;
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index 7b9d1feb8d7..fe6a65bed03 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -322,36 +322,26 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                 },
             }
         } else {
-            match new_kind {
-                Int(I128) | Uint(U128) => {
-                    let func_name = match oop {
-                        OverflowOp::Add => match new_kind {
-                            Int(I128) => "__rust_i128_addo",
-                            Uint(U128) => "__rust_u128_addo",
-                            _ => unreachable!(),
-                        },
-                        OverflowOp::Sub => match new_kind {
-                            Int(I128) => "__rust_i128_subo",
-                            Uint(U128) => "__rust_u128_subo",
-                            _ => unreachable!(),
-                        },
-                        OverflowOp::Mul => match new_kind {
-                            Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead?
-                            Uint(U128) => "__rust_u128_mulo",
-                            _ => unreachable!(),
-                        },
-                    };
-                    return self.operation_with_overflow(func_name, lhs, rhs);
-                }
-                _ => match oop {
-                    OverflowOp::Mul => match new_kind {
-                        Int(I32) => "__mulosi4",
-                        Int(I64) => "__mulodi4",
-                        _ => unreachable!(),
-                    },
-                    _ => unimplemented!("overflow operation for {:?}", new_kind),
+            let (func_name, width) = match oop {
+                OverflowOp::Add => match new_kind {
+                    Int(I128) => ("__rust_i128_addo", 128),
+                    Uint(U128) => ("__rust_u128_addo", 128),
+                    _ => unreachable!(),
                 },
-            }
+                OverflowOp::Sub => match new_kind {
+                    Int(I128) => ("__rust_i128_subo", 128),
+                    Uint(U128) => ("__rust_u128_subo", 128),
+                    _ => unreachable!(),
+                },
+                OverflowOp::Mul => match new_kind {
+                    Int(I32) => ("__mulosi4", 32),
+                    Int(I64) => ("__mulodi4", 64),
+                    Int(I128) => ("__rust_i128_mulo", 128), // TODO(antoyo): use __muloti4d instead?
+                    Uint(U128) => ("__rust_u128_mulo", 128),
+                    _ => unreachable!(),
+                },
+            };
+            return self.operation_with_overflow(func_name, lhs, rhs, width);
         };
 
         let intrinsic = self.context.get_builtin_function(name);
@@ -364,80 +354,87 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
         (res.dereference(self.location).to_rvalue(), overflow)
     }
 
+    /// Non-`__builtin_*` overflow operations with a `fn(T, T, &mut i32) -> T` signature.
     pub fn operation_with_overflow(
         &self,
         func_name: &str,
         lhs: RValue<'gcc>,
         rhs: RValue<'gcc>,
+        width: u64,
     ) -> (RValue<'gcc>, RValue<'gcc>) {
         let a_type = lhs.get_type();
         let b_type = rhs.get_type();
         debug_assert!(a_type.dyncast_array().is_some());
         debug_assert!(b_type.dyncast_array().is_some());
+        let overflow_type = self.i32_type;
+        let overflow_param_type = overflow_type.make_pointer();
+        let res_type = a_type;
+
+        let overflow_value =
+            self.current_func().new_local(self.location, overflow_type, "overflow");
+        let overflow_addr = overflow_value.get_address(self.location);
+
         let param_a = self.context.new_parameter(self.location, a_type, "a");
         let param_b = self.context.new_parameter(self.location, b_type, "b");
-        let result_field = self.context.new_field(self.location, a_type, "result");
-        let overflow_field = self.context.new_field(self.location, self.bool_type, "overflow");
-
-        let ret_ty = Ty::new_tup(self.tcx, &[self.tcx.types.i128, self.tcx.types.bool]);
+        let param_overflow =
+            self.context.new_parameter(self.location, overflow_param_type, "overflow");
+
+        let a_elem_type = a_type.dyncast_array().expect("non-array a value");
+        debug_assert!(a_elem_type.is_integral());
+        let res_ty = match width {
+            32 => self.tcx.types.i32,
+            64 => self.tcx.types.i64,
+            128 => self.tcx.types.i128,
+            _ => unreachable!("unexpected integer size"),
+        };
         let layout = self
             .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ret_ty))
+            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(res_ty))
             .unwrap();
 
         let arg_abi = ArgAbi { layout, mode: PassMode::Direct(ArgAttributes::new()) };
         let mut fn_abi = FnAbi {
-            args: vec![arg_abi.clone(), arg_abi.clone()].into_boxed_slice(),
+            args: vec![arg_abi.clone(), arg_abi.clone(), arg_abi.clone()].into_boxed_slice(),
             ret: arg_abi,
             c_variadic: false,
-            fixed_count: 2,
+            fixed_count: 3,
             conv: Conv::C,
             can_unwind: false,
         };
         fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C { unwind: false }).unwrap();
 
-        let indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
-
-        let return_type = self
-            .context
-            .new_struct_type(self.location, "result_overflow", &[result_field, overflow_field]);
-        let result = if indirect {
-            let return_value =
-                self.current_func().new_local(self.location, return_type.as_type(), "return_value");
-            let return_param_type = return_type.as_type().make_pointer();
-            let return_param =
-                self.context.new_parameter(self.location, return_param_type, "return_value");
+        let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
+
+        let result = if ret_indirect {
+            let res_value = self.current_func().new_local(self.location, res_type, "result_value");
+            let res_addr = res_value.get_address(self.location);
+            let res_param_type = res_type.make_pointer();
+            let param_res = self.context.new_parameter(self.location, res_param_type, "result");
+
             let func = self.context.new_function(
                 self.location,
                 FunctionType::Extern,
                 self.type_void(),
-                &[return_param, param_a, param_b],
+                &[param_res, param_a, param_b, param_overflow],
                 func_name,
                 false,
             );
-            self.llbb().add_eval(
-                self.location,
-                self.context.new_call(self.location, func, &[
-                    return_value.get_address(self.location),
-                    lhs,
-                    rhs,
-                ]),
-            );
-            return_value.to_rvalue()
+            let _void =
+                self.context.new_call(self.location, func, &[res_addr, lhs, rhs, overflow_addr]);
+            res_value.to_rvalue()
         } else {
             let func = self.context.new_function(
                 self.location,
                 FunctionType::Extern,
-                return_type.as_type(),
-                &[param_a, param_b],
+                res_type,
+                &[param_a, param_b, param_overflow],
                 func_name,
                 false,
             );
-            self.context.new_call(self.location, func, &[lhs, rhs])
+            self.context.new_call(self.location, func, &[lhs, rhs, overflow_addr])
         };
-        let overflow = result.access_field(self.location, overflow_field);
-        let int_result = result.access_field(self.location, result_field);
-        (int_result, overflow)
+
+        (result, self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue())
     }
 
     pub fn gcc_icmp(
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 42d189d1b7d..48606f5f91c 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -1001,7 +1001,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                     128 => "__rust_i128_addo",
                     _ => unreachable!(),
                 };
-                let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
+                let (int_result, overflow) =
+                    self.operation_with_overflow(func_name, lhs, rhs, width);
                 self.llbb().add_assignment(self.location, res, int_result);
                 overflow
             };
@@ -1071,7 +1072,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
                     128 => "__rust_i128_subo",
                     _ => unreachable!(),
                 };
-                let (int_result, overflow) = self.operation_with_overflow(func_name, lhs, rhs);
+                let (int_result, overflow) =
+                    self.operation_with_overflow(func_name, lhs, rhs, width);
                 self.llbb().add_assignment(self.location, res, int_result);
                 overflow
             };
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 0c6147f4a46..9fc527a6a3a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3597,7 +3597,7 @@ declare_lint! {
     ///
     /// [Other ABIs]: https://doc.rust-lang.org/reference/items/external-blocks.html#abi
     pub MISSING_ABI,
-    Allow,
+    Warn,
     "No declared ABI for extern declaration"
 }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 0f3943cfe6a..bb603df1129 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1410,19 +1410,33 @@ impl<'v> RootCollector<'_, 'v> {
                     && !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
                 {
                     debug!("RootCollector: ADT drop-glue for `{id:?}`",);
+                    let id_args =
+                        ty::GenericArgs::for_item(self.tcx, id.owner_id.to_def_id(), |param, _| {
+                            match param.kind {
+                                GenericParamDefKind::Lifetime => {
+                                    self.tcx.lifetimes.re_erased.into()
+                                }
+                                GenericParamDefKind::Type { .. }
+                                | GenericParamDefKind::Const { .. } => {
+                                    unreachable!(
+                                        "`own_requires_monomorphization` check means that \
+                                we should have no type/const params"
+                                    )
+                                }
+                            }
+                        });
 
                     // This type is impossible to instantiate, so we should not try to
                     // generate a `drop_in_place` instance for it.
                     if self.tcx.instantiate_and_check_impossible_predicates((
                         id.owner_id.to_def_id(),
-                        ty::List::empty(),
+                        id_args,
                     )) {
                         return;
                     }
 
-                    let ty = self.tcx.erase_regions(
-                        self.tcx.type_of(id.owner_id.to_def_id()).instantiate_identity(),
-                    );
+                    let ty =
+                        self.tcx.type_of(id.owner_id.to_def_id()).instantiate(self.tcx, id_args);
                     assert!(!ty.has_non_region_param());
                     visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                 }
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index cb59bc608c2..0d0092ea1aa 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -804,7 +804,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> {
     #[inline(never)]
     fn region_param_out_of_range(&self, ebr: I::EarlyParamRegion, r: I::Region) -> ! {
         panic!(
-            "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
+            "region parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}",
             ebr,
             r,
             ebr.index(),
diff --git a/library/Cargo.lock b/library/Cargo.lock
index b01fec9b8f5..c8007dd9be0 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -61,9 +61,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.141"
+version = "0.1.143"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e7a0206befe4e574e37d6d7a0fe82e88fdf54bedb0608f239cb11b7a6aa6be"
+checksum = "c85ba2077e3eab3dd81be4ece6b7fb2ad0887c1fb813e9a45400baf75c6c7c29"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 36f617b4526..96caac890a3 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2021"
 
 [dependencies]
 core = { path = "../core" }
-compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] }
 
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 8831443a10f..7180593edf0 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -124,37 +124,25 @@ pub struct CStr {
 ///
 /// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
 /// ```
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
-pub struct FromBytesWithNulError {
-    kind: FromBytesWithNulErrorKind,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum FromBytesWithNulErrorKind {
-    InteriorNul(usize),
+pub enum FromBytesWithNulError {
+    /// Data provided contains an interior nul byte at byte `position`.
+    InteriorNul {
+        /// The position of the interior nul byte.
+        position: usize,
+    },
+    /// Data provided is not nul terminated.
     NotNulTerminated,
 }
 
-// FIXME: const stability attributes should not be required here, I think
-impl FromBytesWithNulError {
-    const fn interior_nul(pos: usize) -> FromBytesWithNulError {
-        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
-    }
-    const fn not_nul_terminated() -> FromBytesWithNulError {
-        FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
-    }
-}
-
 #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
 impl Error for FromBytesWithNulError {
     #[allow(deprecated)]
     fn description(&self) -> &str {
-        match self.kind {
-            FromBytesWithNulErrorKind::InteriorNul(..) => {
-                "data provided contains an interior nul byte"
-            }
-            FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
+        match self {
+            Self::InteriorNul { .. } => "data provided contains an interior nul byte",
+            Self::NotNulTerminated => "data provided is not nul terminated",
         }
     }
 }
@@ -199,8 +187,8 @@ impl fmt::Display for FromBytesWithNulError {
     #[allow(deprecated, deprecated_in_future)]
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(self.description())?;
-        if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
-            write!(f, " at byte pos {pos}")?;
+        if let Self::InteriorNul { position } = self {
+            write!(f, " at byte pos {position}")?;
         }
         Ok(())
     }
@@ -349,25 +337,25 @@ impl CStr {
     /// use std::ffi::CStr;
     ///
     /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
-    /// assert!(cstr.is_ok());
+    /// assert_eq!(cstr, Ok(c"hello"));
     /// ```
     ///
     /// Creating a `CStr` without a trailing nul terminator is an error:
     ///
     /// ```
-    /// use std::ffi::CStr;
+    /// use std::ffi::{CStr, FromBytesWithNulError};
     ///
     /// let cstr = CStr::from_bytes_with_nul(b"hello");
-    /// assert!(cstr.is_err());
+    /// assert_eq!(cstr, Err(FromBytesWithNulError::NotNulTerminated));
     /// ```
     ///
     /// Creating a `CStr` with an interior nul byte is an error:
     ///
     /// ```
-    /// use std::ffi::CStr;
+    /// use std::ffi::{CStr, FromBytesWithNulError};
     ///
     /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
-    /// assert!(cstr.is_err());
+    /// assert_eq!(cstr, Err(FromBytesWithNulError::InteriorNul { position: 2 }));
     /// ```
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
     #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
@@ -379,8 +367,8 @@ impl CStr {
                 // of the byte slice.
                 Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
             }
-            Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
-            None => Err(FromBytesWithNulError::not_nul_terminated()),
+            Some(position) => Err(FromBytesWithNulError::InteriorNul { position }),
+            None => Err(FromBytesWithNulError::NotNulTerminated),
         }
     }
 
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index f34dc185eb1..da58d7c13bd 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.141" }
+compiler_builtins = { version = "=0.1.143" }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.15", default-features = false, features = [
     'rustc-dep-of-std',
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 54fa31620ac..fdf011c1948 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -709,7 +709,7 @@ impl Iterator for ReadDir {
                 // thread safety for readdir() as long an individual DIR* is not accessed
                 // concurrently, which is sufficient for Rust.
                 super::os::set_errno(0);
-                let entry_ptr = readdir64(self.inner.dirp.0);
+                let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
                     // We either encountered an error, or reached the end. Either way,
                     // the next call to next() should return None.
@@ -735,29 +735,19 @@ impl Iterator for ReadDir {
                 // contents were "simply" partially initialized data.
                 //
                 // Like for uninitialized contents, converting entry_ptr to `&dirent64`
-                // would not be legal. However, unique to dirent64 is that we don't even
-                // get to use `&raw const (*entry_ptr).d_name` because that operation
-                // requires the full extent of *entry_ptr to be in bounds of the same
-                // allocation, which is not necessarily the case here.
-                //
-                // Instead we must access fields individually through their offsets.
-                macro_rules! offset_ptr {
-                    ($entry_ptr:expr, $field:ident) => {{
-                        const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize;
-                        if true {
-                            // Cast to the same type determined by the else branch.
-                            $entry_ptr.byte_offset(OFFSET).cast::<_>()
-                        } else {
-                            #[allow(deref_nullptr)]
-                            {
-                                &raw const (*ptr::null::<dirent64>()).$field
-                            }
-                        }
-                    }};
+                // would not be legal. However, we can use `&raw const (*entry_ptr).d_name`
+                // to refer the fields individually, because that operation is equivalent
+                // to `byte_offset` and thus does not require the full extent of `*entry_ptr`
+                // to be in bounds of the same allocation, only the offset of the field
+                // being referenced.
+                macro_rules! entry_field_ptr {
+                    ($field:ident) => {
+                        &raw const (*entry_ptr).$field
+                    };
                 }
 
                 // d_name is guaranteed to be null-terminated.
-                let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast());
+                let name = CStr::from_ptr(entry_field_ptr!(d_name).cast());
                 let name_bytes = name.to_bytes();
                 if name_bytes == b"." || name_bytes == b".." {
                     continue;
@@ -765,14 +755,14 @@ impl Iterator for ReadDir {
 
                 #[cfg(not(target_os = "vita"))]
                 let entry = dirent64_min {
-                    d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
+                    d_ino: *entry_field_ptr!(d_ino) as u64,
                     #[cfg(not(any(
                         target_os = "solaris",
                         target_os = "illumos",
                         target_os = "aix",
                         target_os = "nto",
                     )))]
-                    d_type: *offset_ptr!(entry_ptr, d_type) as u8,
+                    d_type: *entry_field_ptr!(d_type) as u8,
                 };
 
                 #[cfg(target_os = "vita")]
diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
index 8b0fb0710d4..6f33c632181 100644
--- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
@@ -91,9 +91,12 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.debug-assertions=false \
       --set rust.jemalloc \
       --set rust.use-lld=true \
+      --set rust.lto=thin \
       --set rust.codegen-units=1
 
-ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
+ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
+      ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci --  python3 ../x.py dist \
+      --host $HOSTS --target $HOSTS --include-default-paths build-manifest bootstrap
 
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=clang
 ENV LIBCURL_NO_PKG_CONFIG 1
diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs
index e2c27e585fc..4f361f5162b 100644
--- a/src/tools/clippy/tests/ui/boxed_local.rs
+++ b/src/tools/clippy/tests/ui/boxed_local.rs
@@ -173,6 +173,7 @@ mod issue_3739 {
 /// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code.
 pub extern "C" fn do_not_warn_me(_c_pointer: Box<String>) -> () {}
 
+#[allow(missing_abi)]
 #[rustfmt::skip] // Forces rustfmt to not add ABI
 pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
 
diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr
index d3156c820b2..08fe375afb2 100644
--- a/src/tools/clippy/tests/ui/boxed_local.stderr
+++ b/src/tools/clippy/tests/ui/boxed_local.stderr
@@ -14,13 +14,13 @@ LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
    |            ^^^^^^^^^^^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:188:44
+  --> tests/ui/boxed_local.rs:189:44
    |
 LL |         fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
    |                                            ^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:196:16
+  --> tests/ui/boxed_local.rs:197:16
    |
 LL |         fn foo(x: Box<u32>) {}
    |                ^
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 5cf5c608a85..83574a5cd98 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -240,7 +240,7 @@ fn parenthesized_word() {}
 /// UXes
 fn plural_acronym_test() {}
 
-extern {
+extern "C" {
     /// `foo()`
     fn in_extern();
 }
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 420211c6539..20fe89cdc53 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -240,7 +240,7 @@ fn parenthesized_word() {}
 /// UXes
 fn plural_acronym_test() {}
 
-extern {
+extern "C" {
     /// foo()
     fn in_extern();
 }
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index 014fbb85c7a..dd9dedcdd04 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -149,6 +149,7 @@ mod msrv {
         //~^ ERROR: this could be a `const fn`
 
         #[rustfmt::skip]
+        #[allow(missing_abi)]
         const extern fn implicit_c() {}
         //~^ ERROR: this could be a `const fn`
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 4f7c2cbcf0b..f974478540c 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -149,6 +149,7 @@ mod msrv {
         //~^ ERROR: this could be a `const fn`
 
         #[rustfmt::skip]
+        #[allow(missing_abi)]
         extern fn implicit_c() {}
         //~^ ERROR: this could be a `const fn`
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index cc7dfd0888d..33836bdfe9f 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -222,7 +222,7 @@ LL |         const extern "C" fn c() {}
    |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9
    |
 LL |         extern fn implicit_c() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +233,7 @@ LL |         const extern fn implicit_c() {}
    |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:169:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9
    |
 LL | /         pub fn new(strings: Vec<String>) -> Self {
 LL | |             Self { strings }
@@ -246,7 +246,7 @@ LL |         pub const fn new(strings: Vec<String>) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:174:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9
    |
 LL | /         pub fn empty() -> Self {
 LL | |             Self { strings: Vec::new() }
@@ -259,7 +259,7 @@ LL |         pub const fn empty() -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:185:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9
    |
 LL | /         pub fn new(text: String) -> Self {
 LL | |             let vec = Vec::new();
@@ -273,7 +273,7 @@ LL |         pub const fn new(text: String) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:204:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5
    |
 LL |     fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -284,7 +284,7 @@ LL |     const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:208:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:209:5
    |
 LL |     extern "C-unwind" fn c_unwind() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -295,7 +295,7 @@ LL |     const extern "C-unwind" fn c_unwind() {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:210:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:211:5
    |
 LL |     extern "system" fn system() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -306,7 +306,7 @@ LL |     const extern "system" fn system() {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:212:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:213:5
    |
 LL |     extern "system-unwind" fn system_unwind() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 8c7ff08ccd7..f6e84465780 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -473,37 +473,64 @@ impl<'a> LintExtractor<'a> {
             .filter(|line| line.starts_with('{'))
             .map(serde_json::from_str)
             .collect::<Result<Vec<serde_json::Value>, _>>()?;
+
         // First try to find the messages with the `code` field set to our lint.
         let matches: Vec<_> = msgs
             .iter()
             .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
             .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
             .collect();
-        if matches.is_empty() {
-            // Some lints override their code to something else (E0566).
-            // Try to find something that looks like it could be our lint.
-            let matches: Vec<_> = msgs.iter().filter(|msg|
-                matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)))
-                .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
-                .collect();
-            if matches.is_empty() {
-                let rendered: Vec<&str> =
-                    msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
-                let non_json: Vec<&str> =
-                    stderr.lines().filter(|line| !line.starts_with('{')).collect();
-                Err(format!(
-                    "did not find lint `{}` in output of example, got:\n{}\n{}",
-                    name,
-                    non_json.join("\n"),
-                    rendered.join("\n")
-                )
-                .into())
-            } else {
-                Ok(matches.join("\n"))
-            }
-        } else {
-            Ok(matches.join("\n"))
+        if !matches.is_empty() {
+            return Ok(matches.join("\n"));
+        }
+
+        // Try to detect if an unstable lint forgot to enable a `#![feature(..)]`.
+        // Specifically exclude `test_unstable_lint` which exercises this on purpose.
+        if name != "test_unstable_lint"
+            && msgs.iter().any(|msg| {
+                matches!(&msg["code"]["code"], serde_json::Value::String(s) if s=="unknown_lints")
+                    && matches!(&msg["message"], serde_json::Value::String(s) if s.contains(name))
+            })
+        {
+            let rendered: Vec<&str> =
+                msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+            let non_json: Vec<&str> =
+                stderr.lines().filter(|line| !line.starts_with('{')).collect();
+            return Err(format!(
+                "did not find lint `{}` in output of example (got unknown_lints)\n\
+                Is the lint possibly misspelled, or does it need a `#![feature(...)]`?\n\
+                Output was:\n\
+                {}\n{}",
+                name,
+                rendered.join("\n"),
+                non_json.join("\n"),
+            )
+            .into());
         }
+
+        // Some lints override their code to something else (E0566).
+        // Try to find something that looks like it could be our lint.
+        let matches: Vec<_> = msgs
+            .iter()
+            .filter(
+                |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
+            )
+            .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+            .collect();
+        if !matches.is_empty() {
+            return Ok(matches.join("\n"));
+        }
+
+        // Otherwise, give a descriptive error.
+        let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+        let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect();
+        Err(format!(
+            "did not find lint `{}` in output of example, got:\n{}\n{}",
+            name,
+            non_json.join("\n"),
+            rendered.join("\n")
+        )
+        .into())
     }
 
     /// Saves the mdbook lint chapters at the given path.
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index d9efbb8d880..0f1fda38115 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -1,6 +1,7 @@
 use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 
+use crate::environment::Environment;
 use crate::exec::cmd;
 use crate::training::BoltProfile;
 use crate::utils::io::copy_file;
@@ -45,13 +46,21 @@ pub fn with_bolt_instrumented<F: FnOnce(&Utf8Path) -> anyhow::Result<R>, R>(
 }
 
 /// Optimizes the file at `path` with BOLT in-place using the given `profile`.
-pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<()> {
+pub fn bolt_optimize(
+    path: &Utf8Path,
+    profile: &BoltProfile,
+    env: &Environment,
+) -> anyhow::Result<()> {
     // Copy the artifact to a new location, so that we do not use the same input and output file.
     // BOLT cannot handle optimizing when the input and output is the same file, because it performs
     // in-place patching.
     let temp_path = tempfile::NamedTempFile::new()?.into_temp_path();
     copy_file(path, &temp_path)?;
 
+    // FIXME: cdsplit in llvm-bolt is currently broken on AArch64, drop this once it's fixed upstream
+    let split_strategy =
+        if env.host_tuple().starts_with("aarch64") { "profile2" } else { "cdsplit" };
+
     cmd(&["llvm-bolt"])
         .arg(temp_path.display())
         .arg("-data")
@@ -65,7 +74,7 @@ pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<(
         // Split function code into hot and code regions
         .arg("-split-functions")
         // Split using best available strategy (three-way splitting, Cache-Directed Sort)
-        .arg("-split-strategy=cdsplit")
+        .arg(format!("-split-strategy={split_strategy}"))
         // Split as many basic blocks as possible
         .arg("-split-all-cold")
         // Move jump tables to a separate section
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index c871200f3cf..aa05b5f0e76 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -146,6 +146,21 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
             let target_triple =
                 std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing");
 
+            let is_aarch64 = target_triple.starts_with("aarch64");
+
+            let mut skip_tests = vec![
+                // Fails because of linker errors, as of June 2023.
+                "tests/ui/process/nofile-limit.rs".to_string(),
+            ];
+
+            if is_aarch64 {
+                skip_tests.extend([
+                    // Those tests fail only inside of Docker on aarch64, as of December 2024
+                    "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(),
+                    "tests/ui/consts/large_const_alloc.rs".to_string(),
+                ]);
+            }
+
             let checkout_dir = Utf8PathBuf::from("/checkout");
             let env = EnvironmentBuilder::default()
                 .host_tuple(target_triple)
@@ -155,11 +170,9 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .artifact_dir(Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts"))
                 .build_dir(checkout_dir.join("obj"))
                 .shared_llvm(true)
-                .use_bolt(true)
-                .skipped_tests(vec![
-                    // Fails because of linker errors, as of June 2023.
-                    "tests/ui/process/nofile-limit.rs".to_string(),
-                ])
+                // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024.
+                .use_bolt(!is_aarch64)
+                .skipped_tests(skip_tests)
                 .build()?;
 
             (env, shared.build_args)
@@ -304,7 +317,8 @@ fn execute_pipeline(
             // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
             // therefore it will actually optimize all the hard links, which means that the final
             // packaged `libLLVM.so` file *will* be BOLT optimized.
-            bolt_optimize(&llvm_lib, &llvm_profile).context("Could not optimize LLVM with BOLT")?;
+            bolt_optimize(&llvm_lib, &llvm_profile, env)
+                .context("Could not optimize LLVM with BOLT")?;
 
             let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
 
@@ -319,7 +333,7 @@ fn execute_pipeline(
             print_free_disk_space()?;
 
             // Now optimize the library with BOLT.
-            bolt_optimize(&rustc_lib, &rustc_profile)
+            bolt_optimize(&rustc_lib, &rustc_profile, env)
                 .context("Could not optimize rustc with BOLT")?;
 
             // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
diff --git a/tests/codegen-units/item-collection/drop-glue-eager.rs b/tests/codegen-units/item-collection/drop-glue-eager.rs
index 77470767ee1..c81074de490 100644
--- a/tests/codegen-units/item-collection/drop-glue-eager.rs
+++ b/tests/codegen-units/item-collection/drop-glue-eager.rs
@@ -41,3 +41,16 @@ impl<'a> Drop for StructWithDropAndLt<'a> {
 struct StructWithDropAndLt<'a> {
     x: &'a i32,
 }
+
+// Make sure we don't ICE when checking impossible predicates for the struct.
+// Regression test for <https://github.com/rust-lang/rust/issues/135515>.
+//~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithLtAndPredicate<'_>> - shim(Some(StructWithLtAndPredicate<'_>))
+struct StructWithLtAndPredicate<'a: 'a> {
+    x: &'a i32,
+}
+
+// We should be able to monomorphize drops for struct with lifetimes.
+impl<'a> Drop for StructWithLtAndPredicate<'a> {
+    //~ MONO_ITEM fn <StructWithLtAndPredicate<'_> as std::ops::Drop>::drop
+    fn drop(&mut self) {}
+}
diff --git a/tests/ui/associated-types/issue-91231.rs b/tests/ui/associated-types/issue-91231.rs
index d1c99fd44fa..a04ab60a7fc 100644
--- a/tests/ui/associated-types/issue-91231.rs
+++ b/tests/ui/associated-types/issue-91231.rs
@@ -3,7 +3,7 @@
 #![feature(extern_types)]
 #![allow(dead_code)]
 
-extern {
+extern "C" {
     type Extern;
 }
 
diff --git a/tests/ui/attributes/key-value-expansion.rs b/tests/ui/attributes/key-value-expansion.rs
index e5700a75935..9034e0a7398 100644
--- a/tests/ui/attributes/key-value-expansion.rs
+++ b/tests/ui/attributes/key-value-expansion.rs
@@ -39,7 +39,7 @@ bug!();
 macro_rules! doc_comment {
     ($x:expr) => {
         #[doc = $x]
-        extern {}
+        extern "C" {}
     };
 }
 
diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs
index 3a6f8908b21..a2b685cdf6e 100644
--- a/tests/ui/borrowck/issue-92157.rs
+++ b/tests/ui/borrowck/issue-92157.rs
@@ -5,7 +5,7 @@
 
 #[cfg(target_os = "linux")]
 #[link(name = "c")]
-extern {}
+extern "C" {}
 
 #[lang = "start"]
 fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
diff --git a/tests/ui/coherence/coherence-negative-impls-copy.rs b/tests/ui/coherence/coherence-negative-impls-copy.rs
index 377d750f8ba..c0d852180a5 100644
--- a/tests/ui/coherence/coherence-negative-impls-copy.rs
+++ b/tests/ui/coherence/coherence-negative-impls-copy.rs
@@ -18,7 +18,7 @@ impl !Copy for WithDrop {}
 
 struct Type;
 trait Trait {}
-extern {
+extern "C" {
     type ExternType;
 }
 
diff --git a/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs b/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs
index e357d3c6cb5..2ac57f35674 100644
--- a/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs
+++ b/tests/ui/conditional-compilation/cfg_accessible-not_sure.rs
@@ -63,7 +63,7 @@ const B: bool = true;
 
 // ForeignType::unresolved - error
 
-extern {
+extern "C" {
     type ForeignType;
 }
 
diff --git a/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs
index 3502409d576..8a32b170c40 100644
--- a/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs
+++ b/tests/ui/consts/const-eval/validation-ice-extern-type-field.rs
@@ -1,6 +1,6 @@
 #![feature(extern_types)]
 
-extern {
+extern "C" {
     type Opaque;
 }
 
diff --git a/tests/ui/delegation/glob-non-impl.rs b/tests/ui/delegation/glob-non-impl.rs
index d523731eeb3..e3a4061fb15 100644
--- a/tests/ui/delegation/glob-non-impl.rs
+++ b/tests/ui/delegation/glob-non-impl.rs
@@ -11,7 +11,7 @@ trait OtherTrait {
     reuse Trait::*; //~ ERROR glob delegation is only supported in impls
 }
 
-extern {
+extern "C" {
     reuse Trait::*; //~ ERROR delegation is not supported in `extern` blocks
 }
 
diff --git a/tests/ui/extern/extern-type-diag-not-similar.rs b/tests/ui/extern/extern-type-diag-not-similar.rs
index 39d00a6c1bc..cd3eec9f1f7 100644
--- a/tests/ui/extern/extern-type-diag-not-similar.rs
+++ b/tests/ui/extern/extern-type-diag-not-similar.rs
@@ -4,11 +4,11 @@
 // because they are both extern types.
 
 #![feature(extern_types)]
-extern {
+extern "C" {
     type ShouldNotBeMentioned;
 }
 
-extern {
+extern "C" {
     type Foo;
 }
 
diff --git a/tests/ui/extern/issue-10025.rs b/tests/ui/extern/issue-10025.rs
index 140012f4a16..9be0f616fd2 100644
--- a/tests/ui/extern/issue-10025.rs
+++ b/tests/ui/extern/issue-10025.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-#![allow(dead_code)]
+#![allow(dead_code, missing_abi)]
 
 unsafe extern fn foo() {}
 unsafe extern "C" fn bar() {}
diff --git a/tests/ui/extern/issue-95829.rs b/tests/ui/extern/issue-95829.rs
index c5ae4c68265..493d53d2532 100644
--- a/tests/ui/extern/issue-95829.rs
+++ b/tests/ui/extern/issue-95829.rs
@@ -1,6 +1,6 @@
 //@ edition:2018
 
-extern {
+extern "C" {
     async fn L() { //~ ERROR: incorrect function inside `extern` block
         //~^ ERROR: functions in `extern` blocks cannot have `async` qualifier
         async fn M() {}
diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr
index 2f396b8cc04..2acd0fa3a26 100644
--- a/tests/ui/extern/issue-95829.stderr
+++ b/tests/ui/extern/issue-95829.stderr
@@ -1,8 +1,8 @@
 error: incorrect function inside `extern` block
   --> $DIR/issue-95829.rs:4:14
    |
-LL |   extern {
-   |   ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |   extern "C" {
+   |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
 LL |       async fn L() {
    |  ______________^___-
    | |              |
@@ -18,8 +18,8 @@ LL | |     }
 error: functions in `extern` blocks cannot have `async` qualifier
   --> $DIR/issue-95829.rs:4:5
    |
-LL | extern {
-   | ------ in this `extern` block
+LL | extern "C" {
+   | ---------- in this `extern` block
 LL |     async fn L() {
    |     ^^^^^ help: remove the `async` qualifier
 
diff --git a/tests/ui/extern/not-in-block.rs b/tests/ui/extern/not-in-block.rs
index d3bcafdef7b..c2161635090 100644
--- a/tests/ui/extern/not-in-block.rs
+++ b/tests/ui/extern/not-in-block.rs
@@ -1,4 +1,5 @@
 #![crate_type = "lib"]
+#![allow(missing_abi)]
 
 extern fn none_fn(x: bool) -> i32;
 //~^ ERROR free function without a body
diff --git a/tests/ui/extern/not-in-block.stderr b/tests/ui/extern/not-in-block.stderr
index 2544949ab17..f86c279a234 100644
--- a/tests/ui/extern/not-in-block.stderr
+++ b/tests/ui/extern/not-in-block.stderr
@@ -1,5 +1,5 @@
 error: free function without a body
-  --> $DIR/not-in-block.rs:3:1
+  --> $DIR/not-in-block.rs:4:1
    |
 LL | extern fn none_fn(x: bool) -> i32;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,7 +14,7 @@ LL | extern { fn none_fn(x: bool) -> i32; }
    | ~~~~~~~~                             +
 
 error: free function without a body
-  --> $DIR/not-in-block.rs:5:1
+  --> $DIR/not-in-block.rs:6:1
    |
 LL | extern "C" fn c_fn(x: bool) -> i32;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs
index 2ac3ca29355..e8634de86ea 100644
--- a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs
+++ b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.rs
@@ -1,6 +1,6 @@
 // Regression test for issue #91370.
 
-extern {
+extern "C" {
     //~^ `extern` blocks define existing foreign functions
     fn f() {
         //~^ incorrect function inside `extern` block
diff --git a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.stderr b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
index fea2ab61e92..155fdf9d09a 100644
--- a/tests/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
+++ b/tests/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
@@ -1,8 +1,8 @@
 error: incorrect function inside `extern` block
   --> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8
    |
-LL |   extern {
-   |   ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |   extern "C" {
+   |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
 LL |
 LL |       fn f() {
    |  ________^___-
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
index 6eabd9b1015..73a0363904a 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs
@@ -21,7 +21,7 @@ struct S;
 #[rustc_legacy_const_generics(0usize)] //~ ERROR suffixed literals are not allowed in attributes
 fn foo6<const X: usize>() {}
 
-extern {
+extern "C" {
     #[rustc_legacy_const_generics(1)] //~ ERROR attribute should be applied to a function
     fn foo7<const X: usize>(); //~ ERROR foreign items may not have const parameters
 }
diff --git a/tests/ui/link-native-libs/issue-109144.rs b/tests/ui/link-native-libs/issue-109144.rs
index 2f740e55389..6970a4989bb 100644
--- a/tests/ui/link-native-libs/issue-109144.rs
+++ b/tests/ui/link-native-libs/issue-109144.rs
@@ -1,4 +1,4 @@
 #![crate_type = "lib"]
 #[link(kind = "static", modifiers = "+whole-archive,+bundle")]
 //~^ ERROR `#[link]` attribute requires a `name = "string"` argument
-extern  {}
+extern "C" {}
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 e142835a9d6..aae8f7de966 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
@@ -1,6 +1,14 @@
+warning: extern declarations without an explicit ABI are deprecated
+  --> $DIR/suggest-libname-only-1.rs:7:1
+   |
+LL | extern { }
+   | ^^^^^^ help: explicitly specify the C ABI: `extern "C"`
+   |
+   = note: `#[warn(missing_abi)]` on by default
+
 error: could not find native static library `libfoo.a`, perhaps an -L flag is missing?
    |
    = help: only provide the library name `foo`, not the full filename
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
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 392d2f01f61..a2adaee3f97 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
@@ -1,6 +1,14 @@
+warning: extern declarations without an explicit ABI are deprecated
+  --> $DIR/suggest-libname-only-2.rs:7:1
+   |
+LL | extern { }
+   | ^^^^^^ help: explicitly specify the C ABI: `extern "C"`
+   |
+   = note: `#[warn(missing_abi)]` on by default
+
 error: could not find native static library `bar.lib`, perhaps an -L flag is missing?
    |
    = help: only provide the library name `bar`, not the full filename
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/lint/function-item-references.rs b/tests/ui/lint/function-item-references.rs
index 918d72e28a9..4f2fc4de863 100644
--- a/tests/ui/lint/function-item-references.rs
+++ b/tests/ui/lint/function-item-references.rs
@@ -11,7 +11,7 @@ fn baz(x: u32, y: u32) -> u32 { x + y }
 unsafe fn unsafe_fn() { }
 extern "C" fn c_fn() { }
 unsafe extern "C" fn unsafe_c_fn() { }
-unsafe extern fn variadic(_x: u32, _args: ...) { }
+unsafe extern "C" fn variadic(_x: u32, _args: ...) { }
 fn take_generic_ref<'a, T>(_x: &'a T) { }
 fn take_generic_array<T, const N: usize>(_x: [T; N]) { }
 fn multiple_generic<T, U>(_x: T, _y: U) { }
diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs
index dae07930aba..6dd9be10a48 100644
--- a/tests/ui/lint/lint-ctypes.rs
+++ b/tests/ui/lint/lint-ctypes.rs
@@ -72,7 +72,7 @@ extern "C" {
     pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box<u32>`
     pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
 
-    pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
+    pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
     //~^ ERROR: uses type `Option<UnsafeCell<extern "C" fn()>>`
     pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
     //~^ ERROR: uses type `Option<UnsafeCell<&i32>>`
diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr
index 2c81c7b8e4b..8137ae868d3 100644
--- a/tests/ui/lint/lint-ctypes.stderr
+++ b/tests/ui/lint/lint-ctypes.stderr
@@ -227,8 +227,8 @@ LL |     pub fn raw_array(arr: [u8; 8]);
 error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe
   --> $DIR/lint-ctypes.rs:75:26
    |
-LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>);
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs
index 5ae15f32357..2e0bdb151e1 100644
--- a/tests/ui/offset-of/offset-of-dst-field.rs
+++ b/tests/ui/offset-of/offset-of-dst-field.rs
@@ -16,7 +16,7 @@ struct Beta {
     z: dyn Trait,
 }
 
-extern {
+extern "C" {
     type Extern;
 }
 
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.fixed b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
index 558a27cd456..e2a2f9486b7 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.fixed
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.fixed
@@ -4,9 +4,9 @@
 
 pub type T0 =  fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type T1 =  extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type T2 =  unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type T2 =  unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type T3 =  fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type T4 =  extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type T4 =  extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type T5 =  unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type T6 =   unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
@@ -14,9 +14,9 @@ pub type T6 =   unsafe extern "C" fn();
 
 pub type FTT0 = for<'a>  fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type FTT1 = for<'a>  extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type FTT2 = for<'a>  unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type FTT2 = for<'a>  unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type FTT3 = for<'a>  fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type FTT4 = for<'a>  extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type FTT4 = for<'a>  extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type FTT5 = for<'a>  unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `async`
 pub type FTT6 = for<'a>   unsafe extern "C" fn();
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.rs b/tests/ui/parser/bad-fn-ptr-qualifier.rs
index 9750f480935..f2611c93b17 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.rs
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.rs
@@ -4,9 +4,9 @@
 
 pub type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type T2 = const unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type T4 = async extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type T6 = const async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
@@ -14,9 +14,9 @@ pub type T6 = const async unsafe extern "C" fn();
 
 pub type FTT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type FTT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-pub type FTT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+pub type FTT2 = for<'a> const unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 pub type FTT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async`
-pub type FTT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+pub type FTT4 = for<'a> async extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 pub type FTT5 = for<'a> async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `async`
 pub type FTT6 = for<'a> const async unsafe extern "C" fn();
diff --git a/tests/ui/parser/bad-fn-ptr-qualifier.stderr b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
index 523ee47b0c9..ddc8bac678c 100644
--- a/tests/ui/parser/bad-fn-ptr-qualifier.stderr
+++ b/tests/ui/parser/bad-fn-ptr-qualifier.stderr
@@ -29,15 +29,15 @@ LL + pub type T1 =  extern "C" fn();
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:7:15
    |
-LL | pub type T2 = const unsafe extern fn();
-   |               -----^^^^^^^^^^^^^^^^^^^
+LL | pub type T2 = const unsafe extern "C" fn();
+   |               -----^^^^^^^^^^^^^^^^^^^^^^^
    |               |
    |               `const` because of this
    |
 help: remove the `const` qualifier
    |
-LL - pub type T2 = const unsafe extern fn();
-LL + pub type T2 =  unsafe extern fn();
+LL - pub type T2 = const unsafe extern "C" fn();
+LL + pub type T2 =  unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -57,15 +57,15 @@ LL + pub type T3 =  fn();
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:9:15
    |
-LL | pub type T4 = async extern fn();
-   |               -----^^^^^^^^^^^^
+LL | pub type T4 = async extern "C" fn();
+   |               -----^^^^^^^^^^^^^^^^
    |               |
    |               `async` because of this
    |
 help: remove the `async` qualifier
    |
-LL - pub type T4 = async extern fn();
-LL + pub type T4 =  extern fn();
+LL - pub type T4 = async extern "C" fn();
+LL + pub type T4 =  extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -141,15 +141,15 @@ LL + pub type FTT1 = for<'a>  extern "C" fn();
 error: an `fn` pointer type cannot be `const`
   --> $DIR/bad-fn-ptr-qualifier.rs:17:17
    |
-LL | pub type FTT2 = for<'a> const unsafe extern fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
+LL | pub type FTT2 = for<'a> const unsafe extern "C" fn();
+   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                         |
    |                         `const` because of this
    |
 help: remove the `const` qualifier
    |
-LL - pub type FTT2 = for<'a> const unsafe extern fn();
-LL + pub type FTT2 = for<'a>  unsafe extern fn();
+LL - pub type FTT2 = for<'a> const unsafe extern "C" fn();
+LL + pub type FTT2 = for<'a>  unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -169,15 +169,15 @@ LL + pub type FTT3 = for<'a>  fn();
 error: an `fn` pointer type cannot be `async`
   --> $DIR/bad-fn-ptr-qualifier.rs:19:17
    |
-LL | pub type FTT4 = for<'a> async extern fn();
-   |                 ^^^^^^^^-----^^^^^^^^^^^^
+LL | pub type FTT4 = for<'a> async extern "C" fn();
+   |                 ^^^^^^^^-----^^^^^^^^^^^^^^^^
    |                         |
    |                         `async` because of this
    |
 help: remove the `async` qualifier
    |
-LL - pub type FTT4 = for<'a> async extern fn();
-LL + pub type FTT4 = for<'a>  extern fn();
+LL - pub type FTT4 = for<'a> async extern "C" fn();
+LL + pub type FTT4 = for<'a>  extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs
index c614f493885..f29dc53d322 100644
--- a/tests/ui/parser/bad-lit-suffixes.rs
+++ b/tests/ui/parser/bad-lit-suffixes.rs
@@ -1,10 +1,10 @@
 #![feature(rustc_attrs)]
 
-extern
+extern //~ WARN missing_abi
     "C"suffix //~ ERROR suffixes on string literals are invalid
     fn foo() {}
 
-extern
+extern //~ WARN missing_abi
     "C"suffix //~ ERROR suffixes on string literals are invalid
 {}
 
diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr
index b5dacdf7d0d..121db2058f1 100644
--- a/tests/ui/parser/bad-lit-suffixes.stderr
+++ b/tests/ui/parser/bad-lit-suffixes.stderr
@@ -49,6 +49,20 @@ 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
+  --> $DIR/bad-lit-suffixes.rs:3:1
+   |
+LL | extern
+   | ^^^^^^ 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/bad-lit-suffixes.rs:7:1
+   |
+LL | extern
+   | ^^^^^^ help: explicitly specify the C ABI: `extern "C"`
+
 error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:12:5
    |
@@ -149,5 +163,5 @@ LL |     1.0e10suffix;
    |
    = help: valid suffixes are `f32` and `f64`
 
-error: aborting due to 21 previous errors
+error: aborting due to 21 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
index 34b687a0f52..5ecf804de09 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs
@@ -1,4 +1,5 @@
 //@ edition:2018
+#![allow(missing_abi)]
 
 // There is an order to respect for keywords before a function:
 // `<visibility>, const, async, unsafe, extern, "<ABI>"`
diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr
index 0e9f7c51e1a..232da9acef3 100644
--- a/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr
+++ b/tests/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr
@@ -1,5 +1,5 @@
 error: expected `fn`, found keyword `unsafe`
-  --> $DIR/wrong-unsafe.rs:9:8
+  --> $DIR/wrong-unsafe.rs:10:8
    |
 LL | extern unsafe fn test() {}
    | -------^^^^^^
diff --git a/tests/ui/parser/item-kw-case-mismatch.fixed b/tests/ui/parser/item-kw-case-mismatch.fixed
index f5afa482712..4ee8f9c19dc 100644
--- a/tests/ui/parser/item-kw-case-mismatch.fixed
+++ b/tests/ui/parser/item-kw-case-mismatch.fixed
@@ -25,7 +25,7 @@ const unsafe fn _e() {}
 //~| ERROR keyword `unsafe` is written in the wrong case
 //~| ERROR keyword `fn` is written in the wrong case
 
-unsafe extern fn _f() {}
+unsafe extern "C" fn _f() {}
 //~^ ERROR keyword `unsafe` is written in the wrong case
 //~| ERROR keyword `extern` is written in the wrong case
 
diff --git a/tests/ui/parser/item-kw-case-mismatch.rs b/tests/ui/parser/item-kw-case-mismatch.rs
index ea224e08a00..6c858b848cf 100644
--- a/tests/ui/parser/item-kw-case-mismatch.rs
+++ b/tests/ui/parser/item-kw-case-mismatch.rs
@@ -25,7 +25,7 @@ CONST UNSAFE FN _e() {}
 //~| ERROR keyword `unsafe` is written in the wrong case
 //~| ERROR keyword `fn` is written in the wrong case
 
-unSAFE EXTern fn _f() {}
+unSAFE EXTern "C" fn _f() {}
 //~^ ERROR keyword `unsafe` is written in the wrong case
 //~| ERROR keyword `extern` is written in the wrong case
 
diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr
index 0abc59e064a..36df72b5cad 100644
--- a/tests/ui/parser/item-kw-case-mismatch.stderr
+++ b/tests/ui/parser/item-kw-case-mismatch.stderr
@@ -111,23 +111,23 @@ LL | CONST UNSAFE fn _e() {}
 error: keyword `unsafe` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:28:1
    |
-LL | unSAFE EXTern fn _f() {}
+LL | unSAFE EXTern "C" fn _f() {}
    | ^^^^^^
    |
 help: write it in the correct case
    |
-LL | unsafe EXTern fn _f() {}
+LL | unsafe EXTern "C" fn _f() {}
    | ~~~~~~
 
 error: keyword `extern` is written in the wrong case
   --> $DIR/item-kw-case-mismatch.rs:28:8
    |
-LL | unSAFE EXTern fn _f() {}
+LL | unSAFE EXTern "C" fn _f() {}
    |        ^^^^^^
    |
 help: write it in the correct case
    |
-LL | unSAFE extern fn _f() {}
+LL | unSAFE extern "C" fn _f() {}
    |        ~~~~~~
 
 error: keyword `extern` is written in the wrong case
diff --git a/tests/ui/parser/lit-err-in-macro.rs b/tests/ui/parser/lit-err-in-macro.rs
index cff8ee6b40c..ca117ac4a15 100644
--- a/tests/ui/parser/lit-err-in-macro.rs
+++ b/tests/ui/parser/lit-err-in-macro.rs
@@ -1,6 +1,6 @@
 macro_rules! f {
     ($abi:literal) => {
-        extern $abi fn f() {}
+        extern $abi fn f() {} //~ WARN missing_abi
     }
 }
 
diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/lit-err-in-macro.stderr
index 12e6d519060..fc2603d0b10 100644
--- a/tests/ui/parser/lit-err-in-macro.stderr
+++ b/tests/ui/parser/lit-err-in-macro.stderr
@@ -4,5 +4,17 @@ error: suffixes on string literals are invalid
 LL | f!("Foo"__);
    |    ^^^^^^^ invalid suffix `__`
 
-error: aborting due to 1 previous error
+warning: extern declarations without an explicit ABI are deprecated
+  --> $DIR/lit-err-in-macro.rs:3:9
+   |
+LL |         extern $abi fn f() {}
+   |         ^^^^^^ help: explicitly specify the C ABI: `extern "C"`
+...
+LL | f!("Foo"__);
+   | ----------- in this macro invocation
+   |
+   = note: `#[warn(missing_abi)]` on by default
+   = note: this warning originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
index 2d8a3858aa6..45d75349599 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.rs
@@ -2,9 +2,9 @@
 
 type T0 = const fn(); //~ ERROR an `fn` pointer type cannot be `const`
 type T1 = const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-type T2 = const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type T2 = const unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 type T3 = async fn(); //~ ERROR an `fn` pointer type cannot be `async`
-type T4 = async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type T4 = async extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 type T5 = async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 type T6 = const async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
@@ -12,9 +12,9 @@ type T6 = const async unsafe extern "C" fn();
 
 type FT0 = for<'a> const fn(); //~ ERROR an `fn` pointer type cannot be `const`
 type FT1 = for<'a> const extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
-type FT2 = for<'a> const unsafe extern fn(); //~ ERROR an `fn` pointer type cannot be `const`
+type FT2 = for<'a> const unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `const`
 type FT3 = for<'a> async fn(); //~ ERROR an `fn` pointer type cannot be `async`
-type FT4 = for<'a> async extern fn(); //~ ERROR an `fn` pointer type cannot be `async`
+type FT4 = for<'a> async extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 type FT5 = for<'a> async unsafe extern "C" fn(); //~ ERROR an `fn` pointer type cannot be `async`
 type FT6 = for<'a> const async unsafe extern "C" fn();
 //~^ ERROR an `fn` pointer type cannot be `const`
diff --git a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
index 8e5b76163ad..9112a0e135a 100644
--- a/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
+++ b/tests/ui/parser/recover/recover-const-async-fn-ptr.stderr
@@ -29,15 +29,15 @@ LL + type T1 =  extern "C" fn();
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:5:11
    |
-LL | type T2 = const unsafe extern fn();
-   |           -----^^^^^^^^^^^^^^^^^^^
+LL | type T2 = const unsafe extern "C" fn();
+   |           -----^^^^^^^^^^^^^^^^^^^^^^^
    |           |
    |           `const` because of this
    |
 help: remove the `const` qualifier
    |
-LL - type T2 = const unsafe extern fn();
-LL + type T2 =  unsafe extern fn();
+LL - type T2 = const unsafe extern "C" fn();
+LL + type T2 =  unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -57,15 +57,15 @@ LL + type T3 =  fn();
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:7:11
    |
-LL | type T4 = async extern fn();
-   |           -----^^^^^^^^^^^^
+LL | type T4 = async extern "C" fn();
+   |           -----^^^^^^^^^^^^^^^^
    |           |
    |           `async` because of this
    |
 help: remove the `async` qualifier
    |
-LL - type T4 = async extern fn();
-LL + type T4 =  extern fn();
+LL - type T4 = async extern "C" fn();
+LL + type T4 =  extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -141,15 +141,15 @@ LL + type FT1 = for<'a>  extern "C" fn();
 error: an `fn` pointer type cannot be `const`
   --> $DIR/recover-const-async-fn-ptr.rs:15:12
    |
-LL | type FT2 = for<'a> const unsafe extern fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
+LL | type FT2 = for<'a> const unsafe extern "C" fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^
    |                    |
    |                    `const` because of this
    |
 help: remove the `const` qualifier
    |
-LL - type FT2 = for<'a> const unsafe extern fn();
-LL + type FT2 = for<'a>  unsafe extern fn();
+LL - type FT2 = for<'a> const unsafe extern "C" fn();
+LL + type FT2 = for<'a>  unsafe extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
@@ -169,15 +169,15 @@ LL + type FT3 = for<'a>  fn();
 error: an `fn` pointer type cannot be `async`
   --> $DIR/recover-const-async-fn-ptr.rs:17:12
    |
-LL | type FT4 = for<'a> async extern fn();
-   |            ^^^^^^^^-----^^^^^^^^^^^^
+LL | type FT4 = for<'a> async extern "C" fn();
+   |            ^^^^^^^^-----^^^^^^^^^^^^^^^^
    |                    |
    |                    `async` because of this
    |
 help: remove the `async` qualifier
    |
-LL - type FT4 = for<'a> async extern fn();
-LL + type FT4 = for<'a>  extern fn();
+LL - type FT4 = for<'a> async extern "C" fn();
+LL + type FT4 = for<'a>  extern "C" fn();
    |
 
 error: an `fn` pointer type cannot be `async`
diff --git a/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs b/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs
index 76c56a715d2..ab2cfc961df 100644
--- a/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs
+++ b/tests/ui/parser/recover/recover-fn-ptr-with-generics.rs
@@ -19,7 +19,7 @@ fn main() {
     type Hmm = fn<>();
     //~^ ERROR function pointer types may not have generic parameters
 
-    let _: extern fn<'a: 'static>();
+    let _: extern "C" fn<'a: 'static>();
     //~^ ERROR function pointer types may not have generic parameters
     //~| ERROR bounds cannot be used in this context
 
diff --git a/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr
index 6b6cb2d6bdd..9023856ef24 100644
--- a/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr
+++ b/tests/ui/parser/recover/recover-fn-ptr-with-generics.stderr
@@ -59,15 +59,15 @@ LL |     type Hmm = fn<>();
    |                  ^^
 
 error: function pointer types may not have generic parameters
-  --> $DIR/recover-fn-ptr-with-generics.rs:22:21
+  --> $DIR/recover-fn-ptr-with-generics.rs:22:25
    |
-LL |     let _: extern fn<'a: 'static>();
-   |                     ^^^^^^^^^^^^^
+LL |     let _: extern "C" fn<'a: 'static>();
+   |                         ^^^^^^^^^^^^^
    |
 help: consider moving the lifetime parameter to a `for` parameter list
    |
-LL -     let _: extern fn<'a: 'static>();
-LL +     let _: for<'a> extern fn();
+LL -     let _: extern "C" fn<'a: 'static>();
+LL +     let _: for<'a> extern "C" fn();
    |
 
 error: function pointer types may not have generic parameters
@@ -101,10 +101,10 @@ LL |     type Identity = fn<T>(T) -> T;
    |                                 ^ not found in this scope
 
 error: bounds cannot be used in this context
-  --> $DIR/recover-fn-ptr-with-generics.rs:22:26
+  --> $DIR/recover-fn-ptr-with-generics.rs:22:30
    |
-LL |     let _: extern fn<'a: 'static>();
-   |                          ^^^^^^^
+LL |     let _: extern "C" fn<'a: 'static>();
+   |                              ^^^^^^^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.fixed b/tests/ui/parser/recover/recover-missing-semi-before-item.fixed
index 6f85452c6fb..871fa0d24ec 100644
--- a/tests/ui/parser/recover/recover-missing-semi-before-item.fixed
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.fixed
@@ -28,7 +28,7 @@ fn for_fn() {
 
 fn for_extern() {
     let foo = 3; //~ ERROR expected `;`, found keyword `extern`
-    extern fn foo() {}
+    extern "C" fn foo() {}
 }
 
 fn for_impl() {
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.rs b/tests/ui/parser/recover/recover-missing-semi-before-item.rs
index f75945b55c2..de92603a74c 100644
--- a/tests/ui/parser/recover/recover-missing-semi-before-item.rs
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.rs
@@ -28,7 +28,7 @@ fn for_fn() {
 
 fn for_extern() {
     let foo = 3 //~ ERROR expected `;`, found keyword `extern`
-    extern fn foo() {}
+    extern "C" fn foo() {}
 }
 
 fn for_impl() {
diff --git a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr
index 61c43f2f189..3b55cd9ddd0 100644
--- a/tests/ui/parser/recover/recover-missing-semi-before-item.stderr
+++ b/tests/ui/parser/recover/recover-missing-semi-before-item.stderr
@@ -35,7 +35,7 @@ error: expected `;`, found keyword `extern`
    |
 LL |     let foo = 3
    |                ^ help: add `;` here
-LL |     extern fn foo() {}
+LL |     extern "C" fn foo() {}
    |     ------ unexpected token
 
 error: expected `;`, found keyword `impl`
diff --git a/tests/ui/proc-macro/inner-attrs.stderr b/tests/ui/proc-macro/inner-attrs.stderr
index ee8732c650d..3ab180be821 100644
--- a/tests/ui/proc-macro/inner-attrs.stderr
+++ b/tests/ui/proc-macro/inner-attrs.stderr
@@ -22,5 +22,13 @@ error: expected non-macro inner attribute, found attribute macro `print_attr`
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
-error: aborting due to 4 previous errors
+warning: extern declarations without an explicit ABI are deprecated
+  --> $DIR/inner-attrs.rs:82:1
+   |
+LL | extern {
+   | ^^^^^^ help: explicitly specify the C ABI: `extern "C"`
+   |
+   = note: `#[warn(missing_abi)]` on by default
+
+error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/tests/ui/proc-macro/issue-66286.rs b/tests/ui/proc-macro/issue-66286.rs
index 57d1af26e93..882f87fa4ac 100644
--- a/tests/ui/proc-macro/issue-66286.rs
+++ b/tests/ui/proc-macro/issue-66286.rs
@@ -5,7 +5,7 @@
 extern crate issue_66286;
 
 #[issue_66286::vec_ice]
-pub extern fn foo(_: Vec(u32)) -> u32 {
+pub extern "C" fn foo(_: Vec(u32)) -> u32 {
     //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait
     0
 }
diff --git a/tests/ui/proc-macro/issue-66286.stderr b/tests/ui/proc-macro/issue-66286.stderr
index fc4c2062fd7..c92bed1b563 100644
--- a/tests/ui/proc-macro/issue-66286.stderr
+++ b/tests/ui/proc-macro/issue-66286.stderr
@@ -1,13 +1,13 @@
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/issue-66286.rs:8:22
+  --> $DIR/issue-66286.rs:8:26
    |
-LL | pub extern fn foo(_: Vec(u32)) -> u32 {
-   |                      ^^^^^^^^ only `Fn` traits may use parentheses
+LL | pub extern "C" fn foo(_: Vec(u32)) -> u32 {
+   |                          ^^^^^^^^ only `Fn` traits may use parentheses
    |
 help: use angle brackets instead
    |
-LL | pub extern fn foo(_: Vec<u32>) -> u32 {
-   |                         ~   ~
+LL | pub extern "C" fn foo(_: Vec<u32>) -> u32 {
+   |                             ~   ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
index f33a3d62e26..5982c771033 100644
--- a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
+++ b/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
@@ -11,7 +11,7 @@ fn test() {}
 static mut imported_val: i32 = 123;
 
 #[link(name = "exporter", kind = "raw-dylib")]
-extern {
+extern "C" {
     #[link_ordinal(13)]
     fn imported_function();
 
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
index 586881d1807..8b179f7ef93 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
@@ -4,7 +4,7 @@
 macro_rules! tt {
     ($e:tt) => {
         #$e
-        extern fn foo() {}
+        extern "C" fn foo() {}
     }
 }
 
@@ -13,7 +13,7 @@ macro_rules! ident {
         #[unsafe($e)]
         //~^ ERROR: unsafe attribute used without unsafe
         //~| WARN this is accepted in the current edition
-        extern fn bar() {}
+        extern "C" fn bar() {}
     }
 }
 
@@ -22,21 +22,21 @@ macro_rules! ident2 {
         #[unsafe($e = $l)]
         //~^ ERROR: unsafe attribute used without unsafe
         //~| WARN this is accepted in the current edition
-        extern fn bars() {}
+        extern "C" fn bars() {}
     }
 }
 
 macro_rules! meta {
     ($m:meta) => {
         #[$m]
-        extern fn baz() {}
+        extern "C" fn baz() {}
     }
 }
 
 macro_rules! meta2 {
     ($m:meta) => {
         #[$m]
-        extern fn baw() {}
+        extern "C" fn baw() {}
     }
 }
 
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
index 03e122c7d57..34e5a6b96e3 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
@@ -4,7 +4,7 @@
 macro_rules! tt {
     ($e:tt) => {
         #$e
-        extern fn foo() {}
+        extern "C" fn foo() {}
     }
 }
 
@@ -13,7 +13,7 @@ macro_rules! ident {
         #[$e]
         //~^ ERROR: unsafe attribute used without unsafe
         //~| WARN this is accepted in the current edition
-        extern fn bar() {}
+        extern "C" fn bar() {}
     }
 }
 
@@ -22,21 +22,21 @@ macro_rules! ident2 {
         #[$e = $l]
         //~^ ERROR: unsafe attribute used without unsafe
         //~| WARN this is accepted in the current edition
-        extern fn bars() {}
+        extern "C" fn bars() {}
     }
 }
 
 macro_rules! meta {
     ($m:meta) => {
         #[$m]
-        extern fn baz() {}
+        extern "C" fn baz() {}
     }
 }
 
 macro_rules! meta2 {
     ($m:meta) => {
         #[$m]
-        extern fn baw() {}
+        extern "C" fn baw() {}
     }
 }
 
diff --git a/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs b/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs
index a969295c9f9..65c57c42530 100644
--- a/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs
@@ -6,7 +6,7 @@
 
 use std::ptr::NonNull;
 
-extern {
+extern "C" {
     type Extern;
 }
 
diff --git a/tests/ui/statics/uninhabited-static.rs b/tests/ui/statics/uninhabited-static.rs
index a0f83f45079..0f7c5ae6ef4 100644
--- a/tests/ui/statics/uninhabited-static.rs
+++ b/tests/ui/statics/uninhabited-static.rs
@@ -2,7 +2,7 @@
 #![deny(uninhabited_static)]
 
 enum Void {}
-extern {
+extern "C" {
     static VOID: Void; //~ ERROR static of uninhabited type
     //~| WARN: previously accepted
     static NEVER: !; //~ ERROR static of uninhabited type
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 26c253d049b..31af323ecda 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -452,15 +452,15 @@ mod items {
     /// ItemKind::Fn
     mod item_fn {
         pub const unsafe extern "C" fn f() {}
-        pub async unsafe extern fn g() {}
+        pub async unsafe extern "C" fn g() {}
         fn h<'a, T>() where T: 'a {}
 
         trait TraitItems {
-            unsafe extern fn f();
+            unsafe extern "C" fn f();
         }
 
         impl TraitItems for _ {
-            default unsafe extern fn f() {}
+            default unsafe extern "C" fn f() {}
         }
     }
 
@@ -472,7 +472,7 @@ mod items {
     /// ItemKind::ForeignMod
     mod item_foreign_mod {
         unsafe extern "C++" {}
-        unsafe extern {}
+        unsafe extern "C" {}
     }
 
     /// ItemKind::GlobalAsm
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index bd7aa1117cc..11066c90edb 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -433,13 +433,13 @@ mod items {
     /// ItemKind::Fn
     mod item_fn {
         pub const unsafe extern "C" fn f() {}
-        pub async unsafe extern fn g() {}
+        pub async unsafe extern "C" fn g() {}
         fn h<'a, T>() where T: 'a {}
         trait TraitItems {
-            unsafe extern fn f();
+            unsafe extern "C" fn f();
         }
         impl TraitItems for _ {
-            default unsafe extern fn f() {}
+            default unsafe extern "C" fn f() {}
         }
     }
     /// ItemKind::Mod
@@ -447,7 +447,7 @@ mod items {
     /// ItemKind::ForeignMod
     mod item_foreign_mod {
         unsafe extern "C++" {}
-        unsafe extern {}
+        unsafe extern "C" {}
     }
     /// ItemKind::GlobalAsm
     mod item_global_asm {