Skip to content

Commit 233b80e

Browse files
authored
Merge pull request #70503 from apple/egorzhdan/no-abstract-ctors
[cxx-interop] Do not import constructors of abstract C++ classes
2 parents d40fa08 + 3258688 commit 233b80e

File tree

4 files changed

+37
-3
lines changed

4 files changed

+37
-3
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,8 +2372,9 @@ namespace {
23722372

23732373
bool needsEmptyInitializer = true;
23742374
if (cxxRecordDecl) {
2375-
needsEmptyInitializer = !cxxRecordDecl->hasDefaultConstructor() ||
2376-
cxxRecordDecl->ctors().empty();
2375+
needsEmptyInitializer = !cxxRecordDecl->isAbstract() &&
2376+
(!cxxRecordDecl->hasDefaultConstructor() ||
2377+
cxxRecordDecl->ctors().empty());
23772378
}
23782379
if (hasZeroInitializableStorage && needsEmptyInitializer) {
23792380
// Add default constructor for the struct if compiling in C mode.
@@ -3747,6 +3748,19 @@ namespace {
37473748

37483749
Decl *VisitCXXMethodDecl(const clang::CXXMethodDecl *decl) {
37493750
auto method = VisitFunctionDecl(decl);
3751+
3752+
// Do not expose constructors of abstract C++ classes.
3753+
if (auto recordDecl =
3754+
dyn_cast<clang::CXXRecordDecl>(decl->getDeclContext())) {
3755+
if (isa<clang::CXXConstructorDecl>(decl) && recordDecl->isAbstract() &&
3756+
isa_and_nonnull<ValueDecl>(method)) {
3757+
Impl.markUnavailable(
3758+
cast<ValueDecl>(method),
3759+
"constructors of abstract C++ classes are unavailable in Swift");
3760+
return method;
3761+
}
3762+
}
3763+
37503764
if (decl->isVirtual() && isa_and_nonnull<ValueDecl>(method)) {
37513765
if (Impl.isCxxInteropCompatVersionAtLeast(
37523766
version::getUpcomingCxxInteropCompatVersion())) {

test/Interop/Cxx/class/inheritance/Inputs/virtual-methods.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct Base3 { virtual int f() { return 24; } };
1313
struct Derived2 : public Base2 { virtual int f() { return 42; } };
1414
struct Derived3 : public Base3 { virtual int f() { return 42; } };
1515
struct Derived4 : public Base3 { };
16+
struct DerivedFromDerived2 : public Derived2 {};
1617

1718
template <class T>
1819
struct Derived : Base {

test/Interop/Cxx/class/inheritance/virtual-methods-module-interface.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
// RUN: %target-swift-ide-test -print-module -cxx-interoperability-mode=upcoming-swift -print-implicit-attrs -module-to-print=VirtualMethods -I %S/Inputs -source-filename=x | %FileCheck %s
22

33
// CHECK: struct Base {
4-
// CHECK-NEXT: init()
4+
// CHECK-NEXT: @available(*, unavailable, message: "constructors of abstract C++ classes are unavailable in Swift")
5+
// CHECK-NEXT: init()
56
// CHECK-NEXT: @available(*, unavailable, message: "virtual function is not available in Swift because it is pure")
67
// CHECK-NEXT: mutating func foo()
8+
// CHECK: }
9+
10+
// CHECK: struct Base3 {
11+
// CHECK-NEXT: init()
12+
// CHECK: }
13+
14+
// CHECK: struct Derived2 {
15+
// CHECK-NEXT: init()
16+
// CHECK: }
717

818
// CHECK: struct Derived<CInt> {
919
// CHECK-NEXT: init()

test/Interop/Cxx/class/inheritance/virtual-methods-typechecker.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,13 @@
22

33
import VirtualMethods
44

5+
let _ = Base() // expected-error {{'init()' is unavailable: constructors of abstract C++ classes are unavailable in Swift}}
6+
let _ = Base2() // expected-error {{'init()' is unavailable: constructors of abstract C++ classes are unavailable in Swift}}
7+
8+
let _ = DerivedInt()
9+
let _ = Derived2()
10+
let _ = Derived3()
11+
let _ = Derived4()
12+
let _ = DerivedFromDerived2()
13+
514
VirtualNonAbstractBase().nonAbstractMethod()

0 commit comments

Comments
 (0)