mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
296 lines
12 KiB
C++
296 lines
12 KiB
C++
//===--- 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 <class... T>
|
|
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"
|
|
|
|
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]);
|
|
}
|
|
|
|
static void printSwiftResilientStorageClass(raw_ostream &os) {
|
|
auto name = cxx_synthesis::getCxxOpaqueStorageClassName();
|
|
static_assert(TargetValueWitnessFlags<uint64_t>::AlignmentMask ==
|
|
TargetValueWitnessFlags<uint32_t>::AlignmentMask,
|
|
"alignment mask doesn't match");
|
|
os << "/// Container for an opaque Swift value, like resilient struct.\n";
|
|
os << "class " << name << " {\n";
|
|
os << "public:\n";
|
|
os << " inline " << name << "() noexcept : storage(nullptr) { }\n";
|
|
os << " inline " << name
|
|
<< "(ValueWitnessTable * _Nonnull vwTable) noexcept : storage("
|
|
"reinterpret_cast<char *>(opaqueAlloc(vwTable->size, (vwTable->flags &"
|
|
<< TargetValueWitnessFlags<uint64_t>::AlignmentMask << ") + 1))) { }\n";
|
|
os << " inline " << name << "(" << name
|
|
<< "&& other) noexcept : storage(other.storage) { other.storage = "
|
|
"nullptr; }\n";
|
|
os << " inline " << name << "(const " << name << "&) noexcept = delete;\n";
|
|
os << " inline ~" << name
|
|
<< "() noexcept { if (storage) { opaqueFree(static_cast<char "
|
|
"* _Nonnull>(storage)); } }\n";
|
|
os << " void operator =(" << name
|
|
<< "&& other) noexcept { auto temp = storage; storage = other.storage; "
|
|
"other.storage = temp; }\n";
|
|
os << " void operator =(const " << name << "&) noexcept = delete;\n";
|
|
os << " inline char * _Nonnull getOpaquePointer() noexcept { return "
|
|
"static_cast<char "
|
|
"* _Nonnull>(storage); }\n";
|
|
os << " inline const char * _Nonnull getOpaquePointer() const noexcept { "
|
|
"return "
|
|
"static_cast<char * _Nonnull>(storage); }\n";
|
|
os << "private:\n";
|
|
os << " char * _Nullable storage;\n";
|
|
os << "};\n";
|
|
}
|
|
|
|
void printCxxNaiveException(raw_ostream &os) {
|
|
os << "\n";
|
|
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 printGenericTypeTraits(raw_ostream &os) {
|
|
os << "template<class T>\n";
|
|
os << "static inline const constexpr bool isUsableInGenericContext = "
|
|
"false;\n\n";
|
|
os << "template<class T> inline void * _Nonnull getTypeMetadata();\n\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";
|
|
printSwiftResilientStorageClass(os);
|
|
printCxxNaiveException(os);
|
|
});
|
|
os << "\n";
|
|
// C++ only supports inline variables from C++17.
|
|
// FIXME: silence the warning instead?
|
|
os << "#if __cplusplus > 201402L\n";
|
|
printGenericTypeTraits(os);
|
|
printPrimitiveGenericTypeTraits(os, astContext, typeMapping,
|
|
/*isCForwardDefinition=*/false);
|
|
os << "#endif\n";
|
|
});
|
|
}
|