Skip to content

Commit 5b37728

Browse files
committed
Fix OSSA in SILGenFunction::emitIVarDestroyer
It is illegal to borrow an unowned value. Unowned values are only allowed to have specific instantaneous uses. In this case, an unchecked conversion is valid because there is an assumption that within a destructor, self is guaranteed.
1 parent 93c884e commit 5b37728

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

lib/SILGen/SILGenBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ class SILGenBuilder : public SILBuilder {
272272
SILType type);
273273

274274
using SILBuilder::createUncheckedRefCast;
275-
ManagedValue createUncheckedRefCast(SILLocation loc, ManagedValue original,
275+
ManagedValue createUncheckedRefCast(SILLocation loc, ManagedValue value,
276276
SILType type);
277277

278278
using SILBuilder::createUncheckedAddrCast;

lib/SILGen/SILGenDestructor.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ void SILGenFunction::emitIVarDestroyer(SILDeclRef ivarDestroyer) {
169169
prepareEpilog(false, false, cleanupLoc);
170170
{
171171
Scope S(*this, cleanupLoc);
172+
// Self is effectively guaranteed for the duration of any destructor. For
173+
// ObjC classes, self may be unowned. A conversion to guaranteed is required
174+
// to access its members.
175+
if (selfValue.getOwnershipKind() != OwnershipKind::Guaranteed) {
176+
// %guaranteedSelf = unchecked_ownership_conversion %self to @guaranteed
177+
// ...
178+
// end_borrow %guaranteedSelf
179+
auto guaranteedSelf = B.createUncheckedOwnershipConversion(
180+
cleanupLoc, selfValue.forward(*this), OwnershipKind::Guaranteed);
181+
selfValue = emitManagedBorrowedRValueWithCleanup(guaranteedSelf);
182+
}
172183
emitClassMemberDestruction(selfValue, cd, cleanupLoc);
173184
}
174185

@@ -179,7 +190,7 @@ void SILGenFunction::emitIVarDestroyer(SILDeclRef ivarDestroyer) {
179190
void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue,
180191
ClassDecl *cd,
181192
CleanupLocation cleanupLoc) {
182-
selfValue = selfValue.borrow(*this, cleanupLoc);
193+
assert(selfValue.getOwnershipKind() == OwnershipKind::Guaranteed);
183194
for (VarDecl *vd : cd->getStoredProperties()) {
184195
const TypeLowering &ti = getTypeLowering(vd->getType());
185196
if (!ti.isTrivial()) {

test/SILGen/ivar_destroyer_objc.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-emit-silgen(mock-sdk: %clang-importer-sdk) %s | %FileCheck %s
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
6+
// CHECK-LABEL: sil hidden [ossa] @$s19ivar_destroyer_objc7ObjCFooCfETo : $@convention(objc_method) (ObjCFoo) -> () {
7+
// CHECK: bb0(%0 : @unowned $ObjCFoo):
8+
// CHECK: [[CONVERT:%.*]] = unchecked_ownership_conversion %0 : $ObjCFoo, @unowned to @guaranteed
9+
// CHECK: ref_element_addr [[CONVERT]] : $ObjCFoo, #ObjCFoo.object
10+
// CHECK: begin_access [deinit] [static]
11+
// CHECK: destroy_addr
12+
// CHECK: end_access
13+
// CHECK: end_borrow [[CONVERT]] : $ObjCFoo
14+
// CHECK-LABEL: } // end sil function '$s19ivar_destroyer_objc7ObjCFooCfETo'
15+
internal class ObjCFoo : NSObject {
16+
var object: AnyObject
17+
init(o: AnyObject) { object = o }
18+
}

0 commit comments

Comments
 (0)