Skip to content
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
19 changes: 6 additions & 13 deletions stdlib/public/runtime/Casting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,23 +635,13 @@ static bool _dynamicCastToAnyHashable(OpaqueValue *destination,

// If we do find one, the cast succeeds.

// The intrinsic wants the value at +1, so we have to copy it into
// a temporary.
ValueBuffer buffer;
bool mustDeallocBuffer = false;
if (!(flags & DynamicCastFlags::TakeOnSuccess)) {
auto *valueAddr = sourceType->allocateBufferIn(&buffer);
source = sourceType->vw_initializeWithCopy(valueAddr, source);
mustDeallocBuffer = true;
}

// Initialize the destination.
_swift_convertToAnyHashableIndirect(source, destination,
sourceType, hashableConformance);

// Deallocate the buffer if we used it.
if (mustDeallocBuffer) {
sourceType->deallocateBufferIn(&buffer);
// Destroy the value if requested.
if (flags & DynamicCastFlags::TakeOnSuccess) {
sourceType->vw_destroy(source);
Copy link
Contributor

@rjmccall rjmccall Nov 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other way of doing this, by the way, would be to mark the intrinsic parameter as __owned. I don't have an opinion about whether TakeOnSuccess or !TakeOnSuccess is more important to optimize.

}

// The cast succeeded.
Expand Down Expand Up @@ -1932,6 +1922,9 @@ static bool tryDynamicCastBoxedSwiftValue(OpaqueValue *dest,

#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class:
if (swift_unboxFromSwiftValueWithType(src, dest, targetType)) {
// Release the source if we need to.
if (flags & DynamicCastFlags::TakeOnSuccess)
srcType->vw_destroy(src);
return true;
}
#endif
Expand Down
10 changes: 10 additions & 0 deletions test/stdlib/AnyHashableCasts.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ AnyHashableCasts.test("${valueExpr} as ${coercedType} as? ${castType}") {
}
% end

AnyHashableCasts.test("Casting to AnyHashable doesn't leak") {
do {
let tracked = LifetimeTracked(42)
let anyHashable = AnyHashable(tracked)
let anyObject = anyHashable as AnyObject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is testing two different cases. Aren't there 3 types of cast consumption? I think you will need a full on address only type to test that, no? Maybe my memory is wrong.

_ = anyObject as? AnyHashable
}
expectEqual(LifetimeTracked.instances, 0)
}

#if _runtime(_ObjC)
// A wrapper type around Int that bridges to NSNumber.
struct IntWrapper1: _SwiftNewtypeWrapper, Hashable, _ObjectiveCBridgeable {
Expand Down