// RUN: %target-sil-opt -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 //===----------------------------------------------------------------------===// class Klass: ~Copyable { deinit } struct TrivialStruct: ~Copyable { var i: Builtin.Int32 } struct StructDeinit: ~Copyable { var i: Builtin.Int32 deinit } struct SingleFieldNonTrivial: ~Copyable { var k: Klass deinit } 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: apply [[FUNC]]([[ARG]]) // 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: [[FUNC:%.*]] = function_ref @$s4main21SingleFieldNonTrivialVfD : // CHECK: apply [[FUNC]]([[ARG]]) // 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: [[FUNC:%.*]] = function_ref @$s4main15ThreeNonTrivialVfD : // CHECK: apply [[FUNC]]([[ARG]]) // 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: apply [[FUNC]]([[ARG]]) // 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] @trivialStructAddrTest : $@convention(thin) (@in StructDeinit) -> () { // CHECK: bb0([[ARG:%.*]] : $*StructDeinit): // CHECK: [[FUNC:%.*]] = function_ref @$s4main12StructDeinitVfD : // CHECK: [[LOADED_VALUE:%.*]] = load [take] [[ARG]] // CHECK: apply [[FUNC]]([[LOADED_VALUE]]) // CHECK: } // end sil function 'trivialStructAddrTest' sil [ossa] @trivialStructAddrTest : $@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: [[FUNC:%.*]] = function_ref @$s4main21SingleFieldNonTrivialVfD : // CHECK: [[LOADED_VALUE:%.*]] = load [take] [[ARG]] // CHECK: apply [[FUNC]]([[LOADED_VALUE]]) // 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: [[FUNC:%.*]] = function_ref @$s4main15ThreeNonTrivialVfD : // CHECK: [[LOADED_VALUE:%.*]] = load [take] [[ARG]] // CHECK: apply [[FUNC]]([[LOADED_VALUE]]) // 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: [[LOADED_VALUE:%.*]] = load [take] [[ARG]] // CHECK: apply [[FUNC]]([[LOADED_VALUE]]) // 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: [[LOADED_VALUE:%.*]] = load [take] [[ARG]] // CHECK: apply [[FUNC]]([[LOADED_VALUE]]) // 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) (@owned StructDeinit) -> () { bb0(%0 : @owned $StructDeinit): debug_value %0 : $StructDeinit, let, name "self", argno 1 %2 = drop_deinit %0 : $StructDeinit end_lifetime %2 : $StructDeinit %4 = tuple () return %4 : $() } sil hidden [ossa] @$s4main21SingleFieldNonTrivialVfD : $@convention(method) (@owned SingleFieldNonTrivial) -> () { bb0(%0 : @owned $SingleFieldNonTrivial): debug_value %0 : $SingleFieldNonTrivial, let, name "self", argno 1 %1 = drop_deinit %0 : $SingleFieldNonTrivial %2 = destructure_struct %1 : $SingleFieldNonTrivial destroy_value %2 : $Klass %4 = tuple () return %4 : $() } sil hidden [ossa] @$s4main15ThreeNonTrivialVfD : $@convention(method) (@owned ThreeNonTrivial) -> () { bb0(%0 : @owned $ThreeNonTrivial): debug_value %0 : $ThreeNonTrivial, let, name "self", argno 1 %1 = drop_deinit %0 : $ThreeNonTrivial (%2, %3, %4) = destructure_struct %1 : $ThreeNonTrivial destroy_value %2 : $Klass destroy_value %4 : $Klass %7 = tuple () return %7 : $() } sil hidden [ossa] @$s4main19TrivialMoveOnlyEnumOfD : $@convention(method) (@owned TrivialMoveOnlyEnum) -> () { bb0(%0 : @owned $TrivialMoveOnlyEnum): debug_value %0 : $TrivialMoveOnlyEnum, let, name "self", argno 1 switch_enum %0 : $TrivialMoveOnlyEnum, case #TrivialMoveOnlyEnum.first!enumelt: bb1, case #TrivialMoveOnlyEnum.second!enumelt: bb2, case #TrivialMoveOnlyEnum.third!enumelt: bb3 bb1: br bb4 bb2(%4 : $Builtin.Int32): br bb4 bb3(%6 : $(Builtin.Int64, Builtin.Int64)): br bb4 bb4: %8 = tuple () return %8 : $() } // CHECK-LABEL: sil hidden [ossa] @$s4main22NonTrivialMoveOnlyEnumOfD : $@convention(method) (@owned NonTrivialMoveOnlyEnum) -> () { // CHECK: bb5([[ARG:%.*]] : @owned $TrivialMoveOnlyEnum): // CHECK: [[FUNC_REF:%.*]] = function_ref @$s4main19TrivialMoveOnlyEnumOfD : $@convention(method) (@owned TrivialMoveOnlyEnum) -> () // CHECK: apply [[FUNC_REF]]([[ARG]]) // CHECK: } // end sil function '$s4main22NonTrivialMoveOnlyEnumOfD' sil hidden [ossa] @$s4main22NonTrivialMoveOnlyEnumOfD : $@convention(method) (@owned NonTrivialMoveOnlyEnum) -> () { bb0(%0 : @owned $NonTrivialMoveOnlyEnum): debug_value %0 : $NonTrivialMoveOnlyEnum, let, name "self", argno 1 switch_enum %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(%4 : $Builtin.Int32): br bb6 bb3(%6 : @owned $(Klass, Klass)): (%7, %8) = destructure_tuple %6 : $(Klass, Klass) destroy_value %7 : $Klass destroy_value %8 : $Klass br bb6 bb4(%9 : $(Builtin.Int64, Builtin.Int64)): br bb6 bb5(%11 : @owned $TrivialMoveOnlyEnum): destroy_value %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 }