Skip to content

Commit 9325512

Browse files
authored
Merge pull request #77025 from swiftlang/gaborh/support-objc-protocols
[cxx-interop] Support ObjC protocols in C++ interop
2 parents 4e931e7 + 0e03d34 commit 9325512

File tree

10 files changed

+221
-34
lines changed

10 files changed

+221
-34
lines changed

include/swift/AST/SwiftNameTranslation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ StringRef
6767
getNameForCxx(const ValueDecl *VD,
6868
CustomNamesOnly_t customNamesOnly = objc_translation::Normal);
6969

70-
enum RepresentationKind { Representable, Unsupported };
70+
enum RepresentationKind { Representable, ObjCxxOnly, Unsupported };
7171

7272
enum RepresentationError {
7373
UnrepresentableObjC,

lib/AST/SwiftNameTranslation.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "clang/AST/DeclObjC.h"
2828
#include "llvm/ADT/SmallString.h"
29+
#include <optional>
2930

3031
using namespace swift;
3132

@@ -232,8 +233,11 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
232233
genericSignature = AFD->getGenericSignature();
233234
}
234235
if (const auto *typeDecl = dyn_cast<NominalTypeDecl>(VD)) {
235-
if (isa<ProtocolDecl>(typeDecl))
236+
if (isa<ProtocolDecl>(typeDecl)) {
237+
if (typeDecl->hasClangNode())
238+
return {ObjCxxOnly, std::nullopt};
236239
return {Unsupported, UnrepresentableProtocol};
240+
}
237241
// Swift's consume semantics are not yet supported in C++.
238242
if (!typeDecl->canBeCopyable())
239243
return {Unsupported, UnrepresentableMoveOnly};
@@ -336,7 +340,7 @@ bool swift::cxx_translation::isExposableToCxx(GenericSignature genericSig) {
336340
return false;
337341

338342
auto proto = req.getProtocolDecl();
339-
if (!proto->isMarkerProtocol())
343+
if (!proto->isMarkerProtocol() && !proto->hasClangNode())
340344
return false;
341345
}
342346
}

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ void ClangSyntaxPrinter::printObjCBlock(
229229
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
230230
os << "#if defined(__OBJC__)\n";
231231
bodyPrinter(os);
232-
os << "\n#endif\n";
232+
os << "\n#endif // defined(__OBJC__)\n";
233233
}
234234

235235
void ClangSyntaxPrinter::printSwiftImplQualifier() const {

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "swift/AST/SwiftNameTranslation.h"
3535
#include "swift/AST/TypeCheckRequests.h"
3636
#include "swift/AST/TypeVisitor.h"
37+
#include "swift/AST/Types.h"
3738
#include "swift/Basic/Assertions.h"
3839
#include "swift/IDE/CommentConversion.h"
3940
#include "swift/IRGen/IRABIDetailsProvider.h"
@@ -1046,6 +1047,7 @@ class DeclAndTypePrinter::Implementation
10461047
auto result = methodTy->getResult();
10471048
if (result->isUninhabited())
10481049
return getASTContext().TheEmptyTupleType;
1050+
10491051
return result;
10501052
}
10511053

@@ -1493,8 +1495,6 @@ class DeclAndTypePrinter::Implementation
14931495
StringRef comment = "") {
14941496
std::string cRepresentationString;
14951497
llvm::raw_string_ostream cRepresentationOS(cRepresentationString);
1496-
cRepresentationOS << "SWIFT_EXTERN ";
1497-
14981498
DeclAndTypeClangFunctionPrinter funcPrinter(
14991499
cRepresentationOS, owningPrinter.prologueOS, owningPrinter.typeMapping,
15001500
owningPrinter.interopContext, owningPrinter);
@@ -1528,6 +1528,8 @@ class DeclAndTypePrinter::Implementation
15281528
FD->getName().print(os);
15291529
}
15301530
os << "\n";
1531+
if (representation.isObjCxxOnly())
1532+
os << "#endif\n";
15311533
return representation;
15321534
}
15331535

@@ -1636,6 +1638,8 @@ class DeclAndTypePrinter::Implementation
16361638
/*typeDeclContext=*/nullptr, FD->getModuleContext(), resultTy,
16371639
FD->getParameters(), funcTy->isThrowing(), funcTy);
16381640
os << "}\n";
1641+
if (result.isObjCxxOnly())
1642+
os << "#endif\n";
16391643
}
16401644

16411645
enum class PrintLeadingSpace : bool {
@@ -2982,8 +2986,9 @@ void DeclAndTypePrinter::print(const Decl *D) {
29822986
getImpl().print(D);
29832987
}
29842988

2985-
void DeclAndTypePrinter::print(Type ty) {
2986-
getImpl().print(ty, /*overridingOptionality*/ std::nullopt);
2989+
void DeclAndTypePrinter::print(
2990+
Type ty, std::optional<OptionalTypeKind> overrideOptionalTypeKind) {
2991+
getImpl().print(ty, overrideOptionalTypeKind);
29872992
}
29882993

29892994
void DeclAndTypePrinter::printTypeName(raw_ostream &os, Type ty,

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class DeclAndTypePrinter {
8080
public:
8181
DeclAndTypePrinter(ModuleDecl &mod, raw_ostream &out, raw_ostream &prologueOS,
8282
raw_ostream &outOfLineDefinitionsOS,
83-
DelayedMemberSet &delayed,
83+
const DelayedMemberSet &delayed,
8484
CxxDeclEmissionScope &topLevelEmissionScope,
8585
PrimitiveTypeMapping &typeMapping,
8686
SwiftToClangInteropContext &interopContext,
@@ -103,6 +103,13 @@ class DeclAndTypePrinter {
103103
return *cxxDeclEmissionScope;
104104
}
105105

106+
DeclAndTypePrinter withOutputStream(raw_ostream &s) {
107+
return DeclAndTypePrinter(
108+
M, s, prologueOS, outOfLineDefinitionsOS, objcDelayedMembers,
109+
*cxxDeclEmissionScope, typeMapping, interopContext, minRequiredAccess,
110+
requiresExposedAttribute, exposedModules, outputLang);
111+
}
112+
106113
void setCxxDeclEmissionScope(CxxDeclEmissionScope &scope) {
107114
cxxDeclEmissionScope = &scope;
108115
}
@@ -116,7 +123,8 @@ class DeclAndTypePrinter {
116123
bool isVisible(const ValueDecl *vd) const;
117124

118125
void print(const Decl *D);
119-
void print(Type ty);
126+
void print(Type ty, std::optional<OptionalTypeKind> overrideOptionalTypeKind =
127+
std::nullopt);
120128

121129
/// Prints the name of the type including generic arguments.
122130
void printTypeName(raw_ostream &os, Type ty, const ModuleDecl *moduleContext);

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/AST/SwiftNameTranslation.h"
2828
#include "swift/AST/Type.h"
2929
#include "swift/AST/TypeVisitor.h"
30+
#include "swift/AST/Types.h"
3031
#include "swift/Basic/Assertions.h"
3132
#include "swift/ClangImporter/ClangImporter.h"
3233
#include "swift/IRGen/IRABIDetailsProvider.h"
@@ -265,6 +266,22 @@ class CFunctionSignatureTypePrinter
265266
return ClangRepresentation::unsupported;
266267
}
267268

269+
ClangRepresentation
270+
visitExistentialType(ExistentialType *ty,
271+
std::optional<OptionalTypeKind> optionalKind,
272+
bool isInOutParam) {
273+
if (ty->isObjCExistentialType()) {
274+
declPrinter.withOutputStream(os).print(ty, optionalKind);
275+
if (isInOutParam) {
276+
os << " __strong";
277+
printInoutTypeModifier();
278+
}
279+
return ClangRepresentation::objcxxonly;
280+
}
281+
282+
return visitPart(ty->getConstraintType(), optionalKind, isInOutParam);
283+
}
284+
268285
ClangRepresentation
269286
visitTupleType(TupleType *TT, std::optional<OptionalTypeKind> optionalKind,
270287
bool isInOutParam) {
@@ -592,6 +609,14 @@ static std::string encodeTypeInfo(const T &abiTypeInfo,
592609
return std::move(typeEncodingOS.str());
593610
}
594611

612+
static bool isOptionalObjCExistential(Type ty) {
613+
if (auto obj = ty->getOptionalObjectType()) {
614+
if (obj->isObjCExistentialType())
615+
return true;
616+
}
617+
return false;
618+
}
619+
595620
// Returns false if the given direct type is not yet supported because
596621
// of its ABI.
597622
template <class T>
@@ -631,7 +656,8 @@ static bool printDirectReturnOrParamCType(
631656
// FIXME: is this "prettyfying" logic sound for multiple return values?
632657
if (isKnownCType(valueType, typeMapping) ||
633658
(Count == 1 && lastOffset.isZero() && !valueType->hasTypeParameter() &&
634-
valueType->isAnyClassReferenceType())) {
659+
(valueType->isAnyClassReferenceType() ||
660+
isOptionalObjCExistential(valueType)))) {
635661
prettifiedValuePrinter();
636662
return true;
637663
}
@@ -964,8 +990,12 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
964990
// Emit 'void' in an empty parameter list for C function declarations.
965991
functionSignatureOS << "void";
966992
functionSignatureOS << ')';
967-
if (!resultingRepresentation.isUnsupported())
993+
if (!resultingRepresentation.isUnsupported()) {
994+
if (resultingRepresentation.isObjCxxOnly())
995+
os << "#if defined(__OBJC__)\n";
996+
os << "SWIFT_EXTERN ";
968997
os << functionSignatureOS.str();
998+
}
969999
return resultingRepresentation;
9701000
}
9711001

@@ -1010,8 +1040,12 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
10101040
ClangSyntaxPrinter(functionSignatureOS)
10111041
.printSymbolUSRAttribute(
10121042
modifiers.symbolUSROverride ? modifiers.symbolUSROverride : FD);
1013-
if (!resultingRepresentation.isUnsupported())
1043+
if (!resultingRepresentation.isUnsupported()) {
1044+
if (resultingRepresentation.isObjCxxOnly() &&
1045+
outputLang == OutputLanguageMode::Cxx)
1046+
os << "#if defined(__OBJC__)\n";
10141047
os << functionSignatureOS.str();
1048+
}
10151049
return resultingRepresentation;
10161050
}
10171051

@@ -1043,6 +1077,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
10431077
return;
10441078
}
10451079

1080+
if (type->isObjCExistentialType() || isOptionalObjCExistential(type)) {
1081+
if (isInOut)
1082+
os << '&';
1083+
namePrinter();
1084+
return;
1085+
}
10461086
if (auto *classDecl = type->getClassOrBoundGenericClass()) {
10471087
if (classDecl->hasClangNode()) {
10481088
if (isInOut)
@@ -1423,7 +1463,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
14231463
[&]() { printCallToCFunc(/*additionalParam=*/std::nullopt); });
14241464
return;
14251465
}
1426-
if (auto *decl = resultTy->getNominalOrBoundGenericNominal()) {
1466+
if (auto *decl = resultTy->getNominalOrBoundGenericNominal();
1467+
decl && !resultTy->isObjCExistentialType() &&
1468+
!isOptionalObjCExistential(resultTy)) {
14271469
auto valueTypeReturnThunker = [&](StringRef resultPointerName) {
14281470
if (auto directResultType = signature.getDirectResultType()) {
14291471
std::string typeEncoding =
@@ -1458,13 +1500,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
14581500
auto nonOptResultType = resultTy->getOptionalObjectType();
14591501
if (!nonOptResultType)
14601502
nonOptResultType = resultTy;
1461-
if (auto *classDecl = nonOptResultType->getClassOrBoundGenericClass()) {
1462-
assert(classDecl->hasClangNode());
1463-
assert(isa<clang::ObjCContainerDecl>(classDecl->getClangDecl()));
1503+
if (auto *classDecl = nonOptResultType->getClassOrBoundGenericClass();
1504+
classDecl || nonOptResultType->isObjCExistentialType()) {
1505+
assert(!classDecl || classDecl->hasClangNode());
1506+
assert(!classDecl ||
1507+
isa<clang::ObjCContainerDecl>(classDecl->getClangDecl()));
14641508
os << "return (__bridge_transfer ";
1465-
ClangSyntaxPrinter(os).printIdentifier(
1466-
cast<clang::NamedDecl>(classDecl->getClangDecl())->getName());
1467-
os << " *)(__bridge void *)";
1509+
declPrinter.withOutputStream(os).print(nonOptResultType);
1510+
os << ")(__bridge void *)";
14681511
printCallToCFunc(/*additionalParam=*/std::nullopt);
14691512
os << ";\n";
14701513
return;
@@ -1575,6 +1618,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
15751618
declAndTypePrinter.printAvailability(os, FD);
15761619
if (!isDefinition) {
15771620
os << ";\n";
1621+
if (result.isObjCxxOnly())
1622+
os << "#endif\n";
15781623
return;
15791624
}
15801625

@@ -1586,6 +1631,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
15861631
FD->getInterfaceType()->castTo<AnyFunctionType>(), isStatic,
15871632
dispatchInfo);
15881633
os << " }\n";
1634+
if (result.isObjCxxOnly())
1635+
os << "#endif\n";
15891636
}
15901637

15911638
/// Returns true if the given property name like `isEmpty` can be remapped
@@ -1648,6 +1695,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
16481695
declAndTypePrinter.printAvailability(os, accessor->getStorage());
16491696
if (!isDefinition) {
16501697
os << ";\n";
1698+
if (result.isObjCxxOnly())
1699+
os << "#endif\n";
16511700
return;
16521701
}
16531702
os << " {\n";
@@ -1657,6 +1706,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
16571706
accessor->getParameters(),
16581707
/*hasThrows=*/false, nullptr, isStatic, dispatchInfo);
16591708
os << " }\n";
1709+
if (result.isObjCxxOnly())
1710+
os << "#endif\n";
16601711
}
16611712

16621713
void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
@@ -1682,6 +1733,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
16821733
declAndTypePrinter.printAvailability(os, accessor->getStorage());
16831734
if (!isDefinition) {
16841735
os << ";\n";
1736+
if (result.isObjCxxOnly())
1737+
os << "#endif\n";
16851738
if (multiParam)
16861739
os << "#endif // #if __cplusplus >= 202302L\n";
16871740
return;
@@ -1693,6 +1746,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
16931746
accessor->getModuleContext(), resultTy, accessor->getParameters(),
16941747
/*hasThrows=*/false, nullptr, /*isStatic=*/false, dispatchInfo);
16951748
os << " }\n";
1749+
if (result.isObjCxxOnly())
1750+
os << "#endif\n";
16961751
if (multiParam)
16971752
os << "#endif // #if __cplusplus >= 202302L\n";
16981753
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,22 @@ class SwiftToClangInteropContext;
4242
class DeclAndTypePrinter;
4343

4444
struct ClangRepresentation {
45-
enum Kind { representable, unsupported };
45+
enum Kind { representable, objcxxonly, unsupported };
4646

4747
ClangRepresentation(Kind kind) : kind(kind) {}
4848

4949
/// Returns true if the given Swift node is unsupported in Clang in any
5050
/// language mode.
5151
bool isUnsupported() const { return kind == unsupported; }
5252

53+
/// Returns true if the given Swift node is only supported in
54+
/// Objective C++ mode.
55+
bool isObjCxxOnly() const { return kind == objcxxonly; }
56+
5357
const ClangRepresentation &merge(ClangRepresentation other) {
54-
if (kind != unsupported)
58+
if (other.kind == unsupported)
59+
kind = unsupported;
60+
else if (kind == representable)
5561
kind = other.kind;
5662
return *this;
5763
}

0 commit comments

Comments
 (0)