Skip to content

Commit 3d571ad

Browse files
committed
Restrict metatype support in @section to only non-resilient conformances
1 parent ed38036 commit 3d571ad

File tree

12 files changed

+138
-14
lines changed

12 files changed

+138
-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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ final public class ClassDecl: NominalTypeDecl {
7676

7777
final public class ProtocolDecl: NominalTypeDecl {
7878
public var requiresClass: Bool { bridged.ProtocolDecl_requiresClass() }
79+
80+
public var isInvertible: Bool { bridged.ProtocolDecl_isInvertible() }
7981
}
8082

8183
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
@@ -473,7 +473,10 @@ extension Instruction {
473473
}
474474
return false
475475
case let iemi as InitExistentialMetatypeInst:
476-
return !iemi.type.hasTypeParameter
476+
let isAnyConformanceResilient = iemi.conformances.contains {
477+
!$0.protocol.isInvertible && $0.isResilientConformance(currentModule: context.currentModuleContext)
478+
}
479+
return !iemi.type.hasTypeParameter && !isAnyConformanceResilient
477480

478481
case is StructInst,
479482
is TupleInst,

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,10 @@ class OpenExistentialBoxValueInst : SingleValueInstruction, UnaryInstruction {}
901901
final public
902902
class InitExistentialMetatypeInst : SingleValueInstruction, UnaryInstruction {
903903
public var metatype: Value { operand.value }
904+
905+
public var conformances: ConformanceArray {
906+
ConformanceArray(bridged: bridged.InitExistentialMetatypeInst_getConformances())
907+
}
904908
}
905909

906910
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"
@@ -335,6 +336,7 @@ struct BridgedDeclObj {
335336
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType Class_getSuperclass() const;
336337
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj Class_getDestructor() const;
337338
BRIDGED_INLINE bool ProtocolDecl_requiresClass() const;
339+
BRIDGED_INLINE bool ProtocolDecl_isInvertible() const;
338340
BRIDGED_INLINE bool AbstractFunction_isOverridden() const;
339341
BRIDGED_INLINE bool Destructor_isIsolated() const;
340342
BRIDGED_INLINE bool EnumElementDecl_hasAssociatedValues() 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

@@ -222,6 +224,10 @@ bool BridgedDeclObj::ProtocolDecl_requiresClass() const {
222224
return getAs<swift::ProtocolDecl>()->requiresClass();
223225
}
224226

227+
bool BridgedDeclObj::ProtocolDecl_isInvertible() const {
228+
return getAs<swift::ProtocolDecl>()->getInvertibleProtocolKind() != std::nullopt;
229+
}
230+
225231
bool BridgedDeclObj::AbstractFunction_isOverridden() const {
226232
return getAs<swift::AbstractFunctionDecl>()->isOverridden();
227233
}

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ struct BridgedInstruction {
797797
BRIDGED_INLINE bool IndexAddrInst_needsStackProtection() const;
798798
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialRefInst_getConformances() const;
799799
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const;
800+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialMetatypeInst_getConformances() const;
800801
BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const;
801802
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const;
802803
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
@@ -1249,6 +1249,10 @@ BridgedCanType BridgedInstruction::InitExistentialRefInst_getFormalConcreteType(
12491249
return getAs<swift::InitExistentialRefInst>()->getFormalConcreteType();
12501250
}
12511251

1252+
BridgedConformanceArray BridgedInstruction::InitExistentialMetatypeInst_getConformances() const {
1253+
return {getAs<swift::InitExistentialMetatypeInst>()->getConformances()};
1254+
}
1255+
12521256
bool BridgedInstruction::OpenExistentialAddr_isImmutable() const {
12531257
switch (getAs<swift::OpenExistentialAddrInst>()->getAccessKind()) {
12541258
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)