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;
|
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 *******************************/
|
/***************************** Enum Destination *******************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -2187,6 +2197,8 @@ static tryCastFunctionType *selectCasterForDest(const Metadata *destType) {
|
|||||||
return tryCastToOptional;
|
return tryCastToOptional;
|
||||||
case MetadataKind::ForeignClass:
|
case MetadataKind::ForeignClass:
|
||||||
return tryCastToForeignClass;
|
return tryCastToForeignClass;
|
||||||
|
case MetadataKind::ForeignReferenceType:
|
||||||
|
return tryCastToForeignReferenceType;
|
||||||
case MetadataKind::Opaque:
|
case MetadataKind::Opaque:
|
||||||
return tryCastToOpaque;
|
return tryCastToOpaque;
|
||||||
case MetadataKind::Tuple:
|
case MetadataKind::Tuple:
|
||||||
|
|||||||
@@ -61,6 +61,15 @@ WitnessTableTestSuite.test("As a Sequence") {
|
|||||||
expectEqual(count, 3)
|
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()
|
runAllTests()
|
||||||
|
|||||||
Reference in New Issue
Block a user