Skip to content

Commit 129044f

Browse files
committed
Fix MemoryLifetimeVerifier to ignore thin functions.
SILGen optimizes creation of closure down a thin function when it has no captures: %1 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_guaranteed () -> () ValueOwnership.cpp has a sketchy optimization that treat the result like a trivial type, even though it is not: > CONSTANT_OWNERSHIP_INST(None, ThinToThickFunction) commit 8c5737d Date: Fri Oct 23 15:12:18 2020 -0700 [ownership] Change thin_to_thick function to always produce a none value. This creates a mismatch between the SILType and the SILValue ownership. This is not a coherent design--we have a similar problem with enums which is endlessly buggy--but reverting the decision will be hard. Instead, I'll hack the memory verifier to silence this case. Fixes rdar://115735132 (Lifetime verifier error with opaque return type and closure) (cherry picked from commit 047be39)
1 parent 6f0e7ac commit 129044f

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ class MemoryLifetimeVerifier {
4949
Bits storeBorrowLocations;
5050

5151
/// Returns true if the enum location \p locIdx can be proven to hold a
52-
/// hold a trivial value (e non-payload case) at \p atInst.
53-
bool isEnumTrivialAt(int locIdx, SILInstruction *atInst);
52+
/// hold a trivial value (e.g. non-payload case or thin function) at
53+
/// \p atInst.
54+
bool isValueTrivialAt(int locIdx, SILInstruction *atInst);
5455

5556
/// Returns true if an instruction in the range between \p start and \p end
5657
/// stores a trivial enum case into the enum location \p loc.
57-
bool storesTrivialEnum(int locIdx,
58+
bool storesTrivialValue(int locIdx,
5859
SILBasicBlock::reverse_iterator start,
5960
SILBasicBlock::reverse_iterator end);
6061

@@ -70,7 +71,7 @@ class MemoryLifetimeVerifier {
7071

7172
/// Issue an error if any bit in \p wrongBits is set.
7273
void require(const Bits &wrongBits, const Twine &complaint,
73-
SILInstruction *where, bool excludeTrivialEnums = false);
74+
SILInstruction *where, bool excludeTrivialValues = false);
7475

7576
/// Require that all the subLocation bits of the location, associated with
7677
/// \p addr, are clear in \p bits.
@@ -149,7 +150,7 @@ class MemoryLifetimeVerifier {
149150
void verify();
150151
};
151152

152-
bool MemoryLifetimeVerifier::isEnumTrivialAt(int locIdx,
153+
bool MemoryLifetimeVerifier::isValueTrivialAt(int locIdx,
153154
SILInstruction *atInst) {
154155
SILBasicBlock *startBlock = atInst->getParent();
155156

@@ -158,7 +159,7 @@ bool MemoryLifetimeVerifier::isEnumTrivialAt(int locIdx,
158159
while (SILBasicBlock *block = worklist.pop()) {
159160
auto start = (block == atInst->getParent() ? atInst->getReverseIterator()
160161
: block->rbegin());
161-
if (storesTrivialEnum(locIdx, start, block->rend())) {
162+
if (storesTrivialValue(locIdx, start, block->rend())) {
162163
// Stop at trivial stores to the enum.
163164
continue;
164165
}
@@ -191,21 +192,25 @@ static bool injectsNoPayloadCase(InjectEnumAddrInst *IEAI) {
191192
return elemType.isEmpty(*function);
192193
}
193194

194-
bool MemoryLifetimeVerifier::storesTrivialEnum(int locIdx,
195+
bool MemoryLifetimeVerifier::storesTrivialValue(int locIdx,
195196
SILBasicBlock::reverse_iterator start,
196197
SILBasicBlock::reverse_iterator end) {
197198
for (SILInstruction &inst : make_range(start, end)) {
198199
if (auto *IEI = dyn_cast<InjectEnumAddrInst>(&inst)) {
199200
const Location *loc = locations.getLocation(IEI->getOperand());
200201
if (loc && loc->isSubLocation(locIdx))
201-
return isTrivialEnumElem(IEI->getElement(), IEI->getOperand()->getType(),
202+
return isTrivialEnumElem(IEI->getElement(),
203+
IEI->getOperand()->getType(),
202204
function);
203205
}
204206
if (auto *SI = dyn_cast<StoreInst>(&inst)) {
205207
const Location *loc = locations.getLocation(SI->getDest());
206-
if (loc && loc->isSubLocation(locIdx) &&
207-
SI->getSrc()->getType().isOrHasEnum()) {
208-
return SI->getOwnershipQualifier() == StoreOwnershipQualifier::Trivial;
208+
if (loc && loc->isSubLocation(locIdx)) {
209+
auto ty = SI->getSrc()->getType();
210+
if (ty.isOrHasEnum() || ty.isFunction()) {
211+
return
212+
SI->getOwnershipQualifier() == StoreOwnershipQualifier::Trivial;
213+
}
209214
}
210215
}
211216
}
@@ -256,7 +261,7 @@ void MemoryLifetimeVerifier::require(const Bits &wrongBits,
256261
bool excludeTrivialEnums) {
257262
for (int errorLocIdx = wrongBits.find_first(); errorLocIdx >= 0;
258263
errorLocIdx = wrongBits.find_next(errorLocIdx)) {
259-
if (!excludeTrivialEnums || !isEnumTrivialAt(errorLocIdx, where))
264+
if (!excludeTrivialEnums || !isValueTrivialAt(errorLocIdx, where))
260265
reportError(complaint, errorLocIdx, where);
261266
}
262267
}

test/SIL/memory_lifetime.sil

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,3 +763,21 @@ bb3:
763763
return %22 : $()
764764
}
765765

766+
sil @$testTrivialThinToThickClosure : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
767+
sil @$testTrivialThinToThickApply : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
768+
769+
// Test alloc_stack of a non-trivial (thick) function.
770+
// Initialize by storing a thin function, which as ownership .none.
771+
// Deallocation does not require a destroy_adr.
772+
sil [ossa] @testTrivialThinToThick : $@convention(thin) () -> () {
773+
bb0:
774+
%0 = function_ref @$testTrivialThinToThickClosure : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
775+
%1 = thin_to_thick_function %0 : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <Int> to $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
776+
%2 = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
777+
store %1 to [trivial] %2 : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
778+
%4 = function_ref @$testTrivialThinToThickApply : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
779+
%5 = apply %4<() -> Int>(%2) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
780+
dealloc_stack %2 : $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
781+
%7 = tuple ()
782+
return %7 : $()
783+
}

0 commit comments

Comments
 (0)