mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[interop][SwiftToCxx] emit swift type metadata access function declaration for structs
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
@@ -67,6 +68,31 @@ public:
|
||||
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
|
||||
callback);
|
||||
|
||||
/// An representation of a single type, or a C struct with multiple members
|
||||
/// with specified types. The C struct is expected to be passed via swiftcc
|
||||
/// functions.
|
||||
class TypeRecordABIRepresentation {
|
||||
public:
|
||||
ArrayRef<Type> getMembers() const { return members; }
|
||||
|
||||
using MemberVectorTy = SmallVector<Type, 4>;
|
||||
|
||||
private:
|
||||
friend class IRABIDetailsProviderImpl;
|
||||
TypeRecordABIRepresentation(MemberVectorTy members) : members(members) {}
|
||||
|
||||
MemberVectorTy members;
|
||||
};
|
||||
|
||||
struct FunctionABISignature {
|
||||
TypeRecordABIRepresentation returnType;
|
||||
SmallVector<TypeRecordABIRepresentation, 4> parameterTypes;
|
||||
};
|
||||
|
||||
/// Returns the function signature that is used for the the type metadata
|
||||
/// access function.
|
||||
FunctionABISignature getTypeMetadataAccessFunctionSignature();
|
||||
|
||||
private:
|
||||
std::unique_ptr<IRABIDetailsProviderImpl> impl;
|
||||
};
|
||||
|
||||
@@ -107,6 +107,21 @@ public:
|
||||
return hasError;
|
||||
}
|
||||
|
||||
IRABIDetailsProvider::FunctionABISignature
|
||||
getTypeMetadataAccessFunctionSignature() {
|
||||
auto &ctx = IGM.getSwiftModule()->getASTContext();
|
||||
llvm::StructType *responseTy = IGM.getTypeMetadataResponseTy();
|
||||
IRABIDetailsProvider::TypeRecordABIRepresentation::MemberVectorTy members;
|
||||
for (auto *elementTy : responseTy->elements())
|
||||
members.push_back(*getPrimitiveTypeFromLLVMType(ctx, elementTy));
|
||||
auto returnTy =
|
||||
IRABIDetailsProvider::TypeRecordABIRepresentation(std::move(members));
|
||||
auto paramTy = IRABIDetailsProvider::TypeRecordABIRepresentation(
|
||||
{*getPrimitiveTypeFromLLVMType(ctx,
|
||||
IGM.getTypeMetadataRequestParamTy())});
|
||||
return {returnTy, {paramTy}};
|
||||
}
|
||||
|
||||
private:
|
||||
Lowering::TypeConverter typeConverter;
|
||||
// Default silOptions are sufficient, as we don't need to generated SIL.
|
||||
@@ -142,3 +157,8 @@ bool IRABIDetailsProvider::enumerateDirectPassingRecordMembers(
|
||||
callback) {
|
||||
return impl->enumerateDirectPassingRecordMembers(t, callback);
|
||||
}
|
||||
|
||||
IRABIDetailsProvider::FunctionABISignature
|
||||
IRABIDetailsProvider::getTypeMetadataAccessFunctionSignature() {
|
||||
return impl->getTypeMetadataAccessFunctionSignature();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ add_swift_host_library(swiftPrintAsClang STATIC
|
||||
PrintAsClang.cpp
|
||||
PrintClangFunction.cpp
|
||||
PrintClangValueType.cpp
|
||||
PrintSwiftToClangCoreScaffold.cpp
|
||||
SwiftToClangInteropContext.cpp)
|
||||
target_link_libraries(swiftPrintAsClang PRIVATE
|
||||
swiftAST
|
||||
|
||||
@@ -72,6 +72,21 @@ void ClangSyntaxPrinter::printNamespace(
|
||||
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter);
|
||||
}
|
||||
|
||||
void ClangSyntaxPrinter::printExternC(
|
||||
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
|
||||
os << "#ifdef __cplusplus\n";
|
||||
os << "extern \"C\" {\n";
|
||||
os << "#endif\n\n";
|
||||
bodyPrinter(os);
|
||||
os << "\n#ifdef __cplusplus\n";
|
||||
os << "}\n";
|
||||
os << "#endif\n";
|
||||
}
|
||||
|
||||
void ClangSyntaxPrinter::printSwiftImplQualifier() const {
|
||||
os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
|
||||
}
|
||||
|
||||
void ClangSyntaxPrinter::printNullability(
|
||||
Optional<OptionalTypeKind> kind, NullabilityPrintKind printKind) const {
|
||||
if (!kind)
|
||||
|
||||
@@ -55,6 +55,13 @@ public:
|
||||
printNamespace(StringRef name,
|
||||
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
|
||||
|
||||
/// Print an extern C block with given body.
|
||||
void
|
||||
printExternC(llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
|
||||
|
||||
/// Print the `swift::_impl::` namespace qualifier.
|
||||
void printSwiftImplQualifier() const;
|
||||
|
||||
/// Where nullability information should be printed.
|
||||
enum class NullabilityPrintKind {
|
||||
Before,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "DeclAndTypePrinter.h"
|
||||
#include "OutputLanguageMode.h"
|
||||
#include "PrimitiveTypeMapping.h"
|
||||
#include "PrintSwiftToClangCoreScaffold.h"
|
||||
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/Module.h"
|
||||
@@ -138,6 +139,8 @@ public:
|
||||
access, outputLang),
|
||||
outputLangMode(outputLang) {}
|
||||
|
||||
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
|
||||
|
||||
/// Returns true if we added the decl's module to the import set, false if
|
||||
/// the decl is a local decl.
|
||||
///
|
||||
@@ -659,9 +662,14 @@ void swift::printModuleContentsAsCxx(
|
||||
std::string modulePrologueBuf;
|
||||
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
|
||||
|
||||
ModuleWriter(moduleOS, prologueOS, imports, M, interopContext,
|
||||
getRequiredAccess(M), OutputLanguageMode::Cxx)
|
||||
.write();
|
||||
ModuleWriter writer(moduleOS, prologueOS, imports, M, interopContext,
|
||||
getRequiredAccess(M), OutputLanguageMode::Cxx);
|
||||
writer.write();
|
||||
|
||||
os << "#ifndef SWIFT_PRINTED_CORE\n";
|
||||
os << "#define SWIFT_PRINTED_CORE\n";
|
||||
printSwiftToClangCoreScaffold(interopContext, writer.getTypeMapping(), os);
|
||||
os << "#endif\n";
|
||||
|
||||
// FIXME: refactor.
|
||||
if (!prologueOS.str().empty()) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "swift/AST/TypeVisitor.h"
|
||||
#include "swift/ClangImporter/ClangImporter.h"
|
||||
#include "swift/IRGen/IRABIDetailsProvider.h"
|
||||
#include "swift/IRGen/Linking.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
using namespace swift;
|
||||
@@ -59,6 +60,22 @@ printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
|
||||
os << "};\n\n";
|
||||
}
|
||||
|
||||
void printCTypeMetadataTypeFunction(raw_ostream &os,
|
||||
const NominalTypeDecl *typeDecl) {
|
||||
os << "// Type metadata accessor for " << typeDecl->getNameStr() << "\n";
|
||||
auto entity = irgen::LinkEntity::forTypeMetadataAccessFunction(
|
||||
typeDecl->getDeclaredType()->getCanonicalType());
|
||||
os << "SWIFT_EXTERN ";
|
||||
ClangSyntaxPrinter printer(os);
|
||||
printer.printSwiftImplQualifier();
|
||||
os << "MetadataResponseTy ";
|
||||
entity.mangle(os);
|
||||
os << '(';
|
||||
printer.printSwiftImplQualifier();
|
||||
os << "MetadataRequestTy)";
|
||||
os << " SWIFT_NOEXCEPT SWIFT_CALL;\n\n";
|
||||
}
|
||||
|
||||
void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
|
||||
auto typeSizeAlign =
|
||||
interopContext.getIrABIDetails().getTypeSizeAlignment(SD);
|
||||
@@ -78,7 +95,11 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
|
||||
[&](raw_ostream &os) {
|
||||
os << "class ";
|
||||
printCxxImplClassName(os, SD);
|
||||
os << ";\n";
|
||||
os << ";\n\n";
|
||||
|
||||
// Print out special functions, like functions that
|
||||
// access type metadata.
|
||||
printCTypeMetadataTypeFunction(os, SD);
|
||||
});
|
||||
|
||||
// Print out the C++ class itself.
|
||||
|
||||
88
lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp
Normal file
88
lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
//===--- 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/AST/Decl.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/IRGen/IRABIDetailsProvider.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 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 swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
31
lib/PrintAsClang/PrintSwiftToClangCoreScaffold.h
Normal file
31
lib/PrintAsClang/PrintSwiftToClangCoreScaffold.h
Normal file
@@ -0,0 +1,31 @@
|
||||
//===--- PrintSwiftToClangCoreScaffold.h - 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
|
||||
#define SWIFT_PRINTASCLANG_PRINTSWIFTTOCLANGCORESCAFFOLD_H
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
class PrimitiveTypeMapping;
|
||||
class SwiftToClangInteropContext;
|
||||
|
||||
/// Print out the core declarations required by C/C++ that are part of the core
|
||||
/// Swift stdlib code.
|
||||
void printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
|
||||
PrimitiveTypeMapping &typeMapping,
|
||||
llvm::raw_ostream &os);
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
|
||||
// RUN: %FileCheck %s < %t/core.h
|
||||
|
||||
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
|
||||
|
||||
// REQUIRES: PTRSIZE=64
|
||||
|
||||
// CHECK: namespace swift {
|
||||
|
||||
// CHECK: namespace _impl {
|
||||
|
||||
// CHECK: // Swift type metadata response type.
|
||||
// CHECK-NEXT: struct MetadataResponseTy {
|
||||
// CHECK-NEXT: void * _Null_unspecified _0;
|
||||
// CHECK-NEXT: uint64_t _1;
|
||||
// CHECK-NEXT: };
|
||||
// CHECK-NEXT: // Swift type metadata request type.
|
||||
// CHECK-NEXT: typedef uint64_t MetadataRequestTy;
|
||||
35
test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift
Normal file
35
test/Interop/SwiftToCxx/core/swift-impl-defs-in-cxx.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend %s -typecheck -module-name Core -clang-header-expose-public-decls -emit-clang-header-path %t/core.h
|
||||
// RUN: %FileCheck %s < %t/core.h
|
||||
|
||||
// RUN: %check-interop-cxx-header-in-clang(%t/core.h)
|
||||
|
||||
|
||||
// CHECK: #ifndef SWIFT_PRINTED_CORE
|
||||
// CHECK-NEXT: #define SWIFT_PRINTED_CORE
|
||||
// CHECK-NEXT: namespace swift {
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: namespace _impl {
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: #ifdef __cplusplus
|
||||
// CHECK-NEXT: extern "C" {
|
||||
// CHECK-NEXT: #endif
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: // Swift type metadata response type.
|
||||
// CHECK-NEXT: struct MetadataResponseTy {
|
||||
// CHECK-NEXT: void * _Null_unspecified _0;
|
||||
// CHECK-NEXT: uint{{.*}}_t _1;
|
||||
// CHECK-NEXT: };
|
||||
// CHECK-NEXT: // Swift type metadata request type.
|
||||
// CHECK-NEXT: typedef uint{{.*}}_t MetadataRequestTy;
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: #ifdef __cplusplus
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: #endif
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: } // namespace _impl
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: } // namespace swift
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: #endif
|
||||
@@ -13,6 +13,10 @@
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: class _impl_StructWithIntField;
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: // Type metadata accessor for StructWithIntField
|
||||
// CHECK-NEXT: SWIFT_EXTERN swift::_impl::MetadataResponseTy $s7Structs18StructWithIntFieldVMa(swift::_impl::MetadataRequestTy) SWIFT_NOEXCEPT SWIFT_CALL;
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: }
|
||||
|
||||
// CHECK: class StructWithIntField final {
|
||||
|
||||
@@ -70,7 +70,11 @@
|
||||
// CHECK-LABEL: #if defined(__OBJC__)
|
||||
// CHECK-NEXT: #endif
|
||||
// CHECK-NEXT: #if defined(__cplusplus)
|
||||
// CHECK-NEXT: namespace empty {
|
||||
// CHECK-NEXT: #ifndef SWIFT_PRINTED_CORE
|
||||
// CHECK: } // namespace swift
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: #endif
|
||||
// CHECK: namespace empty {
|
||||
// CHECK: } // namespace empty
|
||||
// CHECK: #endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user