//===--- 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/IRGen/IRABIDetailsProvider.h" #include "swift/IRGen/Linking.h" #include "llvm/ADT/STLExtras.h" using namespace swift; static void printKnownCType(Type t, PrimitiveTypeMapping &typeMapping, raw_ostream &os) { auto info = typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); assert(info.hasValue() && "not a known type"); os << info->name; if (info->canBeNullable) os << " _Null_unspecified"; } static void printKnownStruct( 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 << " "; printKnownCType(ty.value(), typeMapping, os); os << " _" << ty.index() << ";\n"; } os << "};\n"; } static void printKnownTypedef( PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name, const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) { assert(typeRecord.getMembers().size() == 1); os << "typedef "; printKnownCType(typeRecord.getMembers()[0], typeMapping, os); os << " " << name << ";\n"; } static void printKnownType( PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name, const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) { if (typeRecord.getMembers().size() == 1) return printKnownTypedef(typeMapping, os, name, typeRecord); printKnownStruct(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(typeMapping, os, "MetadataResponseTy", funcSig.returnType); assert(funcSig.parameterTypes.size() == 1); os << "// Swift type metadata request type.\n"; printKnownType(typeMapping, os, "MetadataRequestTy", funcSig.parameterTypes[0]); } void printCxxNaiveException(raw_ostream &os) { os << "/// Naive exception class that should be thrown\n"; os << "class NaiveException {\n"; os << "public:\n"; os << " inline NaiveException(const char * _Nonnull msg) noexcept : " << "msg_(msg) { }\n"; os << " inline NaiveException(NaiveException&& other) noexcept : " "msg_(other.msg_) { other.msg_ = nullptr; }\n"; os << " inline ~NaiveException() noexcept { }\n"; os << " void operator =(NaiveException&& other) noexcept { auto temp = msg_;" << " msg_ = other.msg_; other.msg_ = temp; }\n"; os << " void operator =(const NaiveException&) noexcept = delete;"; os << "\n"; os << " inline const char * _Nonnull getMessage() const noexcept { " << "return(msg_); }\n"; os << "private:\n"; os << " const char * _Nonnull msg_;\n"; os << "};\n"; } 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()}; for (Type type : llvm::makeArrayRef(supportedPrimitiveTypes)) { auto typeInfo = *typeMapping.getKnownCxxTypeInfo( type->getNominalOrBoundGenericNominal()); auto typeMetadataFunc = irgen::LinkEntity::forTypeMetadata( type->getCanonicalType(), irgen::TypeMetadataAddress::AddressPoint); std::string typeMetadataVarName = typeMetadataFunc.mangleAsString(); if (isCForwardDefinition) { os << "// type metadata address for " << type.getString() << ".\n"; os << "SWIFT_IMPORT_STDLIB_SYMBOL extern size_t " << typeMetadataVarName << ";\n"; continue; } os << "template<>\n"; os << "static inline const constexpr bool isUsableInGenericContext<" << typeInfo.name << "> = true;\n\n"; os << "template<>\ninline void * _Nonnull getTypeMetadata<"; os << typeInfo.name << ">() {\n"; os << " return &" << cxx_synthesis::getCxxImplNamespaceName() << "::" << typeMetadataVarName << ";\n"; os << "}\n\n"; } } void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx, ASTContext &astContext, PrimitiveTypeMapping &typeMapping, raw_ostream &os) { ClangSyntaxPrinter printer(os); printer.printNamespace("swift", [&](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"; printCxxNaiveException(os); }); os << "\n"; // C++ only supports inline variables from C++17. // FIXME: silence the warning instead? os << "#if __cplusplus > 201402L\n"; printPrimitiveGenericTypeTraits(os, astContext, typeMapping, /*isCForwardDefinition=*/false); os << "#endif\n"; }); }