Skip to content

Commit d760bb6

Browse files
committed
fix ZST handling for Windows ABIs on MSVC target
1 parent 67951d9 commit d760bb6

File tree

10 files changed

+130
-275
lines changed

10 files changed

+130
-275
lines changed

Diff for: compiler/rustc_abi/src/extern_abi/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ pub fn is_enabled(
192192
s
193193
}
194194

195+
/// Returns whether the ABI is stable to use.
196+
///
197+
/// Note that there is a separate check determining whether the ABI is even supported
198+
/// on the current target; see `fn is_abi_supported` in `rustc_target::spec`.
195199
pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
196200
match name {
197201
// Stable

Diff for: compiler/rustc_target/src/callconv/mod.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use std::str::FromStr;
22
use std::{fmt, iter};
33

4-
pub use rustc_abi::{Reg, RegKind};
4+
pub use rustc_abi::{ExternAbi, Reg, RegKind};
55
use rustc_macros::HashStable_Generic;
66
use rustc_span::Symbol;
77

88
use crate::abi::{
99
self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface,
1010
TyAndLayout,
1111
};
12-
use crate::spec::abi::Abi as SpecAbi;
13-
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
12+
use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
1413

1514
mod aarch64;
1615
mod amdgpu;
@@ -627,20 +626,20 @@ impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> {
627626
#[derive(Copy, Clone, Debug, HashStable_Generic)]
628627
pub enum AdjustForForeignAbiError {
629628
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
630-
Unsupported { arch: Symbol, abi: spec::abi::Abi },
629+
Unsupported { arch: Symbol, abi: ExternAbi },
631630
}
632631

633632
impl<'a, Ty> FnAbi<'a, Ty> {
634633
pub fn adjust_for_foreign_abi<C>(
635634
&mut self,
636635
cx: &C,
637-
abi: spec::abi::Abi,
636+
abi: ExternAbi,
638637
) -> Result<(), AdjustForForeignAbiError>
639638
where
640639
Ty: TyAbiInterface<'a, C> + Copy,
641640
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
642641
{
643-
if abi == spec::abi::Abi::X86Interrupt {
642+
if abi == ExternAbi::X86Interrupt {
644643
if let Some(arg) = self.args.first_mut() {
645644
arg.pass_by_stack_offset(None);
646645
}
@@ -651,12 +650,10 @@ impl<'a, Ty> FnAbi<'a, Ty> {
651650
match &spec.arch[..] {
652651
"x86" => {
653652
let (flavor, regparm) = match abi {
654-
spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => {
653+
ExternAbi::Fastcall { .. } | ExternAbi::Vectorcall { .. } => {
655654
(x86::Flavor::FastcallOrVectorcall, None)
656655
}
657-
spec::abi::Abi::C { .. }
658-
| spec::abi::Abi::Cdecl { .. }
659-
| spec::abi::Abi::Stdcall { .. } => {
656+
ExternAbi::C { .. } | ExternAbi::Cdecl { .. } | ExternAbi::Stdcall { .. } => {
660657
(x86::Flavor::General, cx.x86_abi_opt().regparm)
661658
}
662659
_ => (x86::Flavor::General, None),
@@ -666,11 +663,13 @@ impl<'a, Ty> FnAbi<'a, Ty> {
666663
x86::compute_abi_info(cx, self, opts);
667664
}
668665
"x86_64" => match abi {
669-
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
670-
spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(cx, self),
666+
ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
667+
ExternAbi::Win64 { .. } | ExternAbi::Vectorcall { .. } => {
668+
x86_win64::compute_abi_info(cx, self, abi)
669+
}
671670
_ => {
672671
if cx.target_spec().is_like_windows {
673-
x86_win64::compute_abi_info(cx, self)
672+
x86_win64::compute_abi_info(cx, self, abi)
674673
} else {
675674
x86_64::compute_abi_info(cx, self)
676675
}
@@ -701,7 +700,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
701700
"sparc" => sparc::compute_abi_info(cx, self),
702701
"sparc64" => sparc64::compute_abi_info(cx, self),
703702
"nvptx64" => {
704-
if cx.target_spec().adjust_abi(abi, self.c_variadic) == spec::abi::Abi::PtxKernel {
703+
if cx.target_spec().adjust_abi(abi, self.c_variadic) == ExternAbi::PtxKernel {
705704
nvptx64::compute_ptx_kernel_abi_info(cx, self)
706705
} else {
707706
nvptx64::compute_abi_info(self)
@@ -730,7 +729,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
730729
Ok(())
731730
}
732731

733-
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: SpecAbi)
732+
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: ExternAbi)
734733
where
735734
Ty: TyAbiInterface<'a, C> + Copy,
736735
C: HasDataLayout + HasTargetSpec,
@@ -821,7 +820,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
821820
// that's how we connect up to LLVM and it's unstable
822821
// anyway, we control all calls to it in libstd.
823822
BackendRepr::Vector { .. }
824-
if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect =>
823+
if abi != ExternAbi::RustIntrinsic && spec.simd_types_indirect =>
825824
{
826825
arg.make_indirect();
827826
continue;

Diff for: compiler/rustc_target/src/callconv/x86_win64.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
use rustc_abi::{BackendRepr, Float, Primitive};
1+
use rustc_abi::{BackendRepr, ExternAbi, Float, Primitive};
22

33
use crate::abi::call::{ArgAbi, FnAbi, Reg};
44
use crate::spec::HasTargetSpec;
55

66
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
77

8-
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
8+
pub(crate) fn compute_abi_info<Ty>(
9+
cx: &impl HasTargetSpec,
10+
fn_abi: &mut FnAbi<'_, Ty>,
11+
abi: ExternAbi,
12+
) {
913
let fixup = |a: &mut ArgAbi<'_, Ty>| {
1014
match a.layout.backend_repr {
1115
BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
@@ -40,11 +44,15 @@ pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'
4044
fixup(&mut fn_abi.ret);
4145
}
4246
for arg in fn_abi.args.iter_mut() {
43-
if arg.is_ignore() {
44-
// x86_64-pc-windows-gnu doesn't ignore ZSTs.
45-
if cx.target_spec().os == "windows"
46-
&& cx.target_spec().env == "gnu"
47-
&& arg.layout.is_zst()
47+
if arg.is_ignore() && arg.layout.is_zst() {
48+
// Windows ABIs do not talk about ZST since such types do not exist in MSVC.
49+
// In that sense we can do whatever we want here, and maybe we should throw an error
50+
// (but of course that would be a massive breaking change now).
51+
// We try to match clang and gcc, so we make windows-gnu and the native
52+
// Windows ABIs (i.e., everything except for `extern "C"`) pass ZST via
53+
// pointer indirection. windows-msvc `extern "C"` still skips ZST.
54+
if (cx.target_spec().os == "windows" && cx.target_spec().env == "gnu")
55+
|| !matches!(abi, ExternAbi::C { .. })
4856
{
4957
arg.make_indirect_from_ignore();
5058
}

Diff for: compiler/rustc_target/src/spec/mod.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -2815,12 +2815,17 @@ impl Target {
28152815
Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
28162816
Abi::EfiApi => Abi::C { unwind: false },
28172817

2818-
// See commentary in `is_abi_supported`.
2819-
Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
2820-
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
2821-
Abi::Fastcall { .. } if self.arch == "x86" => abi,
2818+
// See commentary in `is_abi_supported`: we map these ABIs to "C" when they do not make sense.
2819+
Abi::Stdcall { .. } | Abi::Thiscall { .. } | Abi::Fastcall { .. }
2820+
if self.arch == "x86" =>
2821+
{
2822+
abi
2823+
}
28222824
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
2823-
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
2825+
Abi::Stdcall { unwind }
2826+
| Abi::Thiscall { unwind }
2827+
| Abi::Fastcall { unwind }
2828+
| Abi::Vectorcall { unwind } => Abi::C { unwind },
28242829

28252830
// The Windows x64 calling convention we use for `extern "Rust"`
28262831
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>

Diff for: compiler/rustc_ty_utils/src/abi.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,10 @@ fn fn_sig_for_fn_abi<'tcx>(
267267

268268
#[inline]
269269
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv {
270+
let target = &tcx.sess.target;
271+
270272
use rustc_abi::ExternAbi::*;
271-
match tcx.sess.target.adjust_abi(abi, c_variadic) {
273+
match target.adjust_abi(abi, c_variadic) {
272274
RustIntrinsic | Rust | RustCall => Conv::Rust,
273275

274276
// This is intentionally not using `Conv::Cold`, as that has to preserve
@@ -279,10 +281,37 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv
279281
System { .. } => bug!("system abi should be selected elsewhere"),
280282
EfiApi => bug!("eficall abi should be selected elsewhere"),
281283

282-
Stdcall { .. } => Conv::X86Stdcall,
283-
Fastcall { .. } => Conv::X86Fastcall,
284-
Vectorcall { .. } => Conv::X86VectorCall,
285-
Thiscall { .. } => Conv::X86ThisCall,
284+
// See commentary in `is_abi_supported`: we map these to "C" on targets
285+
// where they do not make sense.
286+
Stdcall { .. } => {
287+
if target.arch == "x86" {
288+
Conv::X86Stdcall
289+
} else {
290+
Conv::C
291+
}
292+
}
293+
Fastcall { .. } => {
294+
if target.arch == "x86" {
295+
Conv::X86Fastcall
296+
} else {
297+
Conv::C
298+
}
299+
}
300+
Vectorcall { .. } => {
301+
if ["x86", "x86_64"].contains(&&target.arch[..]) {
302+
Conv::X86VectorCall
303+
} else {
304+
Conv::C
305+
}
306+
}
307+
Thiscall { .. } => {
308+
if target.arch == "x86" {
309+
Conv::X86ThisCall
310+
} else {
311+
Conv::C
312+
}
313+
}
314+
286315
C { .. } => Conv::C,
287316
Unadjusted => Conv::C,
288317
Win64 { .. } => Conv::X86_64Win64,

Diff for: tests/codegen/abi-win64-zst.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//@ compile-flags: -Z merge-functions=disabled
2+
3+
//@ revisions: windows-gnu
4+
//@[windows-gnu] compile-flags: --target x86_64-pc-windows-gnu
5+
//@[windows-gnu] needs-llvm-components: x86
6+
7+
//@ revisions: windows-msvc
8+
//@[windows-msvc] compile-flags: --target x86_64-pc-windows-msvc
9+
//@[windows-msvc] needs-llvm-components: x86
10+
11+
// Also test what happens when using a Windows ABI on Linux.
12+
//@ revisions: linux
13+
//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
14+
//@[linux] needs-llvm-components: x86
15+
16+
#![feature(no_core, lang_items, rustc_attrs, abi_vectorcall)]
17+
#![no_core]
18+
#![crate_type = "lib"]
19+
20+
#[lang = "sized"]
21+
trait Sized {}
22+
23+
// Make sure the argument is always passed when explicitly requesting a Windows ABI.
24+
// Our goal here is to match clang: <https://clang.godbolt.org/z/Wr4jMWq3P>.
25+
26+
// CHECK: define win64cc void @pass_zst_win64(ptr {{.*}})
27+
#[no_mangle]
28+
extern "win64" fn pass_zst_win64(_: ()) {}
29+
30+
// CHECK: define x86_vectorcallcc void @pass_zst_vectorcall(ptr {{.*}})
31+
#[no_mangle]
32+
extern "vectorcall" fn pass_zst_vectorcall(_: ()) {}
33+
34+
// windows-gnu: define void @pass_zst_fastcall(ptr {{.*}})
35+
// windows-msvc: define void @pass_zst_fastcall(ptr {{.*}})
36+
#[no_mangle]
37+
#[cfg(windows)] // "fastcall" is not valid on 64bit Linux
38+
extern "fastcall" fn pass_zst_fastcall(_: ()) {}
39+
40+
// The sysv64 ABI ignores ZST.
41+
42+
// CHECK: define x86_64_sysvcc void @pass_zst_sysv64()
43+
#[no_mangle]
44+
extern "sysv64" fn pass_zst_sysv64(_: ()) {}
45+
46+
// For `extern "C"` functions, ZST are ignored on windows-msvc.
47+
48+
// linux: define void @pass_zst_c()
49+
// windows-msvc: define void @pass_zst_c()
50+
// windows-gnu: define void @pass_zst_c(ptr {{.*}})
51+
#[no_mangle]
52+
extern "C" fn pass_zst_c(_: ()) {}

Diff for: tests/ui/abi/win64-zst.rs

-24
This file was deleted.

Diff for: tests/ui/abi/win64-zst.x86_64-linux.stderr

-69
This file was deleted.

0 commit comments

Comments
 (0)