mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
260 lines
11 KiB
C++
260 lines
11 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/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 <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"
|
|
|
|
membersOS << "\n constexpr size_t getAlignment() const { return (flags & "
|
|
<< TargetValueWitnessFlags<uint64_t>::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);
|
|
}
|