Skip to content

Commit a81a7e4

Browse files
committed
[cxx-interop] Fix runtime crash when casting from an existential to a foreign reference type
When a C++ foreign reference type is conformed to a Swift protocol via a Swift extension, trying to cast `any MyProtocol` to the foreign reference type crashes the runtime. This was because `selectCasterForDest` wasn't handling C++ foreign reference types, and we were hitting `swift_unreachable`. This change makes sure the runtime doesn't crash for such casts. Notably, Swift doesn't have enough metadata to determine if the conditional cast actually succeeded. This is also a problem for CF types. Casting CF types in a similar fashion triggers a typechecker diagnostic. That diagnostic will be amended in a follow-up patch to also trigger for foreign reference types. rdar://141227849 (cherry picked from commit 84ae5fb)
1 parent 98ab6b2 commit a81a7e4

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,16 @@ tryCastToForeignClass(
591591
return DynamicCastResult::Failure;
592592
}
593593

594+
static DynamicCastResult tryCastToForeignReferenceType(
595+
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
596+
const Metadata *srcType, const Metadata *&destFailureType,
597+
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) {
598+
assert(srcType != destType);
599+
assert(destType->getKind() == MetadataKind::ForeignReferenceType);
600+
601+
return DynamicCastResult::Failure;
602+
}
603+
594604
/******************************************************************************/
595605
/***************************** Enum Destination *******************************/
596606
/******************************************************************************/
@@ -2187,6 +2197,8 @@ static tryCastFunctionType *selectCasterForDest(const Metadata *destType) {
21872197
return tryCastToOptional;
21882198
case MetadataKind::ForeignClass:
21892199
return tryCastToForeignClass;
2200+
case MetadataKind::ForeignReferenceType:
2201+
return tryCastToForeignReferenceType;
21902202
case MetadataKind::Opaque:
21912203
return tryCastToOpaque;
21922204
case MetadataKind::Tuple:

test/Interop/Cxx/foreign-reference/witness-table.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ WitnessTableTestSuite.test("As a Sequence") {
6161
expectEqual(count, 3)
6262
}
6363

64+
WitnessTableTestSuite.test("As an existential") {
65+
let existential: any ListNode = makeLinkedList()
66+
let cast: CxxLinkedList? = existential as? CxxLinkedList
67+
expectNotNil(cast)
68+
expectEqual(cast?.value, 0)
69+
expectEqual(cast?.next()?.value, 1)
70+
expectEqual(cast?.next()?.next()?.value, 2)
71+
}
72+
6473
}
6574

6675
runAllTests()

0 commit comments

Comments
 (0)