Skip to content

Commit 82d07ec

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-rebranch
2 parents 66b77e8 + b8c090d commit 82d07ec

File tree

3 files changed

+73
-7
lines changed

3 files changed

+73
-7
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ class ExistentialTypeFlags {
672672
private:
673673
enum : int_type {
674674
NumWitnessTablesMask = 0x00FFFFFFU,
675-
ClassConstraintMask = 0x80000000U,
675+
ClassConstraintMask = 0x80000000U, // Warning: Set if NOT class-constrained!
676676
HasSuperclassMask = 0x40000000U,
677677
SpecialProtocolMask = 0x3F000000U,
678678
SpecialProtocolShift = 24U,

stdlib/public/runtime/Casting.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,18 +1878,44 @@ static bool tryDynamicCastBoxedSwiftValue(OpaqueValue *dest,
18781878
assert(!(flags & DynamicCastFlags::Unconditional));
18791879
assert(!(flags & DynamicCastFlags::DestroyOnFailure));
18801880

1881+
auto originalSrc = src;
1882+
auto originalSrcType = srcType;
1883+
18811884
// Swift type should be AnyObject or a class type.
1882-
if (!srcType->isAnyClass()) {
1883-
auto existential = dyn_cast<ExistentialTypeMetadata>(srcType);
1884-
if (!existential || !isAnyObjectExistentialType(existential))
1885+
while (true) {
1886+
if (srcType->isAnyClass()) {
1887+
break;
1888+
}
1889+
auto existentialType = dyn_cast<ExistentialTypeMetadata>(srcType);
1890+
if (!existentialType)
1891+
return false;
1892+
switch (existentialType->getRepresentation()) {
1893+
case ExistentialTypeRepresentation::Class: {
1894+
// If it's a Class object, it must be `AnyObject`
1895+
if (isAnyObjectExistentialType(existentialType)) {
1896+
goto validated;
1897+
}
1898+
return false;
1899+
}
1900+
case ExistentialTypeRepresentation::Opaque: {
1901+
// If it's an opaque existential, unwrap it and check again
1902+
auto opaqueContainer = reinterpret_cast<OpaqueExistentialContainer*>(src);
1903+
srcType = opaqueContainer->Type;
1904+
src = existentialType->projectValue(src);
1905+
break;
1906+
}
1907+
default: {
18851908
return false;
1909+
}
1910+
}
18861911
}
1912+
validated:
18871913

18881914
#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class:
18891915
if (swift_unboxFromSwiftValueWithType(src, dest, targetType)) {
18901916
// Release the source if we need to.
18911917
if (flags & DynamicCastFlags::TakeOnSuccess)
1892-
srcType->vw_destroy(src);
1918+
originalSrcType->vw_destroy(originalSrc);
18931919
return true;
18941920
}
18951921
#endif
@@ -1919,7 +1945,7 @@ static bool tryDynamicCastBoxedSwiftValue(OpaqueValue *dest,
19191945
const_cast<OpaqueValue*>(boxedValue));
19201946
// Release the box if we need to.
19211947
if (flags & DynamicCastFlags::TakeOnSuccess)
1922-
objc_release((id)srcSwiftValue);
1948+
originalSrcType->vw_destroy(originalSrc);
19231949
return true;
19241950
}
19251951

@@ -1931,7 +1957,7 @@ static bool tryDynamicCastBoxedSwiftValue(OpaqueValue *dest,
19311957
boxedType, targetType, innerFlags)) {
19321958
// Release the box if we need to.
19331959
if (flags & DynamicCastFlags::TakeOnSuccess)
1934-
objc_release((id)srcSwiftValue);
1960+
originalSrcType->vw_destroy(originalSrc);
19351961
return true;
19361962
}
19371963
#endif

test/stdlib/Casts.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,46 @@ CastsTests.test("Optional<T>.none can be casted to Optional<U>.none in generic c
8080
expectEqual(type(of: test(Bool?.self)), Bool??.self)
8181
}
8282

83+
// Test for SR-3871: Cannot cast from ObjC existential without going through AnyObject
84+
#if _runtime(_ObjC)
85+
protocol P2 {}
86+
CastsTests.test("Cast from ObjC existential to Protocol (SR-3871)") {
87+
struct S: P2 {}
88+
89+
class ObjCWrapper {
90+
@objc dynamic let any: Any = S()
91+
init() {}
92+
}
93+
let a = ObjCWrapper().any
94+
expectTrue(a is P2)
95+
// In SR-3871, the following cast failed (everything else here succeeded)
96+
expectNotNil(a as? P2)
97+
expectNotNil(a as? S)
98+
let b = a as AnyObject
99+
expectTrue(a is P2)
100+
expectNotNil(b as? P2)
101+
expectNotNil(b as? S)
102+
}
103+
#endif
104+
105+
protocol P3 {}
106+
CastsTests.test("Cast from Swift existential to Protocol") {
107+
struct S: P3 {}
108+
class SwiftWrapper {
109+
let any: Any = S()
110+
init() {}
111+
}
112+
let a = SwiftWrapper().any
113+
expectTrue(a is P3)
114+
expectNotNil(a as? P3)
115+
expectNotNil(a as? S)
116+
let b = a as AnyObject
117+
expectTrue(b is P3)
118+
expectNotNil(b as? P3)
119+
expectNotNil(b as? S)
120+
}
121+
122+
83123
#if _runtime(_ObjC)
84124
extension CFBitVector : P {
85125
static func makeImmutable(from values: Array<UInt8>) -> CFBitVector {

0 commit comments

Comments
 (0)