Skip to content

Commit 1caa69b

Browse files
committed
Restrict metatype support in @section to only non-resilient conformances
1 parent 6c47b3e commit 1caa69b

File tree

13 files changed

+139
-17
lines changed

13 files changed

+139
-17
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
@@ -796,6 +796,7 @@ struct BridgedInstruction {
796796
BRIDGED_INLINE bool IndexAddrInst_needsStackProtection() const;
797797
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialRefInst_getConformances() const;
798798
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const;
799+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialMetatypeInst_getConformances() const;
799800
BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const;
800801
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const;
801802
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
@@ -1245,6 +1245,10 @@ BridgedCanType BridgedInstruction::InitExistentialRefInst_getFormalConcreteType(
12451245
return getAs<swift::InitExistentialRefInst>()->getFormalConcreteType();
12461246
}
12471247

1248+
BridgedConformanceArray BridgedInstruction::InitExistentialMetatypeInst_getConformances() const {
1249+
return {getAs<swift::InitExistentialMetatypeInst>()->getConformances()};
1250+
}
1251+
12481252
bool BridgedInstruction::OpenExistentialAddr_isImmutable() const {
12491253
switch (getAs<swift::OpenExistentialAddrInst>()->getAccessKind()) {
12501254
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

@@ -282,15 +281,44 @@ checkSupportedWithSectionAttribute(const Expr *expr,
282281
expressionsToCheck.push_back(identityExpr->getSubExpr());
283282
continue;
284283
}
285-
284+
286285
// Upcasts of metatypes to existential metatypes (e.g. Any.Type)
287286
if (const ErasureExpr *erasureExpr = dyn_cast<ErasureExpr>(expr)) {
288-
if (const DotSelfExpr *dotSelfExpr = dyn_cast<DotSelfExpr>(erasureExpr->getSubExpr())) {
289-
if (const TypeExpr *typeExpr = dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
287+
// Only allow concrete conformances when the protocol, type and
288+
// conformance are all from the current module (except for
289+
// Copyable+Escapable so that we can upcast to Any.Type)
290+
bool allConformanceAreOkay = true;
291+
for (auto conformance : erasureExpr->getConformances()) {
292+
auto concreteConformance = conformance.getConcrete();
293+
if (!concreteConformance) {
294+
allConformanceAreOkay = false;
295+
break;
296+
}
297+
if (conformance.getProtocol()->getInvertibleProtocolKind()) {
298+
continue;
299+
}
300+
auto conformanceModule =
301+
concreteConformance->getDeclContext()->getParentModule();
302+
if (conformanceModule != declContext->getParentModule() ||
303+
conformanceModule != conformance.getProtocol()->getParentModule()) {
304+
allConformanceAreOkay = false;
305+
break;
306+
}
307+
}
308+
309+
if (!allConformanceAreOkay) {
310+
return std::make_pair(expr, TypeExpression);
311+
}
312+
313+
if (const DotSelfExpr *dotSelfExpr =
314+
dyn_cast<DotSelfExpr>(erasureExpr->getSubExpr())) {
315+
if (const TypeExpr *typeExpr =
316+
dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
290317
auto baseType = typeExpr->getType();
291318
if (baseType && baseType->is<MetatypeType>()) {
292319
auto instanceType = baseType->getMetatypeInstanceType();
293-
if (auto nominal = instanceType->getNominalOrBoundGenericNominal()) {
320+
if (auto nominal =
321+
instanceType->getNominalOrBoundGenericNominal()) {
294322
// Allow non-generic, non-resilient types
295323
if (!nominal->isGeneric() && !nominal->isResilient()) {
296324
continue;

test/ConstValues/SectionIR.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,16 @@ func bar(x: Int) -> String { return "test" }
2828
@section("mysection") let funcRef1 = foo // ok
2929
@section("mysection") let funcRef2 = bar // ok
3030

31-
struct S: Hashable, Sendable {}
31+
protocol P1 { }
32+
protocol P2 { }
33+
struct S: Hashable, Sendable, P1, P2 {}
3234

3335
// metatypes
3436
@section("mysection") let metatype1 = Int.self
3537
@section("mysection") let metatype2: Any.Type = Int.self
3638
@section("mysection") let metatype3: Any.Type = S.self
37-
@section("mysection") let metatype4: any (Hashable & Sendable).Type = Int.self
38-
@section("mysection") let metatype5: any (Hashable & Sendable).Type = S.self
39+
@section("mysection") let metatype4: any (P1).Type = S.self
40+
@section("mysection") let metatype5: any (P1 & P2).Type = S.self
3941

4042
// tuples
4143
@section("mysection") let tuple1 = (1, 2, 3, 2.718, true) // ok
@@ -65,8 +67,8 @@ struct S: Hashable, Sendable {}
6567

6668
// CHECK: @"$s9SectionIR9metatype2ypXpvp" = {{.*}}constant ptr @"$sSiN", section "mysection"
6769
// CHECK: @"$s9SectionIR9metatype3ypXpvp" = {{.*}}constant ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), section "mysection"
68-
// CHECK: @"$s9SectionIR9metatype4SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr @"$sSiN", ptr @"$sSiSHsWP" }>, section "mysection"
69-
// CHECK: @"$s9SectionIR9metatype5SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVSHAAWP" }>, section "mysection"
70+
// CHECK: @"$s9SectionIR9metatype4AA2P1_pXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVAA2P1AAWP" }>, section "mysection"
71+
// 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"
7072

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

0 commit comments

Comments
 (0)