//===--- PrintSwiftToClangCoreScaffold.cpp - Print core decls ---*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "PrintSwiftToClangCoreScaffold.h" #include "ClangSyntaxPrinter.h" #include "PrimitiveTypeMapping.h" #include "SwiftToClangInteropContext.h" #include "swift/ABI/MetadataValues.h" #include "swift/AST/Decl.h" #include "swift/AST/Type.h" #include "swift/Basic/Assertions.h" #include "swift/IRGen/IRABIDetailsProvider.h" #include "swift/IRGen/Linking.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" using namespace swift; static void printKnownStruct(const ASTContext &astContext, PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name, const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) { assert(typeRecord.getMembers().size() > 1); os << "struct " << name << " {\n"; for (const auto &ty : llvm::enumerate(typeRecord.getMembers())) { os << " "; ClangSyntaxPrinter(astContext, os).printKnownCType(ty.value(), typeMapping); os << " _" << ty.index() << ";\n"; } os << "};\n"; } static void printKnownTypedef(const ASTContext &astContext, PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name, const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) { assert(typeRecord.getMembers().size() == 1); os << "typedef "; ClangSyntaxPrinter(astContext, os).printKnownCType(typeRecord.getMembers()[0], typeMapping); os << " " << name << ";\n"; } static void printKnownType(const ASTContext &astContext, PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name, const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) { if (typeRecord.getMembers().size() == 1) return printKnownTypedef(astContext, typeMapping, os, name, typeRecord); printKnownStruct(astContext, typeMapping, os, name, typeRecord); } static void printValueWitnessTableFunctionType(raw_ostream &os, StringRef prefix, StringRef name, StringRef returnType, std::string paramTypes, uint16_t ptrauthDisc) { os << "using " << prefix << name << "Ty = " << returnType << "(* __ptrauth_swift_value_witness_function_pointer(" << ptrauthDisc << "))(" << paramTypes << ") SWIFT_NOEXCEPT_FUNCTION_PTR;\n"; } static std::string makeParams(const char *arg) { return arg; } template static std::string makeParams(const char *arg, const T... args) { return std::string(arg) + ", " + makeParams(args...); } static void printValueWitnessTable(raw_ostream &os) { std::string members; llvm::raw_string_ostream membersOS(members); // C++ only supports noexcept on `using` function types in C++17. os << "#if __cplusplus > 201402L\n"; os << "# define SWIFT_NOEXCEPT_FUNCTION_PTR noexcept\n"; os << "#else\n"; os << "# define SWIFT_NOEXCEPT_FUNCTION_PTR\n"; os << "#endif\n\n"; #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define DATA_VALUE_WITNESS(lowerId, upperId, type) \ membersOS << " " << type << " " << #lowerId << ";\n"; #define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ printValueWitnessTableFunctionType( \ os, "ValueWitness", #upperId, returnType, makeParams paramTypes, \ SpecialPointerAuthDiscriminators::upperId); \ membersOS << " ValueWitness" << #upperId << "Ty _Nonnull " << #lowerId \ << ";\n"; #define MUTABLE_VALUE_TYPE "void * _Nonnull" #define IMMUTABLE_VALUE_TYPE "const void * _Nonnull" #define MUTABLE_BUFFER_TYPE "void * _Nonnull" #define IMMUTABLE_BUFFER_TYPE "const void * _Nonnull" #define TYPE_TYPE "void * _Nonnull" #define SIZE_TYPE "size_t" #define INT_TYPE "int" #define UINT_TYPE "unsigned" #define VOID_TYPE "void" #include "swift/ABI/ValueWitness.def" membersOS << "\n constexpr size_t getAlignment() const { return (flags & " << TargetValueWitnessFlags::AlignmentMask << ") + 1; }\n"; os << "\nstruct ValueWitnessTable {\n" << membersOS.str() << "};\n\n"; membersOS.str().clear(); #define WANT_ONLY_ENUM_VALUE_WITNESSES #define DATA_VALUE_WITNESS(lowerId, upperId, type) \ membersOS << " " << type << " " << #lowerId << ";\n"; #define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ printValueWitnessTableFunctionType( \ os, "EnumValueWitness", #upperId, returnType, makeParams paramTypes, \ SpecialPointerAuthDiscriminators::upperId); \ membersOS << " EnumValueWitness" << #upperId << "Ty _Nonnull " << #lowerId \ << ";\n"; #define MUTABLE_VALUE_TYPE "void * _Nonnull" #define IMMUTABLE_VALUE_TYPE "const void * _Nonnull" #define MUTABLE_BUFFER_TYPE "void * _Nonnull" #define IMMUTABLE_BUFFER_TYPE "const void * _Nonnull" #define TYPE_TYPE "void * _Nonnull" #define SIZE_TYPE "size_t" #define INT_TYPE "int" #define UINT_TYPE "unsigned" #define VOID_TYPE "void" #include "swift/ABI/ValueWitness.def" os << "\nstruct EnumValueWitnessTable {\n" << " ValueWitnessTable vwTable;\n" << membersOS.str() << "};\n\n"; os << "#undef SWIFT_NOEXCEPT_FUNCTION_PTR\n\n"; } static void printTypeMetadataResponseType(SwiftToClangInteropContext &ctx, PrimitiveTypeMapping &typeMapping, raw_ostream &os) { os << "// Swift type metadata response type.\n"; // Print out the type metadata structure. auto funcSig = ctx.getIrABIDetails().getTypeMetadataAccessFunctionSignature(); printKnownType(ctx.getASTContext(), typeMapping, os, "MetadataResponseTy", funcSig.returnType); assert(funcSig.parameterTypes.size() == 1); os << "// Swift type metadata request type.\n"; printKnownType(ctx.getASTContext(), typeMapping, os, "MetadataRequestTy", funcSig.parameterTypes[0]); } void printPrimitiveGenericTypeTraits(raw_ostream &os, ASTContext &astContext, PrimitiveTypeMapping &typeMapping, bool isCForwardDefinition) { Type supportedPrimitiveTypes[] = { astContext.getBoolType(), // Primitive integer, C integer and Int/UInt mappings. astContext.getInt8Type(), astContext.getUInt8Type(), astContext.getInt16Type(), astContext.getUInt16Type(), astContext.getInt32Type(), astContext.getUInt32Type(), astContext.getInt64Type(), astContext.getUInt64Type(), // Primitive floating point type mappings. astContext.getFloatType(), astContext.getDoubleType(), // Pointer types. // FIXME: support raw pointers? astContext.getOpaquePointerType(), astContext.getIntType(), astContext.getUIntType()}; auto primTypesArray = llvm::ArrayRef(supportedPrimitiveTypes); // Ensure that `long` and `unsigned long` are treated as valid // generic Swift types (`Int` and `UInt`) on platforms // that do define `Int`/`ptrdiff_t` as `long` and don't define `int64_t` to be // `long`. auto &clangTI = astContext.getClangModuleLoader()->getClangASTContext().getTargetInfo(); bool isSwiftIntLong = clangTI.getPtrDiffType(clang::LangAS::Default) == clang::TransferrableTargetInfo::SignedLong; bool isInt64Long = clangTI.getInt64Type() == clang::TransferrableTargetInfo::SignedLong; if (!(isSwiftIntLong && !isInt64Long)) primTypesArray = primTypesArray.drop_back(2); // We do not have metadata for primitive types in Embedded Swift. // As a result, the following features are not supported with primitive types in this mode: // - Dynamic casts // - Static self // - Generic requirement parameters // - Metadata source parameter bool embedded = astContext.LangOpts.hasFeature(Feature::Embedded); for (Type type : primTypesArray) { auto typeInfo = *typeMapping.getKnownCxxTypeInfo( type->getNominalOrBoundGenericNominal()); if (!isCForwardDefinition) { os << "template<>\n"; os << "inline const constexpr bool isUsableInGenericContext<" << typeInfo.name << "> = true;\n\n"; } if (embedded) continue; auto typeMetadataFunc = irgen::LinkEntity::forTypeMetadata( type->getCanonicalType(), irgen::TypeMetadataAddress::AddressPoint); std::string typeMetadataVarName = typeMetadataFunc.mangleAsString(type->getASTContext()); if (isCForwardDefinition) { os << "// type metadata address for " << type.getString() << ".\n"; os << "SWIFT_IMPORT_STDLIB_SYMBOL extern size_t " << typeMetadataVarName << ";\n"; continue; } os << "template<>\nstruct TypeMetadataTrait<" << typeInfo.name << "> {\n" << " static "; ClangSyntaxPrinter(astContext, os).printInlineForThunk(); os << "void * _Nonnull getTypeMetadata() {\n" << " return &" << cxx_synthesis::getCxxImplNamespaceName() << "::" << typeMetadataVarName << ";\n" << " }\n};\n\n"; } } void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx, ASTContext &astContext, PrimitiveTypeMapping &typeMapping, raw_ostream &os) { ClangSyntaxPrinter printer(astContext, os); printer.printNamespace( cxx_synthesis::getCxxSwiftNamespaceName(), [&](raw_ostream &) { printer.printNamespace( cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &) { printer.printExternC([&](raw_ostream &os) { printTypeMetadataResponseType(ctx, typeMapping, os); os << "\n"; printValueWitnessTable(os); os << "\n"; printPrimitiveGenericTypeTraits(os, astContext, typeMapping, /*isCForwardDefinition=*/true); }); os << "\n"; }); os << "\n"; // C++ only supports inline variables from C++17. ClangSyntaxPrinter(astContext, os).printIgnoredCxx17ExtensionDiagnosticBlock([&]() { printPrimitiveGenericTypeTraits(os, astContext, typeMapping, /*isCForwardDefinition=*/false); }); }, ClangSyntaxPrinter::NamespaceTrivia::AttributeSwiftPrivate); }