Skip to content

Commit 0bd5ddb

Browse files
authored
Merge pull request #40121 from eeckstein/memorylifetimeverifier
Make the MemoryLifetimeVerifier more picky about double destroys of trivial enums
2 parents 28c6dd3 + 1bf0a08 commit 0bd5ddb

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class MemoryLifetimeVerifier {
6767

6868
/// Issue an error if any bit in \p wrongBits is set.
6969
void require(const Bits &wrongBits, const Twine &complaint,
70-
SILInstruction *where);
70+
SILInstruction *where, bool excludeTrivialEnums = false);
7171

7272
/// Require that all the subLocation bits of the location, associated with
7373
/// \p addr, are clear in \p bits.
@@ -252,19 +252,20 @@ void MemoryLifetimeVerifier::reportError(const Twine &complaint,
252252
}
253253

254254
void MemoryLifetimeVerifier::require(const Bits &wrongBits,
255-
const Twine &complaint, SILInstruction *where) {
255+
const Twine &complaint, SILInstruction *where,
256+
bool excludeTrivialEnums) {
256257
for (int errorLocIdx = wrongBits.find_first(); errorLocIdx >= 0;
257258
errorLocIdx = wrongBits.find_next(errorLocIdx)) {
258-
if (!isEnumTrivialAt(errorLocIdx, where))
259+
if (!excludeTrivialEnums || !isEnumTrivialAt(errorLocIdx, where))
259260
reportError(complaint, errorLocIdx, where);
260261
}
261262
}
262263

263264
void MemoryLifetimeVerifier::requireBitsClear(const Bits &bits, SILValue addr,
264265
SILInstruction *where) {
265266
if (auto *loc = locations.getLocation(addr)) {
266-
require(bits & loc->subLocations,
267-
"memory is initialized, but shouldn't", where);
267+
require(bits & loc->subLocations, "memory is initialized, but shouldn't",
268+
where, /*excludeTrivialEnums*/ true);
268269
}
269270
}
270271

@@ -502,7 +503,8 @@ void MemoryLifetimeVerifier::checkFunction(BitDataflow &dataFlow) {
502503
BlockState &predState = dataFlow[pred];
503504
if (predState.reachableFromEntry) {
504505
require((bs.data.entrySet ^ predState.exitSet) & nonTrivialLocations,
505-
"lifetime mismatch in predecessors", pred->getTerminator());
506+
"lifetime mismatch in predecessors", pred->getTerminator(),
507+
/*excludeTrivialEnums*/ true);
506508
}
507509
}
508510

@@ -515,13 +517,15 @@ void MemoryLifetimeVerifier::checkFunction(BitDataflow &dataFlow) {
515517
require(expectedReturnBits & ~bs.data.exitSet,
516518
"indirect argument is not alive at function return", term);
517519
require(bs.data.exitSet & ~expectedReturnBits & nonTrivialLocations,
518-
"memory is initialized at function return but shouldn't", term);
520+
"memory is initialized at function return but shouldn't", term,
521+
/*excludeTrivialEnums*/ true);
519522
break;
520523
case SILInstructionKind::ThrowInst:
521524
require(expectedThrowBits & ~bs.data.exitSet,
522525
"indirect argument is not alive at throw", term);
523526
require(bs.data.exitSet & ~expectedThrowBits & nonTrivialLocations,
524-
"memory is initialized at throw but shouldn't", term);
527+
"memory is initialized at throw but shouldn't", term,
528+
/*excludeTrivialEnums*/ true);
525529
break;
526530
default:
527531
break;

test/SIL/memory_lifetime_failures.sil

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,3 +600,39 @@ bb3:
600600
%15 = tuple ()
601601
return %15 : $()
602602
}
603+
604+
// CHECK: SIL memory lifetime failure in @test_double_enum_destroy: memory is not initialized, but should
605+
sil [ossa] @test_double_enum_destroy : $@convention(thin) (@in Optional<String>) -> () {
606+
bb0(%0 : $*Optional<String>):
607+
%l = load_borrow %0 : $*Optional<String>
608+
switch_enum %l : $Optional<String>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
609+
610+
bb1(%a : @guaranteed $String):
611+
end_borrow %l : $Optional<String>
612+
%2 = load [take] %0 : $*Optional<String>
613+
destroy_value %2 : $Optional<String>
614+
br bb3
615+
616+
bb2:
617+
end_borrow %l : $Optional<String>
618+
%3 = load [take] %0 : $*Optional<String>
619+
destroy_value %3 : $Optional<String>
620+
%4 = load [take] %0 : $*Optional<String>
621+
destroy_value %4 : $Optional<String>
622+
br bb3
623+
624+
bb3:
625+
%r = tuple ()
626+
return %r : $()
627+
}
628+
629+
// CHECK: SIL memory lifetime failure in @test_destroy_enum_before_return: indirect argument is not alive at function return
630+
sil [ossa] @test_destroy_enum_before_return : $@convention(thin) () -> @out Optional<String> {
631+
bb0(%0 : $*Optional<String>):
632+
%1 = enum $Optional<String>, #Optional.none!enumelt
633+
store %1 to [trivial] %0 : $*Optional<String>
634+
destroy_addr %0 : $*Optional<String>
635+
%r = tuple ()
636+
return %r : $()
637+
}
638+

0 commit comments

Comments
 (0)