Skip to content

Commit 74151a9

Browse files
committed
MemoryLifetimeVerifier: treat enum cases with empty payloads (e.g. an empty tuple) like cases with no payloads.
1 parent 25d6340 commit 74151a9

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ static bool isTrivialEnumElem(EnumElementDecl *elem, SILType enumType,
178178
enumType.getEnumElementType(elem, function).isTrivial(*function);
179179
}
180180

181+
static bool injectsNoPayloadCase(InjectEnumAddrInst *IEAI) {
182+
if (!IEAI->getElement()->hasAssociatedValues())
183+
return true;
184+
SILType enumType = IEAI->getOperand()->getType();
185+
SILFunction *function = IEAI->getFunction();
186+
SILType elemType = enumType.getEnumElementType(IEAI->getElement(), function);
187+
// Handle empty types (e.g. the empty tuple) as no-payload.
188+
return elemType.isEmpty(*function);
189+
}
190+
181191
static bool isOrHasEnum(SILType type) {
182192
return type.getASTType().findIf([](Type ty) {
183193
return ty->getEnumOrBoundGenericEnum() != nullptr;
@@ -349,7 +359,7 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
349359
case SILInstructionKind::InjectEnumAddrInst: {
350360
auto *IEAI = cast<InjectEnumAddrInst>(&I);
351361
int enumIdx = locations.getLocationIdx(IEAI->getOperand());
352-
if (enumIdx >= 0 && !IEAI->getElement()->hasAssociatedValues()) {
362+
if (enumIdx >= 0 && injectsNoPayloadCase(IEAI)) {
353363
// This is a bit tricky: an injected no-payload case means that the
354364
// "full" enum is initialized. So, for the purpose of dataflow, we
355365
// treat it like a full initialization of the payload data.
@@ -588,7 +598,7 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
588598
case SILInstructionKind::InjectEnumAddrInst: {
589599
auto *IEAI = cast<InjectEnumAddrInst>(&I);
590600
int enumIdx = locations.getLocationIdx(IEAI->getOperand());
591-
if (enumIdx >= 0 && !IEAI->getElement()->hasAssociatedValues()) {
601+
if (enumIdx >= 0 && injectsNoPayloadCase(IEAI)) {
592602
// Again, an injected no-payload case is treated like a "full"
593603
// initialization. See initDataflowInBlock().
594604
requireBitsClear(bits & nonTrivialLocations, IEAI->getOperand(), &I);

test/SIL/memory_lifetime.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,35 @@ bb0(%0 : $Int, %1 : @guaranteed $@callee_guaranteed (@in_guaranteed (Int, ((), (
650650
dealloc_stack %2 : $*(Int, ((), ()))
651651
return %5 : $Int
652652
}
653+
654+
enum Result<T1, T2>{
655+
case success(T1)
656+
case failure(T2)
657+
}
658+
659+
sil @try_get_error : $@convention(thin) () -> @error Error
660+
661+
sil [ossa] @test_init_enum_empty_case : $@convention(thin) () -> @error Error {
662+
bb0:
663+
%0 = alloc_stack $Result<(), Error>
664+
%1 = function_ref @try_get_error : $@convention(thin) () -> @error Error
665+
try_apply %1() : $@convention(thin) () -> @error Error, normal bb1, error bb2
666+
667+
bb1(%3 : $()):
668+
inject_enum_addr %0 : $*Result<(), Error>, #Result.success!enumelt
669+
br bb3
670+
671+
bb2(%6 : @owned $Error):
672+
%7 = init_enum_data_addr %0 : $*Result<(), Error>, #Result.failure!enumelt
673+
store %6 to [init] %7 : $*Error
674+
inject_enum_addr %0 : $*Result<(), Error>, #Result.failure!enumelt
675+
br bb3
676+
677+
bb3:
678+
%11 = load [take] %0 : $*Result<(), Error>
679+
destroy_value %11 : $Result<(), Error>
680+
dealloc_stack %0 : $*Result<(), Error>
681+
%14 = tuple ()
682+
return %14 : $()
683+
}
684+

test/SIL/memory_lifetime_failures.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,3 +567,36 @@ bb1:
567567
%r = tuple ()
568568
return %r : $()
569569
}
570+
571+
enum Result<T1, T2>{
572+
case success(T1)
573+
case failure(T2)
574+
}
575+
576+
sil @try_get_error : $@convention(thin) () -> @error Error
577+
578+
// CHECK: SIL memory lifetime failure in @test_init_enum_trivial_case: memory is not initialized, but should
579+
sil [ossa] @test_init_enum_trivial_case : $@convention(thin) () -> @error Error {
580+
bb0:
581+
%0 = alloc_stack $Result<Int, Error>
582+
%1 = function_ref @try_get_error : $@convention(thin) () -> @error Error
583+
try_apply %1() : $@convention(thin) () -> @error Error, normal bb1, error bb2
584+
585+
bb1(%3 : $()):
586+
inject_enum_addr %0 : $*Result<Int, Error>, #Result.success!enumelt
587+
br bb3
588+
589+
590+
bb2(%7 : @owned $Error):
591+
%8 = init_enum_data_addr %0 : $*Result<Int, Error>, #Result.failure!enumelt
592+
store %7 to [init] %8 : $*Error
593+
inject_enum_addr %0 : $*Result<Int, Error>, #Result.failure!enumelt
594+
br bb3
595+
596+
bb3:
597+
%12 = load [take] %0 : $*Result<Int, Error>
598+
destroy_value %12 : $Result<Int, Error>
599+
dealloc_stack %0 : $*Result<Int, Error>
600+
%15 = tuple ()
601+
return %15 : $()
602+
}

0 commit comments

Comments
 (0)