diff --git a/lib/PrintAsClang/DeclAndTypePrinter.cpp b/lib/PrintAsClang/DeclAndTypePrinter.cpp index 62d82f8eee711..455d63b6f3bbc 100644 --- a/lib/PrintAsClang/DeclAndTypePrinter.cpp +++ b/lib/PrintAsClang/DeclAndTypePrinter.cpp @@ -243,7 +243,8 @@ class DeclAndTypePrinter::Implementation } /// 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 @@ class DeclAndTypePrinter::Implementation 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 @@ class DeclAndTypePrinter::Implementation 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 @@ class DeclAndTypePrinter::Implementation 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 - - 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'; - } + 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'; + } - 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"; - // 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()); - }); + printMembers(ED->getMembers()); + }, + owningPrinter); } void visitEnumDecl(EnumDecl *ED) { @@ -1024,17 +1033,17 @@ class DeclAndTypePrinter::Implementation if (auto *accessor = dyn_cast(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 @@ class DeclAndTypePrinter::Implementation if (auto *accessor = dyn_cast(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 @@ class DeclAndTypePrinter::Implementation 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 @@ class DeclAndTypePrinter::Implementation os << "SWIFT_UNAVAILABLE_MSG(\"'" << cast(D)->getBaseName() << "' has been renamed to '"; - printRenameForDecl(AvAttr, cast(D), false); + printRenameForDecl(os, AvAttr, cast(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 @@ class DeclAndTypePrinter::Implementation 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(D), true); + printRenameForDecl(os, AvAttr, cast(D), true); } os << ")"; } else { @@ -1655,24 +1671,25 @@ class DeclAndTypePrinter::Implementation if (!AvAttr->Rename.empty() && isa(D)) { os << ",message=\"'" << cast(D)->getBaseName() << "' has been renamed to '"; - printRenameForDecl(AvAttr, cast(D), false); + printRenameForDecl(os, AvAttr, cast(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 @@ class DeclAndTypePrinter::Implementation 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 @@ class DeclAndTypePrinter::Implementation 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 @@ class DeclAndTypePrinter::Implementation 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 members) { getImpl().printAdHocCategory(members); diff --git a/lib/PrintAsClang/DeclAndTypePrinter.h b/lib/PrintAsClang/DeclAndTypePrinter.h index 41a59af07a93c..d668a5ed79194 100644 --- a/lib/PrintAsClang/DeclAndTypePrinter.h +++ b/lib/PrintAsClang/DeclAndTypePrinter.h @@ -81,6 +81,8 @@ class DeclAndTypePrinter { 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); diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index e557f33d86f3b..2a4fab59f4d35 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -289,12 +289,14 @@ class ModuleWriter { 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) { diff --git a/lib/PrintAsClang/PrintClangClassType.cpp b/lib/PrintAsClang/PrintClangClassType.cpp index 769128413e649..ad1de253db0fb 100644 --- a/lib/PrintAsClang/PrintClangClassType.cpp +++ b/lib/PrintAsClang/PrintClangClassType.cpp @@ -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 bodyPrinter) { + const ClassDecl *typeDecl, llvm::function_ref 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( diff --git a/lib/PrintAsClang/PrintClangClassType.h b/lib/PrintAsClang/PrintClangClassType.h index 44fa2c8c68f2e..566f11e841c51 100644 --- a/lib/PrintAsClang/PrintClangClassType.h +++ b/lib/PrintAsClang/PrintClangClassType.h @@ -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 @@ class ClangClassTypePrinter { /// Print the C++ class definition that corresponds to the given Swift class. void printClassTypeDecl(const ClassDecl *typeDecl, - llvm::function_ref bodyPrinter); + llvm::function_ref bodyPrinter, + DeclAndTypePrinter &declAndTypePrinter); static void printClassTypeReturnScaffold(raw_ostream &os, const ClassDecl *type, diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 5fbb447c49055..62b7085129244 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -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; diff --git a/lib/PrintAsClang/PrintClangFunction.h b/lib/PrintAsClang/PrintClangFunction.h index 206c0e8d78b33..536b4fb7cb3c7 100644 --- a/lib/PrintAsClang/PrintClangFunction.h +++ b/lib/PrintAsClang/PrintClangFunction.h @@ -119,6 +119,7 @@ class DeclAndTypeClangFunctionPrinter { /// 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 @@ class DeclAndTypeClangFunctionPrinter { /// 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 @@ class DeclAndTypeClangFunctionPrinter { /// Print the C++ subscript method. void printCxxSubscriptAccessorMethod( + DeclAndTypePrinter &declAndTypePrinter, const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor, const LoweredFunctionSignature &signature, StringRef swiftSymbolName, Type resultTy, bool isDefinition, diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index e02a2c1bf8863..d7719a10f9566 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -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 bodyPrinter) { + const NominalTypeDecl *typeDecl, llvm::function_ref bodyPrinter, + DeclAndTypePrinter &declAndTypePrinter) { // FIXME: Add support for generic structs. llvm::Optional typeSizeAlign; Optional 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(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 typeMetadataFuncRequirements, - const ModuleDecl *moduleContext) { + const ModuleDecl *moduleContext, DeclAndTypePrinter &declAndTypePrinter) { auto *NTD = dyn_cast(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); diff --git a/lib/PrintAsClang/PrintClangValueType.h b/lib/PrintAsClang/PrintClangValueType.h index 008a2822c01eb..f857acb14c742 100644 --- a/lib/PrintAsClang/PrintClangValueType.h +++ b/lib/PrintAsClang/PrintClangValueType.h @@ -22,6 +22,7 @@ namespace swift { +class DeclAndTypePrinter; class ModuleDecl; class NominalTypeDecl; class PrimitiveTypeMapping; @@ -39,7 +40,9 @@ class ClangValueTypePrinter { /// Print the C++ class definition that /// corresponds to the given structure or enum declaration. void printValueTypeDecl(const NominalTypeDecl *typeDecl, - llvm::function_ref bodyPrinter); + llvm::function_ref 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 @@ class ClangValueTypePrinter { static void printTypeGenericTraits( raw_ostream &os, const TypeDecl *typeDecl, StringRef typeMetadataFuncName, ArrayRef 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; diff --git a/test/Interop/SwiftToCxx/class/swift-class-availability-in-cxx.swift b/test/Interop/SwiftToCxx/class/swift-class-availability-in-cxx.swift new file mode 100644 index 0000000000000..809804da33bf0 --- /dev/null +++ b/test/Interop/SwiftToCxx/class/swift-class-availability-in-cxx.swift @@ -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 { +// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) implClassFor + +@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 { +// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") implClassFor diff --git a/test/Interop/SwiftToCxx/initializers/swift-init-availability-in-cxx.swift b/test/Interop/SwiftToCxx/initializers/swift-init-availability-in-cxx.swift new file mode 100644 index 0000000000000..fa339063bf31a --- /dev/null +++ b/test/Interop/SwiftToCxx/initializers/swift-init-availability-in-cxx.swift @@ -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) { diff --git a/test/Interop/SwiftToCxx/methods/swift-method-availability-in-cxx.swift b/test/Interop/SwiftToCxx/methods/swift-method-availability-in-cxx.swift new file mode 100644 index 0000000000000..0bd4f3b8f29aa --- /dev/null +++ b/test/Interop/SwiftToCxx/methods/swift-method-availability-in-cxx.swift @@ -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) diff --git a/test/Interop/SwiftToCxx/properties/swift-property-availability-in-cxx.swift b/test/Interop/SwiftToCxx/properties/swift-property-availability-in-cxx.swift new file mode 100644 index 0000000000000..edec4c60e2c92 --- /dev/null +++ b/test/Interop/SwiftToCxx/properties/swift-property-availability-in-cxx.swift @@ -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") { diff --git a/test/Interop/SwiftToCxx/structs/swift-struct-availability-in-cxx.swift b/test/Interop/SwiftToCxx/structs/swift-struct-availability-in-cxx.swift new file mode 100644 index 0000000000000..7b36347633c46 --- /dev/null +++ b/test/Interop/SwiftToCxx/structs/swift-struct-availability-in-cxx.swift @@ -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 { +// CHECK: struct SWIFT_AVAILABILITY(macos,introduced=11) implClassFor + +@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 { +// CHECK: struct SWIFT_UNAVAILABLE_MSG("stuff happened") implClassFor