[interop][SwiftToCxx] print availability attributes for Swift decls in C++

This commit is contained in:
Alex Lorenz
2023-02-27 10:42:21 -08:00
parent a0e1810f62
commit f8c3895f32
14 changed files with 363 additions and 138 deletions

View File

@@ -243,7 +243,8 @@ private:
}
/// Prints an encoded string, escaped properly for C.
void printEncodedString(StringRef str, bool includeQuotes = true) {
void printEncodedString(raw_ostream &os, StringRef str,
bool includeQuotes = true) {
// NB: We don't use raw_ostream::write_escaped() because it does hex escapes
// for non-ASCII chars.
@@ -296,11 +297,10 @@ private:
if (outputLang == OutputLanguageMode::Cxx) {
// FIXME: Non objc class.
// FIXME: Print availability.
// FIXME: forward decl should be handled by ModuleWriter.
ClangValueTypePrinter::forwardDeclType(os, CD);
ClangValueTypePrinter::forwardDeclType(os, CD, owningPrinter);
ClangClassTypePrinter(os).printClassTypeDecl(
CD, [&]() { printMembers(CD->getMembers()); });
CD, [&]() { printMembers(CD->getMembers()); }, owningPrinter);
return;
}
@@ -347,20 +347,22 @@ private:
if (outputLang != OutputLanguageMode::Cxx)
return;
// FIXME: Print struct's doc comment.
// FIXME: Print struct's availability.
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
owningPrinter.interopContext);
printer.printValueTypeDecl(SD, /*bodyPrinter=*/[&]() {
printMembers(SD->getMembers());
for (const auto *ed :
owningPrinter.interopContext.getExtensionsForNominalType(SD)) {
auto sign = ed->getGenericSignature();
// FIXME: support requirements.
if (!sign.getRequirements().empty())
continue;
printMembers(ed->getMembers());
}
});
printer.printValueTypeDecl(
SD, /*bodyPrinter=*/
[&]() {
printMembers(SD->getMembers());
for (const auto *ed :
owningPrinter.interopContext.getExtensionsForNominalType(SD)) {
auto sign = ed->getGenericSignature();
// FIXME: support requirements.
if (!sign.getRequirements().empty())
continue;
printMembers(ed->getMembers());
}
},
owningPrinter);
}
void visitExtensionDecl(ExtensionDecl *ED) {
@@ -760,81 +762,88 @@ private:
os << ";\n";
};
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
os << '\n';
os << " enum class cases {";
llvm::interleave(
elementTagMapping, os,
[&](const auto &pair) {
os << "\n ";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
syntaxPrinter.printSymbolUSRAttribute(pair.first);
},
",");
// TODO: allow custom name for this special case
auto resilientUnknownDefaultCaseName = "unknownDefault";
if (ED->isResilient()) {
os << (ED->getNumElements() > 0 ? ",\n " : "\n ")
<< resilientUnknownDefaultCaseName;
}
os << "\n };\n\n"; // enum class cases' closing bracket
valueTypePrinter.printValueTypeDecl(
ED, /*bodyPrinter=*/
[&]() {
os << '\n';
os << " enum class cases {";
llvm::interleave(
elementTagMapping, os,
[&](const auto &pair) {
os << "\n ";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
syntaxPrinter.printSymbolUSRAttribute(pair.first);
},
",");
// TODO: allow custom name for this special case
auto resilientUnknownDefaultCaseName = "unknownDefault";
if (ED->isResilient()) {
os << (ED->getNumElements() > 0 ? ",\n " : "\n ")
<< resilientUnknownDefaultCaseName;
}
os << "\n };\n\n"; // enum class cases' closing bracket
os << "#pragma clang diagnostic push\n";
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\" "
<< "// allow use of inline static data member\n";
for (const auto &pair : elementTagMapping) {
// Printing struct
printStruct(pair.first->getNameStr(), pair.first, pair.second);
// Printing `is` function
printIsFunction(pair.first->getNameStr(), ED);
if (pair.first->hasAssociatedValues()) {
// Printing `get` function
printGetFunction(pair.first);
}
os << '\n';
}
os << "#pragma clang diagnostic push\n";
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\" "
<< "// allow use of inline static data member\n";
for (const auto &pair : elementTagMapping) {
// Printing struct
printStruct(pair.first->getNameStr(), pair.first, pair.second);
// Printing `is` function
printIsFunction(pair.first->getNameStr(), ED);
if (pair.first->hasAssociatedValues()) {
// Printing `get` function
printGetFunction(pair.first);
}
os << '\n';
}
if (ED->isResilient()) {
// Printing struct for unknownDefault
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr,
/* elementInfo */ None);
// Printing isUnknownDefault
printIsFunction(resilientUnknownDefaultCaseName, ED);
os << '\n';
}
os << "#pragma clang diagnostic pop\n";
if (ED->isResilient()) {
// Printing struct for unknownDefault
printStruct(resilientUnknownDefaultCaseName,
/* elementDecl */ nullptr,
/* elementInfo */ None);
// Printing isUnknownDefault
printIsFunction(resilientUnknownDefaultCaseName, ED);
os << '\n';
}
os << "#pragma clang diagnostic pop\n";
// Printing operator cases()
os << " ";
ClangSyntaxPrinter(os).printInlineForThunk();
os << "operator cases() const {\n";
if (ED->isResilient()) {
if (!elementTagMapping.empty()) {
os << " auto tag = _getEnumTag();\n";
}
for (const auto &pair : elementTagMapping) {
os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName();
os << "::" << pair.second.globalVariableName << ") return cases::";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
os << ";\n";
}
os << " return cases::" << resilientUnknownDefaultCaseName << ";\n";
} else { // non-resilient enum
os << " switch (_getEnumTag()) {\n";
for (const auto &pair : elementTagMapping) {
os << " case " << pair.second.tag << ": return cases::";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
os << ";\n";
}
// TODO: change to Swift's fatalError when it's available in C++
os << " default: abort();\n";
os << " }\n"; // switch's closing bracket
}
os << " }\n"; // operator cases()'s closing bracket
os << "\n";
printMembers(ED->getMembers());
});
// Printing operator cases()
os << " ";
ClangSyntaxPrinter(os).printInlineForThunk();
os << "operator cases() const {\n";
if (ED->isResilient()) {
if (!elementTagMapping.empty()) {
os << " auto tag = _getEnumTag();\n";
}
for (const auto &pair : elementTagMapping) {
os << " if (tag == "
<< cxx_synthesis::getCxxImplNamespaceName();
os << "::" << pair.second.globalVariableName
<< ") return cases::";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
os << ";\n";
}
os << " return cases::" << resilientUnknownDefaultCaseName
<< ";\n";
} else { // non-resilient enum
os << " switch (_getEnumTag()) {\n";
for (const auto &pair : elementTagMapping) {
os << " case " << pair.second.tag << ": return cases::";
syntaxPrinter.printIdentifier(pair.first->getNameStr());
os << ";\n";
}
// TODO: change to Swift's fatalError when it's available in C++
os << " default: abort();\n";
os << " }\n"; // switch's closing bracket
}
os << " }\n"; // operator cases()'s closing bracket
os << "\n";
printMembers(ED->getMembers());
},
owningPrinter);
}
void visitEnumDecl(EnumDecl *ED) {
@@ -1024,17 +1033,17 @@ private:
if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
if (SD)
declPrinter.printCxxSubscriptAccessorMethod(
typeDeclContext, accessor, funcABI->getSignature(),
owningPrinter, typeDeclContext, accessor, funcABI->getSignature(),
funcABI->getSymbolName(), resultTy,
/*isDefinition=*/false, dispatchInfo);
else
declPrinter.printCxxPropertyAccessorMethod(
typeDeclContext, accessor, funcABI->getSignature(),
owningPrinter, typeDeclContext, accessor, funcABI->getSignature(),
funcABI->getSymbolName(), resultTy,
/*isStatic=*/isClassMethod,
/*isDefinition=*/false, dispatchInfo);
} else {
declPrinter.printCxxMethod(typeDeclContext, AFD,
declPrinter.printCxxMethod(owningPrinter, typeDeclContext, AFD,
funcABI->getSignature(),
funcABI->getSymbolName(), resultTy,
/*isStatic=*/isClassMethod,
@@ -1049,24 +1058,24 @@ private:
if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
if (SD)
defPrinter.printCxxSubscriptAccessorMethod(
typeDeclContext, accessor, funcABI->getSignature(),
owningPrinter, typeDeclContext, accessor, funcABI->getSignature(),
funcABI->getSymbolName(), resultTy, /*isDefinition=*/true,
dispatchInfo);
else
defPrinter.printCxxPropertyAccessorMethod(
typeDeclContext, accessor, funcABI->getSignature(),
owningPrinter, typeDeclContext, accessor, funcABI->getSignature(),
funcABI->getSymbolName(), resultTy,
/*isStatic=*/isClassMethod,
/*isDefinition=*/true, dispatchInfo);
} else {
defPrinter.printCxxMethod(typeDeclContext, AFD, funcABI->getSignature(),
defPrinter.printCxxMethod(owningPrinter, typeDeclContext, AFD,
funcABI->getSignature(),
funcABI->getSymbolName(), resultTy,
/*isStatic=*/isClassMethod,
/*isDefinition=*/true, dispatchInfo);
}
// FIXME: SWIFT_WARN_UNUSED_RESULT
// FIXME: availability
return;
}
printDocumentationComment(AFD);
@@ -1522,9 +1531,16 @@ private:
Yes = true
};
/// Returns \c true if anything was printed.
bool printAvailability(const Decl *D, PrintLeadingSpace printLeadingSpace =
PrintLeadingSpace::Yes) {
return printAvailability(os, D, printLeadingSpace);
}
public:
/// Returns \c true if anything was printed.
bool printAvailability(
raw_ostream &os, const Decl *D,
PrintLeadingSpace printLeadingSpace = PrintLeadingSpace::Yes) {
bool hasPrintedAnything = false;
auto maybePrintLeadingSpace = [&] {
if (printLeadingSpace == PrintLeadingSpace::Yes || hasPrintedAnything)
@@ -1543,17 +1559,17 @@ private:
os << "SWIFT_UNAVAILABLE_MSG(\"'"
<< cast<ValueDecl>(D)->getBaseName()
<< "' has been renamed to '";
printRenameForDecl(AvAttr, cast<ValueDecl>(D), false);
printRenameForDecl(os, AvAttr, cast<ValueDecl>(D), false);
os << '\'';
if (!AvAttr->Message.empty()) {
os << ": ";
printEncodedString(AvAttr->Message, false);
printEncodedString(os, AvAttr->Message, false);
}
os << "\")";
} else if (!AvAttr->Message.empty()) {
maybePrintLeadingSpace();
os << "SWIFT_UNAVAILABLE_MSG(";
printEncodedString(AvAttr->Message);
printEncodedString(os, AvAttr->Message);
os << ")";
} else {
maybePrintLeadingSpace();
@@ -1565,10 +1581,10 @@ private:
if (!AvAttr->Rename.empty() || !AvAttr->Message.empty()) {
maybePrintLeadingSpace();
os << "SWIFT_DEPRECATED_MSG(";
printEncodedString(AvAttr->Message);
printEncodedString(os, AvAttr->Message);
if (!AvAttr->Rename.empty()) {
os << ", ";
printRenameForDecl(AvAttr, cast<ValueDecl>(D), true);
printRenameForDecl(os, AvAttr, cast<ValueDecl>(D), true);
}
os << ")";
} else {
@@ -1655,24 +1671,25 @@ private:
if (!AvAttr->Rename.empty() && isa<ValueDecl>(D)) {
os << ",message=\"'" << cast<ValueDecl>(D)->getBaseName()
<< "' has been renamed to '";
printRenameForDecl(AvAttr, cast<ValueDecl>(D), false);
printRenameForDecl(os, AvAttr, cast<ValueDecl>(D), false);
os << '\'';
if (!AvAttr->Message.empty()) {
os << ": ";
printEncodedString(AvAttr->Message, false);
printEncodedString(os, AvAttr->Message, false);
}
os << "\"";
} else if (!AvAttr->Message.empty()) {
os << ",message=";
printEncodedString(AvAttr->Message);
printEncodedString(os, AvAttr->Message);
}
os << ")";
}
return hasPrintedAnything;
}
void printRenameForDecl(const AvailableAttr *AvAttr, const ValueDecl *D,
bool includeQuotes) {
private:
void printRenameForDecl(raw_ostream &os, const AvailableAttr *AvAttr,
const ValueDecl *D, bool includeQuotes) {
assert(!AvAttr->Rename.empty());
auto *renamedDecl = evaluateOrDefault(
@@ -1683,9 +1700,9 @@ private:
SmallString<128> scratch;
auto renamedObjCRuntimeName =
renamedDecl->getObjCRuntimeName()->getString(scratch);
printEncodedString(renamedObjCRuntimeName, includeQuotes);
printEncodedString(os, renamedObjCRuntimeName, includeQuotes);
} else {
printEncodedString(AvAttr->Rename, includeQuotes);
printEncodedString(os, AvAttr->Rename, includeQuotes);
}
}
@@ -1710,10 +1727,10 @@ private:
os << "method";
os << " '";
auto nominal = VD->getDeclContext()->getSelfNominalTypeDecl();
printEncodedString(nominal->getName().str(), /*includeQuotes=*/false);
printEncodedString(os, nominal->getName().str(), /*includeQuotes=*/false);
os << ".";
SmallString<32> scratch;
printEncodedString(VD->getName().getString(scratch),
printEncodedString(os, VD->getName().getString(scratch),
/*includeQuotes=*/false);
os << "' uses '@objc' inference deprecated in Swift 4; add '@objc' to "
<< "provide an Objective-C entrypoint\")";
@@ -1812,7 +1829,6 @@ private:
if (outputLang == OutputLanguageMode::Cxx) {
// FIXME: Documentation.
// FIXME: availability.
auto *getter = VD->getOpaqueAccessor(AccessorKind::Get);
printAbstractFunctionAsMethod(getter, /*isStatic=*/VD->isStatic());
if (auto *setter = VD->getOpaqueAccessor(AccessorKind::Set))
@@ -2785,6 +2801,10 @@ void DeclAndTypePrinter::print(Type ty) {
getImpl().print(ty, /*overridingOptionality*/None);
}
void DeclAndTypePrinter::printAvailability(raw_ostream &os, const Decl *D) {
getImpl().printAvailability(os, D);
}
void DeclAndTypePrinter::printAdHocCategory(
iterator_range<const ValueDecl * const *> members) {
getImpl().printAdHocCategory(members);

View File

@@ -81,6 +81,8 @@ public:
void print(const Decl *D);
void print(Type ty);
void printAvailability(raw_ostream &os, const Decl *D);
/// Is \p ED empty of members and protocol conformances to include?
bool isEmptyExtensionDecl(const ExtensionDecl *ED);

View File

@@ -289,12 +289,14 @@ public:
return;
auto it = seenClangTypes.insert(clangType.getTypePtr());
if (it.second)
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M);
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M,
printer);
}
void forwardDeclareCxxValueTypeIfNeeded(const NominalTypeDecl *NTD) {
forwardDeclare(NTD,
[&]() { ClangValueTypePrinter::forwardDeclType(os, NTD); });
forwardDeclare(NTD, [&]() {
ClangValueTypePrinter::forwardDeclType(os, NTD, printer);
});
}
void forwardDeclareType(const TypeDecl *TD) {

View File

@@ -12,6 +12,7 @@
#include "PrintClangClassType.h"
#include "ClangSyntaxPrinter.h"
#include "DeclAndTypePrinter.h"
#include "PrintClangValueType.h"
#include "swift/AST/Decl.h"
#include "swift/IRGen/Linking.h"
@@ -19,7 +20,8 @@
using namespace swift;
void ClangClassTypePrinter::printClassTypeDecl(
const ClassDecl *typeDecl, llvm::function_ref<void(void)> bodyPrinter) {
const ClassDecl *typeDecl, llvm::function_ref<void(void)> bodyPrinter,
DeclAndTypePrinter &declAndTypePrinter) {
auto printCxxImplClassName = ClangValueTypePrinter::printCxxImplClassName;
ClangSyntaxPrinter printer(os);
@@ -31,7 +33,9 @@ void ClangClassTypePrinter::printClassTypeDecl(
// Print out a forward declaration of the "hidden" _impl class.
printer.printNamespace(cxx_synthesis::getCxxImplNamespaceName(),
[&](raw_ostream &os) {
os << "class ";
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
os << ' ';
printCxxImplClassName(os, typeDecl);
os << ";\n";
// Print out special functions, like functions that
@@ -57,6 +61,7 @@ void ClangClassTypePrinter::printClassTypeDecl(
}
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
ClangSyntaxPrinter(os).printSymbolUSRAttribute(typeDecl);
os << ' ';
printer.printBaseName(typeDecl);
@@ -83,7 +88,9 @@ void ClangClassTypePrinter::printClassTypeDecl(
// Print out the "hidden" _impl class.
printer.printNamespace(
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) {
os << "class ";
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
os << ' ';
printCxxImplClassName(os, typeDecl);
os << " {\n";
os << "public:\n";
@@ -98,7 +105,7 @@ void ClangClassTypePrinter::printClassTypeDecl(
ClangValueTypePrinter::printTypeGenericTraits(
os, typeDecl, typeMetadataFuncName, /*genericRequirements=*/{},
typeDecl->getModuleContext());
typeDecl->getModuleContext(), declAndTypePrinter);
}
void ClangClassTypePrinter::printClassTypeReturnScaffold(

View File

@@ -21,6 +21,7 @@ namespace swift {
class ClassDecl;
class ModuleDecl;
class DeclAndTypePrinter;
/// Responsible for printing a Swift class decl or in C or C++ mode, to
/// be included in a Swift module's generated clang header.
@@ -30,7 +31,8 @@ public:
/// Print the C++ class definition that corresponds to the given Swift class.
void printClassTypeDecl(const ClassDecl *typeDecl,
llvm::function_ref<void(void)> bodyPrinter);
llvm::function_ref<void(void)> bodyPrinter,
DeclAndTypePrinter &declAndTypePrinter);
static void
printClassTypeReturnScaffold(raw_ostream &os, const ClassDecl *type,

View File

@@ -1377,6 +1377,7 @@ static StringRef getConstructorName(const AbstractFunctionDecl *FD) {
}
void DeclAndTypeClangFunctionPrinter::printCxxMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isStatic, bool isDefinition,
@@ -1401,6 +1402,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
resultTy, FunctionSignatureKind::CxxInlineThunk, modifiers);
assert(!result.isUnsupported() && "C signature should be unsupported too");
declAndTypePrinter.printAvailability(os, FD);
if (!isDefinition) {
os << ";\n";
return;
@@ -1446,6 +1448,7 @@ static std::string remapPropertyName(const AccessorDecl *accessor,
}
void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isStatic, bool isDefinition,
@@ -1466,6 +1469,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
accessor, signature, remapPropertyName(accessor, resultTy), resultTy,
FunctionSignatureKind::CxxInlineThunk, modifiers);
assert(!result.isUnsupported() && "C signature should be unsupported too!");
declAndTypePrinter.printAvailability(os, accessor->getStorage());
if (!isDefinition) {
os << ";\n";
return;
@@ -1480,6 +1484,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
}
void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isDefinition,
@@ -1494,6 +1499,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxSubscriptAccessorMethod(
printFunctionSignature(accessor, signature, "operator []", resultTy,
FunctionSignatureKind::CxxInlineThunk, modifiers);
assert(!result.isUnsupported() && "C signature should be unsupported too!");
declAndTypePrinter.printAvailability(os, accessor->getStorage());
if (!isDefinition) {
os << ";\n";
return;

View File

@@ -119,6 +119,7 @@ public:
/// Print the Swift method as C++ method declaration/definition, including
/// constructors.
void printCxxMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isStatic, bool isDefinition,
@@ -126,6 +127,7 @@ public:
/// Print the C++ getter/setter method signature.
void printCxxPropertyAccessorMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isStatic, bool isDefinition,
@@ -133,6 +135,7 @@ public:
/// Print the C++ subscript method.
void printCxxSubscriptAccessorMethod(
DeclAndTypePrinter &declAndTypePrinter,
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
const LoweredFunctionSignature &signature, StringRef swiftSymbolName,
Type resultTy, bool isDefinition,

View File

@@ -12,6 +12,7 @@
#include "PrintClangValueType.h"
#include "ClangSyntaxPrinter.h"
#include "DeclAndTypePrinter.h"
#include "OutputLanguageMode.h"
#include "PrimitiveTypeMapping.h"
#include "SwiftToClangInteropContext.h"
@@ -81,14 +82,16 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
os << "};\n\n";
}
void ClangValueTypePrinter::forwardDeclType(raw_ostream &os,
const NominalTypeDecl *typeDecl) {
void ClangValueTypePrinter::forwardDeclType(
raw_ostream &os, const NominalTypeDecl *typeDecl,
DeclAndTypePrinter &declAndTypePrinter) {
if (typeDecl->isGeneric()) {
auto genericSignature =
typeDecl->getGenericSignature().getCanonicalSignature();
ClangSyntaxPrinter(os).printGenericSignature(genericSignature);
}
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
ClangSyntaxPrinter(os).printSymbolUSRAttribute(typeDecl);
os << ' ';
ClangSyntaxPrinter(os).printBaseName(typeDecl);
@@ -173,8 +176,8 @@ static void addCppExtensionsToStdlibType(const NominalTypeDecl *typeDecl,
}
void ClangValueTypePrinter::printValueTypeDecl(
const NominalTypeDecl *typeDecl,
llvm::function_ref<void(void)> bodyPrinter) {
const NominalTypeDecl *typeDecl, llvm::function_ref<void(void)> bodyPrinter,
DeclAndTypePrinter &declAndTypePrinter) {
// FIXME: Add support for generic structs.
llvm::Optional<IRABIDetailsProvider::SizeAndAlignment> typeSizeAlign;
Optional<CanGenericSignature> genericSignature;
@@ -221,7 +224,9 @@ void ClangValueTypePrinter::printValueTypeDecl(
printer.printNamespace(cxx_synthesis::getCxxImplNamespaceName(),
[&](raw_ostream &os) {
printGenericSignature(os);
os << "class ";
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
os << ' ';
printCxxImplClassName(os, typeDecl);
os << ";\n\n";
@@ -263,6 +268,7 @@ void ClangValueTypePrinter::printValueTypeDecl(
// Print out the C++ class itself.
printGenericSignature(os);
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
ClangSyntaxPrinter(os).printSymbolUSRAttribute(typeDecl);
os << ' ';
ClangSyntaxPrinter(os).printBaseName(typeDecl);
@@ -408,7 +414,9 @@ void ClangValueTypePrinter::printValueTypeDecl(
printer.printNamespace(
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) {
printGenericSignature(os);
os << "class ";
os << "class";
declAndTypePrinter.printAvailability(os, typeDecl);
os << ' ';
printCxxImplClassName(os, typeDecl);
os << " {\n";
os << "public:\n";
@@ -461,7 +469,7 @@ void ClangValueTypePrinter::printValueTypeDecl(
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName,
typeMetadataFuncGenericParams,
typeDecl->getModuleContext());
typeDecl->getModuleContext(), declAndTypePrinter);
}
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
@@ -512,8 +520,8 @@ void ClangValueTypePrinter::printValueTypeReturnScaffold(
}
void ClangValueTypePrinter::printClangTypeSwiftGenericTraits(
raw_ostream &os, const TypeDecl *typeDecl,
const ModuleDecl *moduleContext) {
raw_ostream &os, const TypeDecl *typeDecl, const ModuleDecl *moduleContext,
DeclAndTypePrinter &declAndTypePrinter) {
assert(typeDecl->hasClangNode());
// Do not reference unspecialized templates.
if (isa<clang::ClassTemplateDecl>(typeDecl->getClangDecl()))
@@ -522,7 +530,8 @@ void ClangValueTypePrinter::printClangTypeSwiftGenericTraits(
typeDecl->getDeclaredInterfaceType()->getCanonicalType());
std::string typeMetadataFuncName = typeMetadataFunc.mangleAsString();
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName,
/*typeMetadataFuncRequirements=*/{}, moduleContext);
/*typeMetadataFuncRequirements=*/{}, moduleContext,
declAndTypePrinter);
}
void ClangValueTypePrinter::printTypePrecedingGenericTraits(
@@ -553,7 +562,7 @@ void ClangValueTypePrinter::printTypePrecedingGenericTraits(
void ClangValueTypePrinter::printTypeGenericTraits(
raw_ostream &os, const TypeDecl *typeDecl, StringRef typeMetadataFuncName,
ArrayRef<GenericRequirement> typeMetadataFuncRequirements,
const ModuleDecl *moduleContext) {
const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter) {
auto *NTD = dyn_cast<NominalTypeDecl>(typeDecl);
ClangSyntaxPrinter printer(os);
// FIXME: avoid popping out of the module's namespace here.
@@ -580,7 +589,9 @@ void ClangValueTypePrinter::printTypeGenericTraits(
}
if (!NTD || printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(NTD))
os << "template<>\n";
os << "struct TypeMetadataTrait<";
os << "struct";
declAndTypePrinter.printAvailability(os, typeDecl);
os << " TypeMetadataTrait<";
if (typeDecl->hasClangNode()) {
printer.printClangTypeReference(typeDecl->getClangDecl());
} else {
@@ -635,7 +646,9 @@ void ClangValueTypePrinter::printTypeGenericTraits(
if (!typeDecl->hasClangNode() && typeMetadataFuncRequirements.empty()) {
assert(NTD);
os << "template<>\n";
os << "struct implClassFor<";
os << "struct";
declAndTypePrinter.printAvailability(os, typeDecl);
os << " implClassFor<";
printer.printBaseName(typeDecl->getModuleContext());
os << "::";
printer.printBaseName(typeDecl);

View File

@@ -22,6 +22,7 @@
namespace swift {
class DeclAndTypePrinter;
class ModuleDecl;
class NominalTypeDecl;
class PrimitiveTypeMapping;
@@ -39,7 +40,9 @@ public:
/// Print the C++ class definition that
/// corresponds to the given structure or enum declaration.
void printValueTypeDecl(const NominalTypeDecl *typeDecl,
llvm::function_ref<void(void)> bodyPrinter);
llvm::function_ref<void(void)> bodyPrinter,
DeclAndTypePrinter &declAndTypePrinter);
/// Print the use of a C++ struct/enum parameter value as it's passed to the
/// underlying C function that represents the native Swift function.
@@ -93,19 +96,21 @@ public:
static void printTypeGenericTraits(
raw_ostream &os, const TypeDecl *typeDecl, StringRef typeMetadataFuncName,
ArrayRef<GenericRequirement> typeMetadataFuncRequirements,
const ModuleDecl *moduleContext);
const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter);
static void printTypePrecedingGenericTraits(raw_ostream &os,
const NominalTypeDecl *typeDecl,
const ModuleDecl *moduleContext);
static void forwardDeclType(raw_ostream &os, const NominalTypeDecl *typeDecl);
static void forwardDeclType(raw_ostream &os, const NominalTypeDecl *typeDecl,
DeclAndTypePrinter &declAndTypePrinter);
/// Print out the type traits that allow a C++ type be used a Swift generic
/// context.
static void printClangTypeSwiftGenericTraits(raw_ostream &os,
const TypeDecl *typeDecl,
const ModuleDecl *moduleContext);
static void
printClangTypeSwiftGenericTraits(raw_ostream &os, const TypeDecl *typeDecl,
const ModuleDecl *moduleContext,
DeclAndTypePrinter &declAndTypePrinter);
private:
raw_ostream &os;

View File

@@ -0,0 +1,35 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Class -clang-header-expose-decls=all-public -emit-clang-header-path %t/class.h
// RUN: %FileCheck %s < %t/class.h
// RUN: %check-interop-cxx-header-in-clang(%t/class.h)
@available(macOS 11, *)
public final class ClassWithMacAvailability {
var field: Int64
init() {
field = 0
}
}
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) _impl_ClassWithMacAvailability;
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) SWIFT_SYMBOL("s:5Class0A19WithMacAvailabilityC") ClassWithMacAvailability final
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) _impl_ClassWithMacAvailability {
// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) TypeMetadataTrait<Class::ClassWithMacAvailability> {
// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) implClassFor<Class::ClassWithMacAvailability>
@available(*, unavailable, message: "stuff happened")
public final class ClassWithUnavailable {
var field: Int64
init() {
field = 0
}
}
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") _impl_ClassWithUnavailable;
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") SWIFT_SYMBOL("s:5Class0A15WithUnavailableC") ClassWithUnavailable final
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") _impl_ClassWithUnavailable {
// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") TypeMetadataTrait<Class::ClassWithUnavailable> {
// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") implClassFor<Class::ClassWithUnavailable>

View File

@@ -0,0 +1,23 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Methods -clang-header-expose-decls=all-public -emit-clang-header-path %t/methods.h
// RUN: %FileCheck %s < %t/methods.h
// RUN: %check-interop-cxx-header-in-clang(%t/methods.h)
public struct Struct {
var field: Int16
init() {
field = 0
}
@available(macOS 11, *)
public init(_ field: Int16) {
self.field = field
}
}
// CHECK: static SWIFT_INLINE_THUNK Struct init(int16_t field) SWIFT_SYMBOL("s:7Methods6StructVyACs5Int16Vcfc") SWIFT_AVAILABILITY(macos,introduced=11);
// CHECK: SWIFT_INLINE_THUNK Struct Struct::init(int16_t field) SWIFT_AVAILABILITY(macos,introduced=11) {

View File

@@ -0,0 +1,40 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Methods -clang-header-expose-decls=all-public -emit-clang-header-path %t/methods.h
// RUN: %FileCheck %s < %t/methods.h
// RUN: %check-interop-cxx-header-in-clang(%t/methods.h)
public struct Struct {
var field: Int16
init() {
field = 0
}
@available(macOS 11, *)
public func method() {}
@available(macOS 11, *)
public static func staticMethod() {}
@available(*, unavailable, message: "stuff happened")
public func unavailableMethod() {}
@available(macOS 11, *)
public subscript (_ x: Int) -> Int {
return 0
}
}
// CHECK: SWIFT_INLINE_THUNK void method() const SWIFT_SYMBOL("s:7Methods6StructV6methodyyF") SWIFT_AVAILABILITY(macos,introduced=11);
// CHECK: static SWIFT_INLINE_THUNK void staticMethod() SWIFT_SYMBOL("s:7Methods6StructV12staticMethodyyFZ") SWIFT_AVAILABILITY(macos,introduced=11);
// CHECK: SWIFT_INLINE_THUNK void unavailableMethod() const SWIFT_SYMBOL("s:7Methods6StructV17unavailableMethodyyF") SWIFT_UNAVAILABLE_MSG("stuff happened");
// CHECK: SWIFT_INLINE_THUNK swift::Int operator [](swift::Int x) const SWIFT_SYMBOL("s:7Methods6StructVyS2icig") SWIFT_AVAILABILITY(macos,introduced=11);
// CHECK: SWIFT_INLINE_THUNK void Struct::method() const SWIFT_AVAILABILITY(macos,introduced=11) {
// CHECK: SWIFT_INLINE_THUNK void Struct::staticMethod() SWIFT_AVAILABILITY(macos,introduced=11) {
// CHECK: SWIFT_INLINE_THUNK void Struct::unavailableMethod() const SWIFT_UNAVAILABLE_MSG("stuff happened") {
// CHECK: SWIFT_INLINE_THUNK swift::Int Struct::operator [](swift::Int x) const SWIFT_SYMBOL("s:7Methods6StructVyS2icig") SWIFT_AVAILABILITY(macos,introduced=11)

View File

@@ -0,0 +1,30 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Methods -clang-header-expose-decls=all-public -emit-clang-header-path %t/methods.h
// RUN: %FileCheck %s < %t/methods.h
// RUN: %check-interop-cxx-header-in-clang(%t/methods.h)
public struct Struct {
public var field: Int16
init() {
field = 0
}
@available(macOS 11, *)
public var getterOnly: Int {
return 0
}
@available(*, unavailable, message: "stuff happened")
public static var staticUnavailableProp: Int {
return 0
}
}
// CHECK: SWIFT_INLINE_THUNK swift::Int getGetterOnly() const SWIFT_SYMBOL("s:7Methods6StructV10getterOnlySivp") SWIFT_AVAILABILITY(macos,introduced=11);
// CHECK: static SWIFT_INLINE_THUNK swift::Int getStaticUnavailableProp() SWIFT_SYMBOL("s:7Methods6StructV21staticUnavailablePropSivpZ") SWIFT_UNAVAILABLE_MSG("stuff happened");
// CHECK: SWIFT_INLINE_THUNK swift::Int Struct::getGetterOnly() const SWIFT_AVAILABILITY(macos,introduced=11) {
// CHECK: SWIFT_INLINE_THUNK swift::Int Struct::getStaticUnavailableProp() SWIFT_UNAVAILABLE_MSG("stuff happened") {

View File

@@ -0,0 +1,37 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Struct -clang-header-expose-decls=all-public -emit-clang-header-path %t/struct.h
// RUN: %FileCheck %s < %t/struct.h
// RUN: %check-interop-cxx-header-in-clang(%t/struct.h)
@available(macOS 11, *)
public struct StructWithMacAvailability {
var field: Int16
init() {
field = 0
}
}
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) SWIFT_SYMBOL("s:6Struct0A19WithMacAvailabilityV") StructWithMacAvailability;
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) _impl_StructWithMacAvailability;
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) SWIFT_SYMBOL("s:6Struct0A19WithMacAvailabilityV") StructWithMacAvailability final {
// CHECK: class SWIFT_AVAILABILITY(macos,introduced=11) _impl_StructWithMacAvailability {
// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) TypeMetadataTrait<Struct::StructWithMacAvailability> {
// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) implClassFor<Struct::StructWithMacAvailability>
@available(*, unavailable, message: "stuff happened")
public struct StructWithUnavailable {
var field: Int16
init() {
field = 0
}
}
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") _impl_StructWithUnavailable;
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") SWIFT_SYMBOL("s:6Struct0A15WithUnavailableV") StructWithUnavailable final
// CHECK: class SWIFT_UNAVAILABLE_MSG("stuff happened") _impl_StructWithUnavailable {
// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") TypeMetadataTrait<Struct::StructWithUnavailable> {
// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") implClassFor<Struct::StructWithUnavailable>