Skip to content

Commit ce97377

Browse files
committed
IRGen: Exclude unavailable enum cases from runtime layout calculations.
When `-unavailable-decl-optimization=complete` is specified, exclude unavailable enum cases from the runtime layout of enums with payloads. Without this, the type metadata for unavailable types may be referenced by enum cases with unavailable payloads and cause linker failures. Resolves rdar://107483852
1 parent 570c364 commit ce97377

File tree

9 files changed

+89
-11
lines changed

9 files changed

+89
-11
lines changed

include/swift/SIL/SILModule.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,11 +1086,11 @@ LLVM_LIBRARY_VISIBILITY bool usesObjCAllocator(ClassDecl *theClass);
10861086
/// Returns true if SIL/IR lowering for the given declaration should be skipped.
10871087
/// A declaration may not require lowering if, for example, it is annotated as
10881088
/// unavailable and optimization settings allow it to be omitted.
1089-
LLVM_LIBRARY_VISIBILITY bool shouldSkipLowering(Decl *D);
1089+
LLVM_LIBRARY_VISIBILITY bool shouldSkipLowering(const Decl *D);
10901090

10911091
/// Returns true if SIL/IR lowering for the given declaration should produce
10921092
/// a stub that traps at runtime because the code ought to be unreachable.
1093-
LLVM_LIBRARY_VISIBILITY bool shouldLowerToUnavailableCodeStub(Decl *D);
1093+
LLVM_LIBRARY_VISIBILITY bool shouldLowerToUnavailableCodeStub(const Decl *D);
10941094
} // namespace Lowering
10951095

10961096
/// Apply the given function to each ABI member of \c D skipping the members

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,9 @@ void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
15681568
RequireMetadata_t requireMetadata) {
15691569
if (!type)
15701570
return;
1571-
1571+
1572+
assert(!Lowering::shouldSkipLowering(type));
1573+
15721574
// Force emission of ObjC protocol descriptors used by type refs.
15731575
if (auto proto = dyn_cast<ProtocolDecl>(type)) {
15741576
if (proto->isObjC()) {

lib/IRGen/GenEnum.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6040,6 +6040,13 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
60406040
continue;
60416041
}
60426042

6043+
// For the purposes of memory layout, treat unavailable cases as if they do
6044+
// not have a payload.
6045+
if (Lowering::shouldSkipLowering(elt)) {
6046+
elementsWithNoPayload.push_back({elt, nullptr, nullptr});
6047+
continue;
6048+
}
6049+
60436050
// If the payload is indirect, we can use the NativeObject type metadata
60446051
// without recurring. The box won't affect loadability or fixed-ness.
60456052
if (elt->isIndirect() || theEnum->isIndirect()) {

lib/IRGen/GenReflection.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,8 +854,11 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
854854
if (hasPayload && (decl->isIndirect() || enumDecl->isIndirect()))
855855
flags.setIsIndirectCase();
856856

857-
addField(flags, decl->getArgumentInterfaceType(),
858-
decl->getBaseIdentifier().str());
857+
Type interfaceType = Lowering::shouldSkipLowering(decl)
858+
? nullptr
859+
: decl->getArgumentInterfaceType();
860+
861+
addField(flags, interfaceType, decl->getBaseIdentifier().str());
859862
}
860863

861864
void layoutEnum() {

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/IRGen/ValueWitness.h"
3737
#include "swift/SIL/RuntimeEffect.h"
3838
#include "swift/SIL/SILFunction.h"
39+
#include "swift/SIL/SILModule.h"
3940
#include "llvm/ADT/DenseMap.h"
4041
#include "llvm/ADT/DenseSet.h"
4142
#include "llvm/ADT/Hashing.h"
@@ -455,6 +456,7 @@ class IRGenerator {
455456
}
456457

457458
void noteLazyReemissionOfNominalTypeDescriptor(NominalTypeDecl *decl) {
459+
assert(!Lowering::shouldSkipLowering(decl));
458460
LazilyReemittedTypeContextDescriptors.insert(decl);
459461
}
460462

@@ -464,6 +466,7 @@ class IRGenerator {
464466
}
465467

466468
void noteUseOfMetadataAccessor(NominalTypeDecl *decl) {
469+
assert(!Lowering::shouldSkipLowering(decl));
467470
if (LazyMetadataAccessors.count(decl) == 0) {
468471
LazyMetadataAccessors.insert(decl);
469472
}

lib/IRGen/MetadataLayout.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "TupleMetadataVisitor.h"
3535

3636
#include "swift/Basic/LLVM.h"
37+
#include "swift/SIL/SILModule.h"
3738
#include "llvm/ADT/Optional.h"
3839

3940
using namespace swift;

lib/SIL/IR/SILModule.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
956956
return theClass->getObjectModel() == ReferenceCounting::ObjC;
957957
}
958958

959-
bool Lowering::shouldSkipLowering(Decl *D) {
959+
bool Lowering::shouldSkipLowering(const Decl *D) {
960960
if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode !=
961961
UnavailableDeclOptimization::Complete)
962962
return false;
@@ -966,7 +966,7 @@ bool Lowering::shouldSkipLowering(Decl *D) {
966966
return D->getSemanticUnavailableAttr() != None;
967967
}
968968

969-
bool Lowering::shouldLowerToUnavailableCodeStub(Decl *D) {
969+
bool Lowering::shouldLowerToUnavailableCodeStub(const Decl *D) {
970970
if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode !=
971971
UnavailableDeclOptimization::Stub)
972972
return false;

test/IRGen/unavailable_decl_optimization_complete_enum.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,27 @@
1010
// CHECK-NO-STRIP: private constant [25 x i8] c"unavailableEnumFirstCase\00"
1111
// CHECK-STRIP-NOT: private constant [25 x i8] c"unavailableEnumFirstCase\00"
1212

13+
@available(*, unavailable)
14+
public struct UnavailableStruct {}
1315

1416
public enum AvailableEnum {
1517
case availableEnumAvailableCase
1618

1719
@available(*, unavailable)
1820
case availableEnumUnavailableCase
1921

22+
@available(*, unavailable)
23+
case availableEnumUnavailableCaseWithAssociatedValue(UnavailableStruct)
24+
2025
// CHECK-NO-STRIP: s4Test13AvailableEnumO17unavailableMethodyyF
2126
// CHECK-STRIP-NOT: s4Test13AvailableEnumO17unavailableMethodyyF
2227
@available(*, unavailable)
2328
public func unavailableMethod() {}
24-
25-
// CHECK: s4Test13AvailableEnumO21__derived_enum_equalsySbAC_ACtFZ
26-
// CHECK: s4Test13AvailableEnumO4hash4intoys6HasherVz_tF
27-
// CHECK: s4Test13AvailableEnumO9hashValueSivg
2829
}
2930

31+
// CHECK-NO-STRIP: s4Test17UnavailableStructVMa
32+
// CHECK-STRIP-NOT: s4Test17UnavailableStructVMa
33+
3034
@available(*, unavailable)
3135
public enum UnavailableEnum {
3236
case unavailableEnumFirstCase
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -Xfrontend -unavailable-decl-optimization=complete -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %target-run %t/a.out
5+
// REQUIRES: executable_test
6+
7+
import StdlibUnittest
8+
9+
@available(*, unavailable)
10+
class UnavailableClass {
11+
var x: UInt8 = 0
12+
}
13+
14+
enum SingletonTrivial {
15+
@available(*, unavailable)
16+
case unavailable(UInt8)
17+
}
18+
19+
enum SingletonClass {
20+
@available(*, unavailable)
21+
case unavailable(UnavailableClass)
22+
}
23+
24+
enum NoPayload {
25+
case x
26+
@available(*, unavailable)
27+
case unavailable
28+
case y
29+
}
30+
31+
enum SinglePayloadTrivial {
32+
case x
33+
@available(*, unavailable)
34+
case unavailable(UInt8)
35+
case y
36+
}
37+
38+
enum MultiPayloadTrivial {
39+
case x(UInt8)
40+
@available(*, unavailable)
41+
case unavailable(UInt8, UInt8)
42+
case y
43+
}
44+
45+
enum MultiPayloadGeneric<T, U> {
46+
case x(T)
47+
@available(*, unavailable)
48+
case unavailable(T, U)
49+
case y
50+
}
51+
52+
expectEqual(MemoryLayout<SingletonTrivial>.size, 0)
53+
expectEqual(MemoryLayout<SingletonClass>.size, 0)
54+
expectEqual(MemoryLayout<NoPayload>.size, 1)
55+
expectEqual(MemoryLayout<SinglePayloadTrivial>.size, 1)
56+
expectEqual(MemoryLayout<MultiPayloadTrivial>.size, 2)
57+
expectEqual(MemoryLayout<MultiPayloadGeneric<UInt8, UInt8>>.size, 2)
58+
expectEqual(MemoryLayout<MultiPayloadGeneric<UInt32, UInt32>>.size, 5)

0 commit comments

Comments
 (0)