mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[embedded] Add support for some foreign metadata
This commit is contained in:
@@ -5308,7 +5308,8 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
|
|||||||
|
|
||||||
return cast<llvm::GlobalValue>(addr);
|
return cast<llvm::GlobalValue>(addr);
|
||||||
}
|
}
|
||||||
|
bool hasEmbeddedExistentials =
|
||||||
|
Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
|
||||||
auto entity =
|
auto entity =
|
||||||
(isPrespecialized &&
|
(isPrespecialized &&
|
||||||
!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
|
!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
|
||||||
@@ -5324,7 +5325,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
|
|||||||
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
|
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
entity = LinkEntity::forTypeMetadata(concreteType,
|
entity = LinkEntity::forTypeMetadata(concreteType,
|
||||||
TypeMetadataAddress::AddressPoint);
|
TypeMetadataAddress::AddressPoint);
|
||||||
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
|
if (hasEmbeddedExistentials)
|
||||||
entity = LinkEntity::forTypeMetadata(concreteType,
|
entity = LinkEntity::forTypeMetadata(concreteType,
|
||||||
TypeMetadataAddress::FullMetadata);
|
TypeMetadataAddress::FullMetadata);
|
||||||
}
|
}
|
||||||
@@ -5350,7 +5351,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
|
|||||||
markGlobalAsUsedBasedOnLinkage(*this, link, var);
|
markGlobalAsUsedBasedOnLinkage(*this, link, var);
|
||||||
|
|
||||||
if (Context.LangOpts.hasFeature(Feature::Embedded) &&
|
if (Context.LangOpts.hasFeature(Feature::Embedded) &&
|
||||||
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
|
!hasEmbeddedExistentials) {
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5361,14 +5362,13 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
|
|||||||
if (auto nominal = concreteType->getAnyNominal()) {
|
if (auto nominal = concreteType->getAnyNominal()) {
|
||||||
// Keep type metadata around for all types (except @_objcImplementation,
|
// Keep type metadata around for all types (except @_objcImplementation,
|
||||||
// since we're using ObjC metadata for that).
|
// since we're using ObjC metadata for that).
|
||||||
if (!isObjCImpl &&
|
if (!isObjCImpl && !hasEmbeddedExistentials)
|
||||||
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
|
|
||||||
addRuntimeResolvableType(nominal);
|
addRuntimeResolvableType(nominal);
|
||||||
|
|
||||||
// Don't define the alias for foreign type metadata, prespecialized
|
// Don't define the alias for foreign type metadata, prespecialized
|
||||||
// generic metadata, or @_objcImplementation classes, since they're not ABI.
|
// generic metadata, or @_objcImplementation classes, since they're not ABI.
|
||||||
if (requiresForeignTypeMetadata(nominal) ||
|
if ((requiresForeignTypeMetadata(nominal) && !hasEmbeddedExistentials) ||
|
||||||
(isPrespecialized && !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) ||
|
(isPrespecialized && !hasEmbeddedExistentials) ||
|
||||||
isObjCImpl)
|
isObjCImpl)
|
||||||
return var;
|
return var;
|
||||||
|
|
||||||
@@ -5382,7 +5382,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
|
if (hasEmbeddedExistentials) {
|
||||||
adjustmentIndex = MetadataAdjustmentIndex::EmbeddedWithExistentials;
|
adjustmentIndex = MetadataAdjustmentIndex::EmbeddedWithExistentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7202,17 +7202,23 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
|
|||||||
auto init = builder.beginStruct();
|
auto init = builder.beginStruct();
|
||||||
init.setPacked(true);
|
init.setPacked(true);
|
||||||
|
|
||||||
|
auto isEmbedded =
|
||||||
|
IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
|
||||||
|
|
||||||
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
|
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
|
||||||
if (classDecl->isForeignReferenceType()) {
|
if (classDecl->isForeignReferenceType()) {
|
||||||
|
assert(!isEmbedded && "emitting foregin reference type not supported");
|
||||||
ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init);
|
ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init);
|
||||||
builder.layout();
|
builder.layout();
|
||||||
|
|
||||||
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
||||||
builder.canBeConstant(),
|
builder.canBeConstant(),
|
||||||
init.finishAndCreateFuture());
|
init.finishAndCreateFuture());
|
||||||
|
if (!isEmbedded)
|
||||||
builder.createMetadataAccessFunction();
|
builder.createMetadataAccessFunction();
|
||||||
} else {
|
} else {
|
||||||
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType);
|
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType);
|
||||||
|
assert(!isEmbedded && "emitting foregin cf class type not supported");
|
||||||
|
|
||||||
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
|
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
|
||||||
builder.layout();
|
builder.layout();
|
||||||
@@ -7220,27 +7226,36 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
|
|||||||
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
||||||
builder.canBeConstant(),
|
builder.canBeConstant(),
|
||||||
init.finishAndCreateFuture());
|
init.finishAndCreateFuture());
|
||||||
|
if (!isEmbedded)
|
||||||
builder.createMetadataAccessFunction();
|
builder.createMetadataAccessFunction();
|
||||||
}
|
}
|
||||||
} else if (auto structDecl = dyn_cast<StructDecl>(decl)) {
|
} else if (auto structDecl = dyn_cast<StructDecl>(decl)) {
|
||||||
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
|
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
|
||||||
|
|
||||||
ForeignStructMetadataBuilder builder(IGM, structDecl, init);
|
ForeignStructMetadataBuilder builder(IGM, structDecl, init);
|
||||||
|
if (isEmbedded)
|
||||||
|
builder.embeddedLayout();
|
||||||
|
else
|
||||||
builder.layout();
|
builder.layout();
|
||||||
|
|
||||||
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
||||||
builder.canBeConstant(),
|
builder.canBeConstant(),
|
||||||
init.finishAndCreateFuture());
|
init.finishAndCreateFuture());
|
||||||
|
if (!isEmbedded)
|
||||||
builder.createMetadataAccessFunction();
|
builder.createMetadataAccessFunction();
|
||||||
} else if (auto enumDecl = dyn_cast<EnumDecl>(decl)) {
|
} else if (auto enumDecl = dyn_cast<EnumDecl>(decl)) {
|
||||||
assert(enumDecl->hasClangNode());
|
assert(enumDecl->hasClangNode());
|
||||||
|
|
||||||
ForeignEnumMetadataBuilder builder(IGM, enumDecl, init);
|
ForeignEnumMetadataBuilder builder(IGM, enumDecl, init);
|
||||||
|
if (isEmbedded)
|
||||||
|
builder.embeddedLayout();
|
||||||
|
else
|
||||||
builder.layout();
|
builder.layout();
|
||||||
|
|
||||||
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
IGM.defineTypeMetadata(type, /*isPattern=*/false,
|
||||||
builder.canBeConstant(),
|
builder.canBeConstant(),
|
||||||
init.finishAndCreateFuture());
|
init.finishAndCreateFuture());
|
||||||
|
if (!isEmbedded)
|
||||||
builder.createMetadataAccessFunction();
|
builder.createMetadataAccessFunction();
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("foreign metadata for unexpected type?!");
|
llvm_unreachable("foreign metadata for unexpected type?!");
|
||||||
|
|||||||
34
test/embedded/Inputs/existential_foreign.h
Normal file
34
test/embedded/Inputs/existential_foreign.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long long f1;
|
||||||
|
unsigned long long f2;
|
||||||
|
} SomeCStruct;
|
||||||
|
|
||||||
|
static inline SomeCStruct createSomeCStruct() {
|
||||||
|
SomeCStruct s;
|
||||||
|
s.f1 = 1;
|
||||||
|
s.f2 = 2;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
caseA,
|
||||||
|
caseB,
|
||||||
|
caseC
|
||||||
|
} SomeCEnum;
|
||||||
|
|
||||||
|
static inline SomeCEnum createSomeCEnum() {
|
||||||
|
return caseA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWIFT_ENUM(_type, _name) enum _name : _type
|
||||||
|
|
||||||
|
typedef SWIFT_ENUM(unsigned short, SomeNSEnum) {
|
||||||
|
someCaseA,
|
||||||
|
someCaseB,
|
||||||
|
} SomeNSEnum;
|
||||||
|
|
||||||
|
static inline SomeNSEnum createSomeNSEnum() {
|
||||||
|
return someCaseB;
|
||||||
|
}
|
||||||
102
test/embedded/existential_foreign.swift
Normal file
102
test/embedded/existential_foreign.swift
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/existential_foreign.h -enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s --check-prefix=OUTPUT
|
||||||
|
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/existential_foreign.h -enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s --check-prefix=OUTPUT
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: swift_feature_Embedded
|
||||||
|
// REQUIRES: swift_feature_EmbeddedExistentials
|
||||||
|
|
||||||
|
protocol P {
|
||||||
|
func printme()
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Q {
|
||||||
|
associatedtype Printable : P
|
||||||
|
|
||||||
|
func getPrintable() -> Printable
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SomeCStruct : P {
|
||||||
|
func printme() {
|
||||||
|
print("SomeCStruct: \(self.f1), \(self.f2)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SomeCEnum : P {
|
||||||
|
func printme() {
|
||||||
|
switch self {
|
||||||
|
case caseA:
|
||||||
|
print("SomeCEnum: .caseA")
|
||||||
|
case caseB:
|
||||||
|
print("SomeCEnum: .caseB")
|
||||||
|
case caseC:
|
||||||
|
print("SomeCEnum: .caseC")
|
||||||
|
default:
|
||||||
|
print("SomeCEnum: default")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SomeCStructContainer : Q {
|
||||||
|
let s: SomeCStruct
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.s = createSomeCStruct()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrintable() -> SomeCStruct {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SomeCEnumContainer : Q {
|
||||||
|
let s: SomeCEnum
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.s = createSomeCEnum()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrintable() -> SomeCEnum {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SomeNSEnum : P {
|
||||||
|
func printme() {
|
||||||
|
switch self {
|
||||||
|
case .someCaseA:
|
||||||
|
print("SomeNSEnum: .someCaseA")
|
||||||
|
case .someCaseB:
|
||||||
|
print("SomeNSEnum: .someCaseB")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SomeNSEnumContainer : Q {
|
||||||
|
let s: SomeNSEnum
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.s = createSomeNSEnum()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrintable() -> SomeNSEnum {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
|
||||||
|
let a: [any Q] = [ SomeCStructContainer(), SomeCEnumContainer(), SomeNSEnumContainer() ]
|
||||||
|
|
||||||
|
for x0 in a {
|
||||||
|
let x = x0.getPrintable()
|
||||||
|
x.printme()
|
||||||
|
// OUTPUT: SomeCStruct: 1, 2
|
||||||
|
// OUTPUT: SomeCEnum: .caseA
|
||||||
|
// OUTPUT: SomeNSEnum: .someCaseB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user