11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ // Note: this test checks passing empty struct fields in .NET; confronting it against C++ on native compilers is just
5+ // a means to assert compliance to the platform calling convention. The native part is using C++ because it defines
6+ // empty structs as 1 byte like in .NET. Empty structs in C are undefined (it's a GCC extension to define them as 0
7+ // bytes) and .NET managed/unmanaged interop follows the C ABI, not C++, so signatures with empty struct fields should
8+ // not be used in any real-world interop calls.
9+
410using System ;
511using System . Runtime . InteropServices ;
612using System . Runtime . CompilerServices ;
@@ -77,8 +83,8 @@ public struct IntEmpty
7783 public static IntEmpty Get ( )
7884 => new IntEmpty { Int0 = 0xBabc1a } ;
7985
80- public bool Equals ( IntEmpty other )
81- => Int0 == other . Int0 ;
86+ public override bool Equals ( object other )
87+ => other is IntEmpty o && Int0 == o . Int0 ;
8288
8389 public override string ToString ( )
8490 => $ "{{Int0:{ Int0 : x} }}";
@@ -128,8 +134,8 @@ public struct IntEmptyPair
128134 public static IntEmptyPair Get ( )
129135 => new IntEmptyPair { IntEmpty0 = IntEmpty . Get ( ) , IntEmpty1 = IntEmpty . Get ( ) } ;
130136
131- public bool Equals ( IntEmptyPair other )
132- => IntEmpty0 . Equals ( other . IntEmpty0 ) && IntEmpty1 . Equals ( other . IntEmpty1 ) ;
137+ public override bool Equals ( object other )
138+ => other is IntEmptyPair o && IntEmpty0 . Equals ( o . IntEmpty0 ) && IntEmpty1 . Equals ( o . IntEmpty1 ) ;
133139
134140 public override string ToString ( )
135141 => $ "{{IntEmpty0:{ IntEmpty0 } , IntEmpty1:{ IntEmpty1 } }}";
@@ -181,8 +187,8 @@ public struct EmptyFloatIntInt
181187 public static EmptyFloatIntInt Get ( )
182188 => new EmptyFloatIntInt { Float0 = 2.71828f , Int0 = 0xBabc1a , Int1 = 0xC10c1a } ;
183189
184- public bool Equals ( EmptyFloatIntInt other )
185- => Float0 == other . Float0 && Int0 == other . Int0 && Int1 == other . Int1 ;
190+ public override bool Equals ( object other )
191+ => other is EmptyFloatIntInt o && Float0 == o . Float0 && Int0 == o . Int0 && Int1 == o . Int1 ;
186192
187193 public override string ToString ( )
188194 => $ "{{Float0:{ Float0 } , Int0:{ Int0 : x} , Int1:{ Int1 : x} }}";
@@ -236,8 +242,8 @@ public struct FloatFloatEmptyFloat
236242 public static FloatFloatEmptyFloat Get ( )
237243 => new FloatFloatEmptyFloat { Float0 = 2.71828f , Float1 = 3.14159f , Float2 = 1.61803f } ;
238244
239- public bool Equals ( FloatFloatEmptyFloat other )
240- => Float0 == other . Float0 && Float1 == other . Float1 && Float2 == other . Float2 ;
245+ public override bool Equals ( object other )
246+ => other is FloatFloatEmptyFloat o && Float0 == o . Float0 && Float1 == o . Float1 && Float2 == o . Float2 ;
241247
242248 public override string ToString ( )
243249 => $ "{{Float0:{ Float0 } , Float1:{ Float1 } , Float2:{ Float2 } }}";
@@ -294,8 +300,8 @@ public struct Empty8Float
294300 public static Empty8Float Get ( )
295301 => new Empty8Float { Float0 = 2.71828f } ;
296302
297- public bool Equals ( Empty8Float other )
298- => Float0 == other . Float0 ;
303+ public override bool Equals ( object other )
304+ => other is Empty8Float o && Float0 == o . Float0 ;
299305
300306 public override string ToString ( )
301307 => $ "{{Float0:{ Float0 } }}";
@@ -474,8 +480,8 @@ public struct FloatEmpty8Float
474480 public static FloatEmpty8Float Get ( )
475481 => new FloatEmpty8Float { Float0 = 2.71828f , Float1 = 3.14159f } ;
476482
477- public bool Equals ( FloatEmpty8Float other )
478- => Float0 == other . Float0 && Float1 == other . Float1 ;
483+ public override bool Equals ( object other )
484+ => other is FloatEmpty8Float o && Float0 == o . Float0 && Float1 == o . Float1 ;
479485
480486 public override string ToString ( )
481487 => $ "{{Float0:{ Float0 } , Float1:{ Float1 } }}";
@@ -654,8 +660,8 @@ public struct FloatEmptyShort
654660 public static FloatEmptyShort Get ( )
655661 => new FloatEmptyShort { Float0 = 2.71828f , Short0 = 0x1dea } ;
656662
657- public bool Equals ( FloatEmptyShort other )
658- => Float0 == other . Float0 && Short0 == other . Short0 ;
663+ public override bool Equals ( object other )
664+ => other is FloatEmptyShort o && Float0 == o . Float0 && Short0 == o . Short0 ;
659665
660666 public override string ToString ( )
661667 => $ "{{Float0:{ Float0 } , Short0:{ Short0 } }}";
@@ -793,8 +799,8 @@ public struct EmptyFloatEmpty5Sbyte
793799 public static EmptyFloatEmpty5Sbyte Get ( )
794800 => new EmptyFloatEmpty5Sbyte { Float0 = 2.71828f , Sbyte0 = - 123 } ;
795801
796- public bool Equals ( EmptyFloatEmpty5Sbyte other )
797- => Float0 == other . Float0 && Sbyte0 == other . Sbyte0 ;
802+ public override bool Equals ( object other )
803+ => other is EmptyFloatEmpty5Sbyte o && Float0 == o . Float0 && Sbyte0 == o . Sbyte0 ;
798804
799805 public override string ToString ( )
800806 => $ "{{Float0:{ Float0 } , Sbyte0:{ Sbyte0 } }}";
@@ -848,8 +854,8 @@ public struct EmptyFloatEmpty5Byte
848854 public static EmptyFloatEmpty5Byte Get ( )
849855 => new EmptyFloatEmpty5Byte { Float0 = 2.71828f , Byte0 = 123 } ;
850856
851- public bool Equals ( EmptyFloatEmpty5Byte other )
852- => Float0 == other . Float0 && Byte0 == other . Byte0 ;
857+ public override bool Equals ( object other )
858+ => other is EmptyFloatEmpty5Byte o && Float0 == o . Float0 && Byte0 == o . Byte0 ;
853859
854860 public override string ToString ( )
855861 => $ "{{Float0:{ Float0 } , Byte0:{ Byte0 } }}";
@@ -1037,8 +1043,8 @@ public struct DoubleFloatNestedEmpty
10371043 public static DoubleFloatNestedEmpty Get ( )
10381044 => new DoubleFloatNestedEmpty { Double0 = 2.71828 , Float0 = 3.14159f } ;
10391045
1040- public bool Equals ( DoubleFloatNestedEmpty other )
1041- => Double0 == other . Double0 && Float0 == other . Float0 ;
1046+ public override bool Equals ( object other )
1047+ => other is DoubleFloatNestedEmpty o && Double0 == o . Double0 && Float0 == o . Float0 ;
10421048
10431049 public override string ToString ( )
10441050 => $ "{{Double0:{ Double0 } , Float0:{ Float0 } }}";
@@ -1123,6 +1129,66 @@ public static void Test_DoubleFloatNestedEmpty_InIntegerRegs_ByReflection_RiscV(
11231129 }
11241130#endregion
11251131
1132+ #region ArrayOfEmptiesFloatDouble_RiscVTests
1133+ [ InlineArray ( 1 ) ]
1134+ public struct ArrayOfEmpties
1135+ {
1136+ public Empty e ;
1137+ }
1138+
1139+ public struct ArrayOfEmptiesFloatDouble
1140+ {
1141+ public ArrayOfEmpties ArrayOfEmpties0 ;
1142+ public float Float0 ;
1143+ public double Double0 ;
1144+
1145+ public static ArrayOfEmptiesFloatDouble Get ( )
1146+ => new ArrayOfEmptiesFloatDouble { Float0 = 3.14159f , Double0 = 2.71828 } ;
1147+
1148+ public override bool Equals ( object other )
1149+ => other is ArrayOfEmptiesFloatDouble o && Float0 == o . Float0 && Double0 == o . Double0 ;
1150+
1151+ public override string ToString ( )
1152+ => $ "{{Float0:{ Float0 } , Double0:{ Double0 } }}";
1153+ }
1154+
1155+ [ DllImport ( "EmptyStructsLib" ) ]
1156+ public static extern ArrayOfEmptiesFloatDouble Echo_ArrayOfEmptiesFloatDouble_RiscV ( int a0 , float fa0 ,
1157+ ArrayOfEmptiesFloatDouble a1_a2 , int a3 , float fa1 ) ;
1158+
1159+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
1160+ public static ArrayOfEmptiesFloatDouble Echo_ArrayOfEmptiesFloatDouble_RiscV_Managed ( int a0 , float fa0 ,
1161+ ArrayOfEmptiesFloatDouble a1_a2 , int a3 , float fa1 )
1162+ {
1163+ a1_a2 . Double0 += ( double ) a3 + fa1 ;
1164+ return a1_a2 ;
1165+ }
1166+
1167+ [ Fact ]
1168+ public static void Test_ArrayOfEmptiesFloatDouble_RiscV ( )
1169+ {
1170+ ArrayOfEmptiesFloatDouble expected = ArrayOfEmptiesFloatDouble . Get ( ) ;
1171+ ArrayOfEmptiesFloatDouble native = Echo_ArrayOfEmptiesFloatDouble_RiscV ( 0 , 0f , expected , 1 , - 1f ) ;
1172+ ArrayOfEmptiesFloatDouble managed = Echo_ArrayOfEmptiesFloatDouble_RiscV_Managed ( 0 , 0f , expected , 1 , - 1f ) ;
1173+
1174+ Assert . Equal ( expected , native ) ;
1175+ Assert . Equal ( expected , managed ) ;
1176+ }
1177+
1178+ [ Fact ]
1179+ public static void Test_ArrayOfEmptiesFloatDouble_ByReflection_RiscV ( )
1180+ {
1181+ var expected = ArrayOfEmptiesFloatDouble . Get ( ) ;
1182+ var native = ( ArrayOfEmptiesFloatDouble ) typeof ( Program ) . GetMethod ( "Echo_ArrayOfEmptiesFloatDouble_RiscV" ) . Invoke (
1183+ null , new object [ ] { 0 , 0f , expected , 1 , - 1f } ) ;
1184+ var managed = ( ArrayOfEmptiesFloatDouble ) typeof ( Program ) . GetMethod ( "Echo_ArrayOfEmptiesFloatDouble_RiscV_Managed" ) . Invoke (
1185+ null , new object [ ] { 0 , 0f , expected , 1 , - 1f } ) ;
1186+
1187+ Assert . Equal ( expected , native ) ;
1188+ Assert . Equal ( expected , managed ) ;
1189+ }
1190+ #endregion
1191+
11261192#region EmptyUshortAndDouble_RiscVTests
11271193 public struct EmptyUshortAndDouble
11281194 {
@@ -1138,8 +1204,8 @@ public struct EmptyUshort
11381204 EmptyUshort0 = new EmptyUshort { Ushort0 = 0xBaca } , Double0 = 2.71828
11391205 } ;
11401206
1141- public bool Equals ( EmptyUshortAndDouble other )
1142- => EmptyUshort0 . Ushort0 == other . EmptyUshort0 . Ushort0 && Double0 == other . Double0 ;
1207+ public override bool Equals ( object other )
1208+ => other is EmptyUshortAndDouble o && EmptyUshort0 . Ushort0 == o . EmptyUshort0 . Ushort0 && Double0 == o . Double0 ;
11431209
11441210 public override string ToString ( )
11451211 => $ "{{EmptyUshort0.Ushort0:{ EmptyUshort0 . Ushort0 } , Double0:{ Double0 } }}";
@@ -1193,8 +1259,8 @@ public struct PackedEmptyFloatLong
11931259 public static PackedEmptyFloatLong Get ( )
11941260 => new PackedEmptyFloatLong { Float0 = 2.71828f , Long0 = 0xDadAddedC0ffee } ;
11951261
1196- public bool Equals ( PackedEmptyFloatLong other )
1197- => Float0 == other . Float0 && Long0 == other . Long0 ;
1262+ public override bool Equals ( object other )
1263+ => other is PackedEmptyFloatLong o && Float0 == o . Float0 && Long0 == o . Long0 ;
11981264
11991265 public override string ToString ( )
12001266 => $ "{{Float0:{ Float0 } , Long0:{ Long0 } }}";
@@ -1383,8 +1449,8 @@ public struct PackedFloatEmptyByte
13831449 public static PackedFloatEmptyByte Get ( )
13841450 => new PackedFloatEmptyByte { Float0 = 2.71828f , Byte0 = 0xba } ;
13851451
1386- public bool Equals ( PackedFloatEmptyByte other )
1387- => Float0 == other . Float0 && Byte0 == other . Byte0 ;
1452+ public override bool Equals ( object other )
1453+ => other is PackedFloatEmptyByte o && Float0 == o . Float0 && Byte0 == o . Byte0 ;
13881454
13891455 public override string ToString ( )
13901456 => $ "{{Float0:{ Float0 } , Byte0:{ Byte0 } }}";
0 commit comments