[cinterop] Fix type annotation for struct containing anonymous union … (#4289)

This commit is contained in:
Vladimir Ivanov
2021-05-18 14:34:56 +03:00
committed by GitHub
parent b01478746c
commit 5a0f113e6d
10 changed files with 591 additions and 165 deletions
@@ -11,7 +11,7 @@ fun assertEquals(value1: Any?, value2: Any?) {
throw AssertionError("Expected $value1, got $value2")
}
fun check(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean) {
fun check(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean, x9: Int) {
assertEquals(x1, s.x1)
assertEquals(x1, getX1(s.ptr))
@@ -35,9 +35,12 @@ fun check(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E
assertEquals(x8, s.x8)
assertEquals(x8, getX8(s.ptr))
assertEquals(x9, s.x9)
assertEquals(x9, getX9(s.ptr))
}
fun assign(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean) {
fun assign(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean, x9: Int) {
s.x1 = x1
s.x2 = x2
s.x3 = x3
@@ -46,9 +49,11 @@ fun assign(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7:
s.x6 = x6
s.x7 = x7
s.x8 = x8
s.x9 = x9
}
fun assignReversed(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean) {
fun assignReversed(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean, x9: Int) {
s.x9 = x9
s.x8 = x8
s.x7 = x7
s.x6 = x6
@@ -59,20 +64,20 @@ fun assignReversed(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Lo
s.x1 = x1
}
fun test(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean) {
assign(s, x1, x2, x3, x4, x5, x6, x7, x8)
check(s, x1, x2, x3, x4, x5, x6, x7, x8)
fun test(s: S, x1: Long, x2: B2, x3: UShort, x4: UInt, x5: Int, x6: Long, x7: E, x8: Boolean, x9: Int) {
assign(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
check(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
assignReversed(s, x1, x2, x3, x4, x5, x6, x7, x8)
check(s, x1, x2, x3, x4, x5, x6, x7, x8)
assignReversed(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
check(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
// Also check with some insignificant bits modified:
assign(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE, x7, x8)
check(s, x1, x2, x3, x4, x5, x6, x7, x8)
assign(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE, x7, x8, x9 + 16)
check(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
assignReversed(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE, x7, x8)
check(s, x1, x2, x3, x4, x5, x6, x7, x8)
assignReversed(s, x1 + 2, x2, (x3 + 8u).toUShort(), x4 - 16u, x5 + 32, x6 + Long.MIN_VALUE, x7, x8, x9 + 16)
check(s, x1, x2, x3, x4, x5, x6, x7, x8, x9)
}
fun main(args: Array<String>) {
@@ -86,6 +91,7 @@ fun main(args: Array<String>) {
for (x6 in longArrayOf(Long.MIN_VALUE/2, -1L shl 36, -325L, 0, 1L shl 48, Long.MAX_VALUE/2))
for (x7 in E.values())
for (x8 in arrayOf(false, true))
test(s, x1, x2, x3.toUShort(), x4, x5, x6, x7, x8)
for (x9 in intArrayOf(-8, -2, -1, 0, 5, 7)) // 4 bits width
test(s, x1, x2, x3.toUShort(), x4, x5, x6, x7, x8, x9)
}
}
@@ -16,6 +16,7 @@ struct __attribute__((packed)) S {
long long x6 : 63;
enum E x7: 2;
_Bool x8 : 1;
struct { int x9:4; };
};
static long long getX1(struct S* s) { return s->x1; }
@@ -26,3 +27,4 @@ static int getX5(struct S* s) { return s->x5; }
static long long getX6(struct S* s) { return s->x6; }
static enum E getX7(struct S* s) { return s->x7; }
static _Bool getX8(struct S* s) { return s->x8; }
static int getX9(struct S* s) { return s->x9; }
@@ -1,4 +1,5 @@
---
// KT-28065
struct StructWithConstFields {
int x;
@@ -0,0 +1,192 @@
---
/*
* Test of return/send-by-value for aggregate type (struct or union) with anonymous inner struct or union member.
* Specific issues: alignment, packed, nested named and anon struct/union, other anon types (named field of anon struct type; anon bitfield)
*/
#include <inttypes.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winitializer-overrides"
union _GLKVector3
{
struct { float x, y, z; };
struct { float r, g, b; };
struct { float s, t, p; };
float v[3];
};
static union _GLKVector3 get_GLKVector3() {
union _GLKVector3 ret = {{1, 2, 3}};
return ret;
}
static float hash_GLKVector3(union _GLKVector3 x) {
union _GLKVector3 ret = {{1, 2, 3}};
return x.x + 2.0f * x.y + 4.0f * x.z;
}
// trivial alignment: member is already aligned, but this implies implicit larger alignment of the root struct
struct StructAnonRecordMember_ImplicitAlignment {
int32_t a[4];
struct {
int b __attribute__((aligned(16)));
};
};
static struct StructAnonRecordMember_ImplicitAlignment retByValue_StructAnonRecordMember_ImplicitAlignment() {
struct StructAnonRecordMember_ImplicitAlignment t = {
.a = {1,2,3,4},
.b = 42
};
return t;
}
struct StructAnonRecordMember_ExplicitAlignment {
char a;
struct {
__attribute__((aligned(4)))
char x;
};
};
static struct StructAnonRecordMember_ExplicitAlignment retByValue_StructAnonRecordMember_ExplicitAlignment() {
struct StructAnonRecordMember_ExplicitAlignment t = {
.a = 'a',
.x = 'x'
};
return t;
}
// Deep nesting
struct StructAnonRecordMember_Nested {
int x;
union { // implicitly aligned to 8 bytes due to int64, or 4 bytes at 32-bit arch
int a[2];
struct {
int64_t b;
};
};
char z;
double y;
};
static struct StructAnonRecordMember_Nested retByValue_StructAnonRecordMember_Nested() {
struct StructAnonRecordMember_Nested c = {
.x = 37,
.b = 42,
.z = 'z',
.y = 3.14
};
return c;
}
static int sendByValue_StructAnonRecordMember_Nested(struct StructAnonRecordMember_Nested c) {
return c.a[0] + 2 * c.a[1];
}
// Basic, 2 levels
struct StructAnonRecordMember_Complicate {
char first; // __attribute__((aligned(16)));
union {
int a[2];
union { char c1; int c2; };
struct { char b1; int64_t b2; }; // implicit 64-bits alignment
};
char second __attribute__((aligned(16)));
struct {
char x;
struct { int64_t b11, b12; } Y2;
float f __attribute__((aligned(16)));
}; // __attribute__((aligned(16)));
char last;
};
#define INIT(T, x) struct T x = \
{ \
.first = 'a', \
.b1 = 'b', \
.b2 = 42, \
.second = 's', \
.last = 'z', \
.f = 3.14, \
.Y2 = {11, 12} \
}
static struct StructAnonRecordMember_Complicate retByValue_StructAnonRecordMember_Complicate() {
INIT(StructAnonRecordMember_Complicate, c);
return c;
}
struct StructAnonRecordMember_Packed {
char first;
union {
int a[2];
union { char c1; int c2; };
struct { char b1; int64_t b2; };
};
char second;
struct {
char x;
struct { int64_t b11, b12; } Y2;
float f;
} __attribute__((aligned(16)));
char last;
} __attribute__ ((packed));
static struct StructAnonRecordMember_Packed retByValue_StructAnonRecordMember_Packed() {
INIT(StructAnonRecordMember_Packed, c);
return c;
}
// Nested struct may be packed too
#pragma pack(1)
struct StructAnonRecordMember_PragmaPacked {
char first;
union {
int a[2];
union { char c1; int c2; };
struct { char b1; int64_t b2; };
};
char second;
struct {
char x;
struct { int64_t b11, b12; } Y2;
float f __attribute__((aligned(16)));
}; // __attribute__((aligned(16)));
char last;
} __attribute__ ((packed));
#pragma pack()
static struct StructAnonRecordMember_PragmaPacked retByValue_StructAnonRecordMember_PragmaPacked() {
INIT(StructAnonRecordMember_PragmaPacked, c);
return c;
}
#pragma pack(2)
struct StructAnonRecordMember_Packed2 {
char first;
union {
int a[2];
union { char c1; int c2; };
struct { char b1; int64_t b2; };
};
char second;
struct {
char x;
struct { int64_t b11, b12; } Y2;
float f __attribute__((aligned(16)));
}; // __attribute__((aligned(16)));
char last;
} __attribute__ ((packed));
#pragma pack()
static struct StructAnonRecordMember_Packed2 retByValue_StructAnonRecordMember_Packed2() {
INIT(StructAnonRecordMember_Packed2, c);
return c;
}
#pragma clang diagnostic pop
@@ -0,0 +1,116 @@
import kotlinx.cinterop.*
import kotlin.test.*
import structAnonym.*
fun test_GLKVector3() {
get_GLKVector3().useContents {
assertEquals(1.0f, x)
assertEquals(2.0f, g)
assertEquals(3.0f, p)
r = 0.1f
g = 0.2f
b = 0.3f
assertEquals(v[0], r)
assertEquals(v[1], g)
assertEquals(v[2], b)
val ret = hash_GLKVector3(this.readValue())
assertEquals(s + 2f * t + 4f * p , ret)
}
}
fun test_StructAnonRecordMember_ImplicitAlignment() {
retByValue_StructAnonRecordMember_ImplicitAlignment()
.useContents {
assertEquals(1, a[0])
assertEquals(4, a[3])
assertEquals(42, b)
}
}
fun test_StructAnonRecordMember_ExplicitAlignment() {
retByValue_StructAnonRecordMember_ExplicitAlignment()
.useContents {
assertEquals('a', a.toInt().toChar())
assertEquals('x', x.toInt().toChar())
}
}
fun test_StructAnonRecordMember_Nested() {
retByValue_StructAnonRecordMember_Nested()
.useContents {
assertEquals(37, x)
assertEquals(42, b)
assertEquals('z', z.toInt().toChar())
assertEquals(3.14, y)
a[0] = 3
a[1] = 5
assertEquals(3 + 2*5, sendByValue_StructAnonRecordMember_Nested(this.readValue()))
}
}
fun test_StructAnonym_Complicate() {
retByValue_StructAnonRecordMember_Complicate()
.useContents{
assertEquals('a', first.toInt().toChar())
assertEquals('s', second.toInt().toChar())
assertEquals('z', last.toInt().toChar())
assertEquals('b', b1.toInt().toChar())
assertEquals(42L, b2)
assertEquals(3.14F, f)
assertEquals(11L, Y2.b11)
}
}
fun test_StructAnonym_Packed() {
retByValue_StructAnonRecordMember_Packed2()
.useContents{
assertEquals('a', first.toInt().toChar())
assertEquals('s', second.toInt().toChar())
assertEquals('z', last.toInt().toChar())
assertEquals('b', b1.toInt().toChar())
assertEquals(42L, b2)
assertEquals(3.14F, f)
assertEquals(11L, Y2.b11)
}
}
fun test_StructAnonym_PragmaPacked() {
retByValue_StructAnonRecordMember_PragmaPacked()
.useContents{
assertEquals('a', first.toInt().toChar())
assertEquals('s', second.toInt().toChar())
assertEquals('z', last.toInt().toChar())
assertEquals('b', b1.toInt().toChar())
assertEquals(42L, b2)
assertEquals(3.14F, f)
assertEquals(11L, Y2.b11)
}
}
fun test_StructAnonym_Packed2() {
retByValue_StructAnonRecordMember_Packed2()
.useContents{
assertEquals('a', first.toInt().toChar())
assertEquals('s', second.toInt().toChar())
assertEquals('z', last.toInt().toChar())
assertEquals('b', b1.toInt().toChar())
assertEquals(42L, b2)
assertEquals(3.14F, f)
assertEquals(11L, Y2.b11)
}
}
fun main() {
test_GLKVector3()
test_StructAnonRecordMember_ImplicitAlignment()
test_StructAnonRecordMember_ExplicitAlignment()
test_StructAnonRecordMember_Nested()
test_StructAnonym_Complicate()
test_StructAnonym_Packed()
test_StructAnonym_PragmaPacked()
test_StructAnonym_Packed2()
}