Skip to content

Commit a0cb7a6

Browse files
authored
Merge pull request #61858 from hyp/eng/genericxx17
[interop][SwiftToCxx] add initial C++14/17 generics support
2 parents a649260 + e6784b8 commit a0cb7a6

22 files changed

+430
-75
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclTemplateSpecifiers(
8383
return false;
8484
}
8585

86+
bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclInnerStaticAssert(
87+
const NominalTypeDecl *typeDecl) {
88+
if (!typeDecl->isGeneric())
89+
return true;
90+
printGenericSignatureInnerStaticAsserts(
91+
typeDecl->getGenericSignature().getCanonicalSignature());
92+
return false;
93+
}
94+
8695
void ClangSyntaxPrinter::printNominalClangTypeReference(
8796
const clang::Decl *typeDecl) {
8897
auto &clangCtx = typeDecl->getASTContext();
@@ -284,6 +293,7 @@ void ClangSyntaxPrinter::printGenericSignature(
284293
printGenericTypeParamTypeName(genericParamType);
285294
});
286295
os << ">\n";
296+
os << "#ifdef __cpp_concepts\n";
287297
os << "requires ";
288298
llvm::interleave(
289299
signature.getInnermostGenericParams(), os,
@@ -293,7 +303,21 @@ void ClangSyntaxPrinter::printGenericSignature(
293303
os << ">";
294304
},
295305
" && ");
296-
os << "\n";
306+
os << "\n#endif // __cpp_concepts\n";
307+
}
308+
309+
void ClangSyntaxPrinter::printGenericSignatureInnerStaticAsserts(
310+
const CanGenericSignature &signature) {
311+
os << "#ifndef __cpp_concepts\n";
312+
llvm::interleave(
313+
signature.getInnermostGenericParams(), os,
314+
[&](const GenericTypeParamType *genericParamType) {
315+
os << "static_assert(swift::isUsableInGenericContext<";
316+
printGenericTypeParamTypeName(genericParamType);
317+
os << ">, \"type cannot be used in a Swift generic context\");";
318+
},
319+
"\n");
320+
os << "\n#endif // __cpp_concepts\n";
297321
}
298322

299323
void ClangSyntaxPrinter::printGenericSignatureParams(
@@ -358,3 +382,16 @@ void ClangSyntaxPrinter::printIncludeForShimHeader(StringRef headerName) {
358382
void ClangSyntaxPrinter::printDefine(StringRef macroName) {
359383
os << "#define " << macroName << "\n";
360384
}
385+
386+
void ClangSyntaxPrinter::printIgnoredDiagnosticBlock(
387+
StringRef diagName, llvm::function_ref<void()> bodyPrinter) {
388+
os << "#pragma clang diagnostic push\n";
389+
os << "#pragma clang diagnostic ignored \"-W" << diagName << "\"\n";
390+
bodyPrinter();
391+
os << "#pragma clang diagnostic pop\n";
392+
}
393+
394+
void ClangSyntaxPrinter::printIgnoredCxx17ExtensionDiagnosticBlock(
395+
llvm::function_ref<void()> bodyPrinter) {
396+
printIgnoredDiagnosticBlock("c++17-extensions", bodyPrinter);
397+
}

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ class ClangSyntaxPrinter {
7878
bool printNominalTypeOutsideMemberDeclTemplateSpecifiers(
7979
const NominalTypeDecl *typeDecl);
8080

81+
/// Print out additional C++ `static_assert` clauses that
82+
/// are required to emit a generic member definition outside a C++ class that
83+
/// is generated for the given Swift type declaration.
84+
///
85+
/// \returns true if nothing was printed.
86+
///
87+
/// Examples:
88+
/// 1) For Swift's `String` type, it will print nothing.
89+
/// 2) For Swift's `Array<T>` type, it will print
90+
/// `static_assert(swift::isUsableInGenericContext<T_0_0>);\n`
91+
bool printNominalTypeOutsideMemberDeclInnerStaticAssert(
92+
const NominalTypeDecl *typeDecl);
93+
8194
/// Print out the C++ class access qualifier for the given Swift type
8295
/// declaration.
8396
///
@@ -163,6 +176,11 @@ class ClangSyntaxPrinter {
163176
/// its requirements.
164177
void printGenericSignature(const CanGenericSignature &signature);
165178

179+
/// Print the `static_assert` statements used for legacy type-checking for
180+
/// generics in C++14/C++17 mode.
181+
void
182+
printGenericSignatureInnerStaticAsserts(const CanGenericSignature &signature);
183+
166184
/// Print the C++ template parameters that should be passed for a given
167185
/// generic signature.
168186
void printGenericSignatureParams(const CanGenericSignature &signature);
@@ -190,6 +208,14 @@ class ClangSyntaxPrinter {
190208
// Print the #define for the given macro.
191209
void printDefine(StringRef macroName);
192210

211+
// Print the ignored Clang diagnostic preprocessor directives around the given
212+
// source.
213+
void printIgnoredDiagnosticBlock(StringRef diagName,
214+
llvm::function_ref<void()> bodyPrinter);
215+
216+
void printIgnoredCxx17ExtensionDiagnosticBlock(
217+
llvm::function_ref<void()> bodyPrinter);
218+
193219
protected:
194220
raw_ostream &os;
195221
};

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,8 +1379,8 @@ class DeclAndTypePrinter::Implementation
13791379
os << " {\n";
13801380
funcPrinter.printCxxThunkBody(
13811381
FD, funcABI.getSignature(), funcABI.getSymbolName(),
1382-
FD->getModuleContext(), resultTy, FD->getParameters(),
1383-
funcTy->isThrowing(), funcTy);
1382+
/*typeDeclContext=*/nullptr, FD->getModuleContext(), resultTy,
1383+
FD->getParameters(), funcTy->isThrowing(), funcTy);
13841384
os << "}\n";
13851385
}
13861386

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -986,17 +986,17 @@ void DeclAndTypeClangFunctionPrinter::printGenericReturnSequence(
986986
llvm::raw_string_ostream os(resultTyName);
987987
ClangSyntaxPrinter(os).printGenericTypeParamTypeName(gtpt);
988988
}
989-
990-
os << " if constexpr (std::is_base_of<::swift::"
991-
<< cxx_synthesis::getCxxImplNamespaceName() << "::RefCountedClass, "
992-
<< resultTyName << ">::value) {\n";
993-
os << " void *returnValue;\n ";
994-
if (!initializeWithTakeFromValue) {
995-
invocationPrinter(/*additionalParam=*/StringRef(ros.str()));
996-
} else {
997-
os << "returnValue = *reinterpret_cast<void **>("
998-
<< *initializeWithTakeFromValue << ")";
999-
}
989+
ClangSyntaxPrinter(os).printIgnoredCxx17ExtensionDiagnosticBlock([&]() {
990+
os << " if constexpr (std::is_base_of<::swift::"
991+
<< cxx_synthesis::getCxxImplNamespaceName() << "::RefCountedClass, "
992+
<< resultTyName << ">::value) {\n";
993+
os << " void *returnValue;\n ";
994+
if (!initializeWithTakeFromValue) {
995+
invocationPrinter(/*additionalParam=*/StringRef(ros.str()));
996+
} else {
997+
os << "returnValue = *reinterpret_cast<void **>("
998+
<< *initializeWithTakeFromValue << ")";
999+
}
10001000
os << ";\n";
10011001
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
10021002
<< "::implClassFor<" << resultTyName
@@ -1010,41 +1010,49 @@ void DeclAndTypeClangFunctionPrinter::printGenericReturnSequence(
10101010
<< ">::type::returnNewValue([&](void * _Nonnull returnValue) {\n";
10111011
if (!initializeWithTakeFromValue) {
10121012
invocationPrinter(/*additionalParam=*/StringRef("returnValue"));
1013-
} else {
1014-
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
1015-
<< "::implClassFor<" << resultTyName
1016-
<< ">::type::initializeWithTake(reinterpret_cast<char * "
1017-
"_Nonnull>(returnValue), "
1018-
<< *initializeWithTakeFromValue << ")";
1019-
}
1020-
os << ";\n });\n";
1021-
os << " } else if constexpr (::swift::"
1022-
<< cxx_synthesis::getCxxImplNamespaceName() << "::isSwiftBridgedCxxRecord<"
1023-
<< resultTyName << ">) {\n";
1024-
if (!initializeWithTakeFromValue) {
1025-
ClangTypeHandler::printGenericReturnScaffold(os, resultTyName,
1026-
invocationPrinter);
1027-
} else {
1028-
// FIXME: support taking a C++ record type.
1029-
os << "abort();\n";
1030-
}
1031-
os << " } else {\n";
1032-
os << " " << resultTyName << " returnValue;\n";
1033-
if (!initializeWithTakeFromValue) {
1034-
invocationPrinter(/*additionalParam=*/StringRef(ros.str()));
1035-
} else {
1036-
os << "memcpy(&returnValue, " << *initializeWithTakeFromValue
1037-
<< ", sizeof(returnValue))";
1038-
}
1039-
os << ";\n return returnValue;\n";
1040-
os << " }\n";
1013+
} else {
1014+
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
1015+
<< "::implClassFor<" << resultTyName
1016+
<< ">::type::initializeWithTake(reinterpret_cast<char * "
1017+
"_Nonnull>(returnValue), "
1018+
<< *initializeWithTakeFromValue << ")";
1019+
}
1020+
os << ";\n });\n";
1021+
os << " } else if constexpr (::swift::"
1022+
<< cxx_synthesis::getCxxImplNamespaceName()
1023+
<< "::isSwiftBridgedCxxRecord<" << resultTyName << ">) {\n";
1024+
if (!initializeWithTakeFromValue) {
1025+
ClangTypeHandler::printGenericReturnScaffold(os, resultTyName,
1026+
invocationPrinter);
1027+
} else {
1028+
// FIXME: support taking a C++ record type.
1029+
os << "abort();\n";
1030+
}
1031+
os << " } else {\n";
1032+
os << " " << resultTyName << " returnValue;\n";
1033+
if (!initializeWithTakeFromValue) {
1034+
invocationPrinter(/*additionalParam=*/StringRef(ros.str()));
1035+
} else {
1036+
os << "memcpy(&returnValue, " << *initializeWithTakeFromValue
1037+
<< ", sizeof(returnValue))";
1038+
}
1039+
os << ";\n return returnValue;\n";
1040+
os << " }\n";
1041+
});
10411042
}
10421043

10431044
void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
10441045
const AbstractFunctionDecl *FD, const LoweredFunctionSignature &signature,
1045-
StringRef swiftSymbolName, const ModuleDecl *moduleContext, Type resultTy,
1046-
const ParameterList *params, bool hasThrows,
1047-
const AnyFunctionType *funcType) {
1046+
StringRef swiftSymbolName, const NominalTypeDecl *typeDeclContext,
1047+
const ModuleDecl *moduleContext, Type resultTy, const ParameterList *params,
1048+
bool hasThrows, const AnyFunctionType *funcType) {
1049+
if (typeDeclContext)
1050+
ClangSyntaxPrinter(os).printNominalTypeOutsideMemberDeclInnerStaticAssert(
1051+
typeDeclContext);
1052+
if (FD->isGeneric()) {
1053+
auto Signature = FD->getGenericSignature().getCanonicalSignature();
1054+
ClangSyntaxPrinter(os).printGenericSignatureInnerStaticAsserts(Signature);
1055+
}
10481056
if (hasThrows) {
10491057
os << " void* opaqueError = nullptr;\n";
10501058
os << " void* _ctx = nullptr;\n";
@@ -1280,8 +1288,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
12801288

12811289
os << " {\n";
12821290
// FIXME: should it be objTy for resultTy?
1283-
printCxxThunkBody(FD, signature, swiftSymbolName, FD->getModuleContext(),
1284-
resultTy, FD->getParameters(), FD->hasThrows(),
1291+
printCxxThunkBody(FD, signature, swiftSymbolName, typeDeclContext,
1292+
FD->getModuleContext(), resultTy, FD->getParameters(),
1293+
FD->hasThrows(),
12851294
FD->getInterfaceType()->castTo<AnyFunctionType>());
12861295
os << " }\n";
12871296
}
@@ -1339,7 +1348,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
13391348
}
13401349
os << " {\n";
13411350
// FIXME: should it be objTy for resultTy?
1342-
printCxxThunkBody(accessor, signature, swiftSymbolName,
1351+
printCxxThunkBody(accessor, signature, swiftSymbolName, typeDeclContext,
13431352
accessor->getModuleContext(), resultTy,
13441353
accessor->getParameters());
13451354
os << " }\n";
@@ -1365,7 +1374,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
13651374
}
13661375
os << " {\n";
13671376
// FIXME: should it be objTy for resultTy?
1368-
printCxxThunkBody(accessor, signature, swiftSymbolName,
1377+
printCxxThunkBody(accessor, signature, swiftSymbolName, typeDeclContext,
13691378
accessor->getModuleContext(), resultTy,
13701379
accessor->getParameters());
13711380
os << " }\n";

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class DeclAndTypeClangFunctionPrinter {
105105
void printCxxThunkBody(const AbstractFunctionDecl *FD,
106106
const LoweredFunctionSignature &signature,
107107
StringRef swiftSymbolName,
108+
const NominalTypeDecl *typeDeclContext,
108109
const ModuleDecl *moduleContext, Type resultTy,
109110
const ParameterList *params, bool hasThrows = false,
110111
const AnyFunctionType *funcType = nullptr);

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ void ClangValueTypePrinter::printValueTypeDecl(
241241
ClangSyntaxPrinter(os).printBaseName(typeDecl);
242242
os << " final {\n";
243243
os << "public:\n";
244+
if (genericSignature)
245+
ClangSyntaxPrinter(os).printGenericSignatureInnerStaticAsserts(
246+
*genericSignature);
244247

245248
// Print out the destructor.
246249
os << " inline ~";
@@ -373,6 +376,9 @@ void ClangValueTypePrinter::printValueTypeDecl(
373376
printCxxImplClassName(os, typeDecl);
374377
os << " {\n";
375378
os << "public:\n";
379+
if (genericSignature)
380+
ClangSyntaxPrinter(os).printGenericSignatureInnerStaticAsserts(
381+
*genericSignature);
376382

377383
os << " static inline char * _Nonnull getOpaquePointer(";
378384
printCxxTypeName(os, typeDecl, moduleContext);

lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,9 @@ void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
243243
});
244244
os << "\n";
245245
// C++ only supports inline variables from C++17.
246-
// FIXME: silence the warning instead?
247-
os << "#if __cplusplus > 201402L\n";
248-
printPrimitiveGenericTypeTraits(os, astContext, typeMapping,
249-
/*isCForwardDefinition=*/false);
250-
os << "#endif\n";
246+
ClangSyntaxPrinter(os).printIgnoredCxx17ExtensionDiagnosticBlock([&]() {
247+
printPrimitiveGenericTypeTraits(os, astContext, typeMapping,
248+
/*isCForwardDefinition=*/false);
249+
});
251250
});
252251
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4
1+
5

test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@
114114
// CHECK-NEXT: } // namespace _impl
115115
// CHECK-EMPTY:
116116
// CHECK-EMPTY:
117-
// CHECK-NEXT: #if __cplusplus > 201402L
117+
// CHECK-NEXT: #pragma clang diagnostic push
118+
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
118119
// CHECK-NEXT: template<>
119120
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<bool> = true;
120121
// CHECK-EMPTY:
@@ -235,7 +236,7 @@
235236
// CHECK-NEXT: }
236237
// CHECK-NEXT: };
237238
// CHECK-EMPTY:
238-
// CHECK-NEXT: #endif
239+
// CHECK-NEXT: #pragma clang diagnostic pop
239240
// CHECK-EMPTY:
240241
// CHECK-NEXT: } // namespace swift
241242
// CHECK-EMPTY:

0 commit comments

Comments
 (0)