diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index f0b94047ed9da..77dd4ccd64ef2 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -113,6 +113,14 @@ impl<'a> PostExpansionVisitor<'a> { "rust-call ABI is subject to change" ); } + "rust-cold" => { + gate_feature_post!( + &self, + rust_cold_cc, + span, + "rust-cold is experimental and subject to change" + ); + } "ptx-kernel" => { gate_feature_post!( &self, diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index decb784199064..ffa5d747b1160 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -23,6 +23,7 @@ fn clif_sig_from_fn_abi<'tcx>( ) -> Signature { let call_conv = match fn_abi.conv { Conv::Rust | Conv::C => default_call_conv, + Conv::RustCold => CallConv::Cold, Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64Win64 => CallConv::WindowsFastcall, Conv::ArmAapcs diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index b9baa87bac7c7..cc8b3a1a4e401 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -393,6 +393,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn llvm_cconv(&self) -> llvm::CallConv { match self.conv { Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv, + Conv::RustCold => llvm::ColdCallConv, Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::AvrInterrupt => llvm::AvrInterrupt, Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5a02661513ca7..cece92bfe8559 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -496,6 +496,8 @@ declare_features! ( (incomplete, repr128, "1.16.0", Some(56071), None), /// Allows `repr(simd)` and importing the various simd intrinsics. (active, repr_simd, "1.4.0", Some(27731), None), + /// Allows `extern "rust-cold"`. + (active, rust_cold_cc, "1.63.0", Some(97544), None), /// Allows the use of SIMD types in functions declared in `extern` blocks. (active, simd_ffi, "1.0.0", Some(27731), None), /// Allows specialization of implementations (RFC 1210). diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 30552c685a33a..3b05e42a53ead 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2971,7 +2971,7 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: Spe | RustIntrinsic | PlatformIntrinsic | Unadjusted => false, - Rust | RustCall => tcx.sess.panic_strategy() == PanicStrategy::Unwind, + Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } } @@ -2980,6 +2980,7 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { use rustc_target::spec::abi::Abi::*; match tcx.sess.target.adjust_abi(abi) { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, + RustCold => Conv::RustCold, // It's the ABI's job to select this, not ours. System { .. } => bug!("system abi should be selected elsewhere"), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6989763f75ade..cfbf17e17c852 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1160,6 +1160,7 @@ symbols! { rust_2024, rust_2024_preview, rust_begin_unwind, + rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, rust_eh_register_frames, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index afce10ff1cbe8..ca1d1302ec68a 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -580,6 +580,11 @@ pub enum Conv { C, Rust, + /// For things unlikely to be called, where smaller caller codegen is + /// preferred over raw speed. + /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. + RustCold, + // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index d9e571c72e53a..337554dc96e82 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -35,6 +35,7 @@ pub enum Abi { RustCall, PlatformIntrinsic, Unadjusted, + RustCold, } #[derive(Copy, Clone)] @@ -81,6 +82,7 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::RustCall, name: "rust-call" }, AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" }, AbiData { abi: Abi::Unadjusted, name: "unadjusted" }, + AbiData { abi: Abi::RustCold, name: "rust-cold" }, ]; /// Returns the ABI with the given name (if any). @@ -139,6 +141,7 @@ impl Abi { RustCall => 31, PlatformIntrinsic => 32, Unadjusted => 33, + RustCold => 34, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6dd245b047cbe..866cd5f0fe77b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1618,7 +1618,8 @@ impl Target { | PlatformIntrinsic | Unadjusted | Cdecl { .. } - | EfiApi => true, + | EfiApi + | RustCold => true, X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), Aapcs { .. } => "arm" == self.arch, CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), diff --git a/src/test/codegen/cold-call-declare-and-call.rs b/src/test/codegen/cold-call-declare-and-call.rs new file mode 100644 index 0000000000000..71d49478bfc74 --- /dev/null +++ b/src/test/codegen/cold-call-declare-and-call.rs @@ -0,0 +1,18 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(rust_cold_cc)] + +// wasm marks the definition as `dso_local`, so allow that as optional. + +// CHECK: define{{( dso_local)?}} coldcc void @this_should_never_happen(i16 +// CHECK: call coldcc void @this_should_never_happen(i16 + +#[no_mangle] +pub extern "rust-cold" fn this_should_never_happen(x: u16) {} + +pub fn do_things(x: u16) { + if x == 12345 { + this_should_never_happen(54321); + } +} diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index e5aef04b6894e..bf7aaa5f0ebbf 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted, rust-cold error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-rust_cold_cc.rs b/src/test/ui/feature-gates/feature-gate-rust_cold_cc.rs new file mode 100644 index 0000000000000..9ba8e32ac07a3 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-rust_cold_cc.rs @@ -0,0 +1,21 @@ +#![crate_type = "lib"] + +extern "rust-cold" fn fu() {} //~ ERROR rust-cold is experimental + +trait T { + extern "rust-cold" fn mu(); //~ ERROR rust-cold is experimental + extern "rust-cold" fn dmu() {} //~ ERROR rust-cold is experimental +} + +struct S; +impl T for S { + extern "rust-cold" fn mu() {} //~ ERROR rust-cold is experimental +} + +impl S { + extern "rust-cold" fn imu() {} //~ ERROR rust-cold is experimental +} + +type TAU = extern "rust-cold" fn(); //~ ERROR rust-cold is experimental + +extern "rust-cold" {} //~ ERROR rust-cold is experimental diff --git a/src/test/ui/feature-gates/feature-gate-rust_cold_cc.stderr b/src/test/ui/feature-gates/feature-gate-rust_cold_cc.stderr new file mode 100644 index 0000000000000..ab7e5f0366da5 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-rust_cold_cc.stderr @@ -0,0 +1,66 @@ +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:3:8 + | +LL | extern "rust-cold" fn fu() {} + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:6:12 + | +LL | extern "rust-cold" fn mu(); + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:7:12 + | +LL | extern "rust-cold" fn dmu() {} + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:12:12 + | +LL | extern "rust-cold" fn mu() {} + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:16:12 + | +LL | extern "rust-cold" fn imu() {} + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:19:19 + | +LL | type TAU = extern "rust-cold" fn(); + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error[E0658]: rust-cold is experimental and subject to change + --> $DIR/feature-gate-rust_cold_cc.rs:21:8 + | +LL | extern "rust-cold" {} + | ^^^^^^^^^^^ + | + = note: see issue #97544 for more information + = help: add `#![feature(rust_cold_cc)]` to the crate attributes to enable + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/issues/issue-8537.stderr b/src/test/ui/parser/issues/issue-8537.stderr index 5f8d4315de829..505d830ef3e8f 100644 --- a/src/test/ui/parser/issues/issue-8537.stderr +++ b/src/test/ui/parser/issues/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted, rust-cold error: aborting due to previous error