Skip to content

Commit cb90479

Browse files
committed
Prototype VaList proposal
1 parent 2f17612 commit cb90479

File tree

23 files changed

+167
-214
lines changed

23 files changed

+167
-214
lines changed

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
175175
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
176176
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
177177
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
178+
/// Returns `true` if the type is always passed indirectly. Currently only
179+
/// used for `VaList`s.
180+
fn is_pass_indirectly(this: TyAndLayout<'a, Self>) -> bool;
178181
}
179182

180183
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -272,6 +275,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
272275
Ty::is_transparent(self)
273276
}
274277

278+
pub fn is_pass_indirectly<C>(self) -> bool
279+
where
280+
Ty: TyAbiInterface<'a, C>,
281+
{
282+
Ty::is_pass_indirectly(self)
283+
}
284+
275285
/// Finds the one field that is not a 1-ZST.
276286
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
277287
pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>

compiler/rustc_abi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ bitflags! {
9292
// Other flags can still inhibit reordering and thus randomization.
9393
// The seed stored in `ReprOptions.field_shuffle_seed`.
9494
const RANDOMIZE_LAYOUT = 1 << 4;
95+
// If true, the type is always passed indirectly in C-like ABIs.
96+
// Currently only used for `VaList`s.
97+
const PASS_INDIRECTLY = 1 << 5;
9598
// Any of these flags being set prevent field reordering optimisation.
9699
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
97100
| ReprFlags::IS_SIMD.bits()

compiler/rustc_codegen_ssa/src/traits/intrinsic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
3232
vtable_byte_offset: u64,
3333
typeid: Self::Metadata,
3434
) -> Self::Value;
35-
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
35+
/// Trait method used to inject `va_start` on the "spoofed" `VaList` in
3636
/// Rust defined C-variadic functions.
3737
fn va_start(&mut self, val: Self::Value) -> Self::Value;
38-
/// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before
38+
/// Trait method used to inject `va_end` on the "spoofed" `VaList` before
3939
/// Rust defined C-variadic functions return.
4040
fn va_end(&mut self, val: Self::Value) -> Self::Value;
4141
}

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{cmp, fmt};
33

44
use rustc_abi::{
55
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6-
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
6+
PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
77
TyAbiInterface, VariantIdx, Variants,
88
};
99
use rustc_error_messages::DiagMessage;
@@ -1165,6 +1165,10 @@ where
11651165
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
11661166
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
11671167
}
1168+
1169+
fn is_pass_indirectly(this: TyAndLayout<'tcx>) -> bool {
1170+
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY))
1171+
}
11681172
}
11691173

11701174
/// Calculates whether a function's ABI can unwind or not.

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,12 @@ impl<'tcx> TyCtxt<'tcx> {
15861586
flags.insert(ReprFlags::IS_LINEAR);
15871587
}
15881588

1589+
if self.is_lang_item(did.to_def_id(), LangItem::VaList)
1590+
&& !flags.contains(ReprFlags::IS_TRANSPARENT)
1591+
{
1592+
flags.insert(ReprFlags::PASS_INDIRECTLY);
1593+
}
1594+
15891595
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
15901596
}
15911597

compiler/rustc_target/src/callconv/aarch64.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ where
114114
// Not touching this...
115115
return;
116116
}
117+
// `is_pass_indirectly` is only `true` for `VaList`, which would be passed indirectly by the
118+
// logic below anyway, so this is just here to make it explicit that this case is handled.
119+
if arg.layout.is_pass_indirectly() {
120+
arg.make_indirect();
121+
return;
122+
}
117123
if !arg.layout.is_aggregate() {
118124
if kind == AbiKind::DarwinPCS {
119125
// On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits,

compiler/rustc_target/src/callconv/powerpc.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use rustc_abi::TyAbiInterface;
2+
13
use crate::callconv::{ArgAbi, FnAbi};
24
use crate::spec::HasTargetSpec;
35

@@ -9,7 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
911
}
1012
}
1113

12-
fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
14+
fn classify_arg<'a, Ty, C>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'a, Ty>)
15+
where
16+
Ty: TyAbiInterface<'a, C> + Copy,
17+
{
1318
if arg.is_ignore() {
1419
// powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
1520
if cx.target_spec().os == "linux"
@@ -20,14 +25,19 @@ fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
2025
}
2126
return;
2227
}
23-
if arg.layout.is_aggregate() {
28+
// `is_pass_indirectly` is only `true` for `VaList` which is already an aggregate, so the
29+
// `.is_pass_indirectly()` call is just to make it explicit that this case is handled.
30+
if arg.layout.is_aggregate() || arg.layout.is_pass_indirectly() {
2431
arg.make_indirect();
2532
} else {
2633
arg.extend_integer_width_to(32);
2734
}
2835
}
2936

30-
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
37+
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'a, Ty>)
38+
where
39+
Ty: TyAbiInterface<'a, C> + Copy,
40+
{
3141
if !fn_abi.ret.is_ignore() {
3242
classify_ret(&mut fn_abi.ret);
3343
}

compiler/rustc_target/src/callconv/s390x.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ where
3737
}
3838
return;
3939
}
40+
// `is_pass_indirectly` is only `true` for `VaList`, which would be passed indirectly by the
41+
// logic below anyway, so this is just here to make it explicit that this case is handled.
42+
if arg.layout.is_pass_indirectly() {
43+
arg.make_indirect();
44+
return;
45+
}
4046

4147
let size = arg.layout.size;
4248
if size.bits() <= 128 {

compiler/rustc_target/src/callconv/x86_64.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ where
185185
// Not touching this...
186186
return;
187187
}
188+
if is_arg && arg.layout.is_pass_indirectly() {
189+
int_regs = int_regs.saturating_sub(1);
190+
arg.make_indirect();
191+
return;
192+
}
188193
let mut cls_or_mem = classify_arg(cx, arg);
189194

190195
if is_arg {

compiler/rustc_target/src/callconv/x86_win64.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
1+
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size, TyAbiInterface};
22

33
use crate::callconv::{ArgAbi, FnAbi, Reg};
44
use crate::spec::{HasTargetSpec, RustcAbi};
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<'a, Ty, C>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'a, Ty>)
9+
where
10+
Ty: TyAbiInterface<'a, C> + Copy,
11+
{
912
let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
1013
match a.layout.backend_repr {
1114
BackendRepr::Memory { sized: false } => {}
@@ -59,6 +62,12 @@ pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'
5962
arg.make_indirect_from_ignore();
6063
continue;
6164
}
65+
// The `win64` ABI can be used on non-Windows targets which set `PASS_INDIRECTLY` on
66+
// `VaList`, so that case is handled here.
67+
if arg.layout.is_pass_indirectly() {
68+
arg.make_indirect();
69+
continue;
70+
}
6271
fixup(arg, false);
6372
}
6473
// FIXME: We should likely also do something about ZST return types, similar to above.

library/core/src/ffi/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub mod c_str;
2828
issue = "44930",
2929
reason = "the `c_variadic` feature has not been properly tested on all supported platforms"
3030
)]
31-
pub use self::va_list::{VaArgSafe, VaList, VaListImpl};
31+
pub use self::va_list::{VaArgSafe, VaList};
3232

3333
#[unstable(
3434
feature = "c_variadic",

0 commit comments

Comments
 (0)