Skip to content

Commit 04fad1b

Browse files
authored
Merge pull request #70223 from atrick/fix-lifetime-verifier
Fix MemoryLifetimeVerifier to ignore thin functions.
2 parents 651d4f8 + 23ddaaf commit 04fad1b

File tree

2 files changed

+36
-13
lines changed

2 files changed

+36
-13
lines changed

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ class MemoryLifetimeVerifier {
4747
/// alloc_stack memory locations which are used for store_borrow.
4848
Bits storeBorrowLocations;
4949

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

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

@@ -69,7 +70,7 @@ class MemoryLifetimeVerifier {
6970

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

7475
/// Require that all the subLocation bits of the location, associated with
7576
/// \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)