mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[cxx-interop] Support ObjC protocols in C++ interop
This patch introduces handling of ObjC protocols similar to how ObjC classes work. Since this only works in ObjC++, all declarations containing ObjC protocols will be protected by the __OBJC__ macro. This patch results in some `_bridgeObjC` methods being exposed, we might end up hiding those in the future, but there is no harm having them in the interop header for the interim period. rdar://136757913
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "swift/AST/SwiftNameTranslation.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/AST/TypeVisitor.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "swift/ClangImporter/ClangImporter.h"
|
||||
#include "swift/IRGen/IRABIDetailsProvider.h"
|
||||
@@ -265,6 +266,22 @@ public:
|
||||
return ClangRepresentation::unsupported;
|
||||
}
|
||||
|
||||
ClangRepresentation
|
||||
visitExistentialType(ExistentialType *ty,
|
||||
std::optional<OptionalTypeKind> optionalKind,
|
||||
bool isInOutParam) {
|
||||
if (ty->isObjCExistentialType()) {
|
||||
declPrinter.withOutputStream(os).print(ty, optionalKind);
|
||||
if (isInOutParam) {
|
||||
os << " __strong";
|
||||
printInoutTypeModifier();
|
||||
}
|
||||
return ClangRepresentation::objcxxonly;
|
||||
}
|
||||
|
||||
return visitPart(ty->getConstraintType(), optionalKind, isInOutParam);
|
||||
}
|
||||
|
||||
ClangRepresentation
|
||||
visitTupleType(TupleType *TT, std::optional<OptionalTypeKind> optionalKind,
|
||||
bool isInOutParam) {
|
||||
@@ -592,6 +609,14 @@ static std::string encodeTypeInfo(const T &abiTypeInfo,
|
||||
return std::move(typeEncodingOS.str());
|
||||
}
|
||||
|
||||
static bool isOptionalObjCExistential(Type ty) {
|
||||
if (auto obj = ty->getOptionalObjectType()) {
|
||||
if (obj->isObjCExistentialType())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns false if the given direct type is not yet supported because
|
||||
// of its ABI.
|
||||
template <class T>
|
||||
@@ -631,7 +656,8 @@ static bool printDirectReturnOrParamCType(
|
||||
// FIXME: is this "prettyfying" logic sound for multiple return values?
|
||||
if (isKnownCType(valueType, typeMapping) ||
|
||||
(Count == 1 && lastOffset.isZero() && !valueType->hasTypeParameter() &&
|
||||
valueType->isAnyClassReferenceType())) {
|
||||
(valueType->isAnyClassReferenceType() ||
|
||||
isOptionalObjCExistential(valueType)))) {
|
||||
prettifiedValuePrinter();
|
||||
return true;
|
||||
}
|
||||
@@ -964,8 +990,12 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
// Emit 'void' in an empty parameter list for C function declarations.
|
||||
functionSignatureOS << "void";
|
||||
functionSignatureOS << ')';
|
||||
if (!resultingRepresentation.isUnsupported())
|
||||
if (!resultingRepresentation.isUnsupported()) {
|
||||
if (resultingRepresentation.isObjCxxOnly())
|
||||
os << "#if defined(__OBJC__)\n";
|
||||
os << "SWIFT_EXTERN ";
|
||||
os << functionSignatureOS.str();
|
||||
}
|
||||
return resultingRepresentation;
|
||||
}
|
||||
|
||||
@@ -1010,8 +1040,12 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
ClangSyntaxPrinter(functionSignatureOS)
|
||||
.printSymbolUSRAttribute(
|
||||
modifiers.symbolUSROverride ? modifiers.symbolUSROverride : FD);
|
||||
if (!resultingRepresentation.isUnsupported())
|
||||
if (!resultingRepresentation.isUnsupported()) {
|
||||
if (resultingRepresentation.isObjCxxOnly() &&
|
||||
outputLang == OutputLanguageMode::Cxx)
|
||||
os << "#if defined(__OBJC__)\n";
|
||||
os << functionSignatureOS.str();
|
||||
}
|
||||
return resultingRepresentation;
|
||||
}
|
||||
|
||||
@@ -1043,6 +1077,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->isObjCExistentialType() || isOptionalObjCExistential(type)) {
|
||||
if (isInOut)
|
||||
os << '&';
|
||||
namePrinter();
|
||||
return;
|
||||
}
|
||||
if (auto *classDecl = type->getClassOrBoundGenericClass()) {
|
||||
if (classDecl->hasClangNode()) {
|
||||
if (isInOut)
|
||||
@@ -1423,7 +1463,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
||||
[&]() { printCallToCFunc(/*additionalParam=*/std::nullopt); });
|
||||
return;
|
||||
}
|
||||
if (auto *decl = resultTy->getNominalOrBoundGenericNominal()) {
|
||||
if (auto *decl = resultTy->getNominalOrBoundGenericNominal();
|
||||
decl && !resultTy->isObjCExistentialType() &&
|
||||
!isOptionalObjCExistential(resultTy)) {
|
||||
auto valueTypeReturnThunker = [&](StringRef resultPointerName) {
|
||||
if (auto directResultType = signature.getDirectResultType()) {
|
||||
std::string typeEncoding =
|
||||
@@ -1458,13 +1500,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
||||
auto nonOptResultType = resultTy->getOptionalObjectType();
|
||||
if (!nonOptResultType)
|
||||
nonOptResultType = resultTy;
|
||||
if (auto *classDecl = nonOptResultType->getClassOrBoundGenericClass()) {
|
||||
assert(classDecl->hasClangNode());
|
||||
assert(isa<clang::ObjCContainerDecl>(classDecl->getClangDecl()));
|
||||
if (auto *classDecl = nonOptResultType->getClassOrBoundGenericClass();
|
||||
classDecl || nonOptResultType->isObjCExistentialType()) {
|
||||
assert(!classDecl || classDecl->hasClangNode());
|
||||
assert(!classDecl ||
|
||||
isa<clang::ObjCContainerDecl>(classDecl->getClangDecl()));
|
||||
os << "return (__bridge_transfer ";
|
||||
ClangSyntaxPrinter(os).printIdentifier(
|
||||
cast<clang::NamedDecl>(classDecl->getClangDecl())->getName());
|
||||
os << " *)(__bridge void *)";
|
||||
declPrinter.withOutputStream(os).print(nonOptResultType);
|
||||
os << ")(__bridge void *)";
|
||||
printCallToCFunc(/*additionalParam=*/std::nullopt);
|
||||
os << ";\n";
|
||||
return;
|
||||
@@ -1575,6 +1618,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
|
||||
declAndTypePrinter.printAvailability(os, FD);
|
||||
if (!isDefinition) {
|
||||
os << ";\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1586,6 +1631,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
|
||||
FD->getInterfaceType()->castTo<AnyFunctionType>(), isStatic,
|
||||
dispatchInfo);
|
||||
os << " }\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
}
|
||||
|
||||
/// Returns true if the given property name like `isEmpty` can be remapped
|
||||
@@ -1648,6 +1695,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
|
||||
declAndTypePrinter.printAvailability(os, accessor->getStorage());
|
||||
if (!isDefinition) {
|
||||
os << ";\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
return;
|
||||
}
|
||||
os << " {\n";
|
||||
@@ -1657,6 +1706,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
|
||||
accessor->getParameters(),
|
||||
/*hasThrows=*/false, nullptr, isStatic, dispatchInfo);
|
||||
os << " }\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
|
||||
@@ -1682,6 +1733,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
|
||||
declAndTypePrinter.printAvailability(os, accessor->getStorage());
|
||||
if (!isDefinition) {
|
||||
os << ";\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
if (multiParam)
|
||||
os << "#endif // #if __cplusplus >= 202302L\n";
|
||||
return;
|
||||
@@ -1693,6 +1746,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
|
||||
accessor->getModuleContext(), resultTy, accessor->getParameters(),
|
||||
/*hasThrows=*/false, nullptr, /*isStatic=*/false, dispatchInfo);
|
||||
os << " }\n";
|
||||
if (result.isObjCxxOnly())
|
||||
os << "#endif\n";
|
||||
if (multiParam)
|
||||
os << "#endif // #if __cplusplus >= 202302L\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user