Skip to content

Commit 6ed6290

Browse files
authored
Merge pull request #61053 from hyp/i/cxx-type-in-generic-ctx
[interop] use C++ value types bridged to Swift in Swift generic context from C++
2 parents a190855 + 0dcb8b5 commit 6ed6290

15 files changed

+231
-40
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#include "swift/AST/Decl.h"
1616
#include "swift/AST/Module.h"
1717
#include "swift/AST/SwiftNameTranslation.h"
18+
#include "clang/AST/ASTContext.h"
19+
#include "clang/AST/DeclTemplate.h"
20+
#include "clang/AST/NestedNameSpecifier.h"
1821

1922
using namespace swift;
2023
using namespace cxx_synthesis;
@@ -80,8 +83,35 @@ bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclTemplateSpecifiers(
8083
return false;
8184
}
8285

86+
void ClangSyntaxPrinter::printNominalClangTypeReference(
87+
const clang::Decl *typeDecl) {
88+
auto &clangCtx = typeDecl->getASTContext();
89+
clang::PrintingPolicy pp(clangCtx.getLangOpts());
90+
const auto *NS = clang::NestedNameSpecifier::getRequiredQualification(
91+
clangCtx, clangCtx.getTranslationUnitDecl(),
92+
typeDecl->getLexicalDeclContext());
93+
if (NS)
94+
NS->print(os, pp);
95+
assert(cast<clang::NamedDecl>(typeDecl)->getDeclName().isIdentifier());
96+
os << cast<clang::NamedDecl>(typeDecl)->getName();
97+
if (auto *ctd = dyn_cast<clang::ClassTemplateSpecializationDecl>(typeDecl)) {
98+
if (ctd->getTemplateArgs().size()) {
99+
os << '<';
100+
llvm::interleaveComma(ctd->getTemplateArgs().asArray(), os,
101+
[&](const clang::TemplateArgument &arg) {
102+
arg.print(pp, os, /*IncludeType=*/true);
103+
});
104+
os << '>';
105+
}
106+
}
107+
}
108+
83109
void ClangSyntaxPrinter::printNominalTypeReference(
84110
const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) {
111+
if (typeDecl->hasClangNode()) {
112+
printNominalClangTypeReference(typeDecl->getClangDecl());
113+
return;
114+
}
85115
printModuleNamespaceQualifiersIfNeeded(typeDecl->getModuleContext(),
86116
moduleContext);
87117
// FIXME: Full qualifiers for nested types?

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class ClangSyntaxPrinter {
9090
void printNominalTypeReference(const NominalTypeDecl *typeDecl,
9191
const ModuleDecl *moduleContext);
9292

93+
/// Print out the C++ record qualifier for the given C++ record.
94+
void printNominalClangTypeReference(const clang::Decl *typeDecl);
95+
9396
/// Print out the C++ class access qualifier for the given Swift type
9497
/// declaration.
9598
///

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class DeclAndTypePrinter {
7272
requiresExposedAttribute(requiresExposedAttribute),
7373
outputLang(outputLang) {}
7474

75+
SwiftToClangInteropContext &getInteropContext() { return interopContext; }
76+
7577
/// Returns true if \p VD should be included in a compatibility header for
7678
/// the options the printer was constructed with.
7779
bool shouldInclude(const ValueDecl *VD);

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "PrimitiveTypeMapping.h"
1919
#include "PrintClangValueType.h"
2020
#include "PrintSwiftToClangCoreScaffold.h"
21+
#include "SwiftToClangInteropContext.h"
2122

2223
#include "swift/AST/ExistentialLayout.h"
2324
#include "swift/AST/Module.h"
@@ -677,8 +678,14 @@ class ModuleWriter {
677678
}
678679
printer.printAdHocCategory(make_range(groupBegin, delayedMembers.end()));
679680
}
681+
680682
// Print any out of line definitions.
681683
os << outOfLineDefinitionsOS.str();
684+
685+
// Print any additional metadata for referenced C++ types.
686+
for (const auto *typeDecl :
687+
printer.getInteropContext().getEmittedClangTypeDecls())
688+
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M);
682689
}
683690
};
684691
} // end anonymous namespace

lib/PrintAsClang/PrintClangClassType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ void ClangClassTypePrinter::printClassTypeDecl(
9595
});
9696

9797
ClangValueTypePrinter::printTypeGenericTraits(
98-
os, typeDecl, typeMetadataFuncName, /*genericRequirements=*/{});
98+
os, typeDecl, typeMetadataFuncName, /*genericRequirements=*/{},
99+
typeDecl->getModuleContext());
99100
}
100101

101102
void ClangClassTypePrinter::printClassTypeReturnScaffold(

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
#include "swift/ClangImporter/ClangImporter.h"
2929
#include "swift/IRGen/IRABIDetailsProvider.h"
3030
#include "clang/AST/ASTContext.h"
31-
#include "clang/AST/DeclTemplate.h"
32-
#include "clang/AST/NestedNameSpecifier.h"
3331
#include "llvm/ADT/STLExtras.h"
3432

3533
using namespace swift;
@@ -108,26 +106,14 @@ class ClangTypeHandler {
108106
}
109107

110108
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-
}
109+
ClangSyntaxPrinter(os).printNominalClangTypeReference(typeDecl);
110+
}
111+
112+
static void
113+
printGenericReturnScaffold(raw_ostream &os, StringRef templateParamName,
114+
llvm::function_ref<void(StringRef)> bodyOfReturn) {
115+
printReturnScaffold(nullptr, os, templateParamName, templateParamName,
116+
bodyOfReturn);
131117
}
132118

133119
void printReturnScaffold(raw_ostream &os,
@@ -140,14 +126,22 @@ class ClangTypeHandler {
140126
llvm::raw_string_ostream unqualTypeNameOS(typeName);
141127
unqualTypeNameOS << cast<clang::NamedDecl>(typeDecl)->getName();
142128
}
129+
printReturnScaffold(typeDecl, os, fullQualifiedType, typeName,
130+
bodyOfReturn);
131+
}
132+
133+
private:
134+
static void
135+
printReturnScaffold(const clang::Decl *typeDecl, raw_ostream &os,
136+
StringRef fullQualifiedType, StringRef typeName,
137+
llvm::function_ref<void(StringRef)> bodyOfReturn) {
143138
os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof("
144139
<< fullQualifiedType << ")];\n";
145140
os << "auto * _Nonnull storageObjectPtr = reinterpret_cast<"
146141
<< fullQualifiedType << " *>(storage);\n";
147142
bodyOfReturn("storage");
148143
os << ";\n";
149-
auto *cxxRecord = cast<clang::CXXRecordDecl>(typeDecl);
150-
if (cxxRecord->isTrivial()) {
144+
if (typeDecl && cast<clang::CXXRecordDecl>(typeDecl)->isTrivial()) {
151145
// Trivial object can be just copied and not destroyed.
152146
os << "return *storageObjectPtr;\n";
153147
return;
@@ -157,7 +151,6 @@ class ClangTypeHandler {
157151
os << "return result;\n";
158152
}
159153

160-
private:
161154
const clang::Decl *typeDecl;
162155
};
163156

@@ -316,6 +309,7 @@ class CFunctionSignatureTypePrinter
316309
handler.printTypeName(os);
317310
if (typeUseKind == FunctionSignatureTypeUse::ParamType)
318311
os << '&';
312+
interopContext.recordEmittedClangTypeDecl(decl);
319313
return ClangRepresentation::representable;
320314
}
321315

@@ -1019,6 +1013,11 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
10191013
<< ">::type::returnNewValue([&](void * _Nonnull returnValue) {\n";
10201014
printCallToCFunc(/*additionalParam=*/StringRef("returnValue"));
10211015
os << ";\n });\n";
1016+
os << " } else if constexpr (::swift::"
1017+
<< cxx_synthesis::getCxxImplNamespaceName()
1018+
<< "::isSwiftBridgedCxxRecord<" << resultTyName << ">) {\n";
1019+
ClangTypeHandler::printGenericReturnScaffold(os, resultTyName,
1020+
printCallToCFunc);
10221021
os << " } else {\n";
10231022
os << " " << resultTyName << " returnValue;\n";
10241023
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
406406
printCValueTypeStorageStruct(cPrologueOS, typeDecl, *typeSizeAlign);
407407

408408
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName,
409-
typeMetadataFuncGenericParams);
409+
typeMetadataFuncGenericParams,
410+
typeDecl->getModuleContext());
410411
}
411412

412413
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
@@ -456,24 +457,47 @@ void ClangValueTypePrinter::printValueTypeReturnScaffold(
456457
os << " });\n";
457458
}
458459

460+
void ClangValueTypePrinter::printClangTypeSwiftGenericTraits(
461+
raw_ostream &os, const NominalTypeDecl *typeDecl,
462+
const ModuleDecl *moduleContext) {
463+
assert(typeDecl->hasClangNode());
464+
// Do not reference unspecialized templates.
465+
if (isa<clang::ClassTemplateDecl>(typeDecl->getClangDecl()))
466+
return;
467+
auto typeMetadataFunc = irgen::LinkEntity::forTypeMetadataAccessFunction(
468+
typeDecl->getDeclaredType()->getCanonicalType());
469+
std::string typeMetadataFuncName = typeMetadataFunc.mangleAsString();
470+
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName,
471+
/*typeMetadataFuncRequirements=*/{}, moduleContext);
472+
}
473+
459474
void ClangValueTypePrinter::printTypeGenericTraits(
460475
raw_ostream &os, const NominalTypeDecl *typeDecl,
461476
StringRef typeMetadataFuncName,
462-
ArrayRef<GenericRequirement> typeMetadataFuncRequirements) {
477+
ArrayRef<GenericRequirement> typeMetadataFuncRequirements,
478+
const ModuleDecl *moduleContext) {
463479
ClangSyntaxPrinter printer(os);
464480
// FIXME: avoid popping out of the module's namespace here.
465481
os << "} // end namespace \n\n";
466482
os << "namespace swift {\n";
467483

484+
if (typeDecl->hasClangNode()) {
485+
/// Print a reference to the type metadata fucntion for a C++ type.
486+
ClangSyntaxPrinter(os).printNamespace(
487+
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) {
488+
ClangSyntaxPrinter(os).printCTypeMetadataTypeFunction(
489+
typeDecl, typeMetadataFuncName, typeMetadataFuncRequirements);
490+
});
491+
}
492+
468493
os << "#pragma clang diagnostic push\n";
469494
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
470495
if (typeMetadataFuncRequirements.empty()) {
471496
// FIXME: generic type support.
472497
os << "template<>\n";
473498
os << "static inline const constexpr bool isUsableInGenericContext<";
474-
printer.printBaseName(typeDecl->getModuleContext());
475-
os << "::";
476-
printer.printBaseName(typeDecl);
499+
printer.printNominalTypeReference(typeDecl,
500+
/*moduleContext=*/nullptr);
477501
os << "> = true;\n";
478502
}
479503
if (printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(typeDecl))
@@ -484,16 +508,27 @@ void ClangValueTypePrinter::printTypeGenericTraits(
484508
os << "> {\n";
485509
os << " static inline void * _Nonnull getTypeMetadata() {\n";
486510
os << " return ";
487-
printer.printBaseName(typeDecl->getModuleContext());
488-
os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
511+
if (!typeDecl->hasClangNode()) {
512+
printer.printBaseName(typeDecl->getModuleContext());
513+
os << "::";
514+
}
515+
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
489516
ClangSyntaxPrinter(os).printSwiftTypeMetadataAccessFunctionCall(
490517
typeMetadataFuncName, typeMetadataFuncRequirements);
491518
os << "._0;\n";
492519
os << " }\n};\n";
493520

494521
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
495522

496-
if (!isa<ClassDecl>(typeDecl) && typeMetadataFuncRequirements.empty()) {
523+
if (typeDecl->hasClangNode()) {
524+
os << "template<>\n";
525+
os << "static inline const constexpr bool isSwiftBridgedCxxRecord<";
526+
printer.printNominalClangTypeReference(typeDecl->getClangDecl());
527+
os << "> = true;\n";
528+
}
529+
530+
if (!isa<ClassDecl>(typeDecl) && !typeDecl->hasClangNode() &&
531+
typeMetadataFuncRequirements.empty()) {
497532
// FIXME: generic support.
498533
os << "template<>\n";
499534
os << "static inline const constexpr bool isValueType<";
@@ -512,7 +547,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
512547
}
513548

514549
// FIXME: generic support.
515-
if (typeMetadataFuncRequirements.empty()) {
550+
if (!typeDecl->hasClangNode() && typeMetadataFuncRequirements.empty()) {
516551
os << "template<>\n";
517552
os << "struct implClassFor<";
518553
printer.printBaseName(typeDecl->getModuleContext());
@@ -528,6 +563,6 @@ void ClangValueTypePrinter::printTypeGenericTraits(
528563
os << "#pragma clang diagnostic pop\n";
529564
os << "} // namespace swift\n";
530565
os << "\nnamespace ";
531-
printer.printBaseName(typeDecl->getModuleContext());
566+
printer.printBaseName(moduleContext);
532567
os << " {\n";
533568
}

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,17 @@ class ClangValueTypePrinter {
9393
static void printTypeGenericTraits(
9494
raw_ostream &os, const NominalTypeDecl *typeDecl,
9595
StringRef typeMetadataFuncName,
96-
ArrayRef<GenericRequirement> typeMetadataFuncRequirements);
96+
ArrayRef<GenericRequirement> typeMetadataFuncRequirements,
97+
const ModuleDecl *moduleContext);
9798

9899
static void forwardDeclType(raw_ostream &os, const NominalTypeDecl *typeDecl);
99100

101+
/// Print out the type traits that allow a C++ type be used a Swift generic
102+
/// context.
103+
static void printClangTypeSwiftGenericTraits(raw_ostream &os,
104+
const NominalTypeDecl *typeDecl,
105+
const ModuleDecl *moduleContext);
106+
100107
private:
101108
raw_ostream &os;
102109
raw_ostream &cPrologueOS;

lib/PrintAsClang/SwiftToClangInteropContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SwiftToClangInteropContext.h"
14+
#include "swift/AST/Decl.h"
1415
#include "swift/IRGen/IRABIDetailsProvider.h"
1516

1617
using namespace swift;
@@ -33,3 +34,9 @@ void SwiftToClangInteropContext::runIfStubForDeclNotEmitted(
3334
if (result.second)
3435
function();
3536
}
37+
38+
void SwiftToClangInteropContext::recordEmittedClangTypeDecl(
39+
const NominalTypeDecl *typeDecl) {
40+
assert(typeDecl->hasClangNode());
41+
referencedClangTypeDecls.insert(typeDecl);
42+
}

lib/PrintAsClang/SwiftToClangInteropContext.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#ifndef SWIFT_PRINTASCLANG_SWIFTTOCLANGINTEROPCONTEXT_H
1414
#define SWIFT_PRINTASCLANG_SWIFTTOCLANGINTEROPCONTEXT_H
1515

16+
#include "llvm/ADT/ArrayRef.h"
1617
#include "llvm/ADT/STLExtras.h"
18+
#include "llvm/ADT/SetVector.h"
1719
#include "llvm/ADT/StringSet.h"
1820
#include <memory>
1921

@@ -23,6 +25,7 @@ class Decl;
2325
class IRABIDetailsProvider;
2426
class IRGenOptions;
2527
class ModuleDecl;
28+
class NominalTypeDecl;
2629

2730
/// The \c SwiftToClangInteropContext class is responsible for providing
2831
/// access to the other required subsystems of the compiler during the emission
@@ -40,11 +43,21 @@ class SwiftToClangInteropContext {
4043
void runIfStubForDeclNotEmitted(llvm::StringRef stubName,
4144
llvm::function_ref<void(void)> function);
4245

46+
/// Records that the given nominal type decl that has a clang declaration was
47+
/// emitted in the generated header.
48+
void recordEmittedClangTypeDecl(const NominalTypeDecl *typeDecl);
49+
50+
inline const llvm::SetVector<const NominalTypeDecl *> &
51+
getEmittedClangTypeDecls() const {
52+
return referencedClangTypeDecls;
53+
}
54+
4355
private:
4456
ModuleDecl &mod;
4557
const IRGenOptions &irGenOpts;
4658
std::unique_ptr<IRABIDetailsProvider> irABIDetails;
4759
llvm::StringSet<> emittedStubs;
60+
llvm::SetVector<const NominalTypeDecl *> referencedClangTypeDecls;
4861
};
4962

5063
} // end namespace swift

stdlib/public/SwiftShims/_SwiftCxxInteroperability.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ template <class T> static inline const constexpr bool isValueType = false;
160160
/// boxed.
161161
template <class T> static inline const constexpr bool isOpaqueLayout = false;
162162

163+
/// True if the given type is a C++ record that was bridged to Swift, giving
164+
/// Swift ability to work with it in a generic context.
165+
template <class T>
166+
static inline const constexpr bool isSwiftBridgedCxxRecord = false;
167+
163168
/// Returns the opaque pointer to the given value.
164169
template <class T>
165170
inline const void *_Nonnull getOpaquePointer(const T &value) {

0 commit comments

Comments
 (0)