Skip to content

Commit 4f72147

Browse files
committed
[cxx-interop] Use "c function conventions" for static methods and ctors (not "cxx method conventions").
Otherwise we will incorrectly use the "self" type's conventions when lowering the parameters (off-by-one).
1 parent f8bf74b commit 4f72147

File tree

4 files changed

+61
-9
lines changed

4 files changed

+61
-9
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3005,6 +3005,13 @@ class CFunctionConventions : public CFunctionTypeConventions {
30053005
}
30063006

30073007
ResultConvention getResult(const TypeLowering &tl) const override {
3008+
// C++ constructors return indirectly.
3009+
// TODO: this may be different depending on the ABI, so we may have to
3010+
// check with clang here.
3011+
if (isa<clang::CXXConstructorDecl>(TheDecl)) {
3012+
return ResultConvention::Indirect;
3013+
}
3014+
30083015
if (isCFTypedef(tl, TheDecl->getReturnType())) {
30093016
// The CF attributes aren't represented in the type, so we need
30103017
// to check them here.
@@ -3109,15 +3116,19 @@ static CanSILFunctionType getSILFunctionTypeForClangDecl(
31093116
}
31103117

31113118
if (auto method = dyn_cast<clang::CXXMethodDecl>(clangDecl)) {
3112-
AbstractionPattern origPattern = AbstractionPattern::getCXXMethod(origType, method,
3113-
foreignInfo.self);
3114-
bool isMutating =
3115-
TC.Context.getClangModuleLoader()->isCXXMethodMutating(method);
3116-
auto conventions = CXXMethodConventions(method, isMutating);
3117-
return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern,
3118-
substInterfaceType, extInfoBuilder, conventions,
3119-
foreignInfo, constant, constant, None,
3120-
ProtocolConformanceRef());
3119+
// Static methods and ctors should be lowered like plane functions
3120+
// (case below).
3121+
if (!isa<clang::CXXConstructorDecl>(method) || method->isStatic()) {
3122+
AbstractionPattern origPattern = AbstractionPattern::getCXXMethod(origType, method,
3123+
foreignInfo.self);
3124+
bool isMutating =
3125+
TC.Context.getClangModuleLoader()->isCXXMethodMutating(method);
3126+
auto conventions = CXXMethodConventions(method, isMutating);
3127+
return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern,
3128+
substInterfaceType, extInfoBuilder, conventions,
3129+
foreignInfo, constant, constant, None,
3130+
ProtocolConformanceRef());
3131+
}
31213132
}
31223133

31233134
if (auto func = dyn_cast<clang::FunctionDecl>(clangDecl)) {

test/Interop/Cxx/class/method/Inputs/methods.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,13 @@ struct HasMethods {
2727
NonTrivialInWrapper constPassThroughAsWrapper(int a) const { return {a}; }
2828
};
2929

30+
struct ReferenceParams {
31+
int a;
32+
int b;
33+
ReferenceParams(const int &a, const int &b) : a(a), b(b) { }
34+
static void staticMethod(const int &a, const int &b) {
35+
ReferenceParams t{a, b};
36+
}
37+
};
38+
3039
#endif // TEST_INTEROP_CXX_CLASS_METHOD_METHODS_H
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-emit-silgen -I %S/Inputs -enable-experimental-cxx-interop %s | %FileCheck %s
2+
3+
import Methods
4+
5+
// clang name: ReferenceParams::ReferenceParams
6+
// CHECK: sil [clang ReferenceParams.init] @_ZN15ReferenceParamsC1ERKiS1_ : $@convention(c) (@in_guaranteed Int32, @in_guaranteed Int32) -> @out ReferenceParams
7+
8+
// clang name: ReferenceParams::staticMethod
9+
// CHECK: sil [clang ReferenceParams.staticMethod] @_ZN15ReferenceParams12staticMethodERKiS1_ : $@convention(c) (@in_guaranteed Int32, @in_guaranteed Int32) -> ()
10+
11+
public func use() {
12+
let a = CInt(42)
13+
let b = CInt(42)
14+
_ = ReferenceParams(a, b)
15+
ReferenceParams.staticMethod(a, b)
16+
}

test/Interop/Cxx/class/method/methods.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,20 @@ CxxMethodTestSuite.test("(Int) -> NonTrivialInWrapper") {
5252
expectEqual(42, instance.constPassThroughAsWrapper(42).value)
5353
}
5454

55+
CxxMethodTestSuite.test("Constructor with ref params") {
56+
let a = CInt(42)
57+
let b = CInt(11)
58+
var instance = ReferenceParams(a, b)
59+
60+
expectEqual(42, instance.a)
61+
expectEqual(11, instance.b)
62+
}
63+
64+
// Just make sure we don't crash
65+
CxxMethodTestSuite.test("Static method with ref params") {
66+
let a = CInt(42)
67+
let b = CInt(11)
68+
ReferenceParams.staticMethod(a, b)
69+
}
70+
5571
runAllTests()

0 commit comments

Comments
 (0)