Skip to content

Commit f92693a

Browse files
committed
[silgen] Balance out the +1 from the self argument in deallocating deinits using end_lifetime.
The issue here is that: 1. Self is passed into deallocating deinits at +1. 2. Destroying deinits take in self as a +0 value that is then returned at +1. This means that the lifetime of self can not be modeled statically in a deallocating deinit without analyzing the body of the destroying deinit (something that violates semantic sil). Thus we add an artifical destroy of self before the actual destroy of self so that the verifier can understand that self is being properly balanced. rdar://29791263
1 parent 4bc12ae commit f92693a

File tree

2 files changed

+25
-8
lines changed

2 files changed

+25
-8
lines changed

lib/SILGen/SILGenDestructor.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,29 +85,45 @@ void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
8585
loc.markAutoGenerated();
8686

8787
// Emit the prolog.
88-
SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl());
88+
SILValue initialSelfValue = emitSelfDecl(dd->getImplicitSelfDecl());
8989

9090
// Form a reference to the destroying destructor.
9191
SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer);
92-
auto classTy = selfValue->getType();
92+
auto classTy = initialSelfValue->getType();
9393
ManagedValue dtorValue;
9494
SILType dtorTy;
9595
SubstitutionList subs = classTy.gatherAllSubstitutions(SGM.M);
9696
std::tie(dtorValue, dtorTy, subs)
97-
= emitSiblingMethodRef(loc, selfValue, dtorConstant, subs);
97+
= emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subs);
9898

9999
// Call the destroying destructor.
100+
SILValue selfForDealloc;
100101
{
101102
FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc));
102-
ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, selfValue);
103+
ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue);
103104
SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
104-
selfValue = B.createApply(loc, dtorValue.forward(*this),
105-
dtorTy, objectPtrTy, subs, borrowedSelf.getUnmanagedValue());
105+
selfForDealloc = B.createApply(loc, dtorValue.forward(*this),
106+
dtorTy, objectPtrTy, subs, borrowedSelf.getUnmanagedValue());
106107
}
107108

109+
// Balance out the +1 from the self argument using end_lifetime.
110+
//
111+
// The issue here is that:
112+
//
113+
// 1. Self is passed into deallocating deinits at +1.
114+
// 2. Destroying deinits take in self as a +0 value that is then returned at
115+
// +1.
116+
//
117+
// This means that the lifetime of self can not be modeled statically in a
118+
// deallocating deinit without analyzing the body of the destroying deinit
119+
// (something that violates semantic sil). Thus we add an artifical destroy of
120+
// self before the actual destroy of self so that the verifier can understand
121+
// that self is being properly balanced.
122+
B.createEndLifetime(loc, initialSelfValue);
123+
108124
// Deallocate the object.
109-
selfValue = B.createUncheckedRefCast(loc, selfValue, classTy);
110-
B.createDeallocRef(loc, selfValue, false);
125+
selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy);
126+
B.createDeallocRef(loc, selfForDealloc, false);
111127

112128
// Return.
113129
B.createReturn(loc, emitEmptyTuple(loc));

test/SILGen/lifetime.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ class Foo<T> {
530530
// CHECK-NEXT: [[BORROWED_SELF:%.*]] = begin_borrow [[SELF]]
531531
// CHECK-NEXT: [[RESULT_SELF:%[0-9]+]] = apply [[DESTROYING_REF]]<T>([[BORROWED_SELF]]) : $@convention(method) <τ_0_0> (@guaranteed Foo<τ_0_0>) -> @owned Builtin.NativeObject
532532
// CHECK-NEXT: end_borrow [[BORROWED_SELF]] from [[SELF]]
533+
// CHECK-NEXT: end_lifetime [[SELF]]
533534
// CHECK-NEXT: [[SELF:%[0-9]+]] = unchecked_ref_cast [[RESULT_SELF]] : $Builtin.NativeObject to $Foo<T>
534535
// CHECK-NEXT: dealloc_ref [[SELF]] : $Foo<T>
535536
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ()

0 commit comments

Comments
 (0)