From 5a4a78f2c69199a34596f72fb9821db5f556a255 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Wed, 22 Sep 2021 17:22:31 +0300 Subject: [PATCH] [K/N] Throw exception on abstract class instantiation in ObjC --- .../kotlin/backend/konan/llvm/ContextUtils.kt | 1 + .../llvm/objcexport/ObjCExportCodeGenerator.kt | 6 ++++++ .../backend.native/tests/build.gradle | 8 ++++++++ .../abstractInstantiation.kt | 8 ++++++++ .../abstractInstantiation.swift | 18 ++++++++++++++++++ .../tests/objcexport/sealedClass.swift | 1 - .../runtime/src/main/cpp/ObjCExport.mm | 8 ++++++++ 7 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.kt create mode 100644 kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.swift diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 016ad4d75ed..0e268215670 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -525,6 +525,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti val Kotlin_ObjCExport_convertUnitToRetained by lazyRtFunction val Kotlin_ObjCExport_GetAssociatedObject by lazyRtFunction val Kotlin_ObjCExport_AbstractMethodCalled by lazyRtFunction + val Kotlin_ObjCExport_AbstractClassConstructorCalled by lazyRtFunction val Kotlin_ObjCExport_RethrowExceptionAsNSError by lazyRtFunction val Kotlin_ObjCExport_WrapExceptionToNSError by lazyRtFunction val Kotlin_ObjCExport_RethrowNSErrorAsException by lazyRtFunction diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index dda76e29a35..ef5948cceef 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -876,6 +876,12 @@ private fun ObjCExportCodeGenerator.generateObjCImp( isDirect = !isVirtual, baseMethod = baseMethod ) { args, resultLifetime, exceptionHandler -> + if (target is IrConstructor && target.constructedClass.isAbstract()) { + callFromBridge( + context.llvm.Kotlin_ObjCExport_AbstractClassConstructorCalled, + listOf(param(0), codegen.typeInfoValue(target.parent as IrClass)) + ) + } val llvmTarget = if (!isVirtual) { codegen.llvmFunction(target) } else { diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 1dae9a941fa..352ffbb9aae 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -5450,6 +5450,14 @@ if (isAppleTarget(project)) { swiftSources = ['framework/stacktraceByLibbacktrace/'] } + frameworkTest("testAbstractInstantiationFramework") { + framework('AbstractInstantiation') { + sources = ['framework/abstractInstantiation'] + } + swiftSources = ['framework/abstractInstantiation/'] + expectedExitStatus = 134 + } + frameworkTest("testFrameworkBundleId") { def currentTarget = project.target.name enabled = currentTarget.startsWith("mac") diff --git a/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.kt b/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.kt new file mode 100644 index 00000000000..40b3ccde0ee --- /dev/null +++ b/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2010-2021 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. + */ + +public abstract class AbstractBase(val y: Int) { + abstract val x: Int +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.swift b/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.swift new file mode 100644 index 00000000000..f23f268d9f9 --- /dev/null +++ b/kotlin-native/backend.native/tests/framework/abstractInstantiation/abstractInstantiation.swift @@ -0,0 +1,18 @@ +import Foundation +import AbstractInstantiation + +func testInstantiate() throws { + // this is failure test, it shouldn't work + let base = AbstractBase(y: 5) +} + +class AbstractInstantiationTests : TestProvider { + var tests: [TestCase] = [] + + init() { + providers.append(self) + tests = [ + TestCase(name: "testInstantiate", method: withAutorelease(testInstantiate)) + ] + } +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/objcexport/sealedClass.swift b/kotlin-native/backend.native/tests/objcexport/sealedClass.swift index 9c060293775..c32090ff6f6 100644 --- a/kotlin-native/backend.native/tests/objcexport/sealedClass.swift +++ b/kotlin-native/backend.native/tests/objcexport/sealedClass.swift @@ -2,7 +2,6 @@ import Kt private func test1() throws { let user = Person.User(id: 1) - let worker = Person.Worker() let employee = Person.WorkerEmployee(id: 2) let contractor = Person.WorkerContractor(id: 3) let userAsPerson: Person = user diff --git a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm index 8cc6c492168..79740d8e6e7 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm @@ -1111,6 +1111,14 @@ extern "C" void Kotlin_ObjCExport_AbstractMethodCalled(id self, SEL selector) { class_getName(object_getClass(self)), sel_getName(selector)]; } +extern "C" void Kotlin_ObjCExport_AbstractClassConstructorCalled(id self, const TypeInfo *clazz) { + Class objectClass = object_getClass(self); + Class constructorClass = getOrCreateClass(clazz); + if (objectClass == constructorClass) { + [NSException raise:NSGenericException format:@"Class %s is abstract and can't be instantiated", class_getName(objectClass)]; + } +} + extern "C" NSInteger Kotlin_ObjCExport_NSIntegerTypeProvider() { return 0; }