// RUN: %target-sil-opt -enable-library-evolution -module-name main -enable-sil-verify-all -deinit-devirtualizer -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyEnumDeinits %s | %FileCheck %s // REQUIRES: swift_in_compiler // REQUIRES: swift_feature_MoveOnlyClasses // REQUIRES: swift_feature_MoveOnlyEnumDeinits sil_stage raw import Builtin import Swift //===----------------------------------------------------------------------===// // Declarations //===----------------------------------------------------------------------===// public class Klass: ~Copyable { deinit } public struct StructDeinit: ~Copyable { var i: Builtin.Int32 deinit } public struct SingleFieldNonTrivial: ~Copyable { var k: Klass deinit } public struct ThreeNonTrivial: ~Copyable { var k: Klass var i: Builtin.Int32 var k2: Klass deinit } struct ThreeNonTrivialNoDeinit: ~Copyable { var k: Klass var i: Builtin.Int32 var k2: Klass } enum TrivialMoveOnlyEnum: ~Copyable { case first case second(Builtin.Int32) case third(Builtin.Int64, Builtin.Int64) deinit } enum NonTrivialMoveOnlyEnum: ~Copyable { case first case second(Builtin.Int32) case third(Klass, Klass) case fourth(Builtin.Int64, Builtin.Int64) case fifth(TrivialMoveOnlyEnum) deinit } //===----------------------------------------------------------------------===// // Object Tests //===----------------------------------------------------------------------===// // CHECK-LABEL: sil [ossa] @structDeinitTest : $@convention(thin) (@owned StructDeinit) -> () { // CHECK: bb0([[ARG:%.*]] : @owned $StructDeinit): // CHECK: [[FUNC:%.*]] = function_ref @$s4main12StructDeinitVfD : // CHECK: [[STACK:%.*]] = alloc_stack $ // CHECK: store [[ARG]] to [init] [[STACK]] // CHECK: apply [[FUNC]]([[STACK]]) // CHECK: } // end sil function 'structDeinitTest' sil [ossa] @structDeinitTest : $@convention(thin) (@owned StructDeinit) -> () { bb0(%0 : @owned $StructDeinit): destroy_value %0 : $StructDeinit %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @singleFieldNonTrivialTest : $@convention(thin) (@owned SingleFieldNonTrivial) -> () { // CHECK: bb0([[ARG:%.*]] : @owned $Single // CHECK: [[FUNC:%.*]] = function_ref @$s4main21SingleFieldNonTrivialVfD : // CHECK: [[STACK:%.*]] = alloc_stack $ // CHECK: store [[ARG]] to [init] [[STACK]] // CHECK: apply [[FUNC]]([[STACK]]) // CHECK: } // end sil function 'singleFieldNonTrivialTest' sil [ossa] @singleFieldNonTrivialTest : $@convention(thin) (@owned SingleFieldNonTrivial) -> () { bb0(%0 : @owned $SingleFieldNonTrivial): destroy_value %0 : $SingleFieldNonTrivial %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @multiFieldNonTrivialTest : $@convention(thin) (@owned ThreeNonTrivial) -> () { // CHECK: bb0([[ARG:%.*]] : @owned $ // CHECK: [[FUNC:%.*]] = function_ref @$s4main15ThreeNonTrivialVfD : // CHECK: [[STACK:%.*]] = alloc_stack $ // CHECK: store [[ARG]] to [init] [[STACK]] // CHECK: apply [[FUNC]]([[STACK]]) // CHECK: } // end sil function 'multiFieldNonTrivialTest' sil [ossa] @multiFieldNonTrivialTest : $@convention(thin) (@owned ThreeNonTrivial) -> () { bb0(%0 : @owned $ThreeNonTrivial): destroy_value %0 : $ThreeNonTrivial %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @trivialMoveOnlyEnum : $@convention(thin) (@owned TrivialMoveOnlyEnum) -> () { // CHECK: [[FUNC:%.*]] = function_ref @$s4main19TrivialMoveOnlyEnumOfD : // CHECK: [[STACK:%.*]] = alloc_stack $ // CHECK: store [[ARG]] to [init] [[STACK]] // CHECK: apply [[FUNC]]([[STACK]]) // CHECK: } // end sil function 'trivialMoveOnlyEnum' sil [ossa] @trivialMoveOnlyEnum : $@convention(thin) (@owned TrivialMoveOnlyEnum) -> () { bb0(%0 : @owned $TrivialMoveOnlyEnum): destroy_value %0 : $TrivialMoveOnlyEnum %9999 = tuple() return %9999 : $() } sil [ossa] @nonTrivialMoveOnlyEnum : $@convention(thin) (@owned NonTrivialMoveOnlyEnum) -> () { bb0(%0 : @owned $NonTrivialMoveOnlyEnum): destroy_value %0 : $NonTrivialMoveOnlyEnum %9999 = tuple() return %9999 : $() } //===----------------------------------------------------------------------===// // Var Tests //===----------------------------------------------------------------------===// // CHECK-LABEL: sil [ossa] @structDeinitAddrTest : $@convention(thin) (@in StructDeinit) -> () { // CHECK: bb0([[ARG:%.*]] : $*StructDeinit): // CHECK: [[FUNC:%.*]] = function_ref @$s4main12StructDeinitVfD : // CHECK: apply [[FUNC]]([[ARG]]) // CHECK: } // end sil function 'structDeinitAddrTest' sil [ossa] @structDeinitAddrTest : $@convention(thin) (@in StructDeinit) -> () { bb0(%0 : $*StructDeinit): destroy_addr %0 : $*StructDeinit %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @singleFieldNonTrivialAddrTest : $@convention(thin) (@in SingleFieldNonTrivial) -> () { // CHECK: bb0([[ARG:%.*]] : $ // CHECK: [[FUNC:%.*]] = function_ref @$s4main21SingleFieldNonTrivialVfD : // CHECK: apply [[FUNC]]([[ARG]]) // CHECK: } // end sil function 'singleFieldNonTrivialAddrTest' sil [ossa] @singleFieldNonTrivialAddrTest : $@convention(thin) (@in SingleFieldNonTrivial) -> () { bb0(%0 : $*SingleFieldNonTrivial): destroy_addr %0 : $*SingleFieldNonTrivial %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @multiFieldNonTrivialAddrTest : $@convention(thin) (@in ThreeNonTrivial) -> () { // CHECK: bb0([[ARG:%.*]] : $ // CHECK: [[FUNC:%.*]] = function_ref @$s4main15ThreeNonTrivialVfD : // CHECK: apply [[FUNC]]([[ARG]]) // CHECK: } // end sil function 'multiFieldNonTrivialAddrTest' sil [ossa] @multiFieldNonTrivialAddrTest : $@convention(thin) (@in ThreeNonTrivial) -> () { bb0(%0 : $*ThreeNonTrivial): destroy_addr %0 : $*ThreeNonTrivial %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @trivialMoveOnlyEnumArg : $@convention(thin) (@in TrivialMoveOnlyEnum) -> () { // CHECK: bb0([[ARG:%.*]] : $*TrivialMoveOnlyEnum): // CHECK: [[FUNC:%.*]] = function_ref @$s4main19TrivialMoveOnlyEnumOfD // CHECK: apply [[FUNC]]([[ARG]]) // CHECK: } // end sil function 'trivialMoveOnlyEnumArg' sil [ossa] @trivialMoveOnlyEnumArg : $@convention(thin) (@in TrivialMoveOnlyEnum) -> () { bb0(%0 : $*TrivialMoveOnlyEnum): destroy_addr %0 : $*TrivialMoveOnlyEnum %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @nonTrivialMoveOnlyEnumAddrTest : $@convention(thin) (@in NonTrivialMoveOnlyEnum) -> () { // CHECK: bb0([[ARG:%.*]] : $*NonTrivialMoveOnlyEnum): // CHECK: [[FUNC:%.*]] = function_ref @$s4main22NonTrivialMoveOnlyEnumOfD : // CHECK: apply [[FUNC]]([[ARG]]) // CHECK: } // end sil function 'nonTrivialMoveOnlyEnumAddrTest' sil [ossa] @nonTrivialMoveOnlyEnumAddrTest : $@convention(thin) (@in NonTrivialMoveOnlyEnum) -> () { bb0(%0 : $*NonTrivialMoveOnlyEnum): destroy_addr %0 : $*NonTrivialMoveOnlyEnum %9999 = tuple() return %9999 : $() } //===----------------------------------------------------------------------===// // Type Without Deinit //===----------------------------------------------------------------------===// // CHECK-LABEL: sil [ossa] @multiFieldNonTrivialNoDeinitTest : $@convention(thin) (@owned ThreeNonTrivialNoDeinit) -> () { // CHECK: destroy_value // CHECK: } // end sil function 'multiFieldNonTrivialNoDeinitTest' sil [ossa] @multiFieldNonTrivialNoDeinitTest : $@convention(thin) (@owned ThreeNonTrivialNoDeinit) -> () { bb0(%0 : @owned $ThreeNonTrivialNoDeinit): destroy_value %0 : $ThreeNonTrivialNoDeinit %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @multiFieldNonTrivialNoDeinitAddrTest : $@convention(thin) (@in ThreeNonTrivialNoDeinit) -> () { // CHECK: destroy_addr // CHECK: } // end sil function 'multiFieldNonTrivialNoDeinitAddrTest' sil [ossa] @multiFieldNonTrivialNoDeinitAddrTest : $@convention(thin) (@in ThreeNonTrivialNoDeinit) -> () { bb0(%0 : $*ThreeNonTrivialNoDeinit): destroy_addr %0 : $*ThreeNonTrivialNoDeinit %9999 = tuple() return %9999 : $() } //===----------------------------------------------------------------------===// // Destructors //===----------------------------------------------------------------------===// sil hidden [ossa] @$s4main12StructDeinitVfD : $@convention(method) (@in StructDeinit) -> () { bb0(%0 : $*StructDeinit): debug_value %0 : $*StructDeinit, let, name "self", argno 1 %2 = drop_deinit %0 : $*StructDeinit %3 = tuple () return %3 : $() } sil hidden [ossa] @$s4main21SingleFieldNonTrivialVfD : $@convention(method) (@in SingleFieldNonTrivial) -> () { bb0(%0 : $*SingleFieldNonTrivial): debug_value %0 : $*SingleFieldNonTrivial, let, name "self", argno 1 %2 = struct_element_addr %0 : $*SingleFieldNonTrivial, #SingleFieldNonTrivial.k destroy_addr %2 : $*Klass %4 = tuple () return %4 : $() } sil hidden [ossa] @$s4main15ThreeNonTrivialVfD : $@convention(method) (@in ThreeNonTrivial) -> () { bb0(%0 : $*ThreeNonTrivial): debug_value %0 : $*ThreeNonTrivial, let, name "self", argno 1 %2 = struct_element_addr %0 : $*ThreeNonTrivial, #ThreeNonTrivial.k %3 = struct_element_addr %0 : $*ThreeNonTrivial, #ThreeNonTrivial.k2 destroy_addr %2 : $*Klass destroy_addr %3 : $*Klass %7 = tuple () return %7 : $() } sil hidden [ossa] @$s4main19TrivialMoveOnlyEnumOfD : $@convention(method) (@in TrivialMoveOnlyEnum) -> () { bb0(%0 : $*TrivialMoveOnlyEnum): debug_value %0 : $*TrivialMoveOnlyEnum, let, name "self", argno 1 switch_enum_addr %0 : $*TrivialMoveOnlyEnum, case #TrivialMoveOnlyEnum.first!enumelt: bb1, case #TrivialMoveOnlyEnum.second!enumelt: bb2, case #TrivialMoveOnlyEnum.third!enumelt: bb3 bb1: br bb4 bb2: br bb4 bb3: br bb4 bb4: %8 = tuple () return %8 : $() } // CHECK-LABEL: sil hidden [ossa] @$s4main22NonTrivialMoveOnlyEnumOfD : $@convention(method) (@in NonTrivialMoveOnlyEnum) -> () { // CHECK: bb0([[ARG:%.*]] : $* // CHECK: bb5: // CHECK: [[ADDR:%.*]] = unchecked_take_enum_data_addr [[ARG]] // CHECK: [[FUNC_REF:%.*]] = function_ref @$s4main19TrivialMoveOnlyEnumOfD : $@convention(method) (@in TrivialMoveOnlyEnum) -> () // CHECK: apply [[FUNC_REF]]([[ADDR]]) // CHECK: } // end sil function '$s4main22NonTrivialMoveOnlyEnumOfD' sil hidden [ossa] @$s4main22NonTrivialMoveOnlyEnumOfD : $@convention(method) (@in NonTrivialMoveOnlyEnum) -> () { bb0(%0 : $*NonTrivialMoveOnlyEnum): debug_value %0 : $*NonTrivialMoveOnlyEnum, let, name "self", argno 1 switch_enum_addr %0 : $*NonTrivialMoveOnlyEnum, case #NonTrivialMoveOnlyEnum.first!enumelt: bb1, case #NonTrivialMoveOnlyEnum.second!enumelt: bb2, case #NonTrivialMoveOnlyEnum.third!enumelt: bb3, case #NonTrivialMoveOnlyEnum.fourth!enumelt: bb4, case #NonTrivialMoveOnlyEnum.fifth!enumelt: bb5 bb1: br bb6 bb2: br bb6 bb3: %6 = unchecked_take_enum_data_addr %0 : $*NonTrivialMoveOnlyEnum, #NonTrivialMoveOnlyEnum.third %7 = tuple_element_addr %6 : $*(Klass, Klass), 0 %8 = tuple_element_addr %6 : $*(Klass, Klass), 1 destroy_addr %7 : $*Klass destroy_addr %8 : $*Klass br bb6 bb4: br bb6 bb5: %11 = unchecked_take_enum_data_addr %0 : $*NonTrivialMoveOnlyEnum, #NonTrivialMoveOnlyEnum.fifth destroy_addr %11 : $*TrivialMoveOnlyEnum br bb6 bb6: %14 = tuple () return %14 : $() } //===----------------------------------------------------------------------===// // drop_deinit Tests //===----------------------------------------------------------------------===// // CHECK-LABEL: sil [ossa] @dropDeinitOnStruct : $@convention(thin) (@owned StructDeinit) -> () { // CHECK: %1 = drop_deinit %0 // CHECK-NEXT: end_lifetime %1 // CHECK: } // end sil function 'dropDeinitOnStruct' sil [ossa] @dropDeinitOnStruct : $@convention(thin) (@owned StructDeinit) -> () { bb0(%0 : @owned $StructDeinit): %1 = drop_deinit %0 : $StructDeinit destroy_value %1 : $StructDeinit %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @dropDeinitOnMovedStruct : $@convention(thin) (@owned StructDeinit) -> () { // CHECK: %1 = drop_deinit %0 // CHECK-NEXT: %2 = move_value %1 // CHECK-NEXT: end_lifetime %2 // CHECK: } // end sil function 'dropDeinitOnMovedStruct' sil [ossa] @dropDeinitOnMovedStruct : $@convention(thin) (@owned StructDeinit) -> () { bb0(%0 : @owned $StructDeinit): %1 = drop_deinit %0 : $StructDeinit %2 = move_value %1 : $StructDeinit destroy_value %2 : $StructDeinit %9999 = tuple() return %9999 : $() } sil @$s4main5KlassCfD : $@convention(method) (@owned Klass) -> () sil @$s4main5KlassCACycfc : $@convention(method) (@owned Klass) -> @owned Klass sil @$s4main5KlassCfd : $@convention(method) (@guaranteed Klass) -> @owned Builtin.NativeObject sil_moveonlydeinit Klass { @$s4main5KlassCfD } sil_moveonlydeinit StructDeinit { @$s4main12StructDeinitVfD // StructDeinit.deinit } sil_moveonlydeinit SingleFieldNonTrivial { @$s4main21SingleFieldNonTrivialVfD // SingleFieldNonTrivial.deinit } sil_moveonlydeinit ThreeNonTrivial { @$s4main15ThreeNonTrivialVfD // ThreeNonTrivial.deinit } sil_vtable Klass { #Klass.deinit!deallocator: @$s4main5KlassCfD // Klass.__deallocating_deinit } sil_moveonlydeinit TrivialMoveOnlyEnum { @$s4main19TrivialMoveOnlyEnumOfD } sil_moveonlydeinit NonTrivialMoveOnlyEnum { @$s4main22NonTrivialMoveOnlyEnumOfD }