Native: fix error message for C union with nested struct with bitfields

tryRenderStructOrUnion can return null for a struct or union to indicate
that passing it by value to or from C is not supported (e.g. it has
bitfields).

It incorrectly handled the case when passing a nested struct or union by
value was unsupported -- instead of null, it returned incorrect struct
declaration.

As a result, when passing such a complex struct or union by value to or
from C, the backend generated C stubs with syntax errors, which resulted
into obscure compilation error ("unable to compile C bridge").

This commit fixes this case in tryRenderStructOrUnion function, and thus
makes the compilation error message more understandable.

^KT-55030
This commit is contained in:
Svyatoslav Scherbina
2023-02-23 18:45:22 +01:00
committed by Space Team
parent d00513599b
commit 3904966e2c
2 changed files with 56 additions and 1 deletions
@@ -113,7 +113,7 @@ private fun tryRenderVar(type: Type, name: String): String? = when (type) {
is IntegerType -> "${type.spelling} $name"
is FloatingType -> "${type.spelling} $name"
is VectorType -> "${type.spelling} $name"
is RecordType -> "${tryRenderStructOrUnion(type.decl.def!!)} $name"
is RecordType -> tryRenderStructOrUnion(type.decl.def!!)?.let { "$it $name" }
is EnumType -> tryRenderVar(type.def.baseType, name)
is PointerType -> "void* $name"
is ConstArrayType -> tryRenderVar(type.elemType, "$name[${type.length}]")
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.native.interop.gen
import org.jetbrains.kotlin.native.interop.indexer.StructDef
import org.jetbrains.kotlin.native.interop.indexer.buildNativeIndex
import kotlin.test.Test
import kotlin.test.assertEquals
class StructRenderingTests : InteropTestsBase() {
// See https://youtrack.jetbrains.com/issue/KT-55030#focus=Comments-27-6742454.0-0
@Test
fun kt55030() {
val files = TempFiles("kt55030")
val header = files.file("header.h", """
union SupportedValue {
struct {
int a;
} b;
int c;
};
union UnsupportedValue {
struct {
int a : 5;
} b;
int c;
};
""".trimIndent())
val defFile = files.file("kt55030.def", """
headers = ${header.name}
""".trimIndent())
val library = buildNativeLibraryFrom(defFile, files.directory)
val index = buildNativeIndex(library, verbose = false).index
fun getUnionDef(name: String): StructDef {
return index.structs.find { it.spelling == "union $name" }!!.def!!
}
assertEquals(
null,
tryRenderStructOrUnion(getUnionDef("UnsupportedValue"))
)
assertEquals(
"union { struct { int a; } b; int c; }",
tryRenderStructOrUnion(getUnionDef("SupportedValue"))
)
}
}