Skip to content

Commit 43df05a

Browse files
committed
[SE-0470] Prohibit isolated conformances in dynamic casts marked as such
Certain dynamic casts cannot work safely with isolated conformances, regardless of what executor the code runs on. For such cases, reject all attempts to conform to the type.
1 parent e0b52cd commit 43df05a

File tree

8 files changed

+200
-82
lines changed

8 files changed

+200
-82
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ enum class DynamicCastFlags : size_t {
313313
/// True if the cast should destroy the source value on failure;
314314
/// false if the value should be left in place.
315315
DestroyOnFailure = 0x4,
316+
317+
/// True if the cast should prohibit the use of any isolated conformances,
318+
/// for example because there is a Sendable constraint on the existential
319+
/// type we're casting to.
320+
ProhibitIsolatedConformances = 0x8,
316321
};
317322
inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) {
318323
return (size_t(a) & size_t(b)) != 0;

lib/IRGen/GenCast.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ using namespace swift;
4242
using namespace irgen;
4343

4444
/// Compute the flags to pass to swift_dynamicCast.
45-
static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind,
46-
CheckedCastMode mode) {
45+
static DynamicCastFlags getDynamicCastFlags(
46+
CastConsumptionKind consumptionKind,
47+
CheckedCastMode mode,
48+
CastingIsolatedConformances isolatedConformances
49+
) {
4750
DynamicCastFlags flags = DynamicCastFlags::Default;
4851

4952
if (mode == CheckedCastMode::Unconditional)
@@ -53,6 +56,14 @@ static DynamicCastFlags getDynamicCastFlags(CastConsumptionKind consumptionKind,
5356
if (shouldTakeOnSuccess(consumptionKind))
5457
flags |= DynamicCastFlags::TakeOnSuccess;
5558

59+
switch (isolatedConformances) {
60+
case CastingIsolatedConformances::Allow:
61+
break;
62+
case CastingIsolatedConformances::Prohibit:
63+
flags |= DynamicCastFlags::ProhibitIsolatedConformances;
64+
break;
65+
}
66+
5667
return flags;
5768
}
5869

@@ -63,10 +74,12 @@ llvm::Value *irgen::emitCheckedCast(IRGenFunction &IGF,
6374
Address dest,
6475
CanType targetType,
6576
CastConsumptionKind consumptionKind,
66-
CheckedCastMode mode) {
77+
CheckedCastMode mode,
78+
CastingIsolatedConformances isolatedConformances) {
6779
// TODO: attempt to specialize this based on the known types.
6880

69-
DynamicCastFlags flags = getDynamicCastFlags(consumptionKind, mode);
81+
DynamicCastFlags flags = getDynamicCastFlags(consumptionKind, mode,
82+
isolatedConformances);
7083

7184
// Cast both addresses to opaque pointer type.
7285
dest = IGF.Builder.CreateElementBitCast(dest, IGF.IGM.OpaqueTy);
@@ -847,6 +860,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
847860
SILType targetLoweredType,
848861
CanType targetFormalType,
849862
CheckedCastMode mode,
863+
CastingIsolatedConformances isolatedConformances,
850864
Explosion &out) {
851865
assert(sourceLoweredType.isObject());
852866
assert(targetLoweredType.isObject());
@@ -976,7 +990,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
976990
src, sourceFormalType,
977991
dest, targetFormalType,
978992
CastConsumptionKind::TakeAlways,
979-
mode);
993+
mode, isolatedConformances);
980994
llvm::Value *successResult = IGF.Builder.CreateLoad(dest);
981995
llvm::Value *failureResult = llvm::ConstantPointerNull::get(destPtrType);
982996
llvm::Value *result = IGF.Builder.CreateSelect(success, successResult, failureResult);

lib/IRGen/GenCast.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace swift {
2828
class SILType;
2929
class ProtocolDecl;
3030
enum class CastConsumptionKind : unsigned char;
31+
enum class CastingIsolatedConformances: uint8_t;
3132

3233
namespace irgen {
3334
class Address;
@@ -46,14 +47,16 @@ namespace irgen {
4647
Address dest,
4748
CanType toType,
4849
CastConsumptionKind consumptionKind,
49-
CheckedCastMode mode);
50+
CheckedCastMode mode,
51+
CastingIsolatedConformances isolatedConformances);
5052

5153
void emitScalarCheckedCast(IRGenFunction &IGF, Explosion &value,
5254
SILType sourceLoweredType,
5355
CanType sourceFormalType,
5456
SILType targetLoweredType,
5557
CanType targetFormalType,
5658
CheckedCastMode mode,
59+
CastingIsolatedConformances isolatedConformances,
5760
Explosion &out);
5861

5962
llvm::Value *emitFastClassCastIfPossible(

lib/IRGen/IRGenSIL.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7186,7 +7186,8 @@ visitUncheckedRefCastAddrInst(swift::UncheckedRefCastAddrInst *i) {
71867186
src, i->getSourceFormalType(),
71877187
dest, i->getTargetFormalType(),
71887188
CastConsumptionKind::TakeAlways,
7189-
CheckedCastMode::Unconditional);
7189+
CheckedCastMode::Unconditional,
7190+
CastingIsolatedConformances::Allow);
71907191
}
71917192

71927193
void IRGenSILFunction::visitUncheckedAddrCastInst(
@@ -7416,6 +7417,7 @@ void IRGenSILFunction::visitUnconditionalCheckedCastInst(
74167417
i->getTargetLoweredType(),
74177418
i->getTargetFormalType(),
74187419
CheckedCastMode::Unconditional,
7420+
i->getIsolatedConformances(),
74197421
ex);
74207422
setLoweredExplosion(i, ex);
74217423
}
@@ -7604,7 +7606,8 @@ void IRGenSILFunction::visitUnconditionalCheckedCastAddrInst(
76047606
src, i->getSourceFormalType(),
76057607
dest, i->getTargetFormalType(),
76067608
CastConsumptionKind::TakeAlways,
7607-
CheckedCastMode::Unconditional);
7609+
CheckedCastMode::Unconditional,
7610+
i->getIsolatedConformances());
76087611
}
76097612

76107613
void IRGenSILFunction::visitCheckedCastBranchInst(
@@ -7625,6 +7628,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst(
76257628
i->getTargetLoweredType(),
76267629
i->getTargetFormalType(),
76277630
CheckedCastMode::Conditional,
7631+
i->getIsolatedConformances(),
76287632
ex);
76297633
auto val = ex.claimNext();
76307634
castResult.casted = val;
@@ -7662,7 +7666,8 @@ void IRGenSILFunction::visitCheckedCastAddrBranchInst(
76627666
emitCheckedCast(*this,
76637667
src, i->getSourceFormalType(),
76647668
dest, i->getTargetFormalType(),
7665-
i->getConsumptionKind(), CheckedCastMode::Conditional);
7669+
i->getConsumptionKind(), CheckedCastMode::Conditional,
7670+
i->getIsolatedConformances());
76667671
Builder.CreateCondBr(castSucceeded,
76677672
getLoweredBB(i->getSuccessBB()).bb,
76687673
getLoweredBB(i->getFailureBB()).bb);

stdlib/public/runtime/Casting.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -614,12 +614,19 @@ bool swift::_conformsToProtocolInContext(
614614
const OpaqueValue *value,
615615
const Metadata *type,
616616
ProtocolDescriptorRef protocol,
617-
const WitnessTable **conformance) {
617+
const WitnessTable **conformance,
618+
bool prohibitIsolatedConformances) {
618619

619620
ConformanceExecutionContext context;
620621
if (!_conformsToProtocol(value, type, protocol, conformance, &context))
621622
return false;
622623

624+
// If we aren't allowed to use isolated conformances and we ended up with
625+
// one, fail.
626+
if (prohibitIsolatedConformances &&
627+
context.globalActorIsolationType)
628+
return false;
629+
623630
if (!swift_isInConformanceExecutionContext(type, &context))
624631
return false;
625632

@@ -631,7 +638,8 @@ bool swift::_conformsToProtocolInContext(
631638
static bool _conformsToProtocols(const OpaqueValue *value,
632639
const Metadata *type,
633640
const ExistentialTypeMetadata *existentialType,
634-
const WitnessTable **conformances) {
641+
const WitnessTable **conformances,
642+
bool prohibitIsolatedConformances) {
635643
if (auto *superclass = existentialType->getSuperclassConstraint()) {
636644
if (!swift_dynamicCastMetatype(type, superclass))
637645
return false;
@@ -644,7 +652,7 @@ static bool _conformsToProtocols(const OpaqueValue *value,
644652

645653
for (auto protocol : existentialType->getProtocols()) {
646654
if (!_conformsToProtocolInContext(
647-
value, type, protocol, conformances))
655+
value, type, protocol, conformances, prohibitIsolatedConformances))
648656
return false;
649657
if (conformances != nullptr && protocol.needsWitnessTable()) {
650658
assert(*conformances != nullptr);
@@ -1050,9 +1058,10 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
10501058
}
10511059

10521060
static const Metadata *
1053-
swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
1054-
const Metadata *targetType,
1055-
const char *file, unsigned line, unsigned column) {
1061+
swift_dynamicCastMetatypeUnconditionalImpl(
1062+
const Metadata *sourceType,
1063+
const Metadata *targetType,
1064+
const char *file, unsigned line, unsigned column) {
10561065
auto origSourceType = sourceType;
10571066

10581067
// Identical types always succeed
@@ -1138,7 +1147,8 @@ swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
11381147

11391148
case MetadataKind::Existential: {
11401149
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
1141-
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
1150+
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential,
1151+
nullptr, /*prohibitIsolatedConformances=*/false))
11421152
return origSourceType;
11431153
swift_dynamicCastFailure(sourceType, targetType);
11441154
}

0 commit comments

Comments
 (0)