Fix handling of 'null' passed as C string (#3452)

This commit is contained in:
SvyatoslavScherbina
2019-10-11 10:00:19 +03:00
committed by GitHub
parent 496ebbe2a8
commit 5081adbf87
4 changed files with 55 additions and 13 deletions
@@ -1375,8 +1375,10 @@ private class ObjCBlockPointerValuePassing(
private class WCStringArgumentPassing : KotlinToCArgumentPassing {
override fun KotlinToCCallBuilder.passValue(expression: IrExpression): CExpression {
val wcstr = irBuilder.irCall(symbols.interopWcstr.owner).apply {
extensionReceiver = expression
val wcstr = irBuilder.irSafeTransform(expression) {
irCall(symbols.interopWcstr.owner).apply {
extensionReceiver = it
}
}
return with(CValuesRefArgumentPassing) { passValue(wcstr) }
}
@@ -1386,8 +1388,10 @@ private class WCStringArgumentPassing : KotlinToCArgumentPassing {
private class CStringArgumentPassing : KotlinToCArgumentPassing {
override fun KotlinToCCallBuilder.passValue(expression: IrExpression): CExpression {
val cstr = irBuilder.irCall(symbols.interopCstr.owner).apply {
extensionReceiver = expression
val cstr = irBuilder.irSafeTransform(expression) {
irCall(symbols.interopCstr.owner).apply {
extensionReceiver = it
}
}
return with(CValuesRefArgumentPassing) { passValue(cstr) }
}
@@ -1410,25 +1414,33 @@ private fun KotlinToCCallBuilder.cValuesRefToPointer(
value: IrExpression
): IrExpression = if (value.type.classifierOrNull == symbols.interopCPointer) {
value // Optimization
} else with(irBuilder) {
} else {
val getPointerFunction = symbols.interopCValuesRef.owner
.simpleFunctions()
.single { it.name.asString() == "getPointer" }
fun getPointer(expression: IrExpression) = irCall(getPointerFunction).apply {
dispatchReceiver = expression
putValueArgument(0, bridgeCallBuilder.getMemScope())
irBuilder.irSafeTransform(value) {
irCall(getPointerFunction).apply {
dispatchReceiver = it
putValueArgument(0, bridgeCallBuilder.getMemScope())
}
}
}
if (!value.type.isNullable()) {
getPointer(value) // Optimization
} else irLetS(value) { valueVarSymbol ->
private fun IrBuilderWithScope.irSafeTransform(
value: IrExpression,
block: IrBuilderWithScope.(IrExpression) -> IrExpression
): IrExpression = if (!value.type.isNullable()) {
block(value) // Optimization
} else {
irLetS(value) { valueVarSymbol ->
val valueVar = valueVarSymbol.owner
val transformed = block(irGet(valueVar))
irIfThenElse(
type = symbols.interopCPointer.typeWithStarProjections.makeNullable(),
type = transformed.type.makeNullable(),
condition = irEqeqeq(irGet(valueVar), irNull()),
thenPart = irNull(),
elsePart = getPointer(irGet(valueVar))
elsePart = transformed
)
}
}
+10
View File
@@ -3292,6 +3292,10 @@ createInterop("ctypes") {
it.defFile 'interop/basics/ctypes.def'
}
createInterop("cvalues") {
it.defFile 'interop/basics/cvalues.def'
}
createInterop("ccallbacksAndVarargs") {
it.defFile 'interop/basics/ccallbacksAndVarargs.def'
}
@@ -3449,6 +3453,12 @@ interopTest("interop_types") {
interop = 'ctypes'
}
interopTest("interop_values") {
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
source = "interop/basics/values.kt"
interop = 'cvalues'
}
interopTest("interop_callbacksAndVarargs") {
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
source = "interop/basics/callbacksAndVarargs.kt"
@@ -0,0 +1,10 @@
---
_Bool isNullString(const char* str) {
return str == (const char*)0;
}
typedef const short* LPCWSTR;
_Bool isNullWString(LPCWSTR str) {
return str == (LPCWSTR)0;
}
@@ -0,0 +1,10 @@
import kotlinx.cinterop.*
import kotlin.test.*
import cvalues.*
fun main() {
assertTrue(isNullString(null))
assertTrue(isNullWString(null))
assertFalse(isNullString("a"))
assertFalse(isNullWString("b"))
}