Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/rustc_abi/src/canon_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub enum CanonAbi {
C,
Rust,
RustCold,
RustPreserveNone,

/// An ABI that rustc does not know how to call or define.
Custom,
Expand Down Expand Up @@ -54,7 +55,7 @@ pub enum CanonAbi {
impl CanonAbi {
pub fn is_rustic_abi(self) -> bool {
match self {
CanonAbi::Rust | CanonAbi::RustCold => true,
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
CanonAbi::C
| CanonAbi::Custom
| CanonAbi::Arm(_)
Expand All @@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
CanonAbi::C => ExternAbi::C { unwind: false },
CanonAbi::Rust => ExternAbi::Rust,
CanonAbi::RustCold => ExternAbi::RustCold,
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
CanonAbi::Custom => ExternAbi::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_abi/src/extern_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ pub enum ExternAbi {
/// in a platform-agnostic way.
RustInvalid,

/// Preserves no registers.
///
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
/// and may fall-back to a more conservative calling convention if the backend does not support
/// forcing callers to save all registers.
RustPreserveNone,

/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
Unadjusted,
Expand Down Expand Up @@ -163,6 +170,7 @@ abi_impls! {
RustCall =><= "rust-call",
RustCold =><= "rust-cold",
RustInvalid =><= "rust-invalid",
RustPreserveNone =><= "rust-preserve-none",
Stdcall { unwind: false } =><= "stdcall",
Stdcall { unwind: true } =><= "stdcall-unwind",
System { unwind: false } =><= "system",
Expand Down Expand Up @@ -243,7 +251,7 @@ impl ExternAbi {
/// - are subject to change between compiler versions
pub fn is_rustic_abi(self) -> bool {
use ExternAbi::*;
matches!(self, Rust | RustCall | RustCold)
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
}

/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
Expand Down Expand Up @@ -315,7 +323,8 @@ impl ExternAbi {
| Self::Thiscall { .. }
| Self::Vectorcall { .. }
| Self::SysV64 { .. }
| Self::Win64 { .. } => true,
| Self::Win64 { .. }
| Self::RustPreserveNone => true,
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_ast_lowering/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
ExternAbi::RustCold => {
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
}
ExternAbi::RustPreserveNone => Err(UnstableAbi {
abi,
feature: sym::rust_preserve_none_cc,
explain: GateReason::Experimental,
}),
ExternAbi::RustInvalid => {
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> {
CanonAbi::C
| CanonAbi::Rust
| CanonAbi::RustCold
| CanonAbi::RustPreserveNone
| CanonAbi::Arm(_)
| CanonAbi::X86(_) => { /* nothing to check */ }

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
CanonAbi::Rust | CanonAbi::C => default_call_conv,
CanonAbi::RustCold => CallConv::Cold,

// Cranelift doesn't currently have anything for this.
CanonAbi::RustPreserveNone => default_call_conv,

// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_gcc/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option<FnAttribute<'gcc>> {
let attribute = match conv {
CanonAbi::C | CanonAbi::Rust => return None,
// gcc/gccjit does not have anything for this.
CanonAbi::RustPreserveNone => return None,
CanonAbi::RustCold => FnAttribute::Cold,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,10 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm:
match abi {
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
CanonAbi::RustCold => llvm::PreserveMost,
CanonAbi::RustPreserveNone => match &sess.target.arch {
Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone,
_ => llvm::CCallConv,
},
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
}

/// Helper for `FnAbi::apply_attrs_llfn`:
/// Helper for `FnAbiLlvmExt::apply_attrs_llfn`:
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ pub(crate) enum CallConv {
PreserveMost = 14,
PreserveAll = 15,
Tail = 18,
PreserveNone = 21,
X86StdcallCallConv = 64,
X86FastcallCallConv = 65,
ArmAapcsCallConv = 67,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,8 @@ declare_features! (
(unstable, rtm_target_feature, "1.35.0", Some(150258)),
/// Allows `extern "rust-cold"`.
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
/// Allows `extern "rust-preserve-none"`.
(unstable, rust_preserve_none_cc, "CURRENT_RUSTC_VERSION", Some(151401)),
/// Target features on s390x.
(unstable, s390x_target_feature, "1.82.0", Some(150259)),
/// Allows the use of the `sanitize` attribute.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
CanonAbi::C
| CanonAbi::Rust
| CanonAbi::RustCold
| CanonAbi::RustPreserveNone
| CanonAbi::Arm(_)
| CanonAbi::X86(_) => {}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
| RiscvInterruptS
| RustInvalid
| Unadjusted => false,
Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(),
Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(),
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ pub enum CallConvention {
Cold,
PreserveMost,
PreserveAll,
PreserveNone,

Custom,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,7 @@ pub enum Abi {
RustCold,
RiscvInterruptM,
RiscvInterruptS,
RustPreserveNone,
RustInvalid,
Custom,
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/unstable/convert/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ impl RustcInternal for Abi {
Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid,
Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
Abi::RustPreserveNone => rustc_abi::ExternAbi::RustPreserveNone,
Abi::Custom => rustc_abi::ExternAbi::Custom,
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/unstable/convert/stable/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
CanonAbi::C => CallConvention::C,
CanonAbi::Rust => CallConvention::Rust,
CanonAbi::RustCold => CallConvention::Cold,
CanonAbi::RustPreserveNone => CallConvention::PreserveNone,
CanonAbi::Custom => CallConvention::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => CallConvention::ArmAapcs,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_public/src/unstable/convert/stable/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
ExternAbi::RustCall => Abi::RustCall,
ExternAbi::Unadjusted => Abi::Unadjusted,
ExternAbi::RustCold => Abi::RustCold,
ExternAbi::RustPreserveNone => Abi::RustPreserveNone,
ExternAbi::RustInvalid => Abi::RustInvalid,
ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,7 @@ symbols! {
rust_future,
rust_logo,
rust_out,
rust_preserve_none_cc,
rustc,
rustc_abi,
// FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/abi_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ impl AbiMap {

(ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
(ExternAbi::RustCold, _) => CanonAbi::RustCold,
(ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone,

(ExternAbi::Custom, _) => CanonAbi::Custom,

Expand Down
3 changes: 3 additions & 0 deletions src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ pub enum FnAbi {
Win64,
Win64Unwind,
X86Interrupt,
RustPreserveNone,
Unknown,
}

Expand Down Expand Up @@ -271,6 +272,7 @@ impl FnAbi {
s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
s if *s == sym::rust_dash_call => FnAbi::RustCall,
s if *s == sym::rust_dash_cold => FnAbi::RustCold,
s if *s == sym::rust_dash_preserve_dash_none => FnAbi::RustPreserveNone,
s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
s if *s == sym::Rust => FnAbi::Rust,
s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
Expand Down Expand Up @@ -314,6 +316,7 @@ impl FnAbi {
FnAbi::Rust => "Rust",
FnAbi::RustCall => "rust-call",
FnAbi::RustCold => "rust-cold",
FnAbi::RustPreserveNone => "rust-preserve-none",
FnAbi::RustIntrinsic => "rust-intrinsic",
FnAbi::Stdcall => "stdcall",
FnAbi::StdcallUnwind => "stdcall-unwind",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ define_symbols! {
vectorcall_dash_unwind = "vectorcall-unwind",
win64_dash_unwind = "win64-unwind",
x86_dash_interrupt = "x86-interrupt",
rust_dash_preserve_dash_none = "preserve-none",

@PLAIN:
__ra_fixup,
Expand Down
33 changes: 33 additions & 0 deletions tests/codegen-llvm/preserve-none.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//@ add-minicore
//@ revisions: X86 AARCH64 UNSUPPORTED
//@ [X86] compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
//@ [X86] needs-llvm-components: x86
//@ [AARCH64] compile-flags: -C no-prepopulate-passes --target=aarch64-unknown-linux-gnu
//@ [AARCH64] needs-llvm-components: aarch64
//@ [UNSUPPORTED] compile-flags: -C no-prepopulate-passes --target=i686-unknown-linux-gnu
//@ [UNSUPPORTED] needs-llvm-components: x86

#![crate_type = "lib"]
#![feature(rust_preserve_none_cc)]
#![feature(no_core, lang_items)]
#![no_core]

extern crate minicore;

// X86: define{{( dso_local)?}} preserve_nonecc void @peach(i16
// AARCH64: define{{( dso_local)?}} preserve_nonecc void @peach(i16
// UNSUPPORTED: define{{( dso_local)?}} void @peach(i16
#[no_mangle]
#[inline(never)]
pub extern "rust-preserve-none" fn peach(x: u16) {
loop {}
}

// X86: call preserve_nonecc void @peach(i16
// AARCH64: call preserve_nonecc void @peach(i16
// UNSUPPORTED: call void @peach(i16
pub fn quince(x: u16) {
if let 12345u16 = x {
peach(54321);
}
}
67 changes: 67 additions & 0 deletions tests/ui/abi/rust-preserve-none-cc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//@ run-pass
//@ needs-unwind

#![feature(rust_preserve_none_cc)]

struct CrateOf<'a> {
mcintosh: f64,
golden_delicious: u64,
jonagold: Option<&'a u64>,
rome: [u64; 12],
}

#[inline(never)]
extern "rust-preserve-none" fn oven_explosion() {
panic!("bad time");
}

#[inline(never)]
fn bite_into(yummy: u64) -> u64 {
let did_it_actually = std::panic::catch_unwind(move || {
oven_explosion()
});
assert!(did_it_actually.is_err());
yummy - 25
}

#[inline(never)]
extern "rust-preserve-none" fn lotsa_apples(
honeycrisp: u64,
gala: u32,
fuji: f64,
granny_smith: &[u64],
pink_lady: (),
and_a: CrateOf<'static>,
cosmic_crisp: u64,
ambrosia: f64,
winesap: &[u64],
) -> (u64, f64, u64, u64) {
assert_eq!(honeycrisp, 220);
assert_eq!(gala, 140);
assert_eq!(fuji, 210.54201234);
assert_eq!(granny_smith, &[180, 210]);
assert_eq!(pink_lady, ());
assert_eq!(and_a.mcintosh, 150.0);
assert_eq!(and_a.golden_delicious, 185);
assert_eq!(and_a.jonagold, None); // my scales can't weight these gargantuans.
assert_eq!(and_a.rome, [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]);
assert_eq!(cosmic_crisp, 270);
assert_eq!(ambrosia, 193.1);
assert_eq!(winesap, &[]);
(
and_a.rome.iter().sum(),
fuji + ambrosia,
cosmic_crisp - honeycrisp,
bite_into(and_a.golden_delicious)
)
}

fn main() {
let pie = lotsa_apples(220, 140, 210.54201234, &[180, 210], (), CrateOf {
mcintosh: 150.0,
golden_delicious: 185,
jonagold: None,
rome: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202]
}, 270, 193.1, &[]);
assert_eq!(pie, (2292, 403.64201234, 50, 160));
}
21 changes: 21 additions & 0 deletions tests/ui/feature-gates/feature-gate-rust-preserve-none-cc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![crate_type = "lib"]

extern "rust-preserve-none" fn apple() {} //~ ERROR "rust-preserve-none" ABI is experimental

trait T {
extern "rust-preserve-none" fn banana(); //~ ERROR "rust-preserve-none" ABI is experimental
extern "rust-preserve-none" fn citrus() {} //~ ERROR "rust-preserve-none" ABI is experimental
}

struct S;
impl T for S {
extern "rust-preserve-none" fn banana() {} //~ ERROR "rust-preserve-none" ABI is experimental
}

impl S {
extern "rust-preserve-none" fn durian() {} //~ ERROR "rust-preserve-none" ABI is experimental
}

type Fig = extern "rust-preserve-none" fn(); //~ ERROR "rust-preserve-none" ABI is experimental

extern "rust-preserve-none" {} //~ ERROR "rust-preserve-none" ABI is experimental
Loading
Loading