diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 95a835cb07a..f4781b4ca5c 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -1791,7 +1791,12 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { } if (Dest->args_empty()) { - SILBuilderWithScope(SEI).createBranch(SEI->getLoc(), Dest); + SILBuilderWithScope builder(SEI); + if (SEI->getOperand()->getOwnershipKind() == OwnershipKind::Owned) { + // Note that a `destroy_value` would be wrong for non-copyable enums with deinits. + builder.createEndLifetime(SEI->getLoc(), SEI->getOperand()); + } + builder.createBranch(SEI->getLoc(), Dest); addToWorklist(SEI->getParent()); addToWorklist(Dest); diff --git a/test/SILOptimizer/simplify_cfg_ossa.sil b/test/SILOptimizer/simplify_cfg_ossa.sil index 60be68a61b6..9bb6480af1d 100644 --- a/test/SILOptimizer/simplify_cfg_ossa.sil +++ b/test/SILOptimizer/simplify_cfg_ossa.sil @@ -1,4 +1,6 @@ -// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s +// RUN: %target-sil-opt -sil-print-types -enable-objc-interop -enable-experimental-feature MoveOnlyEnumDeinits -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s + +// REQUIRES: swift_feature_MoveOnlyEnumDeinits // OSSA form of tests from simplify_cfg.sil and simplify_cfg_simple.sil. // @@ -64,6 +66,12 @@ struct S { var b: NonTrivial } +enum NCE: ~Copyable { + case a + case b(AnyObject) + deinit +} + /////////// // Tests // /////////// @@ -1944,6 +1952,44 @@ bb3: return %t : $() } +// CHECK-LABEL: sil [ossa] @insert_compensating_endlifetime_in_switch_enum_destination_block : +// CHECK: bb0(%0 : @owned $Optional): +// CHECK-NEXT: end_lifetime %0 +// CHECK-NEXT: tuple +// CHECK: } // end sil function 'insert_compensating_endlifetime_in_switch_enum_destination_block' +sil [ossa] @insert_compensating_endlifetime_in_switch_enum_destination_block : $@convention(thin) (@owned Optional) -> () { +bb0(%0 : @owned $Optional): + switch_enum %0, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2 + +bb1: + %15 = tuple () + return %15 + +bb2(%4 : @owned $AnyObject): + destroy_value %4 + unreachable +} + +// CHECK-LABEL: sil [ossa] @insert_compensating_endlifetime_in_switch_enum_destination_block2 : +// CHECK: bb0(%0 : @owned $NCE): +// CHECK-NEXT: %1 = drop_deinit %0 +// CHECK-NEXT: end_lifetime %1 +// CHECK-NEXT: tuple +// CHECK: } // end sil function 'insert_compensating_endlifetime_in_switch_enum_destination_block2' +sil [ossa] @insert_compensating_endlifetime_in_switch_enum_destination_block2 : $@convention(thin) (@owned NCE) -> () { +bb0(%0 : @owned $NCE): + %1 = drop_deinit %0 + switch_enum %1, case #NCE.a!enumelt: bb1, case #NCE.b!enumelt: bb2 + +bb1: + %15 = tuple () + return %15 + +bb2(%4 : @owned $AnyObject): + destroy_value %4 + unreachable +} + // CHECK-LABEL: sil [ossa] @replace_phi_arg_with_borrowed_from_use : // CHECK: bb3([[R:%.*]] : @reborrow $B): // CHECK: bb6([[G:%.*]] : @guaranteed $E):