Skip to content

Commit 036361d

Browse files
committed
[cxx-interop] Add SIL function representation cxx_method; Support extending C++ types.
There are three major changes here: 1. The addition of "SILFunctionTypeRepresentation::CXXMethod". 2. C++ methods are imported with their members *last*. Then the arguments are switched when emitting the IR for an application of the function. 3. Clang decls are now marked as foreign witnesses. These are all steps towards being able to have C++ protocol conformance.
1 parent 2928459 commit 036361d

37 files changed

+370
-102
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,8 @@ Types
591591
FUNCTION-KIND ::= 'B' // objc block function type
592592
FUNCTION-KIND ::= 'zB' C-TYPE // objc block type with non-canonical C type
593593
FUNCTION-KIND ::= 'L' // objc block function type with canonical C type (escaping) (DWARF only; otherwise use 'B' or 'zB' C-TYPE)
594-
FUNCTION-KIND ::= 'C' // C function pointer type
595-
FUNCTION-KIND ::= 'zC' C-TYPE // C function pointer type with with non-canonical C type
594+
FUNCTION-KIND ::= 'C' // C function pointer / C++ method type
595+
FUNCTION-KIND ::= 'zC' C-TYPE // C function pointer / C++ method type with with non-canonical C type
596596
FUNCTION-KIND ::= 'A' // @auto_closure function type (escaping)
597597
FUNCTION-KIND ::= 'E' // function type (noescape)
598598

include/swift/AST/ExtInfo.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ enum class SILFunctionTypeRepresentation : uint8_t {
167167

168168
/// A closure invocation function that has not been bound to a context.
169169
Closure,
170+
171+
/// A C++ method that takes a "this" argument (not a static C++ method or
172+
/// constructor). Except for
173+
/// handling the "this" argument, has the same behavior as "CFunctionPointer".
174+
CXXMethod,
170175
};
171176

172177
/// Returns true if the function with this convention doesn't carry a context.
@@ -196,6 +201,7 @@ isThinRepresentation(SILFunctionTypeRepresentation rep) {
196201
case SILFunctionTypeRepresentation::WitnessMethod:
197202
case SILFunctionTypeRepresentation::CFunctionPointer:
198203
case SILFunctionTypeRepresentation::Closure:
204+
case SILFunctionTypeRepresentation::CXXMethod:
199205
return true;
200206
}
201207
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
@@ -232,6 +238,7 @@ convertRepresentation(SILFunctionTypeRepresentation rep) {
232238
return {FunctionTypeRepresentation::Block};
233239
case SILFunctionTypeRepresentation::Thin:
234240
return {FunctionTypeRepresentation::Thin};
241+
case SILFunctionTypeRepresentation::CXXMethod:
235242
case SILFunctionTypeRepresentation::CFunctionPointer:
236243
return {FunctionTypeRepresentation::CFunctionPointer};
237244
case SILFunctionTypeRepresentation::Method:
@@ -252,6 +259,7 @@ constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
252259
case SILFunctionTypeRepresentation::CFunctionPointer:
253260
case SILFunctionTypeRepresentation::Block:
254261
case SILFunctionTypeRepresentation::Closure:
262+
case SILFunctionTypeRepresentation::CXXMethod:
255263
return false;
256264
case SILFunctionTypeRepresentation::ObjCMethod:
257265
case SILFunctionTypeRepresentation::Method:
@@ -269,6 +277,7 @@ template <typename Repr> constexpr bool shouldStoreClangType(Repr repr) {
269277
switch (static_cast<SILFunctionTypeRepresentation>(repr)) {
270278
case SILFunctionTypeRepresentation::CFunctionPointer:
271279
case SILFunctionTypeRepresentation::Block:
280+
case SILFunctionTypeRepresentation::CXXMethod:
272281
return true;
273282
case SILFunctionTypeRepresentation::ObjCMethod:
274283
case SILFunctionTypeRepresentation::Thick:
@@ -392,6 +401,7 @@ class ASTExtInfoBuilder {
392401
case SILFunctionTypeRepresentation::ObjCMethod:
393402
case SILFunctionTypeRepresentation::Method:
394403
case SILFunctionTypeRepresentation::WitnessMethod:
404+
case SILFunctionTypeRepresentation::CXXMethod:
395405
return true;
396406
}
397407
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
@@ -618,6 +628,7 @@ SILFunctionLanguage getSILFunctionLanguage(SILFunctionTypeRepresentation rep) {
618628
case SILFunctionTypeRepresentation::ObjCMethod:
619629
case SILFunctionTypeRepresentation::CFunctionPointer:
620630
case SILFunctionTypeRepresentation::Block:
631+
case SILFunctionTypeRepresentation::CXXMethod:
621632
return SILFunctionLanguage::C;
622633
case SILFunctionTypeRepresentation::Thick:
623634
case SILFunctionTypeRepresentation::Thin:
@@ -750,6 +761,7 @@ class SILExtInfoBuilder {
750761
case Representation::ObjCMethod:
751762
case Representation::Method:
752763
case Representation::WitnessMethod:
764+
case SILFunctionTypeRepresentation::CXXMethod:
753765
return true;
754766
}
755767
llvm_unreachable("Unhandled Representation in switch.");
@@ -767,6 +779,7 @@ class SILExtInfoBuilder {
767779
case Representation::Method:
768780
case Representation::WitnessMethod:
769781
case Representation::Closure:
782+
case SILFunctionTypeRepresentation::CXXMethod:
770783
return false;
771784
}
772785
llvm_unreachable("Unhandled Representation in switch.");

include/swift/SIL/ApplySite.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ class ApplySite {
237237
bool isCalleeThin() const {
238238
switch (getSubstCalleeType()->getRepresentation()) {
239239
case SILFunctionTypeRepresentation::CFunctionPointer:
240+
case SILFunctionTypeRepresentation::CXXMethod:
240241
case SILFunctionTypeRepresentation::Thin:
241242
case SILFunctionTypeRepresentation::Method:
242243
case SILFunctionTypeRepresentation::ObjCMethod:

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ getSILFunctionTypeRepresentationString(SILFunctionType::Representation value) {
129129
case SILFunctionType::Representation::Thick: return "thick";
130130
case SILFunctionType::Representation::Block: return "block";
131131
case SILFunctionType::Representation::CFunctionPointer: return "c";
132+
case SILFunctionType::Representation::CXXMethod:
133+
return "cxx_method";
132134
case SILFunctionType::Representation::Thin: return "thin";
133135
case SILFunctionType::Representation::Method: return "method";
134136
case SILFunctionType::Representation::ObjCMethod: return "objc_method";

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,7 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
18281828
OpArgs.push_back('B');
18291829
appendClangTypeToVec(OpArgs);
18301830
break;
1831+
case SILFunctionTypeRepresentation::CXXMethod:
18311832
case SILFunctionTypeRepresentation::CFunctionPointer:
18321833
if (!mangleClangType) {
18331834
OpArgs.push_back('C');

lib/AST/ASTPrinter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4885,6 +4885,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
48854885
case SILFunctionType::Representation::Method:
48864886
Printer << "method";
48874887
break;
4888+
case SILFunctionType::Representation::CXXMethod:
4889+
Printer << "cxx_method";
4890+
break;
48884891
case SILFunctionType::Representation::ObjCMethod:
48894892
Printer << "objc_method";
48904893
break;
@@ -4963,6 +4966,9 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
49634966
case SILFunctionType::Representation::Method:
49644967
Printer << "method";
49654968
break;
4969+
case SILFunctionType::Representation::CXXMethod:
4970+
Printer << "cxx_method";
4971+
break;
49664972
case SILFunctionType::Representation::ObjCMethod:
49674973
Printer << "objc_method";
49684974
break;

lib/AST/ClangTypeConverter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ const clang::Type *ClangTypeConverter::getFunctionType(
212212
return nullptr;
213213

214214
switch (repr) {
215+
case SILFunctionType::Representation::CXXMethod:
215216
case SILFunctionType::Representation::CFunctionPointer:
216217
return ClangASTContext.getPointerType(fn).getTypePtr();
217218
case SILFunctionType::Representation::Block:

lib/AST/ExtInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Optional<UnexpectedClangTypeError> UnexpectedClangTypeError::checkClangType(
6868
#else
6969
bool isBlock = true;
7070
switch (silRep) {
71+
case SILFunctionTypeRepresentation::CXXMethod:
7172
case SILFunctionTypeRepresentation::CFunctionPointer:
7273
isBlock = false;
7374
LLVM_FALLTHROUGH;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,18 +4085,20 @@ namespace {
40854085
templateParams);
40864086

40874087
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
4088+
// Subscripts and call operators are imported as normal methods.
4089+
bool staticOperator = mdecl->isOverloadedOperator() &&
4090+
mdecl->getOverloadedOperator() != clang::OO_Call &&
4091+
mdecl->getOverloadedOperator() != clang::OO_Subscript;
40884092
if (mdecl->isStatic() ||
40894093
// C++ operators that are implemented as non-static member
40904094
// functions get imported into Swift as static member functions
40914095
// that use an additional parameter for the left-hand side operand
40924096
// instead of the receiver object.
4093-
(mdecl->getDeclName().getNameKind() ==
4094-
clang::DeclarationName::CXXOperatorName &&
4095-
isImportedAsStatic(mdecl->getOverloadedOperator()))) {
4097+
staticOperator) {
40964098
selfIdx = None;
40974099
} else {
4098-
selfIdx = 0;
4099-
// Don't import members of a class decl as mutating.
4100+
// Swift imports the "self" param last, even for clang functions.
4101+
selfIdx = bodyParams ? bodyParams->size() : 0;
41004102
// If the method is imported as mutating, this implicitly makes the
41014103
// parameter indirect.
41024104
selfIsInOut =

lib/ClangImporter/ImportType.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1897,7 +1897,11 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
18971897
// imported into Swift as static methods that have an additional
18981898
// parameter for the left-hand side operand instead of the receiver object.
18991899
if (auto CMD = dyn_cast<clang::CXXMethodDecl>(clangDecl)) {
1900-
if (clangDecl->isOverloadedOperator() && isImportedAsStatic(clangDecl->getOverloadedOperator())) {
1900+
// Subscripts and call operators are imported as normal methods.
1901+
bool staticOperator = clangDecl->isOverloadedOperator() &&
1902+
clangDecl->getOverloadedOperator() != clang::OO_Call &&
1903+
clangDecl->getOverloadedOperator() != clang::OO_Subscript;
1904+
if (staticOperator) {
19011905
auto param = new (SwiftContext)
19021906
ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
19031907
SwiftContext.getIdentifier("lhs"), dc);

lib/IRGen/Callee.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ namespace irgen {
462462
/// Given that this callee is a block, return the block pointer.
463463
llvm::Value *getBlockObject() const;
464464

465+
/// Given that this callee is a C++ method, return the self argument.
466+
llvm::Value *getCXXMethodSelf() const;
467+
465468
/// Given that this callee is an ObjC method, return the receiver
466469
/// argument. This might not be 'self' anymore.
467470
llvm::Value *getObjCMethodReceiver() const;

lib/IRGen/GenCall.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ llvm::CallingConv::ID irgen::expandCallingConv(IRGenModule &IGM,
293293
switch (convention) {
294294
case SILFunctionTypeRepresentation::CFunctionPointer:
295295
case SILFunctionTypeRepresentation::ObjCMethod:
296+
case SILFunctionTypeRepresentation::CXXMethod:
296297
case SILFunctionTypeRepresentation::Block:
297298
return llvm::CallingConv::C;
298299

@@ -1326,6 +1327,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
13261327
paramTys.push_back(clangCtx.VoidPtrTy);
13271328
break;
13281329

1330+
case SILFunctionTypeRepresentation::CXXMethod:
13291331
case SILFunctionTypeRepresentation::CFunctionPointer:
13301332
// No implicit arguments.
13311333
break;
@@ -1642,6 +1644,7 @@ void SignatureExpansion::expandParameters() {
16421644
case SILFunctionType::Representation::Method:
16431645
case SILFunctionType::Representation::WitnessMethod:
16441646
case SILFunctionType::Representation::ObjCMethod:
1647+
case SILFunctionType::Representation::CXXMethod:
16451648
case SILFunctionType::Representation::Thin:
16461649
case SILFunctionType::Representation::Closure:
16471650
return FnType->hasErrorResult();
@@ -1809,6 +1812,7 @@ void SignatureExpansion::expandAsyncEntryType() {
18091812
case SILFunctionType::Representation::ObjCMethod:
18101813
case SILFunctionType::Representation::Thin:
18111814
case SILFunctionType::Representation::Closure:
1815+
case SILFunctionType::Representation::CXXMethod:
18121816
return false;
18131817

18141818
case SILFunctionType::Representation::Thick:
@@ -2203,7 +2207,20 @@ class SyncCallEmission final : public CallEmission {
22032207
break;
22042208

22052209
case SILFunctionTypeRepresentation::Block:
2206-
adjusted.add(getCallee().getBlockObject());
2210+
case SILFunctionTypeRepresentation::CXXMethod:
2211+
if (getCallee().getRepresentation() == SILFunctionTypeRepresentation::Block) {
2212+
adjusted.add(getCallee().getBlockObject());
2213+
} else {
2214+
auto selfParam = origCalleeType->getSelfParameter();
2215+
auto *arg = getCallee().getCXXMethodSelf();
2216+
// We might need to fix the level of indirection for foreign reference types.
2217+
if (selfParam.getInterfaceType().isForeignReferenceType() &&
2218+
isIndirectFormalParameter(selfParam.getConvention()))
2219+
arg = IGF.Builder.CreateLoad(arg, IGF.IGM.getPointerAlignment());
2220+
2221+
adjusted.add(arg);
2222+
}
2223+
22072224
LLVM_FALLTHROUGH;
22082225

22092226
case SILFunctionTypeRepresentation::CFunctionPointer:
@@ -2462,14 +2479,9 @@ class AsyncCallEmission final : public CallEmission {
24622479
// Translate the formal arguments and handle any special arguments.
24632480
switch (getCallee().getRepresentation()) {
24642481
case SILFunctionTypeRepresentation::ObjCMethod:
2465-
assert(false && "Should not reach this");
2466-
break;
2467-
24682482
case SILFunctionTypeRepresentation::Block:
2469-
assert(false && "Should not reach this");
2470-
break;
2471-
24722483
case SILFunctionTypeRepresentation::CFunctionPointer:
2484+
case SILFunctionTypeRepresentation::CXXMethod:
24732485
assert(false && "Should not reach this");
24742486
break;
24752487

@@ -3148,6 +3160,9 @@ Callee::Callee(CalleeInfo &&info, const FunctionPointer &fn,
31483160
case SILFunctionTypeRepresentation::CFunctionPointer:
31493161
assert(!FirstData && !SecondData);
31503162
break;
3163+
case SILFunctionTypeRepresentation::CXXMethod:
3164+
assert(FirstData && !SecondData);
3165+
break;
31513166
}
31523167
#endif
31533168

@@ -3160,6 +3175,7 @@ llvm::Value *Callee::getSwiftContext() const {
31603175
case SILFunctionTypeRepresentation::CFunctionPointer:
31613176
case SILFunctionTypeRepresentation::Thin:
31623177
case SILFunctionTypeRepresentation::Closure:
3178+
case SILFunctionTypeRepresentation::CXXMethod:
31633179
return nullptr;
31643180

31653181
case SILFunctionTypeRepresentation::WitnessMethod:
@@ -3182,6 +3198,14 @@ llvm::Value *Callee::getBlockObject() const {
31823198
return FirstData;
31833199
}
31843200

3201+
llvm::Value *Callee::getCXXMethodSelf() const {
3202+
assert(Info.OrigFnType->getRepresentation() ==
3203+
SILFunctionTypeRepresentation::CXXMethod &&
3204+
"not a C++ method");
3205+
assert(FirstData && "no self object set on callee");
3206+
return FirstData;
3207+
}
3208+
31853209
llvm::Value *Callee::getObjCMethodReceiver() const {
31863210
assert(Info.OrigFnType->getRepresentation() ==
31873211
SILFunctionTypeRepresentation::ObjCMethod &&
@@ -3496,6 +3520,7 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
34963520
// The index of the first "physical" parameter from paramTys/FI that
34973521
// corresponds to a logical parameter from params.
34983522
unsigned firstParam = 0;
3523+
unsigned paramEnd = FI.arg_size();
34993524

35003525
// Handle the ObjC prefix.
35013526
if (callee.getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) {
@@ -3509,14 +3534,19 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
35093534
== SILFunctionTypeRepresentation::Block) {
35103535
// Ignore the physical block-object parameter.
35113536
firstParam += 1;
3512-
// Or the indirect result parameter.
3513-
} else if (fnType->getNumResults() > 0 &&
3537+
} else if (callee.getRepresentation() ==
3538+
SILFunctionTypeRepresentation::CXXMethod) {
3539+
// Skip the "self" param.
3540+
paramEnd--;
3541+
}
3542+
3543+
if (fnType->getNumResults() > 0 &&
35143544
fnType->getSingleResult().isFormalIndirect()) {
35153545
// Ignore the indirect result parameter.
35163546
firstParam += 1;
35173547
}
35183548

3519-
for (unsigned i = firstParam, e = FI.arg_size(); i != e; ++i) {
3549+
for (unsigned i = firstParam; i != paramEnd; ++i) {
35203550
auto clangParamTy = FI.arg_begin()[i].type;
35213551
auto &AI = FI.arg_begin()[i].info;
35223552

lib/IRGen/GenFunc.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ const TypeInfo *TypeConverter::convertFunctionType(SILFunctionType *T) {
528528

529529
case SILFunctionType::Representation::Thin:
530530
case SILFunctionType::Representation::Method:
531+
case SILFunctionType::Representation::CXXMethod:
531532
case SILFunctionType::Representation::WitnessMethod:
532533
case SILFunctionType::Representation::ObjCMethod:
533534
case SILFunctionType::Representation::CFunctionPointer:
@@ -583,6 +584,7 @@ getFuncSignatureInfoForLowered(IRGenModule &IGM, CanSILFunctionType type) {
583584
case SILFunctionType::Representation::Thin:
584585
case SILFunctionType::Representation::CFunctionPointer:
585586
case SILFunctionType::Representation::Method:
587+
case SILFunctionType::Representation::CXXMethod:
586588
case SILFunctionType::Representation::WitnessMethod:
587589
case SILFunctionType::Representation::ObjCMethod:
588590
case SILFunctionType::Representation::Closure:

lib/IRGen/GenPointerAuth.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ static const PointerAuthSchema &getFunctionPointerSchema(IRGenModule &IGM,
190190
CanSILFunctionType fnType) {
191191
auto &options = IGM.getOptions().PointerAuth;
192192
switch (fnType->getRepresentation()) {
193+
case SILFunctionTypeRepresentation::CXXMethod:
193194
case SILFunctionTypeRepresentation::CFunctionPointer:
194195
return options.FunctionPointers;
195196

@@ -583,6 +584,7 @@ PointerAuthEntity::getTypeDiscriminator(IRGenModule &IGM) const {
583584
}
584585

585586
// C function pointers are undiscriminated.
587+
case SILFunctionTypeRepresentation::CXXMethod:
586588
case SILFunctionTypeRepresentation::CFunctionPointer:
587589
return llvm::ConstantInt::get(IGM.Int64Ty, 0);
588590

lib/IRGen/GenProto.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,7 @@ bool irgen::hasPolymorphicParameters(CanSILFunctionType ty) {
23212321

23222322
case SILFunctionTypeRepresentation::CFunctionPointer:
23232323
case SILFunctionTypeRepresentation::ObjCMethod:
2324+
case SILFunctionTypeRepresentation::CXXMethod:
23242325
// May be polymorphic at the SIL level, but no type metadata is actually
23252326
// passed.
23262327
return false;

lib/IRGen/IRGenSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,6 +2930,7 @@ Callee LoweredValue::getCallee(IRGenFunction &IGF,
29302930
return getBlockPointerCallee(IGF, functionValue, std::move(calleeInfo));
29312931

29322932
case SILFunctionType::Representation::ObjCMethod:
2933+
case SILFunctionType::Representation::CXXMethod:
29332934
case SILFunctionType::Representation::Thick:
29342935
llvm_unreachable("unexpected function with singleton representation");
29352936

@@ -2991,6 +2992,7 @@ static std::unique_ptr<CallEmission> getCallEmissionForLoweredValue(
29912992
}
29922993

29932994
case SILFunctionType::Representation::ObjCMethod:
2995+
case SILFunctionType::Representation::CXXMethod:
29942996
case SILFunctionType::Representation::Thick:
29952997
case SILFunctionType::Representation::Block:
29962998
case SILFunctionType::Representation::Thin:
@@ -3363,6 +3365,7 @@ getPartialApplicationFunction(IRGenSILFunction &IGF, SILValue v,
33633365
case SILFunctionTypeRepresentation::CFunctionPointer:
33643366
case SILFunctionTypeRepresentation::Block:
33653367
case SILFunctionTypeRepresentation::ObjCMethod:
3368+
case SILFunctionTypeRepresentation::CXXMethod:
33663369
llvm_unreachable("partial_apply of foreign functions not implemented");
33673370

33683371
case SILFunctionTypeRepresentation::WitnessMethod:

0 commit comments

Comments
 (0)