Skip to content

Commit efd4e62

Browse files
committed
rustc_target/riscv: Fix passing of transparent unions with only one non-ZST member
This ensures that `MaybeUninit<T>` has the same ABI as `T` when passed through an `extern "C"` function. Fixes #115481.
1 parent a989e25 commit efd4e62

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

compiler/rustc_middle/src/ty/layout.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ where
11181118
fn is_unit(this: TyAndLayout<'tcx>) -> bool {
11191119
matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
11201120
}
1121+
1122+
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
1123+
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
1124+
}
11211125
}
11221126

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

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

+25-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,31 @@ where
8787
FieldsShape::Primitive => {
8888
unreachable!("aggregates can't have `FieldsShape::Primitive`")
8989
}
90-
FieldsShape::Union(_) => {
90+
FieldsShape::Union(count) => {
91+
if arg_layout.is_transparent() {
92+
let mut non_1zst_elem = None;
93+
for i in 0..count.get() {
94+
let elem_layout = arg_layout.field(cx, i);
95+
if elem_layout.is_1zst() {
96+
continue;
97+
}
98+
// There can only be one.
99+
if non_1zst_elem.is_some() {
100+
unreachable!("two non-1-ZST fields in repr(transparent) union");
101+
}
102+
non_1zst_elem = Some(elem_layout);
103+
}
104+
if let Some(non_1zst_elem) = non_1zst_elem {
105+
return should_use_fp_conv_helper(
106+
cx,
107+
&non_1zst_elem,
108+
xlen,
109+
flen,
110+
field1_kind,
111+
field2_kind,
112+
);
113+
}
114+
}
91115
if !arg_layout.is_zst() {
92116
return Err(CannotUseFpConv);
93117
}

compiler/rustc_target/src/abi/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
5555
fn is_never(this: TyAndLayout<'a, Self>) -> bool;
5656
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
5757
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
58+
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
5859
}
5960

6061
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
125126
Ty::is_unit(self)
126127
}
127128

129+
pub fn is_transparent<C>(self) -> bool
130+
where
131+
Ty: TyAbiInterface<'a, C>,
132+
{
133+
Ty::is_transparent(self)
134+
}
135+
128136
pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
129137
where
130138
Ty: TyAbiInterface<'a, C>,

0 commit comments

Comments
 (0)