blob: 8cf7d85da3043431a66ae849d611b682cf7c9d25 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -definite-init -raw-sil-inst-lowering -verify | %FileCheck %s
// This test only tests mark_uninitialized [delegatingself]
sil_stage raw
import Builtin
import Swift
protocol P {}
class C : P {}
struct MyStruct : P {}
struct MyStruct2 {
var x: P
init(delegate: ())
init()
}
sil @selfinit : $@convention(thin) () -> MyStruct // user: %7
class SomeClass {}
class RootClassWithNontrivialStoredProperties {
var x, y: SomeClass
init()
}
class DerivedClassWithNontrivialStoredProperties : RootClassWithNontrivialStoredProperties {
var a, b: SomeClass
override init()
}
// CHECK-LABEL: @self_init_assert_instruction
// CHECK: apply
// CHECK-NEXT: store
// CHECK-NEXT: load
// CHECK: return
sil [ossa] @self_init_assert_instruction : $@convention(thin) (Int, @thin MyStruct.Type) -> MyStruct {
bb0(%0 : $Int, %1 : $@thin MyStruct.Type):
%2 = alloc_stack $MyStruct, var, name "sf"
%3 = mark_uninitialized [delegatingself] %2 : $*MyStruct
%6 = function_ref @selfinit : $@convention(thin) () -> MyStruct
%7 = apply %6() : $@convention(thin) () -> MyStruct
assign %7 to %3 : $*MyStruct
%9 = load [trivial] %3 : $*MyStruct
dealloc_stack %2 : $*MyStruct
return %9 : $MyStruct
}
sil [ossa] @selfinit_delegate : $@convention(thin) (@thin MyStruct2.Type) -> @out MyStruct2
// <rdar://problem/18089574> Protocol member in struct + delegating init miscompilation
// CHECK-LABEL: @self_init_copyaddr
sil [ossa] @self_init_copyaddr : $@convention(thin) (@thin MyStruct2.Type) -> @out MyStruct2 {
bb0(%0 : $*MyStruct2, %1 : $@thin MyStruct2.Type):
// CHECK: [[SELF:%[0-9]+]] = alloc_stack $MyStruct2
%2 = alloc_stack $MyStruct2, var, name "sf"
%3 = mark_uninitialized [delegatingself] %2 : $*MyStruct2
%6 = metatype $@thin MyStruct2.Type
%7 = function_ref @selfinit_delegate : $@convention(thin) (@thin MyStruct2.Type) -> @out MyStruct2
%8 = alloc_stack $MyStruct2
// Make sure this copy_addr ends up being an initialization.
apply %7(%8, %6) : $@convention(thin) (@thin MyStruct2.Type) -> @out MyStruct2
copy_addr [take] %8 to %3 : $*MyStruct2
dealloc_stack %8 : $*MyStruct2
// CHECK: apply
// CHECK-NEXT: copy_addr [take] {{.*}} to [initialization] [[SELF]] : $*MyStruct2
// CHECK-NEXT: dealloc_stack
copy_addr [take] %3 to [initialization] %0 : $*MyStruct2
%13 = tuple ()
dealloc_stack %2 : $*MyStruct2
return %13 : $()
}
// CHECK-LABEL: sil [ossa] @test_delegating_box_release
// CHECK: bb0([[ARG:%.*]] : @owned $RootClassWithNontrivialStoredProperties):
// CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_box $<τ_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELFBOX]]
// CHECK-NEXT: store [[ARG]] to [init] [[PB]]
// CHECK-NEXT: [[SELF:%[0-9]+]] = load [take] [[PB]]
// CHECK-NEXT: [[METATYPE:%[0-9]+]] = value_metatype $@thick RootClassWithNontrivialStoredProperties.Type, [[SELF]] : $RootClassWithNontrivialStoredProperties
// CHECK-NEXT: dealloc_partial_ref [[SELF]] : $RootClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick RootClassWithNontrivialStoredProperties.Type
// CHECK-NEXT: dealloc_box [[SELFBOX]]
sil [ossa] @test_delegating_box_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () {
bb0(%0 : @owned $RootClassWithNontrivialStoredProperties):
%2 = alloc_box $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
%2a = project_box %2 : $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>, 0
%4 = mark_uninitialized [delegatingselfallocated] %2a : $*RootClassWithNontrivialStoredProperties
store %0 to [init] %4 : $*RootClassWithNontrivialStoredProperties
destroy_value %2 : $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
%13 = tuple ()
return %13 : $()
}
// CHECK-LABEL: sil [ossa] @test_delegating_rvalue_release
// CHECK: bb0([[ARG:%.*]] : @owned $RootClassWithNontrivialStoredProperties):
// CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_box $<τ_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
// CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELFBOX]]
// CHECK-NEXT: store [[ARG]] to [init] [[PB]]
// CHECK-NEXT: [[SELF:%[0-9]+]] = load [take] [[PB]]
// CHECK-NEXT: [[METATYPE:%[0-9]+]] = value_metatype $@thick RootClassWithNontrivialStoredProperties.Type, [[SELF]] : $RootClassWithNontrivialStoredProperties
// CHECK-NEXT: dealloc_partial_ref [[SELF]] : $RootClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick RootClassWithNontrivialStoredProperties.Type
// CHECK-NEXT: [[SELF2:%[0-9]+]] = load [take] [[PB]]
// CHECK-NEXT: [[METATYPE2:%[0-9]+]] = value_metatype $@thick RootClassWithNontrivialStoredProperties.Type, [[SELF2]] : $RootClassWithNontrivialStoredProperties
// CHECK-NEXT: dealloc_partial_ref [[SELF2]] : $RootClassWithNontrivialStoredProperties, [[METATYPE2]] : $@thick RootClassWithNontrivialStoredProperties.Type
// CHECK-NEXT: dealloc_box [[SELFBOX]]
sil [ossa] @test_delegating_rvalue_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () {
bb0(%0 : @owned $RootClassWithNontrivialStoredProperties):
%2 = alloc_box $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
%2a = project_box %2 : $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>, 0
%4 = mark_uninitialized [delegatingselfallocated] %2a : $*RootClassWithNontrivialStoredProperties
store %0 to [init] %4 : $*RootClassWithNontrivialStoredProperties
%6 = load [take] %4 : $*RootClassWithNontrivialStoredProperties
destroy_value %6 : $RootClassWithNontrivialStoredProperties
destroy_value %2 : $_0_0> { var τ_0_0 } <RootClassWithNontrivialStoredProperties>
%13 = tuple ()
return %13 : $()
}
// CHECK-LABEL: sil [ossa] @test_delegating_derived_release
// CHECK: bb0([[ARG:%.*]] : @owned $DerivedClassWithNontrivialStoredProperties):
// CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_stack $DerivedClassWithNontrivialStoredProperties
// CHECK-NEXT: store [[ARG]] to [init] [[SELFBOX]]
// CHECK-NEXT: [[SELF:%[0-9]+]] = load [take] [[SELFBOX]]
// CHECK-NEXT: [[METATYPE:%[0-9]+]] = value_metatype $@thick DerivedClassWithNontrivialStoredProperties.Type, [[SELF]] : $DerivedClassWithNontrivialStoredProperties
// CHECK-NEXT: dealloc_partial_ref [[SELF]] : $DerivedClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick DerivedClassWithNontrivialStoredProperties.Type
// CHECK-NEXT: dealloc_stack [[SELFBOX]]
sil [ossa] @test_delegating_derived_release : $@convention(method) (@owned DerivedClassWithNontrivialStoredProperties) -> () {
bb0(%0 : @owned $DerivedClassWithNontrivialStoredProperties):
%2 = alloc_stack $DerivedClassWithNontrivialStoredProperties
%4 = mark_uninitialized [delegatingselfallocated] %2 : $*DerivedClassWithNontrivialStoredProperties
store %0 to [init] %4 : $*DerivedClassWithNontrivialStoredProperties
destroy_addr %4 : $*DerivedClassWithNontrivialStoredProperties
dealloc_stack %2 : $*DerivedClassWithNontrivialStoredProperties
%13 = tuple ()
return %13 : $()
}
// <rdar://problem/20608881> DI miscompiles this testcase into a memory leak
struct MyStruct3 {
@_hasStorage var c: C
}
sil @selfinit_mystruct3 : $@convention(thin) () -> @owned MyStruct3
// CHECK-LABEL: sil hidden [ossa] @test_conditional_destroy_delegating_init
sil hidden [ossa] @test_conditional_destroy_delegating_init : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
// CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int1
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_stack $MyStruct3
%2 = alloc_stack $MyStruct3
%3 = mark_uninitialized [delegatingself] %2 : $*MyStruct3
// CHECK: cond_br %0, [[SUCCESS:bb[0-9]+]], [[EXIT:bb[0-9]+]]
cond_br %0, bb1, bb2
// CHECK: [[SUCCESS]]:
bb1:
%9 = function_ref @selfinit_mystruct3 : $@convention(thin) () -> @owned MyStruct3
%10 = apply %9() : $@convention(thin) () -> @owned MyStruct3
assign %10 to %3 : $*MyStruct3
// CHECK: [[NEW_SELF:%[0-9]+]] = apply {{.*}}() : $@convention(thin) () -> @owned MyStruct3
// CHECK-NEXT: [[SET:%[0-9]+]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: store [[SET]] to [trivial] [[CONTROL]] : $*Builtin.Int1
// CHECK-NEXT: store [[NEW_SELF]] to [init] [[SELF_BOX]] : $*MyStruct3
// CHECK-NEXT: br [[CHECK:bb[0-9]+]]
br bb2
// CHECK: [[CHECK]]:
bb2:
// CHECK-NEXT: [[BIT:%[0-9]+]] = load [trivial] [[CONTROL]] : $*Builtin.Int1
// CHECK-NEXT: cond_br [[BIT]], [[INITIALIZED:bb[0-9]+]], [[UNINITIALIZED:bb[0-9]+]]
// CHECK: [[INITIALIZED]]:
// CHECK-NEXT: destroy_addr [[SELF_BOX]] : $*MyStruct3
// CHECK-NEXT: br [[EXIT:bb[0-9]+]]
// CHECK: [[UNINITIALIZED]]:
// CHECK-NEXT: br [[EXIT]]
// CHECK: [[EXIT]]:
destroy_addr %3 : $*MyStruct3
dealloc_stack %2 : $*MyStruct3
%15 = tuple ()
return %15 : $()
}
// <rdar://problem/21991742> DI miscompiles this testcase into a double free
class MyClass3 {
}
sil @selfinit_myclass3 : $@convention(thin) (@owned MyClass3) -> @owned MyClass3
// CHECK-LABEL: sil hidden [ossa] @test_conditional_destroy_class_delegating_init
sil hidden [ossa] @test_conditional_destroy_class_delegating_init : $@convention(thin) (Builtin.Int1, @owned MyClass3) -> () {
bb0(%0 : $Builtin.Int1, %1 : @owned $MyClass3):
// CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int2
// CHECK-NEXT: [[SELF_BOX:%[0-9]+]] = alloc_stack $MyClass3
%2 = alloc_stack $MyClass3
%3 = mark_uninitialized [delegatingselfallocated] %2 : $*MyClass3
store %1 to [init] %3 : $*MyClass3
// CHECK: cond_br %0, [[SUCCESS:bb[0-9]+]], [[EXIT:bb[0-9]+]]
cond_br %0, bb1, bb2
// CHECK: [[SUCCESS]]:
bb1:
%4 = load [take] %3 : $*MyClass3
%5 = function_ref @selfinit_myclass3 : $@convention(thin) (@owned MyClass3) -> @owned MyClass3
%6 = apply %5(%4) : $@convention(thin) (@owned MyClass3) -> @owned MyClass3
store %6 to [init] %3 : $*MyClass3
// CHECK: [[SET:%[0-9]+]] = integer_literal $Builtin.Int2, -2
// CHECK-NEXT: [[OLD:%.*]] = load [trivial] [[CONTROL]]
// CHECK-NEXT: [[UPDATE:%.*]] = builtin "or_Int2"([[OLD]] : $Builtin.Int2, [[SET]] : $Builtin.Int2)
// CHECK-NEXT: store [[UPDATE]] to [trivial] [[CONTROL]] : $*Builtin.Int2
// CHECK: [[SET:%[0-9]+]] = integer_literal $Builtin.Int2, 1
// CHECK-NEXT: [[OLD:%.*]] = load [trivial] [[CONTROL]]
// CHECK-NEXT: [[UPDATE:%.*]] = builtin "or_Int2"([[OLD]] : $Builtin.Int2, [[SET]] : $Builtin.Int2)
// CHECK-NEXT: store [[UPDATE]] to [trivial] [[CONTROL]] : $*Builtin.Int2
// CHECK: [[NEW_SELF:%[0-9]+]] = apply {{.*}}({{.*}}) : $@convention(thin) (@owned MyClass3) -> @owned MyClass3
// CHECK-NEXT: store [[NEW_SELF]] to [init] [[SELF_BOX]] : $*MyClass3
// CHECK-NEXT: br [[CHECK:bb[0-9]+]]
br bb2
// CHECK: [[CHECK]]:
bb2:
// CHECK-NEXT: [[BIT:%.*]] = load [trivial] [[CONTROL]]
// CHECK-NEXT: [[COND:%.*]] = builtin "trunc_Int2_Int1"([[BIT]] : $Builtin.Int2) : $Builtin.Int1
// CHECK-NEXT: cond_br [[COND]], [[PARTIAL:bb[0-9]+]], [[UNINITIALIZED:bb[0-9]+]]
// CHECK: [[PARTIAL]]:
// CHECK-NEXT: [[BIT:%.*]] = load [trivial] [[CONTROL]]
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1
// CHECK-NEXT: [[SHIFTED:%.*]] = builtin "lshr_Int2"([[BIT]] : $Builtin.Int2, [[ONE]] : $Builtin.Int2) : $Builtin.Int2
// CHECK-NEXT: [[COND:%.*]] = builtin "trunc_Int2_Int1"([[SHIFTED]] : $Builtin.Int2) : $Builtin.Int1
// CHECK-NEXT: cond_br [[COND]], [[INITIALIZED:bb[0-9]+]], [[CONSUMED:bb[0-9]+]]
// CHECK: [[INITIALIZED]]:
// CHECK-NEXT: destroy_addr [[SELF_BOX]] : $*MyClass3
// CHECK-NEXT: br [[EXIT:bb[0-9]+]]
// CHECK: [[CONSUMED]]:
// CHECK-NEXT: br [[EXIT]]
// CHECK: [[UNINITIALIZED]]:
// CHECK-NEXT: [[OLD_SELF:%[0-9]+]] = load [take] [[SELF_BOX]] : $*MyClass3
// CHECK-NEXT: [[METATYPE:%[0-9]+]] = value_metatype $@thick MyClass3.Type, [[OLD_SELF]] : $MyClass3
// CHECK-NEXT: dealloc_partial_ref [[OLD_SELF]] : $MyClass3, [[METATYPE]] : $@thick MyClass3.Type
// CHECK-NEXT: br [[EXIT:bb[0-9]+]]
// CHECK: [[EXIT]]:
destroy_addr %3 : $*MyClass3
dealloc_stack %2 : $*MyClass3
%7 = tuple ()
return %7 : $()
}