Skip to content

Commit 7b507db

Browse files
authored
Rollup merge of #119587 - beepster4096:system_varargs, r=petrochenkov
Varargs support for system ABI This PR allows functions with the `system` ABI to be variadic (under the `extended_varargs_abi_support` feature tracked in #100189). On x86 windows, the `system` ABI is equivalent to `C` for variadic functions. On other platforms, `system` is already equivalent to `C`. Fixes #110505
2 parents 284cb71 + 41e224b commit 7b507db

File tree

8 files changed

+34
-13
lines changed

8 files changed

+34
-13
lines changed

compiler/rustc_hir_analysis/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ use rustc_hir::def::DefKind;
116116
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
117117

118118
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
119-
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
119+
const CONVENTIONS_UNSTABLE: &str =
120+
"`C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`";
120121
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
121122
const UNSTABLE_EXPLAIN: &str =
122123
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";

compiler/rustc_metadata/src/native_libs.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -520,11 +520,23 @@ impl<'tcx> Collector<'tcx> {
520520
) -> DllImport {
521521
let span = self.tcx.def_span(item);
522522

523+
// this logic is similar to `Target::adjust_abi` (in rustc_target/src/spec/mod.rs) but errors on unsupported inputs
523524
let calling_convention = if self.tcx.sess.target.arch == "x86" {
524525
match abi {
525526
Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
526-
Abi::Stdcall { .. } | Abi::System { .. } => {
527-
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
527+
Abi::Stdcall { .. } => DllCallingConvention::Stdcall(self.i686_arg_list_size(item)),
528+
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
529+
// `__stdcall` only applies on x86 and on non-variadic functions:
530+
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
531+
Abi::System { .. } => {
532+
let c_variadic =
533+
self.tcx.type_of(item).instantiate_identity().fn_sig(self.tcx).c_variadic();
534+
535+
if c_variadic {
536+
DllCallingConvention::C
537+
} else {
538+
DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
539+
}
528540
}
529541
Abi::Fastcall { .. } => {
530542
DllCallingConvention::Fastcall(self.i686_arg_list_size(item))

compiler/rustc_target/src/abi/call/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
840840
"sparc" => sparc::compute_abi_info(cx, self),
841841
"sparc64" => sparc64::compute_abi_info(cx, self),
842842
"nvptx64" => {
843-
if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
843+
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel {
844844
nvptx64::compute_ptx_kernel_abi_info(cx, self)
845845
} else {
846846
nvptx64::compute_abi_info(self)
@@ -849,7 +849,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
849849
"hexagon" => hexagon::compute_abi_info(self),
850850
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
851851
"wasm32" | "wasm64" => {
852-
if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::Wasm {
852+
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::Wasm {
853853
wasm::compute_wasm_abi_info(self)
854854
} else {
855855
wasm::compute_c_abi_info(cx, self)

compiler/rustc_target/src/spec/abi/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,16 @@ impl Abi {
7070
// * C and Cdecl obviously support varargs.
7171
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
7272
// * EfiApi is based on Win64 or C, so it also supports it.
73+
// * System falls back to C for functions with varargs.
7374
//
7475
// * Stdcall does not, because it would be impossible for the callee to clean
7576
// up the arguments. (callee doesn't know how many arguments are there)
7677
// * Same for Fastcall, Vectorcall and Thiscall.
77-
// * System can become Stdcall, so is also a no-no.
7878
// * Other calling conventions are related to hardware or the compiler itself.
7979
match self {
8080
Self::C { .. }
8181
| Self::Cdecl { .. }
82+
| Self::System { .. }
8283
| Self::Aapcs { .. }
8384
| Self::Win64 { .. }
8485
| Self::SysV64 { .. }

compiler/rustc_target/src/spec/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2401,10 +2401,14 @@ impl DerefMut for Target {
24012401

24022402
impl Target {
24032403
/// Given a function ABI, turn it into the correct ABI for this target.
2404-
pub fn adjust_abi(&self, abi: Abi) -> Abi {
2404+
pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi {
24052405
match abi {
24062406
Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi),
2407-
Abi::System { unwind } if self.is_like_windows && self.arch == "x86" => {
2407+
2408+
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
2409+
// `__stdcall` only applies on x86 and on non-variadic functions:
2410+
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
2411+
Abi::System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
24082412
Abi::Stdcall { unwind }
24092413
}
24102414
Abi::System { unwind } => Abi::C { unwind },

compiler/rustc_ty_utils/src/abi.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ fn fn_sig_for_fn_abi<'tcx>(
228228
}
229229

230230
#[inline]
231-
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
231+
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv {
232232
use rustc_target::spec::abi::Abi::*;
233-
match tcx.sess.target.adjust_abi(abi) {
233+
match tcx.sess.target.adjust_abi(abi, c_variadic) {
234234
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
235235

236236
// This is intentionally not using `Conv::Cold`, as that has to preserve
@@ -488,7 +488,7 @@ fn fn_abi_new_uncached<'tcx>(
488488
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
489489
let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
490490

491-
let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
491+
let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
492492

493493
let mut inputs = sig.inputs();
494494
let extra_args = if sig.abi == RustCall {

tests/ui/c-variadic/variadic-ffi-2.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33

44
fn baz(f: extern "stdcall" fn(usize, ...)) {
55
//~^ ERROR: C-variadic function must have a compatible calling convention,
6-
// like C, cdecl, aapcs, win64, sysv64 or efiapi
6+
// like C, cdecl, system, aapcs, win64, sysv64 or efiapi
77
f(22, 44);
88
}
99

10+
fn system(f: extern "system" fn(usize, ...)) {
11+
f(22, 44);
12+
}
1013
fn aapcs(f: extern "aapcs" fn(usize, ...)) {
1114
f(22, 44);
1215
}

tests/ui/c-variadic/variadic-ffi-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`
1+
error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `system`, `aapcs`, `win64`, `sysv64` or `efiapi`
22
--> $DIR/variadic-ffi-2.rs:4:11
33
|
44
LL | fn baz(f: extern "stdcall" fn(usize, ...)) {

0 commit comments

Comments
 (0)