|
27 | 27 | #include "swift/AST/TypeVisitor.h"
|
28 | 28 | #include "swift/ClangImporter/ClangImporter.h"
|
29 | 29 | #include "swift/IRGen/IRABIDetailsProvider.h"
|
| 30 | +#include "clang/AST/ASTContext.h" |
| 31 | +#include "clang/AST/DeclTemplate.h" |
| 32 | +#include "clang/AST/NestedNameSpecifier.h" |
30 | 33 | #include "llvm/ADT/STLExtras.h"
|
31 | 34 |
|
32 | 35 | using namespace swift;
|
@@ -90,6 +93,74 @@ struct CFunctionSignatureTypePrinterModifierDelegate {
|
90 | 93 | mapValueTypeUseKind = None;
|
91 | 94 | };
|
92 | 95 |
|
| 96 | +class ClangTypeHandler { |
| 97 | +public: |
| 98 | + ClangTypeHandler(const clang::Decl *typeDecl) : typeDecl(typeDecl) {} |
| 99 | + |
| 100 | + bool isRepresentable() const { |
| 101 | + // We can only return trivial types, or |
| 102 | + // types that can be moved or copied. |
| 103 | + if (auto *record = dyn_cast<clang::CXXRecordDecl>(typeDecl)) { |
| 104 | + return record->isTrivial() || record->hasMoveConstructor() || |
| 105 | + record->hasCopyConstructorWithConstParam(); |
| 106 | + } |
| 107 | + return false; |
| 108 | + } |
| 109 | + |
| 110 | + void printTypeName(raw_ostream &os) const { |
| 111 | + auto &clangCtx = typeDecl->getASTContext(); |
| 112 | + clang::PrintingPolicy pp(clangCtx.getLangOpts()); |
| 113 | + const auto *NS = clang::NestedNameSpecifier::getRequiredQualification( |
| 114 | + clangCtx, clangCtx.getTranslationUnitDecl(), |
| 115 | + typeDecl->getLexicalDeclContext()); |
| 116 | + if (NS) |
| 117 | + NS->print(os, pp); |
| 118 | + assert(cast<clang::NamedDecl>(typeDecl)->getDeclName().isIdentifier()); |
| 119 | + os << cast<clang::NamedDecl>(typeDecl)->getName(); |
| 120 | + if (auto *ctd = |
| 121 | + dyn_cast<clang::ClassTemplateSpecializationDecl>(typeDecl)) { |
| 122 | + if (ctd->getTemplateArgs().size()) { |
| 123 | + os << '<'; |
| 124 | + llvm::interleaveComma(ctd->getTemplateArgs().asArray(), os, |
| 125 | + [&](const clang::TemplateArgument &arg) { |
| 126 | + arg.print(pp, os, /*IncludeType=*/true); |
| 127 | + }); |
| 128 | + os << '>'; |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + void printReturnScaffold(raw_ostream &os, |
| 134 | + llvm::function_ref<void(StringRef)> bodyOfReturn) { |
| 135 | + std::string fullQualifiedType; |
| 136 | + std::string typeName; |
| 137 | + { |
| 138 | + llvm::raw_string_ostream typeNameOS(fullQualifiedType); |
| 139 | + printTypeName(typeNameOS); |
| 140 | + llvm::raw_string_ostream unqualTypeNameOS(typeName); |
| 141 | + unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName(); |
| 142 | + } |
| 143 | + os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof(" |
| 144 | + << fullQualifiedType << ")];\n"; |
| 145 | + os << "auto * _Nonnull storageObjectPtr = reinterpret_cast<" |
| 146 | + << fullQualifiedType << " *>(storage);\n"; |
| 147 | + bodyOfReturn("storage"); |
| 148 | + os << ";\n"; |
| 149 | + auto *cxxRecord = cast<clang::CXXRecordDecl>(typeDecl); |
| 150 | + if (cxxRecord->isTrivial()) { |
| 151 | + // Trivial object can be just copied and not destroyed. |
| 152 | + os << "return *storageObjectPtr;\n"; |
| 153 | + return; |
| 154 | + } |
| 155 | + os << fullQualifiedType << " result(std::move(*storageObjectPtr));\n"; |
| 156 | + os << "storageObjectPtr->~" << typeName << "();\n"; |
| 157 | + os << "return result;\n"; |
| 158 | + } |
| 159 | + |
| 160 | +private: |
| 161 | + const clang::Decl *typeDecl; |
| 162 | +}; |
| 163 | + |
93 | 164 | // Prints types in the C function signature that corresponds to the
|
94 | 165 | // native Swift function/method.
|
95 | 166 | class CFunctionSignatureTypePrinter
|
@@ -235,6 +306,14 @@ class CFunctionSignatureTypePrinter
|
235 | 306 | if (languageMode != OutputLanguageMode::Cxx)
|
236 | 307 | return ClangRepresentation::unsupported;
|
237 | 308 |
|
| 309 | + if (decl->hasClangNode()) { |
| 310 | + ClangTypeHandler handler(decl->getClangDecl()); |
| 311 | + if (!handler.isRepresentable()) |
| 312 | + return ClangRepresentation::unsupported; |
| 313 | + handler.printTypeName(os); |
| 314 | + return ClangRepresentation::representable; |
| 315 | + } |
| 316 | + |
238 | 317 | // FIXME: Handle optional structures.
|
239 | 318 | if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
|
240 | 319 | if (!isInOutParam) {
|
@@ -938,24 +1017,31 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
938 | 1017 | return;
|
939 | 1018 | }
|
940 | 1019 | if (auto *decl = resultTy->getNominalOrBoundGenericNominal()) {
|
| 1020 | + auto valueTypeReturnThunker = [&](StringRef resultPointerName) { |
| 1021 | + if (auto directResultType = signature.getDirectResultType()) { |
| 1022 | + std::string typeEncoding = |
| 1023 | + encodeTypeInfo(*directResultType, moduleContext, typeMapping); |
| 1024 | + os << cxx_synthesis::getCxxImplNamespaceName() |
| 1025 | + << "::swift_interop_returnDirect_" << typeEncoding << '(' |
| 1026 | + << resultPointerName << ", "; |
| 1027 | + printCallToCFunc(None); |
| 1028 | + os << ')'; |
| 1029 | + } else { |
| 1030 | + printCallToCFunc(/*firstParam=*/resultPointerName); |
| 1031 | + } |
| 1032 | + }; |
| 1033 | + if (decl->hasClangNode()) { |
| 1034 | + ClangTypeHandler handler(decl->getClangDecl()); |
| 1035 | + assert(handler.isRepresentable()); |
| 1036 | + handler.printReturnScaffold(os, valueTypeReturnThunker); |
| 1037 | + return; |
| 1038 | + } |
941 | 1039 | ClangValueTypePrinter valueTypePrinter(os, cPrologueOS, interopContext);
|
942 | 1040 |
|
943 | 1041 | valueTypePrinter.printValueTypeReturnScaffold(
|
944 | 1042 | decl, moduleContext,
|
945 | 1043 | [&]() { printTypeImplTypeSpecifier(resultTy, moduleContext); },
|
946 |
| - [&](StringRef resultPointerName) { |
947 |
| - if (auto directResultType = signature.getDirectResultType()) { |
948 |
| - std::string typeEncoding = |
949 |
| - encodeTypeInfo(*directResultType, moduleContext, typeMapping); |
950 |
| - os << cxx_synthesis::getCxxImplNamespaceName() |
951 |
| - << "::swift_interop_returnDirect_" << typeEncoding << '(' |
952 |
| - << resultPointerName << ", "; |
953 |
| - printCallToCFunc(None); |
954 |
| - os << ')'; |
955 |
| - } else { |
956 |
| - printCallToCFunc(/*firstParam=*/resultPointerName); |
957 |
| - } |
958 |
| - }); |
| 1044 | + valueTypeReturnThunker); |
959 | 1045 | return;
|
960 | 1046 | }
|
961 | 1047 | }
|
|
0 commit comments