diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 9a0e72d7b640a..8b425ce0267d2 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -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. diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index d90dce2a08785..abcc8824dcfb2 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -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); } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index dd435dbb0a306..29636514935e1 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -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> { @@ -125,6 +126,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_unit(self) } + pub fn is_transparent(self) -> bool + where + Ty: TyAbiInterface<'a, C>, + { + Ty::is_transparent(self) + } + pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size where Ty: TyAbiInterface<'a, C>,