mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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
This commit is contained in:
@@ -591,6 +591,16 @@ tryCastToForeignClass(
|
||||
return DynamicCastResult::Failure;
|
||||
}
|
||||
|
||||
static DynamicCastResult tryCastToForeignReferenceType(
|
||||
OpaqueValue *destLocation, const Metadata *destType, OpaqueValue *srcValue,
|
||||
const Metadata *srcType, const Metadata *&destFailureType,
|
||||
const Metadata *&srcFailureType, bool takeOnSuccess, bool mayDeferChecks) {
|
||||
assert(srcType != destType);
|
||||
assert(destType->getKind() == MetadataKind::ForeignReferenceType);
|
||||
|
||||
return DynamicCastResult::Failure;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Enum Destination *******************************/
|
||||
/******************************************************************************/
|
||||
@@ -2187,6 +2197,8 @@ static tryCastFunctionType *selectCasterForDest(const Metadata *destType) {
|
||||
return tryCastToOptional;
|
||||
case MetadataKind::ForeignClass:
|
||||
return tryCastToForeignClass;
|
||||
case MetadataKind::ForeignReferenceType:
|
||||
return tryCastToForeignReferenceType;
|
||||
case MetadataKind::Opaque:
|
||||
return tryCastToOpaque;
|
||||
case MetadataKind::Tuple:
|
||||
|
||||
@@ -61,6 +61,15 @@ WitnessTableTestSuite.test("As a Sequence") {
|
||||
expectEqual(count, 3)
|
||||
}
|
||||
|
||||
WitnessTableTestSuite.test("As an existential") {
|
||||
let existential: any ListNode = makeLinkedList()
|
||||
let cast: CxxLinkedList? = existential as? CxxLinkedList
|
||||
expectNotNil(cast)
|
||||
expectEqual(cast?.value, 0)
|
||||
expectEqual(cast?.next()?.value, 1)
|
||||
expectEqual(cast?.next()?.next()?.value, 2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user