Skip to content

Commit c118b0a

Browse files
committed
Restrict metatype support in @section to only non-resilient conformances
1 parent 2a1f1e6 commit c118b0a

File tree

12 files changed

+137
-14
lines changed

12 files changed

+137
-14
lines changed

SwiftCompilerSources/Sources/AST/Conformance.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ public struct Conformance: CustomStringConvertible, Hashable, NoReflectionChildr
8787
assert(isConcrete)
8888
return bridged.getAssociatedConformance(assocType.bridged, proto.bridged).conformance
8989
}
90+
91+
// This is a less precise definition of "resilient conformance" because it's
92+
// only used for SIL optimizations -- where it's okay to think a conformance
93+
// is resilient even if IRGen will decide it's not (see
94+
// IRGenModule::isResilientConformance).
95+
public func isResilientConformance(currentModule: ModuleDecl) -> Bool {
96+
let conformanceModule = self.protocol.parentModule
97+
let protocolModule = self.protocol.parentModule
98+
99+
// If the protocol and the conformance are both in the current module,
100+
// they're not resilient.
101+
if conformanceModule == currentModule && protocolModule == currentModule {
102+
return false
103+
}
104+
105+
return true
106+
}
90107
}
91108

92109
public struct ConformanceArray : RandomAccessCollection, CustomReflectable {

SwiftCompilerSources/Sources/AST/Declarations.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ final public class ClassDecl: NominalTypeDecl {
135135
final public class ProtocolDecl: NominalTypeDecl {
136136
public var requiresClass: Bool { bridged.ProtocolDecl_requiresClass() }
137137
public var isMarkerProtocol: Bool { bridged.ProtocolDecl_isMarkerProtocol() }
138+
public var isInvertible: Bool { bridged.ProtocolDecl_isInvertible() }
138139
}
139140

140141
final public class BuiltinTupleDecl: NominalTypeDecl {}

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,10 @@ extension Instruction {
514514
}
515515
return false
516516
case let iemi as InitExistentialMetatypeInst:
517-
return !iemi.type.hasTypeParameter
517+
let isAnyConformanceResilient = iemi.conformances.contains {
518+
!$0.protocol.isInvertible && $0.isResilientConformance(currentModule: context.currentModuleContext)
519+
}
520+
return !iemi.type.hasTypeParameter && !isAnyConformanceResilient
518521

519522
case is StructInst,
520523
is TupleInst,

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,10 @@ class OpenExistentialBoxValueInst : SingleValueInstruction, UnaryInstruction {}
944944
final public
945945
class InitExistentialMetatypeInst : SingleValueInstruction, UnaryInstruction {
946946
public var metatype: Value { operand.value }
947+
948+
public var conformances: ConformanceArray {
949+
ConformanceArray(bridged: bridged.InitExistentialMetatypeInst_getConformances())
950+
}
947951
}
948952

949953
final public

include/swift/AST/ASTBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/// include here and keep these includes minimal!
1818
///
1919
/// See include guidelines and caveats in `BasicBridging.h`.
20+
#include "swift/ABI/InvertibleProtocols.h"
2021
#include "swift/AST/AccessorKind.h"
2122
#include "swift/AST/AttrKind.h"
2223
#include "swift/AST/DiagnosticKind.h"
@@ -350,6 +351,7 @@ struct BridgedDeclObj {
350351
BRIDGED_INLINE bool Class_isForeign() const;
351352
BRIDGED_INLINE bool ProtocolDecl_requiresClass() const;
352353
BRIDGED_INLINE bool ProtocolDecl_isMarkerProtocol() const;
354+
BRIDGED_INLINE bool ProtocolDecl_isInvertible() const;
353355
BRIDGED_INLINE bool AbstractFunction_isOverridden() const;
354356
BRIDGED_INLINE bool Constructor_isInheritable() const;
355357
BRIDGED_INLINE bool Destructor_isIsolated() const;

include/swift/AST/ASTBridgingImpl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@
2222
#include "swift/AST/GenericSignature.h"
2323
#include "swift/AST/GenericEnvironment.h"
2424
#include "swift/AST/IfConfigClauseRangeInfo.h"
25+
#include "swift/AST/KnownProtocols.h"
2526
#include "swift/AST/MacroDeclaration.h"
2627
#include "swift/AST/ProtocolConformance.h"
2728
#include "swift/AST/ProtocolConformanceRef.h"
2829
#include "swift/AST/SourceFile.h"
2930
#include "swift/AST/Stmt.h"
3031
#include "swift/Basic/Assertions.h"
3132
#include "swift/Basic/Fingerprint.h"
33+
#include <optional>
3234

3335
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
3436

@@ -268,6 +270,10 @@ bool BridgedDeclObj::ProtocolDecl_isMarkerProtocol() const {
268270
return getAs<swift::ProtocolDecl>()->isMarkerProtocol();
269271
}
270272

273+
bool BridgedDeclObj::ProtocolDecl_isInvertible() const {
274+
return getAs<swift::ProtocolDecl>()->getInvertibleProtocolKind() != std::nullopt;
275+
}
276+
271277
bool BridgedDeclObj::AbstractFunction_isOverridden() const {
272278
return getAs<swift::AbstractFunctionDecl>()->isOverridden();
273279
}

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ struct BridgedInstruction {
810810
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const;
811811
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialAddrInst_getConformances() const;
812812
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialAddrInst_getFormalConcreteType() const;
813+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialMetatypeInst_getConformances() const;
813814
BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const;
814815
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const;
815816
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar AllocGlobalInst_getGlobal() const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,10 @@ BridgedCanType BridgedInstruction::InitExistentialAddrInst_getFormalConcreteType
12961296
return getAs<swift::InitExistentialAddrInst>()->getFormalConcreteType();
12971297
}
12981298

1299+
BridgedConformanceArray BridgedInstruction::InitExistentialMetatypeInst_getConformances() const {
1300+
return {getAs<swift::InitExistentialMetatypeInst>()->getConformances()};
1301+
}
1302+
12991303
bool BridgedInstruction::OpenExistentialAddr_isImmutable() const {
13001304
switch (getAs<swift::OpenExistentialAddrInst>()->getAccessKind()) {
13011305
case swift::OpenedExistentialAccess::Immutable: return true;

lib/Sema/LegalConstExprVerifier.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
#include "TypeChecker.h"
2121
#include "swift/AST/ASTContext.h"
2222
#include "swift/AST/ASTWalker.h"
23-
#include "swift/AST/Expr.h"
2423
#include "swift/AST/ParameterList.h"
2524
#include "swift/AST/SemanticAttrs.h"
26-
#include "swift/AST/Type.h"
25+
#include "swift/AST/ProtocolConformance.h"
2726
#include "swift/Basic/Assertions.h"
2827
using namespace swift;
2928

@@ -345,15 +344,44 @@ checkSupportedWithSectionAttribute(const Expr *expr,
345344
expressionsToCheck.push_back(identityExpr->getSubExpr());
346345
continue;
347346
}
348-
347+
349348
// Upcasts of metatypes to existential metatypes (e.g. Any.Type)
350349
if (const ErasureExpr *erasureExpr = dyn_cast<ErasureExpr>(expr)) {
351-
if (const DotSelfExpr *dotSelfExpr = dyn_cast<DotSelfExpr>(erasureExpr->getSubExpr())) {
352-
if (const TypeExpr *typeExpr = dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
350+
// Only allow concrete conformances when the protocol, type and
351+
// conformance are all from the current module (except for
352+
// Copyable+Escapable so that we can upcast to Any.Type)
353+
bool allConformanceAreOkay = true;
354+
for (auto conformance : erasureExpr->getConformances()) {
355+
auto concreteConformance = conformance.getConcrete();
356+
if (!concreteConformance) {
357+
allConformanceAreOkay = false;
358+
break;
359+
}
360+
if (conformance.getProtocol()->getInvertibleProtocolKind()) {
361+
continue;
362+
}
363+
auto conformanceModule =
364+
concreteConformance->getDeclContext()->getParentModule();
365+
if (conformanceModule != declContext->getParentModule() ||
366+
conformanceModule != conformance.getProtocol()->getParentModule()) {
367+
allConformanceAreOkay = false;
368+
break;
369+
}
370+
}
371+
372+
if (!allConformanceAreOkay) {
373+
return std::make_pair(expr, TypeExpression);
374+
}
375+
376+
if (const DotSelfExpr *dotSelfExpr =
377+
dyn_cast<DotSelfExpr>(erasureExpr->getSubExpr())) {
378+
if (const TypeExpr *typeExpr =
379+
dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
353380
auto baseType = typeExpr->getType();
354381
if (baseType && baseType->is<MetatypeType>()) {
355382
auto instanceType = baseType->getMetatypeInstanceType();
356-
if (auto nominal = instanceType->getNominalOrBoundGenericNominal()) {
383+
if (auto nominal =
384+
instanceType->getNominalOrBoundGenericNominal()) {
357385
// Allow non-generic, non-resilient types
358386
if (!nominal->isGeneric() && !nominal->isResilient()) {
359387
continue;

test/ConstValues/SectionIR.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ struct W {
3939
@section("mysection") static let closure7: @convention(c) (Int) -> Int = { x in x * 2 }
4040
}
4141

42-
struct S: Hashable, Sendable {}
42+
protocol P1 { }
43+
protocol P2 { }
44+
struct S: Hashable, Sendable, P1, P2 {}
4345

4446
// metatypes
4547
@section("mysection") let metatype1 = Int.self
4648
@section("mysection") let metatype2: Any.Type = Int.self
4749
@section("mysection") let metatype3: Any.Type = S.self
48-
@section("mysection") let metatype4: any (Hashable & Sendable).Type = Int.self
49-
@section("mysection") let metatype5: any (Hashable & Sendable).Type = S.self
50+
@section("mysection") let metatype4: any (P1).Type = S.self
51+
@section("mysection") let metatype5: any (P1 & P2).Type = S.self
5052

5153
// tuples
5254
@section("mysection") let tuple1 = (1, 2, 3, 2.718, true) // ok
@@ -84,8 +86,8 @@ struct S: Hashable, Sendable {}
8486

8587
// CHECK: @"$s9SectionIR9metatype2ypXpvp" = {{.*}}constant ptr @"$sSiN", section "mysection"
8688
// CHECK: @"$s9SectionIR9metatype3ypXpvp" = {{.*}}constant ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), section "mysection"
87-
// CHECK: @"$s9SectionIR9metatype4SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr @"$sSiN", ptr @"$sSiSHsWP" }>, section "mysection"
88-
// CHECK: @"$s9SectionIR9metatype5SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVSHAAWP" }>, section "mysection"
89+
// CHECK: @"$s9SectionIR9metatype4AA2P1_pXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVAA2P1AAWP" }>, section "mysection"
90+
// CHECK: @"$s9SectionIR9metatype5AA2P1_AA2P2pXpvp" = {{.*}}constant <{ ptr, ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVAA2P1AAWP", ptr @"$s9SectionIR1SVAA2P2AAWP" }>, section "mysection"
8991

9092
// CHECK: @"$s9SectionIR6tuple1Si_S2iSdSbtvp" = {{.*}}constant <{ %TSi, %TSi, %TSi, {{.*}} }> <{ %TSi <{ {{i64|i32}} 1 }>, %TSi <{ {{i64|i32}} 2 }>, %TSi <{ {{i64|i32}} 3 }>, {{.*}} }>, section "mysection"
9193
// CHECK: @"$s9SectionIR6tuple2Si_SfSbtvp" = {{.*}}constant <{ %TSi, %TSf, %TSb }> <{ %TSi <{ {{i64|i32}} 42 }>, %TSf <{ float 0x40091EB860000000 }>, %TSb zeroinitializer }>, section "mysection"

0 commit comments

Comments
 (0)