1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
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
+
4
10
using System ;
5
11
using System . Runtime . InteropServices ;
6
12
using System . Runtime . CompilerServices ;
@@ -77,8 +83,8 @@ public struct IntEmpty
77
83
public static IntEmpty Get ( )
78
84
=> new IntEmpty { Int0 = 0xBabc1a } ;
79
85
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 ;
82
88
83
89
public override string ToString ( )
84
90
=> $ "{{Int0:{ Int0 : x} }}";
@@ -128,8 +134,8 @@ public struct IntEmptyPair
128
134
public static IntEmptyPair Get ( )
129
135
=> new IntEmptyPair { IntEmpty0 = IntEmpty . Get ( ) , IntEmpty1 = IntEmpty . Get ( ) } ;
130
136
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 ) ;
133
139
134
140
public override string ToString ( )
135
141
=> $ "{{IntEmpty0:{ IntEmpty0 } , IntEmpty1:{ IntEmpty1 } }}";
@@ -181,8 +187,8 @@ public struct EmptyFloatIntInt
181
187
public static EmptyFloatIntInt Get ( )
182
188
=> new EmptyFloatIntInt { Float0 = 2.71828f , Int0 = 0xBabc1a , Int1 = 0xC10c1a } ;
183
189
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 ;
186
192
187
193
public override string ToString ( )
188
194
=> $ "{{Float0:{ Float0 } , Int0:{ Int0 : x} , Int1:{ Int1 : x} }}";
@@ -236,8 +242,8 @@ public struct FloatFloatEmptyFloat
236
242
public static FloatFloatEmptyFloat Get ( )
237
243
=> new FloatFloatEmptyFloat { Float0 = 2.71828f , Float1 = 3.14159f , Float2 = 1.61803f } ;
238
244
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 ;
241
247
242
248
public override string ToString ( )
243
249
=> $ "{{Float0:{ Float0 } , Float1:{ Float1 } , Float2:{ Float2 } }}";
@@ -294,8 +300,8 @@ public struct Empty8Float
294
300
public static Empty8Float Get ( )
295
301
=> new Empty8Float { Float0 = 2.71828f } ;
296
302
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 ;
299
305
300
306
public override string ToString ( )
301
307
=> $ "{{Float0:{ Float0 } }}";
@@ -474,8 +480,8 @@ public struct FloatEmpty8Float
474
480
public static FloatEmpty8Float Get ( )
475
481
=> new FloatEmpty8Float { Float0 = 2.71828f , Float1 = 3.14159f } ;
476
482
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 ;
479
485
480
486
public override string ToString ( )
481
487
=> $ "{{Float0:{ Float0 } , Float1:{ Float1 } }}";
@@ -654,8 +660,8 @@ public struct FloatEmptyShort
654
660
public static FloatEmptyShort Get ( )
655
661
=> new FloatEmptyShort { Float0 = 2.71828f , Short0 = 0x1dea } ;
656
662
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 ;
659
665
660
666
public override string ToString ( )
661
667
=> $ "{{Float0:{ Float0 } , Short0:{ Short0 } }}";
@@ -793,8 +799,8 @@ public struct EmptyFloatEmpty5Sbyte
793
799
public static EmptyFloatEmpty5Sbyte Get ( )
794
800
=> new EmptyFloatEmpty5Sbyte { Float0 = 2.71828f , Sbyte0 = - 123 } ;
795
801
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 ;
798
804
799
805
public override string ToString ( )
800
806
=> $ "{{Float0:{ Float0 } , Sbyte0:{ Sbyte0 } }}";
@@ -848,8 +854,8 @@ public struct EmptyFloatEmpty5Byte
848
854
public static EmptyFloatEmpty5Byte Get ( )
849
855
=> new EmptyFloatEmpty5Byte { Float0 = 2.71828f , Byte0 = 123 } ;
850
856
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 ;
853
859
854
860
public override string ToString ( )
855
861
=> $ "{{Float0:{ Float0 } , Byte0:{ Byte0 } }}";
@@ -1037,8 +1043,8 @@ public struct DoubleFloatNestedEmpty
1037
1043
public static DoubleFloatNestedEmpty Get ( )
1038
1044
=> new DoubleFloatNestedEmpty { Double0 = 2.71828 , Float0 = 3.14159f } ;
1039
1045
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 ;
1042
1048
1043
1049
public override string ToString ( )
1044
1050
=> $ "{{Double0:{ Double0 } , Float0:{ Float0 } }}";
@@ -1123,6 +1129,66 @@ public static void Test_DoubleFloatNestedEmpty_InIntegerRegs_ByReflection_RiscV(
1123
1129
}
1124
1130
#endregion
1125
1131
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
+
1126
1192
#region EmptyUshortAndDouble_RiscVTests
1127
1193
public struct EmptyUshortAndDouble
1128
1194
{
@@ -1138,8 +1204,8 @@ public struct EmptyUshort
1138
1204
EmptyUshort0 = new EmptyUshort { Ushort0 = 0xBaca } , Double0 = 2.71828
1139
1205
} ;
1140
1206
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 ;
1143
1209
1144
1210
public override string ToString ( )
1145
1211
=> $ "{{EmptyUshort0.Ushort0:{ EmptyUshort0 . Ushort0 } , Double0:{ Double0 } }}";
@@ -1193,8 +1259,8 @@ public struct PackedEmptyFloatLong
1193
1259
public static PackedEmptyFloatLong Get ( )
1194
1260
=> new PackedEmptyFloatLong { Float0 = 2.71828f , Long0 = 0xDadAddedC0ffee } ;
1195
1261
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 ;
1198
1264
1199
1265
public override string ToString ( )
1200
1266
=> $ "{{Float0:{ Float0 } , Long0:{ Long0 } }}";
@@ -1383,8 +1449,8 @@ public struct PackedFloatEmptyByte
1383
1449
public static PackedFloatEmptyByte Get ( )
1384
1450
=> new PackedFloatEmptyByte { Float0 = 2.71828f , Byte0 = 0xba } ;
1385
1451
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 ;
1388
1454
1389
1455
public override string ToString ( )
1390
1456
=> $ "{{Float0:{ Float0 } , Byte0:{ Byte0 } }}";
0 commit comments