Skip to content

Commit

Permalink
rustc_target/riscv: Fix passing of transparent unions with only one n…
Browse files Browse the repository at this point in the history
…on-ZST member

This ensures that `MaybeUninit<T>` has the same ABI as `T` when passed
through an `extern "C"` function.

Fixes rust-lang#115481.
  • Loading branch information
msizanoen1 committed Sep 3, 2023
1 parent a989e25 commit efd4e62
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,10 @@ where
fn is_unit(this: TyAndLayout<'tcx>) -> bool {
matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
}

fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
}
}

/// Calculates whether a function's ABI can unwind or not.
Expand Down
26 changes: 25 additions & 1 deletion compiler/rustc_target/src/abi/call/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,31 @@ where
FieldsShape::Primitive => {
unreachable!("aggregates can't have `FieldsShape::Primitive`")
}
FieldsShape::Union(_) => {
FieldsShape::Union(count) => {
if arg_layout.is_transparent() {
let mut non_1zst_elem = None;
for i in 0..count.get() {
let elem_layout = arg_layout.field(cx, i);
if elem_layout.is_1zst() {
continue;
}
// There can only be one.
if non_1zst_elem.is_some() {
unreachable!("two non-1-ZST fields in repr(transparent) union");
}
non_1zst_elem = Some(elem_layout);
}
if let Some(non_1zst_elem) = non_1zst_elem {
return should_use_fp_conv_helper(
cx,
&non_1zst_elem,
xlen,
flen,
field1_kind,
field2_kind,
);
}
}
if !arg_layout.is_zst() {
return Err(CannotUseFpConv);
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_target/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
fn is_never(this: TyAndLayout<'a, Self>) -> bool;
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
}

impl<'a, Ty> TyAndLayout<'a, Ty> {
Expand Down Expand Up @@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_unit(self)
}

pub fn is_transparent<C>(self) -> bool
where
Ty: TyAbiInterface<'a, C>,
{
Ty::is_transparent(self)
}

pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
where
Ty: TyAbiInterface<'a, C>,
Expand Down

0 comments on commit efd4e62

Please sign in to comment.