From d06929ccd24dfb4a984c7f5534c5261f0a0611f1 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Mon, 8 Dec 2025 09:43:21 -0800 Subject: [PATCH 1/2] [embedded] Add support for some foreign metadata --- lib/IRGen/GenDecl.cpp | 16 ++-- lib/IRGen/GenMeta.cpp | 29 ++++-- test/embedded/Inputs/existential_foreign.h | 34 +++++++ test/embedded/existential_foreign.swift | 102 +++++++++++++++++++++ 4 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 test/embedded/Inputs/existential_foreign.h create mode 100644 test/embedded/existential_foreign.swift diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 1a6921606165b..a8bb024b1dce3 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -5308,7 +5308,8 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( return cast(addr); } - + bool hasEmbeddedExistentials = + Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); auto entity = (isPrespecialized && !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( @@ -5324,7 +5325,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( if (Context.LangOpts.hasFeature(Feature::Embedded)) { entity = LinkEntity::forTypeMetadata(concreteType, TypeMetadataAddress::AddressPoint); - if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) + if (hasEmbeddedExistentials) entity = LinkEntity::forTypeMetadata(concreteType, TypeMetadataAddress::FullMetadata); } @@ -5350,7 +5351,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( markGlobalAsUsedBasedOnLinkage(*this, link, var); if (Context.LangOpts.hasFeature(Feature::Embedded) && - !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + !hasEmbeddedExistentials) { return var; } @@ -5361,14 +5362,13 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( if (auto nominal = concreteType->getAnyNominal()) { // Keep type metadata around for all types (except @_objcImplementation, // since we're using ObjC metadata for that). - if (!isObjCImpl && - !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) + if (!isObjCImpl && !hasEmbeddedExistentials) addRuntimeResolvableType(nominal); // Don't define the alias for foreign type metadata, prespecialized // generic metadata, or @_objcImplementation classes, since they're not ABI. - if (requiresForeignTypeMetadata(nominal) || - (isPrespecialized && !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) || + if ((requiresForeignTypeMetadata(nominal) && !hasEmbeddedExistentials) || + (isPrespecialized && !hasEmbeddedExistentials) || isObjCImpl) return var; @@ -5382,7 +5382,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( } } - if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (hasEmbeddedExistentials) { adjustmentIndex = MetadataAdjustmentIndex::EmbeddedWithExistentials; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 2d81558ca997a..0f73cecb1293e 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -7202,17 +7202,23 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) { auto init = builder.beginStruct(); init.setPacked(true); + auto isEmbedded = + IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + if (auto classDecl = dyn_cast(decl)) { if (classDecl->isForeignReferenceType()) { + assert(!isEmbedded && "emitting foregin reference type not supported"); ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init); builder.layout(); IGM.defineTypeMetadata(type, /*isPattern=*/false, builder.canBeConstant(), init.finishAndCreateFuture()); - builder.createMetadataAccessFunction(); + if (!isEmbedded) + builder.createMetadataAccessFunction(); } else { assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType); + assert(!isEmbedded && "emitting foregin cf class type not supported"); ForeignClassMetadataBuilder builder(IGM, classDecl, init); builder.layout(); @@ -7220,28 +7226,37 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) { IGM.defineTypeMetadata(type, /*isPattern=*/false, builder.canBeConstant(), init.finishAndCreateFuture()); - builder.createMetadataAccessFunction(); + if (!isEmbedded) + builder.createMetadataAccessFunction(); } } else if (auto structDecl = dyn_cast(decl)) { assert(isa(structDecl->getModuleScopeContext())); ForeignStructMetadataBuilder builder(IGM, structDecl, init); - builder.layout(); + if (isEmbedded) + builder.embeddedLayout(); + else + builder.layout(); IGM.defineTypeMetadata(type, /*isPattern=*/false, builder.canBeConstant(), init.finishAndCreateFuture()); - builder.createMetadataAccessFunction(); + if (!isEmbedded) + builder.createMetadataAccessFunction(); } else if (auto enumDecl = dyn_cast(decl)) { assert(enumDecl->hasClangNode()); - + ForeignEnumMetadataBuilder builder(IGM, enumDecl, init); - builder.layout(); + if (isEmbedded) + builder.embeddedLayout(); + else + builder.layout(); IGM.defineTypeMetadata(type, /*isPattern=*/false, builder.canBeConstant(), init.finishAndCreateFuture()); - builder.createMetadataAccessFunction(); + if (!isEmbedded) + builder.createMetadataAccessFunction(); } else { llvm_unreachable("foreign metadata for unexpected type?!"); } diff --git a/test/embedded/Inputs/existential_foreign.h b/test/embedded/Inputs/existential_foreign.h new file mode 100644 index 0000000000000..a5d6547df2d76 --- /dev/null +++ b/test/embedded/Inputs/existential_foreign.h @@ -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; +} diff --git a/test/embedded/existential_foreign.swift b/test/embedded/existential_foreign.swift new file mode 100644 index 0000000000000..05cbb637bec38 --- /dev/null +++ b/test/embedded/existential_foreign.swift @@ -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 + } + } +} From 4d879967a7b4faf8704727901ce4a7d0964dcebe Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Tue, 9 Dec 2025 09:13:49 -0800 Subject: [PATCH 2/2] [embedded] Feature::EmbeddedExistentials requires Feature::Embedded --- .../Optimizer/PassManager/Options.swift | 2 +- include/swift/AST/DiagnosticsFrontend.def | 2 ++ include/swift/IRGen/Linking.h | 4 ++- lib/Frontend/CompilerInvocation.cpp | 5 ++++ lib/IRGen/ClassMetadataVisitor.h | 4 +-- lib/IRGen/GenCast.cpp | 2 +- lib/IRGen/GenClass.cpp | 7 ++--- lib/IRGen/GenDecl.cpp | 16 +++++----- lib/IRGen/GenExistential.cpp | 5 ++-- lib/IRGen/GenMeta.cpp | 29 +++++++++---------- lib/IRGen/GenProto.cpp | 4 +-- lib/IRGen/GenValueWitness.cpp | 8 ++--- lib/IRGen/IRGenModule.cpp | 6 ++++ lib/IRGen/IRGenModule.h | 2 ++ lib/IRGen/Linking.cpp | 13 +++++++-- lib/IRGen/MetadataRequest.cpp | 6 ++-- test/embedded/existential.swift | 5 ++++ 17 files changed, 73 insertions(+), 47 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift index 41da345a569ef..6f926f1778877 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/Options.swift @@ -45,7 +45,7 @@ struct Options { } var enableEmbeddedSwiftExistentials: Bool { - hasFeature(.EmbeddedExistentials) + hasFeature(.Embedded) && hasFeature(.EmbeddedExistentials) } var enableMergeableTraps: Bool { diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 552bc042cdd57..31e59eb31a184 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -572,6 +572,8 @@ ERROR(layout_string_instantiation_without_layout_strings,none, ERROR(evolution_with_embedded,none, "Library evolution cannot be enabled with embedded Swift.", ()) +ERROR(embedded_existentials_without_embedded,none, + "EmbeddedExistentials requires enabling embedded Swift.", ()) ERROR(wmo_with_embedded,none, "Whole module optimization (wmo) must be enabled with embedded Swift.", ()) ERROR(objc_with_embedded,none, diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 6c811bf11dedf..d0cbd58e0269e 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -98,8 +98,10 @@ inline bool isEmbeddedWithoutEmbeddedExitentials(CanType t) { // expect for classes (both generic and non-generic), dynamic self, and // class-bound existentials. inline bool isMetadataAllowedInEmbedded(CanType t) { + auto &langOpts = t->getASTContext().LangOpts; bool embeddedExistentials = - t->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials); + langOpts.hasFeature(Feature::EmbeddedExistentials) && + langOpts.hasFeature(Feature::Embedded); if (isa(t) || isa(t) || isa(t)) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index cdbb4e9e56428..506f41a0c21fc 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1838,6 +1838,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } Opts.BypassResilienceChecks |= Args.hasArg(OPT_bypass_resilience); + if (Opts.hasFeature(Feature::EmbeddedExistentials) && + !Opts.hasFeature(Feature::Embedded)) { + Diags.diagnose(SourceLoc(), diag::embedded_existentials_without_embedded); + HadError = true; + } if (Opts.hasFeature(Feature::Embedded)) { Opts.UnavailableDeclOptimizationMode = UnavailableDeclOptimization::Complete; Opts.DisableImplicitStringProcessingModuleImport = true; diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h index 0c8fad95291f1..62819d37af5fa 100644 --- a/lib/IRGen/ClassMetadataVisitor.h +++ b/lib/IRGen/ClassMetadataVisitor.h @@ -77,7 +77,7 @@ template class ClassMetadataVisitor // The regular `layout` method can be used for layout tasks for which the // actual superclass pointer is not relevant. void layoutEmbedded(CanType classTy) { - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) + if (IGM.isEmbeddedWithExistentials()) asImpl().addValueWitnessTable(); asImpl().noteAddressPoint(); asImpl().addEmbeddedSuperclass(classTy); @@ -91,7 +91,7 @@ template class ClassMetadataVisitor "Adjustment index must be synchronized with this layout"); if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) { - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) + if (IGM.isEmbeddedWithExistentials()) asImpl().addValueWitnessTable(); asImpl().noteAddressPoint(); asImpl().addSuperclass(); diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index 8b7a43a68fc35..728fad4219593 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -88,7 +88,7 @@ llvm::Value *irgen::emitCheckedCast(IRGenFunction &IGF, llvm::Value *srcMetadata = nullptr; // Embedded swift currently only supports existential -> concrete type casts. - if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGF.IGM.isEmbeddedWithExistentials()) { srcMetadata = llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy); } else { srcMetadata = IGF.emitTypeMetadataRef(srcType); diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 223b3c2162180..ea73318f4c249 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1051,18 +1051,17 @@ void IRGenModule::emitClassDecl(ClassDecl *D) { auto &resilientLayout = classTI.getClassLayout(*this, selfType, /*forBackwardDeployment=*/false); - auto isEmbeddedWithExistentials = - Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + auto hasEmbeddedWithExistentials = isEmbeddedWithExistentials(); // As a matter of policy, class metadata is never emitted lazily for now. - assert(isEmbeddedWithExistentials || !IRGen.hasLazyMetadata(D)); + assert(hasEmbeddedWithExistentials || !IRGen.hasLazyMetadata(D)); // Emit the class metadata. if (!D->getASTContext().LangOpts.hasFeature(Feature::Embedded)) { emitClassMetadata(*this, D, fragileLayout, resilientLayout); emitFieldDescriptor(D); } else { - if (!isEmbeddedWithExistentials && !D->isGenericContext()) { + if (!hasEmbeddedWithExistentials && !D->isGenericContext()) { emitEmbeddedClassMetadata(*this, D); } else { // We create all metadata lazily in embedded with existentials mode. diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index a8bb024b1dce3..a4b01dbf1bf91 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1588,8 +1588,10 @@ bool IRGenerator::hasLazyMetadata(TypeDecl *type) { auto found = HasLazyMetadata.find(type); if (found != HasLazyMetadata.end()) return found->second; - - if (SIL.getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) && + auto &langOpts = SIL.getASTContext().LangOpts; + auto isEmbeddedWithExistentials = langOpts.hasFeature(Feature::Embedded) && + langOpts.hasFeature(Feature::EmbeddedExistentials); + if (isEmbeddedWithExistentials && (isa(type) || isa(type))) { bool isGeneric = cast(type)->isGenericContext(); HasLazyMetadata[type] = !isGeneric; @@ -5308,8 +5310,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata( return cast(addr); } - bool hasEmbeddedExistentials = - Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + bool hasEmbeddedExistentials = isEmbeddedWithExistentials(); auto entity = (isPrespecialized && !irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable( @@ -5427,7 +5428,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, llvm::Type *defaultVarTy; unsigned adjustmentIndex; - if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + auto hasEmbeddedExistentials = isEmbeddedWithExistentials(); + if (hasEmbeddedExistentials) { adjustmentIndex = 0; defaultVarTy = EmbeddedExistentialsMetadataStructTy; } else if (concreteType->isAny() || concreteType->isAnyObject() || concreteType->isVoid() || concreteType->is() || concreteType->is()) { @@ -5474,7 +5476,7 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, } } - if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (hasEmbeddedExistentials) { if ((isa(nominal) || isa(nominal)) && nominal->isGenericContext()) { IRGen.noteUseOfSpecializedValueMetadata(concreteType); @@ -5482,7 +5484,7 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType, } } - if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials) && + if (hasEmbeddedExistentials && (isa(concreteType) || isa(concreteType))) { IRGen.noteUseOfSpecializedValueMetadata(concreteType); diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index 89e017d922d96..9c5ee02a84695 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -2314,7 +2314,7 @@ Address irgen::emitAllocateBoxedOpaqueExistentialBuffer( if (fixedTI->getFixedPacking(IGF.IGM) == FixedPacking::OffsetZero) { return valueTI.getAddressForPointer(IGF.Builder.CreateBitCast( existentialBuffer.getAddress(), IGF.IGM.PtrTy)); - } else if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + } else if (IGF.IGM.isEmbeddedWithExistentials()) { llvm::Value *box, *address; auto *metadata = existLayout.loadMetadataRef(IGF, existentialContainer); IGF.emitAllocBoxCall(metadata, box, address); @@ -2897,8 +2897,7 @@ static llvm::Function *getDestroyBoxedOpaqueExistentialBufferFunction( Builder.CreateBitCast(buffer.getAddress(), IGM.PtrTy); auto *reference = Builder.CreateLoad(Address( referenceAddr, IGM.RefCountedPtrTy, buffer.getAlignment())); - if (IGF.IGM.Context.LangOpts - .hasFeature(Feature::EmbeddedExistentials)) { + if (IGF.IGM.isEmbeddedWithExistentials()) { IGF.emitReleaseBox(reference); } else IGF.emitNativeStrongRelease(reference, IGF.getDefaultAtomicity()); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 0f73cecb1293e..225b465f14ae1 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -2973,7 +2973,7 @@ void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM, void irgen::emitLazyTypeMetadata(IRGenModule &IGM, NominalTypeDecl *type) { // Embedded existentials emit very spares metadata records and don't have type // context descriptors. - if (!type->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials)) + if (!IGM.isEmbeddedWithExistentials()) eraseExistingTypeContextDescriptor(IGM, type); if (requiresForeignTypeMetadata(type)) { @@ -4270,7 +4270,7 @@ namespace { auto type = (Target->checkAncestry(AncestryFlags::ObjC) ? IGM.Context.getAnyObjectType() : IGM.Context.TheNativeObjectType); - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGM.isEmbeddedWithExistentials()) { return irgen::emitValueWitnessTable(IGM, type, false, false); } auto wtable = IGM.getAddrOfValueWitnessTable(type); @@ -5577,9 +5577,8 @@ void irgen::emitLazyClassMetadata(IRGenModule &IGM, CanType classTy) { // Might already be emitted, skip if that's the case. auto entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint); - - auto isEmbeddedWithExistentials = IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); - if (isEmbeddedWithExistentials) { + auto hasEmbeddedWithExistentials = IGM.isEmbeddedWithExistentials(); + if (hasEmbeddedWithExistentials) { entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::FullMetadata); } auto *existingVar = cast( @@ -5588,7 +5587,7 @@ void irgen::emitLazyClassMetadata(IRGenModule &IGM, CanType classTy) { return; } - if (isEmbeddedWithExistentials) { + if (hasEmbeddedWithExistentials) { emitEmbeddedClassMetadata(IGM, classTy->getClassOrBoundGenericClass()); return; } @@ -6225,8 +6224,7 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) { bool isPattern; bool canBeConstant; - bool hasEmbeddedExistentialFeature = - IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + bool hasEmbeddedExistentialFeature = IGM.isEmbeddedWithExistentials(); if (structDecl->isGenericContext()) { assert(!hasEmbeddedExistentialFeature); GenericStructMetadataBuilder builder(IGM, structDecl, init); @@ -6268,7 +6266,7 @@ void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM, CanType type, bool isPattern = false; SpecializedGenericStructMetadataBuilder builder(IGM, type, decl, init); - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGM.isEmbeddedWithExistentials()) { builder.embeddedLayout(); } else { builder.layout(); @@ -6315,7 +6313,7 @@ class TupleMetadataBuilder : public TupleMetadataVisitor { }; } // end anonymous namespace void irgen::emitLazyTupleMetadata(IRGenModule &IGM, CanType tupleTy) { - assert(IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)); + assert(IGM.isEmbeddedWithExistentials()); assert(isa(tupleTy)); Type ty = tupleTy.getPointer(); @@ -6374,7 +6372,7 @@ class FunctionMetadataBuilder : public FunctionMetadataVisitor(funTy)); Type ty = funTy.getPointer(); @@ -6771,8 +6769,7 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) { bool isPattern; bool canBeConstant; - bool hasEmbeddedExistentialFeature = - IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + bool hasEmbeddedExistentialFeature = IGM.isEmbeddedWithExistentials(); if (theEnum->isGenericContext()) { assert(!hasEmbeddedExistentialFeature); GenericEnumMetadataBuilder builder(IGM, theEnum, init); @@ -6813,7 +6810,8 @@ void irgen::emitSpecializedGenericEnumMetadata(IRGenModule &IGM, CanType type, init.setPacked(true); SpecializedGenericEnumMetadataBuilder builder(IGM, type, decl, init); - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + + if (IGM.isEmbeddedWithExistentials()) { builder.embeddedLayout(); } else { builder.layout(); @@ -7202,8 +7200,7 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) { auto init = builder.beginStruct(); init.setPacked(true); - auto isEmbedded = - IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials); + auto isEmbedded = IGM.isEmbeddedWithExistentials(); if (auto classDecl = dyn_cast(decl)) { if (classDecl->isForeignReferenceType()) { diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index ad4f91d517246..57b81621cebbc 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -1756,7 +1756,7 @@ class AccessorConformanceInfo : public ConformanceInfo { else typeWitness = Conformance.getTypeWitness(assocType); - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGM.isEmbeddedWithExistentials()) { // In Embedded Swift associated type witness point to the metadata. llvm::Constant *witnessEntry = IGM.getAddrOfTypeMetadata( typeWitness->getCanonicalType()); @@ -4558,7 +4558,7 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, // Im embedded with existentials mode the type metadata is directly referenced // by the witness table. - if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGM.isEmbeddedWithExistentials()) { auto proto = assocType->getProtocol(); assert(!IGF.IGM.isResilient(proto, ResilienceExpansion::Maximal)); assert(!IGF.IGM.IRGen.Opts.UseRelativeProtocolWitnessTables); diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 36a7d5addcbf9..6e989bbbbcfba 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -1386,7 +1386,7 @@ static void addValueWitnessesForAbstractType(IRGenModule &IGM, // that is we have a specialized generic type, we have decided for code size // reasons to continue using "generic" value witness table functions i.e the // same once used for runtime instantiated generic metadata. - if (!IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (!IGM.isEmbeddedWithExistentials()) { auto *nomDecl = abstractType->getNominalOrBoundGenericNominal(); if (abstractType->isSpecialized() && nomDecl) { CanType concreteFormalType = getFormalTypeInPrimaryContext(abstractType); @@ -1540,8 +1540,8 @@ ConstantReference irgen::emitValueWitnessTable(IRGenModule &IGM, bool isPattern, bool relativeReference) { // See if we can use a prefab witness table from the runtime. - if (!isPattern && - !IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + auto hasEmbeddedWithExistentials = IGM.isEmbeddedWithExistentials(); + if (!isPattern && !hasEmbeddedWithExistentials) { if (auto known = getAddrOfKnownValueWitnessTable(IGM, abstractType, relativeReference)) { return known; @@ -1549,7 +1549,7 @@ ConstantReference irgen::emitValueWitnessTable(IRGenModule &IGM, } // There might already be a definition emitted in embedded mode. - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (hasEmbeddedWithExistentials) { auto addr = IGM.getAddrOfValueWitnessTable(abstractType); if (!cast(addr)->isDeclaration()) { return {addr, ConstantReference::Direct}; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 0d259aae6b912..4e429d5e5d0fa 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -2455,3 +2455,9 @@ bool swift::writeEmptyOutputFilesFor( } return false; } + +bool IRGenModule::isEmbeddedWithExistentials() const { + auto &langOpts = Context.LangOpts; + return langOpts.hasFeature(Feature::Embedded) && + langOpts.hasFeature(Feature::EmbeddedExistentials); +} diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 908b3fc4eb806..50256a3de5671 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -2061,6 +2061,8 @@ private: \ /// Returns true if the given Clang function does not throw exceptions. bool isCxxNoThrow(clang::FunctionDecl *fd, bool defaultNoThrow = false); + bool isEmbeddedWithExistentials() const; + private: llvm::Constant * getAddrOfSharedContextDescriptor(LinkEntity entity, diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index d16f61aa6fe17..21d48ef9cfec1 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -632,7 +632,10 @@ SILDeclRef LinkEntity::getSILDeclRef() const { static bool isLazyEmissionOfPublicSymbolInMultipleModulesPossible(CanType ty) { // In embedded existenitals mode we generate lazy public metadata on demand // which makes it non unique. - if (ty->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + auto &langOpts = ty->getASTContext().LangOpts; + auto isEmbeddedWithExistentials = langOpts.hasFeature(Feature::Embedded) && + langOpts.hasFeature(Feature::EmbeddedExistentials); + if (isEmbeddedWithExistentials) { if (auto nominal = ty->getAnyNominal()) { if (SILDeclRef::declHasNonUniqueDefinition(nominal)) { return true; @@ -1144,14 +1147,18 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const { case Kind::TypeMetadata: case Kind::NoncanonicalSpecializedGenericTypeMetadata: switch (getMetadataAddress()) { - case TypeMetadataAddress::FullMetadata: - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + case TypeMetadataAddress::FullMetadata: { + auto &langOpts = IGM.Context.LangOpts; + auto isEmbeddedWithExistentials = langOpts.hasFeature(Feature::Embedded) && + langOpts.hasFeature(Feature::EmbeddedExistentials); + if (isEmbeddedWithExistentials) { return IGM.EmbeddedExistentialsMetadataStructTy; } if (getType().getClassOrBoundGenericClass()) return IGM.FullHeapMetadataStructTy; else return IGM.FullTypeMetadataStructTy; + } case TypeMetadataAddress::AddressPoint: return IGM.TypeMetadataStructTy; } diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 08c64b8cbf51a..7a438ddd5d09e 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -886,7 +886,7 @@ bool irgen::isCompleteSpecializedNominalTypeMetadataStaticallyAddressable( return false; } - if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials) && + if (IGM.isEmbeddedWithExistentials() && (isa(type) || isa(type) || isa(type) || isa(type))) { if (type->hasArchetype()) { @@ -1263,7 +1263,7 @@ static MetadataResponse emitFixedArrayMetadataRef(IRGenFunction &IGF, static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF, CanTupleType type, DynamicMetadataRequest request) { - if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGF.IGM.isEmbeddedWithExistentials()) { return MetadataResponse::forComplete(IGF.IGM.getAddrOfTypeMetadata(type)); } @@ -1568,7 +1568,7 @@ static CanPackType getInducedPackType(AnyFunctionType::CanParamArrayRef params, static MetadataResponse emitFunctionTypeMetadataRef(IRGenFunction &IGF, CanFunctionType type, DynamicMetadataRequest request) { - if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) { + if (IGF.IGM.isEmbeddedWithExistentials()) { return MetadataResponse::forComplete(IGF.IGM.getAddrOfTypeMetadata(type)); } auto result = diff --git a/test/embedded/existential.swift b/test/embedded/existential.swift index 9998a3699cddb..9f9e2edf379e5 100644 --- a/test/embedded/existential.swift +++ b/test/embedded/existential.swift @@ -2,12 +2,17 @@ // RUN: %target-run-simple-swift(-enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s --check-prefix=OUTPUT // RUN: %target-run-simple-swift(-enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s --check-prefix=OUTPUT +// RUN: not %target-swift-frontend -enable-experimental-feature EmbeddedExistentials -parse-as-library -wmo -emit-sil %s 2>&1 | %FileCheck --check-prefix=ERRMSG %s + // REQUIRES: swift_in_compiler // REQUIRES: executable_test // REQUIRES: optimized_stdlib // REQUIRES: swift_feature_Embedded // REQUIRES: swift_feature_EmbeddedExistentials +// EmbeddedExistentials requires Embedded +// ERRMSG: error: EmbeddedExistentials requires enabling embedded Swift. + class CP { }