Skip to content

Commit 93c4c62

Browse files
authored
[cxx-interop] Walk initializer decls when walking constructor decls (#41584)
This addresses SR-15272. When you have a function (e.g. 'foo') which is used in a constructor initializer (e.g. constructor of some class 'Bar'), and you use the constructor from swift code without directly using the function (e.g. Bar's ctor is used from swift but foo isn't, foo is used from Bar's ctor), you will get a link error. My fix is as follows: When walking the clangAST to be imported, make sure you look at each CXXCtorInitializer for each CXXConstructorDecl you see.
1 parent 78a410c commit 93c4c62

11 files changed

+113
-4
lines changed

lib/IRGen/GenClangDecl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ class ClangDeclFinder
5353
return true;
5454
}
5555

56+
bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *CXXCD) {
57+
callback(CXXCD);
58+
for (clang::CXXCtorInitializer *CXXCI : CXXCD->inits()) {
59+
if (clang::FieldDecl *FD = CXXCI->getMember())
60+
callback(FD);
61+
}
62+
return true;
63+
}
64+
5665
bool VisitCXXConstructExpr(clang::CXXConstructExpr *CXXCE) {
5766
callback(CXXCE->getConstructor());
5867
return true;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_CODEGEN_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_CALLS_H
2+
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_CODEGEN_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_CALLS_H
3+
4+
inline int get42Level4() { return 42; }
5+
inline int get42Level3() { return get42Level4(); }
6+
inline int get42Level2() { return get42Level3(); }
7+
inline int get42Level1() { return get42Level2(); }
8+
9+
struct Hold42WithLongInitCallGraph {
10+
int m = get42Level1();
11+
};
12+
13+
#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_STRUCT_H

test/Interop/Cxx/class/inline-function-codegen/Inputs/constructor-calls-function-from-nested-struct.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,18 @@ inline int callConstructor(int value) {
1414
return IncrementUser::Incrementor(value).value;
1515
}
1616

17+
inline int get42() { return 42; }
18+
19+
struct HoldMemberThatHolds42 {
20+
struct Hold42 {
21+
int m = get42();
22+
};
23+
24+
Hold42 holder;
25+
};
26+
27+
struct HoldMemberThatHoldsMemberThatHolds42 {
28+
HoldMemberThatHolds42 holder;
29+
};
30+
1731
#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_STRUCT_H

test/Interop/Cxx/class/inline-function-codegen/Inputs/constructor-calls-function.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,19 @@ struct Incrementor {
1010

1111
inline int callConstructor(int value) { return Incrementor(value).incrementee; }
1212

13+
inline int get42() { return 42; }
14+
15+
template <typename T>
16+
T passThroughArgT(T t) {
17+
return t;
18+
}
19+
20+
struct Hold42 {
21+
int m = get42();
22+
};
23+
24+
struct Hold23 {
25+
int m = passThroughArgT<int>(23);
26+
};
27+
1328
#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_H

test/Interop/Cxx/class/inline-function-codegen/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module ConstructorCallsFunctionFromNestedStruct {
88
requires cplusplus
99
}
1010

11+
module ConstructorCallsFunctionFromNestedCalls {
12+
header "constructor-calls-function-from-nested-calls.h"
13+
requires cplusplus
14+
}
15+
1116
module ConstructorCallsMethod {
1217
header "constructor-calls-method.h"
1318
requires cplusplus

test/Interop/Cxx/class/inline-function-codegen/constructor-calls-function-execution.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ import StdlibUnittest
77

88
var MembersTestSuite = TestSuite("MembersTestSuite")
99

10-
MembersTestSuite.test("constructor calls function") {
10+
MembersTestSuite.test("constructor calls function (explicit)") {
1111
expectEqual(42, callConstructor(41))
1212
}
1313

14+
MembersTestSuite.test("constructor calls function (implicit)") {
15+
let holder = Hold42()
16+
expectEqual(42, holder.m)
17+
}
18+
19+
MembersTestSuite.test("constructor calls template function (implicit)") {
20+
let holder = Hold23()
21+
expectEqual(23, holder.m)
22+
}
23+
1424
runAllTests()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
2+
//
3+
// REQUIRES: executable_test
4+
5+
import ConstructorCallsFunctionFromNestedCalls
6+
import StdlibUnittest
7+
8+
var MembersTestSuite = TestSuite("MembersTestSuite")
9+
10+
MembersTestSuite.test("constructor calls function from nested calls") {
11+
let holder = Hold42WithLongInitCallGraph()
12+
expectEqual(42, holder.m)
13+
}
14+
15+
runAllTests()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s
2+
3+
import ConstructorCallsFunctionFromNestedCalls
4+
5+
let a = Hold42WithLongInitCallGraph()
6+
7+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z11get42Level1v|"\?get42Level1@@YAHXZ"}}
8+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z11get42Level2v|"\?get42Level2@@YAHXZ"}}
9+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z11get42Level3v|"\?get42Level3@@YAHXZ"}}
10+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z11get42Level4v|"\?get42Level4@@YAHXZ"}}

test/Interop/Cxx/class/inline-function-codegen/constructor-calls-function-from-nested-struct-execution.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ import StdlibUnittest
77

88
var MembersTestSuite = TestSuite("MembersTestSuite")
99

10-
MembersTestSuite.test("constructor calls function from nested struct") {
10+
MembersTestSuite.test("constructor calls function from nested struct (explicit)") {
1111
expectEqual(42, callConstructor(41))
1212
}
1313

14+
MembersTestSuite.test("constructor calls function from nested struct (implicit)") {
15+
let holder = HoldMemberThatHolds42()
16+
expectEqual(42, holder.holder.m)
17+
}
18+
1419
runAllTests()

test/Interop/Cxx/class/inline-function-codegen/constructor-calls-function-from-nested-struct-irgen.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@ public func getIncrementorValue() -> CInt {
66
return callConstructor(41)
77
}
88

9-
// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
9+
let a = HoldMemberThatHolds42()
10+
let b = HoldMemberThatHoldsMemberThatHolds42()
11+
12+
let sum = a.holder.m + b.holder.holder.m
13+
14+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
15+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z5get42v|"\?get42@@YAHXZ"}}

test/Interop/Cxx/class/inline-function-codegen/constructor-calls-function-irgen.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,11 @@ public func getIncrementorValue() -> CInt {
66
return callConstructor(41)
77
}
88

9-
// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
9+
let a = Hold42()
10+
let b = Hold23()
11+
12+
let sum = a.m + b.m
13+
14+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
15+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z5get42v|"\?get42@@YAHXZ"}}
16+
// CHECK-DAG: define linkonce_odr{{( dso_local)?}} i32 @{{_Z15passThroughArgTIiET_S0_|"\?\?\$passThroughArgT@H@@YAHH@Z"}}

0 commit comments

Comments
 (0)