Skip to content

[SE-0470] Prohibit isolated conformances in dynamic casts that can't safely use them #80337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,14 @@ private extension AllocStackInst {
builder.createCheckedCastAddrBranch(
source: newAlloc, sourceFormalType: concreteFormalType,
destination: cab.destination, targetFormalType: cab.targetFormalType,
isolatedConformances: cab.isolatedConformances,
consumptionKind: cab.consumptionKind,
successBlock: cab.successBlock, failureBlock: cab.failureBlock)
context.erase(instruction: cab)
case let ucca as UnconditionalCheckedCastAddrInst:
let builder = Builder(before: ucca, context)
builder.createUnconditionalCheckedCastAddr(
isolatedConformances: ucca.isolatedConformances,
source: newAlloc, sourceFormalType: concreteFormalType,
destination: ucca.destination, targetFormalType: ucca.targetFormalType)
context.erase(instruction: ucca)
Expand Down
13 changes: 10 additions & 3 deletions SwiftCompilerSources/Sources/SIL/Builder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ public struct Builder {
public func createCheckedCastAddrBranch(
source: Value, sourceFormalType: CanonicalType,
destination: Value, targetFormalType: CanonicalType,
consumptionKind: CheckedCastAddrBranchInst.CastConsumptionKind,
isolatedConformances: CastingIsolatedConformances,
consumptionKind: CheckedCastAddrBranchInst.CastConsumptionKind,
successBlock: BasicBlock,
failureBlock: BasicBlock
) -> CheckedCastAddrBranchInst {
Expand All @@ -191,20 +192,26 @@ public struct Builder {
case .TakeOnSuccess: bridgedConsumption = .TakeOnSuccess
case .CopyOnSuccess: bridgedConsumption = .CopyOnSuccess
}

let cast = bridged.createCheckedCastAddrBranch(source.bridged, sourceFormalType.bridged,
destination.bridged, targetFormalType.bridged,
isolatedConformances.bridged,
bridgedConsumption,
successBlock.bridged, failureBlock.bridged)
return notifyNew(cast.getAs(CheckedCastAddrBranchInst.self))
}

@discardableResult
public func createUnconditionalCheckedCastAddr(
isolatedConformances: CastingIsolatedConformances,
source: Value, sourceFormalType: CanonicalType,
destination: Value, targetFormalType: CanonicalType
) -> UnconditionalCheckedCastAddrInst {
let cast = bridged.createUnconditionalCheckedCastAddr(source.bridged, sourceFormalType.bridged,
destination.bridged, targetFormalType.bridged)
let cast = bridged.createUnconditionalCheckedCastAddr(
isolatedConformances.bridged, source.bridged,
sourceFormalType.bridged,
destination.bridged, targetFormalType.bridged
)
return notifyNew(cast.getAs(UnconditionalCheckedCastAddrInst.self))
}

Expand Down
44 changes: 44 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,14 @@ final public class UnconditionalCheckedCastAddrInst : Instruction, SourceDestAdd
public var isTakeOfSrc: Bool { true }
public var isInitializationOfDest: Bool { true }
public override var mayTrap: Bool { true }

public var isolatedConformances: CastingIsolatedConformances {
switch bridged.UnconditionalCheckedCastAddr_getIsolatedConformances() {
case .Allow: .allow
case .Prohibit: .prohibit
@unknown default: fatalError("Unhandled CastingIsolatedConformances")
}
}
}

final public class BeginDeallocRefInst : SingleValueInstruction, UnaryInstruction {
Expand Down Expand Up @@ -1032,6 +1040,14 @@ class UnconditionalCheckedCastInst : SingleValueInstruction, UnaryInstruction {
public var targetFormalType: CanonicalType {
CanonicalType(bridged: bridged.UnconditionalCheckedCast_getTargetFormalType())
}

public var isolatedConformances: CastingIsolatedConformances {
switch bridged.UnconditionalCheckedCast_getIsolatedConformances() {
case .Allow: .allow
case .Prohibit: .prohibit
@unknown default: fatalError("Unhandled CastingIsolatedConformances")
}
}
}

final public
Expand Down Expand Up @@ -1771,6 +1787,18 @@ final public class DynamicMethodBranchInst : TermInst {
final public class AwaitAsyncContinuationInst : TermInst, UnaryInstruction {
}

public enum CastingIsolatedConformances {
case allow
case prohibit

var bridged: BridgedInstruction.CastingIsolatedConformances {
switch self {
case .allow: return .Allow
case .prohibit: return .Prohibit
}
}
}

final public class CheckedCastBranchInst : TermInst, UnaryInstruction {
public var source: Value { operand.value }
public var successBlock: BasicBlock { bridged.CheckedCastBranch_getSuccessBlock().block }
Expand All @@ -1779,6 +1807,14 @@ final public class CheckedCastBranchInst : TermInst, UnaryInstruction {
public func updateSourceFormalTypeFromOperandLoweredType() {
bridged.CheckedCastBranch_updateSourceFormalTypeFromOperandLoweredType()
}

public var isolatedConformances: CastingIsolatedConformances {
switch bridged.CheckedCastBranch_getIsolatedConformances() {
case .Allow: return .allow
case .Prohibit: return .prohibit
default: fatalError("Bad CastingIsolatedConformances value")
}
}
}

final public class CheckedCastAddrBranchInst : TermInst {
Expand Down Expand Up @@ -1819,6 +1855,14 @@ final public class CheckedCastAddrBranchInst : TermInst {
fatalError("invalid cast consumption kind")
}
}

public var isolatedConformances: CastingIsolatedConformances {
switch bridged.CheckedCastAddrBranch_getIsolatedConformances() {
case .Allow: .allow
case .Prohibit: .prohibit
@unknown default: fatalError("Unhandled CastingIsolatedConformances")
}
}
}

final public class ThunkInst : Instruction {
Expand Down
15 changes: 12 additions & 3 deletions docs/SIL/Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4851,7 +4851,9 @@ on whether the cast succeeds or not.
### unconditional_checked_cast

```
sil-instruction ::= 'unconditional_checked_cast' sil-operand 'to' sil-type
sil-instruction ::= 'unconditional_checked_cast'
sil-prohibit-isolated-conformances?
sil-operand 'to' sil-type

%1 = unconditional_checked_cast %0 : $A to $B
%1 = unconditional_checked_cast %0 : $*A to $*B
Expand All @@ -4867,8 +4869,9 @@ ownership are unsupported.

```
sil-instruction ::= 'unconditional_checked_cast_addr'
sil-type 'in' sil-operand 'to'
sil-type 'in' sil-operand
sil-prohibit-isolated-conformances?
sil-type 'in' sil-operand 'to'
sil-type 'in' sil-operand

unconditional_checked_cast_addr $A in %0 : $*@thick A to $B in %1 : $*@thick B
// $A and $B must be both addresses
Expand Down Expand Up @@ -5231,10 +5234,12 @@ instruction branches to `bb2`.

```
sil-terminator ::= 'checked_cast_br' sil-checked-cast-exact?
sil-prohibit-isolated-conformances?
sil-type 'in'
sil-operand 'to' sil-type ','
sil-identifier ',' sil-identifier
sil-checked-cast-exact ::= '[' 'exact' ']'
sil-prohibit-isolated-conformances ::= '[' 'prohibit_isolated_conformances' ']'

checked_cast_br A in %0 : $A to $B, bb1, bb2
checked_cast_br *A in %0 : $*A to $*B, bb1, bb2
Expand All @@ -5253,10 +5258,14 @@ An exact cast checks whether the dynamic type is exactly the target
type, not any possible subtype of it. The source and target types must
be class types.

A cast can specify that the runtime should prohibit all uses of isolated
conformances when attempting to satisfy protocol requirements of existentials.

### checked_cast_addr_br

```
sil-terminator ::= 'checked_cast_addr_br'
sil-prohibit-isolated-conformances?
sil-cast-consumption-kind
sil-type 'in' sil-operand 'to'
sil-stype 'in' sil-operand ','
Expand Down
5 changes: 5 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ enum class DynamicCastFlags : size_t {
/// True if the cast should destroy the source value on failure;
/// false if the value should be left in place.
DestroyOnFailure = 0x4,

/// True if the cast should prohibit the use of any isolated conformances,
/// for example because there is a Sendable constraint on the existential
/// type we're casting to.
ProhibitIsolatedConformances = 0x8,
};
inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) {
return (size_t(a) & size_t(b)) != 0;
Expand Down
16 changes: 16 additions & 0 deletions include/swift/SIL/DynamicCasts.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ bool canIRGenUseScalarCheckedCastInstructions(SILModule &M,
/// using a scalar cast operation.
void emitIndirectConditionalCastWithScalar(
SILBuilder &B, ModuleDecl *M, SILLocation loc,
CastingIsolatedConformances isolatedConformances,
CastConsumptionKind consumption, SILValue src, CanType sourceType,
SILValue dest, CanType targetType, SILBasicBlock *trueBB,
SILBasicBlock *falseBB, ProfileCounter TrueCount = ProfileCounter(),
Expand Down Expand Up @@ -452,6 +453,21 @@ struct SILDynamicCastInst {
return swift::canSILUseScalarCheckedCastInstructions(
getModule(), getSourceFormalType(), getTargetFormalType());
}

CastingIsolatedConformances getIsolatedConformances() const {
switch (getKind()) {
case SILDynamicCastKind::CheckedCastAddrBranchInst:
return cast<CheckedCastAddrBranchInst>(inst)->getIsolatedConformances();
case SILDynamicCastKind::CheckedCastBranchInst:
return cast<CheckedCastBranchInst>(inst)->getIsolatedConformances();
case SILDynamicCastKind::UnconditionalCheckedCastAddrInst:
return cast<UnconditionalCheckedCastAddrInst>(inst)
->getIsolatedConformances();
case SILDynamicCastKind::UnconditionalCheckedCastInst:
return cast<UnconditionalCheckedCastInst>(inst)
->getIsolatedConformances();
}
}
};

} // end namespace swift
Expand Down
27 changes: 21 additions & 6 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,11 @@ struct BridgedInstruction {
CopyOnSuccess
};

enum class CastingIsolatedConformances {
Allow,
Prohibit
};

SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef CondFailInst_getMessage() const;
BRIDGED_INLINE SwiftInt LoadInst_getLoadOwnership() const ;
BRIDGED_INLINE bool LoadBorrowInst_isUnchecked() const ;
Expand Down Expand Up @@ -802,14 +807,22 @@ struct BridgedInstruction {
BRIDGED_INLINE void LoadInst_setOwnership(SwiftInt ownership) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType UnconditionalCheckedCast_getSourceFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType UnconditionalCheckedCast_getTargetFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE CastingIsolatedConformances
UnconditionalCheckedCast_getIsolatedConformances() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType UnconditionalCheckedCastAddr_getSourceFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType UnconditionalCheckedCastAddr_getTargetFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE CastingIsolatedConformances
UnconditionalCheckedCastAddr_getIsolatedConformances() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock CheckedCastBranch_getSuccessBlock() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock CheckedCastBranch_getFailureBlock() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE CastingIsolatedConformances
CheckedCastBranch_getIsolatedConformances() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType CheckedCastAddrBranch_getSourceFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType CheckedCastAddrBranch_getTargetFormalType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock CheckedCastAddrBranch_getSuccessBlock() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock CheckedCastAddrBranch_getFailureBlock() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE CastingIsolatedConformances
CheckedCastAddrBranch_getIsolatedConformances() const;
BRIDGED_INLINE void CheckedCastBranch_updateSourceFormalTypeFromOperandLoweredType() const;
BRIDGED_INLINE CastConsumptionKind CheckedCastAddrBranch_getConsumptionKind() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSubstitutionMap ApplySite_getSubstitutionMap() const;
Expand Down Expand Up @@ -1122,13 +1135,15 @@ struct BridgedBuilder{
BridgedType type) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUpcast(BridgedValue op, BridgedType type) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createCheckedCastAddrBranch(
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType,
BridgedInstruction::CastConsumptionKind consumptionKind,
BridgedBasicBlock successBlock, BridgedBasicBlock failureBlock) const;
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType,
BridgedInstruction::CastingIsolatedConformances isolatedConformances,
BridgedInstruction::CastConsumptionKind consumptionKind,
BridgedBasicBlock successBlock, BridgedBasicBlock failureBlock) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUnconditionalCheckedCastAddr(
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType) const;
BridgedInstruction::CastingIsolatedConformances isolatedConformances,
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createLoad(BridgedValue op, SwiftInt ownership) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createLoadBorrow(BridgedValue op) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBeginDeallocRef(BridgedValue reference,
Expand Down
53 changes: 41 additions & 12 deletions include/swift/SIL/SILBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,12 @@ BridgedCanType BridgedInstruction::UnconditionalCheckedCast_getTargetFormalType(
return {getAs<swift::UnconditionalCheckedCastInst>()->getTargetFormalType()};
}

BridgedInstruction::CastingIsolatedConformances
BridgedInstruction::UnconditionalCheckedCast_getIsolatedConformances() const {
return static_cast<BridgedInstruction::CastingIsolatedConformances>(
getAs<swift::UnconditionalCheckedCastInst>()->getIsolatedConformances());
}

BridgedCanType BridgedInstruction::UnconditionalCheckedCastAddr_getSourceFormalType() const {
return {getAs<swift::UnconditionalCheckedCastAddrInst>()->getSourceFormalType()};
}
Expand All @@ -1483,6 +1489,12 @@ BridgedCanType BridgedInstruction::UnconditionalCheckedCastAddr_getTargetFormalT
return {getAs<swift::UnconditionalCheckedCastAddrInst>()->getTargetFormalType()};
}

BridgedInstruction::CastingIsolatedConformances
BridgedInstruction::UnconditionalCheckedCastAddr_getIsolatedConformances() const {
return static_cast<BridgedInstruction::CastingIsolatedConformances>(
getAs<swift::UnconditionalCheckedCastAddrInst>()->getIsolatedConformances());
}

BridgedBasicBlock BridgedInstruction::CheckedCastBranch_getSuccessBlock() const {
return {getAs<swift::CheckedCastBranchInst>()->getSuccessBB()};
}
Expand All @@ -1491,6 +1503,12 @@ BridgedBasicBlock BridgedInstruction::CheckedCastBranch_getFailureBlock() const
return {getAs<swift::CheckedCastBranchInst>()->getFailureBB()};
}

BridgedInstruction::CastingIsolatedConformances
BridgedInstruction::CheckedCastBranch_getIsolatedConformances() const {
return static_cast<BridgedInstruction::CastingIsolatedConformances>(
getAs<swift::CheckedCastBranchInst>()->getIsolatedConformances());
}

BridgedCanType BridgedInstruction::CheckedCastAddrBranch_getSourceFormalType() const {
return {getAs<swift::CheckedCastAddrBranchInst>()->getSourceFormalType()};
}
Expand Down Expand Up @@ -1519,6 +1537,11 @@ BridgedInstruction::CastConsumptionKind BridgedInstruction::CheckedCastAddrBranc
getAs<swift::CheckedCastAddrBranchInst>()->getConsumptionKind());
}

BridgedInstruction::CastingIsolatedConformances
BridgedInstruction::CheckedCastAddrBranch_getIsolatedConformances() const {
return static_cast<BridgedInstruction::CastingIsolatedConformances>(
getAs<swift::CheckedCastAddrBranchInst>()->getIsolatedConformances());
}

BridgedSubstitutionMap BridgedInstruction::ApplySite_getSubstitutionMap() const {
auto as = swift::ApplySite(unbridged());
Expand Down Expand Up @@ -2065,25 +2088,31 @@ BridgedInstruction BridgedBuilder::createUpcast(BridgedValue op, BridgedType typ
}

BridgedInstruction BridgedBuilder::createCheckedCastAddrBranch(
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType,
BridgedInstruction::CastConsumptionKind consumptionKind,
BridgedBasicBlock successBlock, BridgedBasicBlock failureBlock) const
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType,
BridgedInstruction::CastingIsolatedConformances isolatedConformances,
BridgedInstruction::CastConsumptionKind consumptionKind,
BridgedBasicBlock successBlock, BridgedBasicBlock failureBlock) const
{
return {unbridged().createCheckedCastAddrBranch(
regularLoc(), (swift::CastConsumptionKind)consumptionKind,
source.getSILValue(), sourceFormalType.unbridged(),
destination.getSILValue(), targetFormalType.unbridged(),
successBlock.unbridged(), failureBlock.unbridged())};
regularLoc(),
(swift::CastingIsolatedConformances)isolatedConformances,
(swift::CastConsumptionKind)consumptionKind,
source.getSILValue(), sourceFormalType.unbridged(),
destination.getSILValue(), targetFormalType.unbridged(),
successBlock.unbridged(), failureBlock.unbridged())};
}

BridgedInstruction BridgedBuilder::createUnconditionalCheckedCastAddr(
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType) const
BridgedInstruction::CastingIsolatedConformances isolatedConformances,
BridgedValue source, BridgedCanType sourceFormalType,
BridgedValue destination, BridgedCanType targetFormalType) const
{
return {unbridged().createUnconditionalCheckedCastAddr(
regularLoc(), source.getSILValue(), sourceFormalType.unbridged(),
destination.getSILValue(), targetFormalType.unbridged())};
regularLoc(),
(swift::CastingIsolatedConformances)isolatedConformances,
source.getSILValue(), sourceFormalType.unbridged(),
destination.getSILValue(), targetFormalType.unbridged())};
}

BridgedInstruction BridgedBuilder::createLoad(BridgedValue op, SwiftInt ownership) const {
Expand Down
Loading