| // RUN: %target-sil-opt -enable-sil-verify-all %s -definite-init -verify | FileCheck %s |
| |
| import Builtin |
| import Swift |
| |
| |
| sil @takes_Int_inout : $@convention(thin) (@inout Int) -> () |
| sil @makesInt : $@convention(thin) () -> Int |
| |
| |
| |
| // CHECK-LABEL: sil @use_before_init |
| sil @use_before_init : $@convention(thin) () -> Int { |
| bb0: |
| %0 = alloc_box $Int |
| %0a = project_box %0 : $@box Int |
| %1 = mark_uninitialized [var] %0a : $*Int // expected-note {{variable defined here}} |
| %4 = load %1 : $*Int // expected-error {{variable '<unknown>' used before being initialized}} |
| strong_release %0 : $@box Int |
| %9 = return %4 : $Int |
| } |
| |
| |
| // CHECK-LABEL: @inout_uninit |
| sil @inout_uninit : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_box $Int |
| %0a = project_box %0 : $@box Int |
| %1 = mark_uninitialized [var] %0a : $*Int // expected-note {{variable defined here}} |
| |
| %5 = function_ref @takes_Int_inout : $@convention(thin) (@inout Int) -> () |
| %6 = apply %5(%1) : $@convention(thin) (@inout Int) -> () // expected-error {{variable '<unknown>' passed by reference before being initialized}} |
| |
| %t = tuple () |
| strong_release %0 : $@box Int |
| return %t : $() |
| } |
| |
| |
| |
| |
| // This function shouldn't produce any diagnostics. |
| // |
| // func used_by_inout(a : Int) -> (Int, Int) { |
| // var t = a |
| // takes_Int_inout(&a) |
| // return (t, a) |
| //} |
| // CHECK-LABEL: sil @used_by_inout |
| sil @used_by_inout : $@convention(thin) (Int) -> (Int, Int) { |
| bb0(%0 : $Int): |
| %91 = alloc_box $Int |
| %91a = project_box %91 : $@box Int |
| %1 = mark_uninitialized [var] %91a : $*Int |
| |
| %2 = store %0 to %1 : $*Int |
| %3 = load %1 : $*Int |
| %5 = function_ref @takes_Int_inout : $@convention(thin) (@inout Int) -> () |
| %6 = apply %5(%1) : $@convention(thin) (@inout Int) -> () |
| %7 = load %1 : $*Int |
| %8 = tuple (%3 : $Int, %7 : $Int) |
| strong_release %91 : $@box Int |
| %11 = return %8 : $(Int, Int) |
| } |
| |
| |
| struct AddressOnlyStruct { |
| var a : Any |
| var b : Int |
| } |
| |
| /// returns_generic_struct - This returns a struct by reference. |
| sil @returns_generic_struct : $@convention(thin) () -> @out AddressOnlyStruct |
| |
| // There should be no error in this function. |
| // CHECK-LABEL: sil @call_struct_return_function |
| sil @call_struct_return_function : $@convention(thin) () -> Int { |
| bb0: |
| %0 = alloc_box $AddressOnlyStruct |
| %0a = project_box %0 : $@box AddressOnlyStruct |
| %1 = mark_uninitialized [var] %0a : $*AddressOnlyStruct |
| |
| %2 = function_ref @returns_generic_struct : $@convention(thin) () -> @out AddressOnlyStruct |
| %3 = apply %2(%1) : $@convention(thin) () -> @out AddressOnlyStruct |
| %4 = struct_element_addr %1 : $*AddressOnlyStruct, #AddressOnlyStruct.b |
| %5 = load %4 : $*Int |
| strong_release %0 : $@box AddressOnlyStruct |
| return %5 : $Int |
| } |
| |
| |
| // CHECK-LABEL: sil @tuple_elements1 |
| sil @tuple_elements1 : $@convention(thin) (Int) -> () { |
| bb0(%0 : $Int): |
| %2 = alloc_box $(Int, Int) |
| %2a = project_box %2 : $@box (Int, Int) |
| %3 = mark_uninitialized [var] %2a : $*(Int, Int) // expected-note {{variable defined here}} |
| %4 = tuple_element_addr %3 : $*(Int, Int), 0 |
| %5 = tuple_element_addr %3 : $*(Int, Int), 1 |
| %14 = function_ref @takes_Int_inout : $@convention(thin) (@inout Int) -> () |
| %15 = tuple_element_addr %3 : $*(Int, Int), 1 |
| %16 = apply %14(%15) : $@convention(thin) (@inout Int) -> () // expected-error {{variable '<unknown>.1' passed by reference before being initialized}} |
| |
| strong_release %2 : $@box (Int, Int) |
| %99 = tuple () |
| return %99 : $() |
| } |
| |
| // CHECK-LABEL: sil @tuple_elements2 |
| sil @tuple_elements2 : $@convention(thin) (Int) -> (Int, Int) { |
| bb0(%0 : $Int): |
| %2 = alloc_box $(Int, Int) |
| %2a = project_box %2 : $@box (Int, Int) |
| %3 = mark_uninitialized [var] %2a : $*(Int, Int) // expected-note {{variable defined here}} |
| %18 = tuple_element_addr %3 : $*(Int, Int), 0 |
| store %0 to %18 : $*Int |
| %20 = load %3 : $*(Int, Int) // expected-error {{variable '<unknown>.1' used before being initialized}} |
| %21 = tuple_extract %20 : $(Int, Int), 0 |
| %22 = tuple_extract %20 : $(Int, Int), 1 |
| %23 = tuple (%21 : $Int, %22 : $Int) |
| strong_release %2 : $@box (Int, Int) |
| return %23 : $(Int, Int) |
| } |
| |
| |
| |
| // CHECK-LABEL: sil @copy_addr1 |
| sil @copy_addr1 : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| %3 = alloc_box $T |
| %3a = project_box %3 : $@box T |
| %4 = mark_uninitialized [var] %3a : $*T |
| copy_addr [take] %1 to [initialization] %4 : $*T |
| copy_addr %4 to [initialization] %0 : $*T |
| strong_release %3 : $@box T |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: sil @copy_addr2 |
| sil @copy_addr2 : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| %3 = alloc_box $T |
| %3a = project_box %3 : $@box T |
| %4 = mark_uninitialized [var] %3a : $*T // expected-note {{variable defined here}} |
| copy_addr %4 to [initialization] %0 : $*T // expected-error {{variable '<unknown>' used before being initialized}} |
| strong_release %3 : $@box T |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| |
| sil @takes_closure : $@convention(thin) (@callee_owned () -> ()) -> () |
| sil @closure0 : $@convention(thin) (@owned @box Int) -> () |
| |
| // CHECK-LABEL: sil @closure_test |
| sil @closure_test : $@convention(thin) () -> () { |
| bb0: |
| %1 = alloc_box $Int |
| %1a = project_box %1 : $@box Int |
| %0 = mark_uninitialized [var] %1a : $*Int // expected-note {{variable defined here}} |
| |
| %5 = function_ref @takes_closure : $@convention(thin) (@callee_owned () -> ()) -> () |
| %6 = function_ref @closure0 : $@convention(thin) (@owned @box Int) -> () |
| strong_retain %1 : $@box Int |
| mark_function_escape %0 : $*Int // expected-error {{variable '<unknown>' used by function definition before being initialized}} |
| %8 = partial_apply %6(%1) : $@convention(thin) (@owned @box Int) -> () |
| %9 = apply %5(%8) : $@convention(thin) (@callee_owned () -> ()) -> () |
| strong_release %1 : $@box Int |
| |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| |
| class SomeClass {} |
| |
| sil @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| sil @getSomeOptionalClass : $@convention(thin) () -> Optional<SomeClass> |
| |
| |
| // CHECK-LABEL: sil @assign_test_trivial |
| sil @assign_test_trivial : $@convention(thin) (Int) -> Int { |
| bb0(%0 : $Int): |
| %7 = alloc_box $Int |
| %7a = project_box %7 : $@box Int |
| %1 = mark_uninitialized [var] %7a : $*Int |
| |
| // These assigns are a mix of init + store forms, but because Int is trivial, |
| // they all turn into stores. |
| assign %0 to %1 : $*Int |
| assign %0 to %1 : $*Int |
| assign %0 to %1 : $*Int |
| |
| %2 = load %1 : $*Int |
| strong_release %7 : $@box Int |
| |
| return %2 : $Int |
| } |
| |
| // CHECK-LABEL: sil @assign_test_nontrivial |
| sil @assign_test_nontrivial : $@convention(thin) () -> () { |
| bb0: |
| // Assignments of nontrivial types. The first becomes an initialize (i.e., |
| // lone store), the second becomes an assignment (retain/release dance). |
| |
| %b = alloc_box $SomeClass |
| %ba = project_box %b : $@box SomeClass |
| %c = mark_uninitialized [var] %ba : $*SomeClass |
| |
| %f = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| |
| %4 = apply %f() : $@convention(thin) () -> @owned SomeClass |
| // CHECK: [[C1:%[0-9]+]] = apply |
| |
| assign %4 to %c : $*SomeClass |
| // CHECK-NEXT: store |
| |
| %8 = apply %f() : $@convention(thin) () -> @owned SomeClass |
| // CHECK-NEXT: [[C2:%[0-9]+]] = apply |
| |
| assign %8 to %c : $*SomeClass |
| // CHECK-NEXT: load |
| // CHECK-NEXT: store [[C2]] |
| // CHECK-NEXT: strong_release |
| |
| destroy_addr %c : $*SomeClass |
| // CHECK-NEXT: destroy_addr |
| dealloc_box %b : $@box SomeClass |
| |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| |
| // CHECK-LABEL: sil @assign_test_addressonly |
| sil @assign_test_addressonly : $@convention(thin) <T> (@in T) -> @out T { |
| bb0(%0 : $*T, %1 : $*T): |
| %b = alloc_box $T |
| %ba = project_box %b : $@box T |
| %2 = mark_uninitialized [var] %ba : $*T |
| |
| // CHECK: [[PB:%[0-9]+]] = project_box |
| |
| // This should become an initialization of %4 |
| copy_addr %1 to %2 : $*T |
| // CHECK-NEXT: copy_addr %1 to [initialization] [[PB]] : $*T |
| |
| // This should stay an assignment of %4 |
| copy_addr [take] %1 to %2 : $*T |
| // CHECK-NEXT: copy_addr [take] %1 to [[PB]] : $*T |
| |
| // This is a load, and shouldn't be changed. |
| copy_addr %2 to [initialization] %0 : $*T |
| // CHECK-NEXT: copy_addr [[PB]] to [initialization] %0 : $*T |
| |
| strong_release %b : $@box T |
| // CHECK-NEXT: strong_release %2 |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: sil @assign_test_weak |
| sil @assign_test_weak : $@convention(thin) () -> () { |
| bb0: |
| // Assignments of weak pointer. The first becomes an initialize, and the |
| // second becomes an assignment. |
| |
| %b = alloc_box $@sil_weak Optional<SomeClass> |
| %ba = project_box %b : $@box @sil_weak Optional<SomeClass> |
| %c = mark_uninitialized [var] %ba : $*@sil_weak Optional<SomeClass> // expected-note {{variable defined here}} |
| |
| // Invalid load to keep the alloc_box around so we can check init semantics. |
| load_weak %c : $*@sil_weak Optional<SomeClass> // expected-error {{used before being initialized}} |
| |
| %f = function_ref @getSomeOptionalClass : $@convention(thin) () -> Optional<SomeClass> |
| |
| %4 = apply %f() : $@convention(thin) () -> Optional<SomeClass> |
| // CHECK: [[C1:%[0-9]+]] = apply |
| |
| // This should become an initialization. |
| store_weak %4 to %c : $*@sil_weak Optional<SomeClass> |
| // CHECK-NEXT: store_weak [[C1]] to [initialization] %1 |
| |
| release_value %4 : $Optional<SomeClass> |
| // CHECK-NEXT: release_value [[C1]] |
| |
| %8 = apply %f() : $@convention(thin) () -> Optional<SomeClass> |
| // CHECK-NEXT: [[C2:%[0-9]+]] = apply |
| |
| store_weak %8 to %c : $*@sil_weak Optional<SomeClass> |
| // CHECK-NEXT: store_weak [[C2]] to %1 |
| |
| release_value %8 : $Optional<SomeClass> |
| // CHECK-NEXT: release_value [[C2]] |
| |
| strong_release %b : $@box @sil_weak Optional<SomeClass> |
| |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| // CHECK-LABEL: sil @assign_test_unowned |
| sil @assign_test_unowned : $@convention(thin) () -> () { |
| bb0: |
| // Assignments of unowned pointer. The first becomes an initialize, and the |
| // second becomes an assignment. |
| |
| %b = alloc_box $@sil_unowned SomeClass |
| %ba = project_box %b : $@box @sil_unowned SomeClass |
| %c = mark_uninitialized [var] %ba : $*@sil_unowned SomeClass |
| |
| %f = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| |
| %4 = apply %f() : $@convention(thin) () -> @owned SomeClass |
| // CHECK: [[C1:%[0-9]+]] = apply |
| |
| // This should become an initialization. |
| %5 = ref_to_unowned %4 : $SomeClass to $@sil_unowned SomeClass |
| // CHECK-NEXT: [[C1u:%[0-9]+]] = ref_to_unowned [[C1]] |
| unowned_retain %5 : $@sil_unowned SomeClass |
| // CHECK-NEXT: unowned_retain [[C1u]] |
| assign %5 to %c : $*@sil_unowned SomeClass |
| // CHECK-NEXT: store [[C1u]] |
| strong_release %4 : $SomeClass |
| // CHECK-NEXT: strong_release [[C1]] |
| |
| %8 = apply %f() : $@convention(thin) () -> @owned SomeClass |
| // CHECK-NEXT: [[C2:%[0-9]+]] = apply |
| |
| %9 = ref_to_unowned %8 : $SomeClass to $@sil_unowned SomeClass |
| // CHECK: [[C2u:%[0-9]+]] = ref_to_unowned [[C2]] |
| |
| unowned_retain %9 : $@sil_unowned SomeClass |
| // CHECK-NEXT: unowned_retain [[C2u]] |
| |
| assign %9 to %c : $*@sil_unowned SomeClass |
| // CHECK-NEXT: load |
| // CHECK-NEXT: store |
| // CHECK-NEXT: unowned_release |
| |
| strong_release %8 : $SomeClass |
| // CHECK-NEXT: strong_release [[C2]] |
| |
| destroy_addr %c : $*@sil_unowned SomeClass |
| dealloc_box %b : $@box @sil_unowned SomeClass |
| |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| |
| |
| struct ContainsNativeObject { |
| var x : Int |
| var y : Builtin.NativeObject |
| } |
| |
| sil @test_struct : $@convention(thin) (@inout ContainsNativeObject) -> () { |
| bb0(%0 : $*ContainsNativeObject): |
| %b = alloc_box $ContainsNativeObject |
| %ba = project_box %b : $@box ContainsNativeObject |
| %c = mark_uninitialized [var] %ba : $*ContainsNativeObject |
| %1 = load %0 : $*ContainsNativeObject |
| assign %1 to %c : $*ContainsNativeObject |
| |
| strong_release %b : $@box ContainsNativeObject |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK-LABEL: sil @non_box_assign_trivial |
| // CHECK-NOT: load |
| // CHECK: store |
| // CHECK: return |
| sil @non_box_assign_trivial : $@convention(thin) (@inout Bool, Bool) -> () { |
| bb0(%0 : $*Bool, %1 : $Bool): |
| assign %1 to %0 : $*Bool |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: sil @non_box_assign |
| // CHECK: load |
| // CHECK: store |
| // CHECK: return |
| sil @non_box_assign : $@convention(thin) (@inout SomeClass, @owned SomeClass) -> () { |
| bb0(%0 : $*SomeClass, %1 : $SomeClass): |
| assign %1 to %0 : $*SomeClass |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| sil_global @int_global : $Int |
| |
| |
| // CHECK-LABEL: sil @test_tlc |
| // CHECK-NOT: mark_uninitialized |
| // CHECK: return |
| sil @test_tlc : $() -> () { |
| %0 = global_addr @int_global : $*Int |
| %1 = mark_uninitialized [var] %0 : $*Int |
| |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| |
| struct XYStruct { var x, y : Int } |
| sil @init_xy_struct : $@convention(thin) () -> XYStruct |
| |
| |
| |
| protocol P {} |
| class C : P {} |
| |
| sil @use : $@convention(thin) (@in P) -> () |
| |
| |
| // CHECK-LABEL: sil @release_not_constructed |
| sil @release_not_constructed : $@convention(thin) () -> () { |
| bb0: // CHECK: bb0: |
| %3 = alloc_stack $SomeClass |
| // CHECK-NEXT: alloc_stack |
| %c = mark_uninitialized [var] %3 : $*SomeClass |
| |
| |
| // This should get removed. |
| destroy_addr %c : $*SomeClass |
| |
| dealloc_stack %3 : $*SomeClass |
| // CHECK-NEXT: dealloc_stack |
| |
| // CHECK-NEXT: tuple () |
| %15 = tuple () |
| return %15 : $() |
| } |
| |
| // CHECK-LABEL: sil @release_some_constructed |
| sil @release_some_constructed : $@convention(thin) () -> () { |
| bb0: |
| %0 = tuple () |
| %b = alloc_stack $(SomeClass, SomeClass) |
| %1 = mark_uninitialized [var] %b : $*(SomeClass, SomeClass) |
| |
| %2 = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| %3 = apply %2() : $@convention(thin) () -> @owned SomeClass |
| %4 = tuple_element_addr %1 : $*(SomeClass, SomeClass), 0 |
| store %3 to %4 : $*SomeClass |
| // CHECK: store |
| |
| // Only Element #0 should get released. |
| |
| // CHECK-NEXT: [[ELT0:%[0-9]+]] = tuple_element_addr {{.*}}, 0 |
| // CHECK-NEXT: destroy_addr [[ELT0]] |
| destroy_addr %1 : $*(SomeClass, SomeClass) |
| |
| // CHECK-NEXT: dealloc_stack |
| dealloc_stack %b : $*(SomeClass, SomeClass) |
| %8 = tuple () |
| return %8 : $() |
| } |
| |
| |
| |
| // rdar://15379013 |
| // CHECK-LABEL: sil @init_existential_with_class |
| sil @init_existential_with_class : $@convention(thin) (@inout C) -> () { |
| entry(%a : $*C): |
| %p = alloc_stack $P |
| %b = mark_uninitialized [var] %p : $*P |
| |
| %q = init_existential_addr %b : $*P, $C |
| |
| // CHECK: copy_addr {{.*}} to [initialization] %2 : $*C |
| copy_addr %a to [initialization] %q : $*C |
| %u = function_ref @use : $@convention(thin) (@in P) -> () |
| %v = apply %u(%b) : $@convention(thin) (@in P) -> () |
| dealloc_stack %p : $*P |
| %z = tuple () |
| return %z : $() |
| } |
| |
| // CHECK-LABEL: sil @conditional_init |
| // This test checks conditional destruction logic. Because the value is only |
| // initialized on some paths, we need to either hoist up the destroy_addr or |
| // emit a boolean control value to make sure the value is only destroyed if |
| // actually initialized. |
| sil @conditional_init : $@convention(thin) (Bool) -> () { |
| bb0(%0 : $Bool): |
| %2 = alloc_stack $SomeClass |
| %3 = mark_uninitialized [var] %2 : $*SomeClass |
| |
| // CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int1 |
| // CHECK: [[ZERO:%[0-9]+]] = integer_literal $Builtin.Int1, 0 |
| // CHECK: store [[ZERO]] to [[CONTROL]] : $*Builtin.Int1 |
| %5 = integer_literal $Builtin.Int1, 1 |
| cond_br %5, bb1, bb2 |
| |
| bb1: |
| // CHECK: bb1: |
| // CHECK: function_ref @getSomeClass |
| // CHECK: [[ONE:%[0-9]+]] = integer_literal $Builtin.Int1, -1 |
| // CHECK: store [[ONE]] to [[CONTROL]] : $*Builtin.Int1 |
| %f = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| %6 = apply %f() : $@convention(thin) () -> @owned SomeClass |
| assign %6 to %3 : $*SomeClass |
| br bb2 |
| |
| bb2: |
| destroy_addr %3 : $*SomeClass |
| dealloc_stack %2 : $*SomeClass |
| %14 = tuple () |
| return %14 : $() |
| } |
| |
| // CHECK-LABEL: sil @conditionalInitOrAssign |
| sil @conditionalInitOrAssign : $@convention(thin) (Builtin.Int1) -> () { |
| bb0(%0 : $Builtin.Int1): |
| // CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int1 |
| // CHECK: [[CLASSVAL:%[0-9]+]] = alloc_stack $SomeClass |
| // CHECK: integer_literal $Builtin.Int1, 0 |
| // CHECK: store |
| %5 = alloc_stack $SomeClass |
| %6 = mark_uninitialized [var] %5 : $*SomeClass |
| cond_br %0, bb1, bb2 |
| |
| bb1: |
| // CHECK: = function_ref |
| %2 = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| // CHECK-NEXT: [[V1:%[0-9]+]] = apply |
| %12 = apply %2() : $@convention(thin) () -> @owned SomeClass |
| |
| // This assign becomes a simple store, since it is an initialize. This updates |
| // the control variable to say that it is initialized. |
| // CHECK: integer_literal $Builtin.Int1, -1 |
| // CHECK: store {{.*}} to [[CONTROL]] |
| // CHECK: store [[V1]] to [[CLASSVAL]] |
| assign %12 to %6 : $*SomeClass // id: %13 |
| br bb2 // id: %14 |
| |
| bb2: |
| // CHECK: = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| %3 = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass |
| // CHECK-NEXT: [[V2:%[0-9]+]] = apply |
| %17 = apply %3() : $@convention(thin) () -> @owned SomeClass |
| |
| // This assign is either an initialize or an assign depending on whether %0 is |
| // true or not. This gets expanded out to a conditional destroy of the value. |
| // CHECK: load [[CONTROL]] |
| // CHECK: cond_br |
| // CHECK: bb3: |
| // CHECK: destroy_addr [[CLASSVAL]] |
| // CHECK: br bb4 |
| // CHECK: bb4: |
| // CHECK: store [[V2]] to [[CLASSVAL]] |
| |
| assign %17 to %6 : $*SomeClass // id: %18 |
| destroy_addr %6 : $*SomeClass // id: %19 |
| dealloc_stack %5 : $*SomeClass // id: %20 |
| %23 = tuple () // user: %24 |
| return %23 : $() // id: %24 |
| } |
| |
| /// Root class tests. |
| |
| class RootClassWithIVars { |
| var x: Int // expected-note {{'self.x' not initialized}} |
| var y: Int |
| var z: (Int, Int) // expected-note 2 {{'self.z.1' not initialized}} expected-note {{'self.z.0' not initialized}} |
| init() |
| } |
| |
| |
| // CHECK-LABEL: sil @rootclass_test1 |
| sil @rootclass_test1 : $@convention(method) (@owned RootClassWithIVars, Int) -> @owned RootClassWithIVars { |
| bb0(%0 : $RootClassWithIVars, %1 : $Int): |
| %3 = mark_uninitialized [rootself] %0 : $RootClassWithIVars |
| |
| %10 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.x |
| assign %1 to %10 : $*Int |
| |
| %11 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.y |
| assign %1 to %11 : $*Int |
| |
| %12 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.z |
| %13 = tuple_element_addr %12 : $*(Int, Int), 0 |
| assign %1 to %13 : $*Int |
| %14 = tuple_element_addr %12 : $*(Int, Int), 1 |
| assign %1 to %14 : $*Int |
| |
| return %3 : $RootClassWithIVars |
| } |
| |
| // CHECK-LABEL: sil @rootclass_test2 |
| sil @rootclass_test2 : $@convention(method) (@owned RootClassWithIVars, Int) -> @owned RootClassWithIVars { |
| bb0(%0 : $RootClassWithIVars, %1 : $Int): |
| %3 = mark_uninitialized [rootself] %0 : $RootClassWithIVars |
| |
| %10 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.x |
| assign %1 to %10 : $*Int |
| |
| %11 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.y |
| assign %1 to %11 : $*Int |
| |
| %12 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.z |
| %13 = tuple_element_addr %12 : $*(Int, Int), 0 |
| assign %1 to %13 : $*Int |
| |
| return %3 : $RootClassWithIVars // expected-error {{return from initializer without initializing all stored properties}} |
| } |
| |
| // CHECK-LABEL: sil @rootclass_test3 |
| sil @rootclass_test3 : $@convention(method) (@owned RootClassWithIVars, Int) -> @owned RootClassWithIVars { |
| bb0(%0 : $RootClassWithIVars, %1 : $Int): |
| %3 = mark_uninitialized [rootself] %0 : $RootClassWithIVars |
| |
| %11 = ref_element_addr %3 : $RootClassWithIVars, #RootClassWithIVars.y |
| assign %1 to %11 : $*Int |
| |
| return %3 : $RootClassWithIVars // expected-error {{return from initializer without initializing all stored properties}} |
| } |
| |
| class DerivedClassWithIVars : RootClassWithIVars { |
| var a: Int |
| override init() |
| } |
| |
| sil @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| |
| |
| sil @derived_test1 : $@convention(method) (@owned DerivedClassWithIVars) -> @owned DerivedClassWithIVars { |
| bb0(%0 : $DerivedClassWithIVars): |
| %1 = alloc_box $DerivedClassWithIVars |
| %1a = project_box %1 : $@box DerivedClassWithIVars |
| %3 = mark_uninitialized [derivedself] %1a : $*DerivedClassWithIVars |
| store %0 to %3 : $*DerivedClassWithIVars |
| |
| // Get an int |
| %5 = function_ref @makesInt : $@convention(thin) () -> Int |
| %7 = apply %5() : $@convention(thin) () -> Int |
| |
| // Initialize the 'a' ivar with the int. |
| %8 = load %3 : $*DerivedClassWithIVars |
| %9 = ref_element_addr %8 : $DerivedClassWithIVars, #DerivedClassWithIVars.a |
| assign %7 to %9 : $*Int |
| |
| |
| %11 = load %3 : $*DerivedClassWithIVars |
| %13 = upcast %11 : $DerivedClassWithIVars to $RootClassWithIVars |
| %14 = function_ref @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| %15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| |
| %16 = unconditional_checked_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars |
| assign %16 to %3 : $*DerivedClassWithIVars |
| %18 = load %3 : $*DerivedClassWithIVars |
| strong_retain %18 : $DerivedClassWithIVars |
| strong_release %1 : $@box DerivedClassWithIVars |
| return %18 : $DerivedClassWithIVars |
| } |
| |
| sil @derived_test2 : $@convention(method) (@owned DerivedClassWithIVars) -> @owned DerivedClassWithIVars { |
| bb0(%0 : $DerivedClassWithIVars): |
| %1 = alloc_box $DerivedClassWithIVars |
| %1a = project_box %1 : $@box DerivedClassWithIVars |
| %3 = mark_uninitialized [derivedself] %1a : $*DerivedClassWithIVars |
| store %0 to %3 : $*DerivedClassWithIVars |
| |
| %11 = load %3 : $*DerivedClassWithIVars |
| %13 = upcast %11 : $DerivedClassWithIVars to $RootClassWithIVars |
| %14 = function_ref @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| %15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars // expected-error {{property 'self.a' not initialized at super.init call}} |
| |
| %16 = unconditional_checked_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars |
| assign %16 to %3 : $*DerivedClassWithIVars |
| %18 = load %3 : $*DerivedClassWithIVars |
| strong_retain %18 : $DerivedClassWithIVars |
| strong_release %1 : $@box DerivedClassWithIVars |
| return %18 : $DerivedClassWithIVars |
| } |
| |
| struct MyStruct : P {} |
| |
| //CHECK-LABEL: @self_init_assert_instruction |
| //CHECK: apply |
| //CHECK-NEXT: store |
| //CHECK-NEXT: load |
| //CHECK: return |
| sil @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" // users: %3, %10 |
| %3 = mark_uninitialized [delegatingself] %2 : $*MyStruct // users: %8, %9 |
| debug_value %0 : $Int, let, name "i" // id: %4 |
| |
| %6 = function_ref @selfinit : $@convention(thin) () -> MyStruct |
| %7 = apply %6() : $@convention(thin) () -> MyStruct |
| assign %7 to %3 : $*MyStruct |
| %9 = load %3 : $*MyStruct |
| dealloc_stack %2 : $*MyStruct |
| return %9 : $MyStruct |
| } |
| |
| sil @selfinit : $@convention(thin) () -> MyStruct // user: %7 |
| |
| struct MyStruct2 { |
| var x: P |
| init(delegate: ()) |
| init() |
| } |
| |
| sil @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 @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 : $() |
| } |
| |
| class RootClassWithNontrivialStoredProperties { |
| var x, y: SomeClass |
| |
| init() |
| } |
| |
| class DerivedClassWithNontrivialStoredProperties : RootClassWithNontrivialStoredProperties { |
| var a, b: SomeClass |
| override init() |
| } |
| |
| // CHECK-LABEL: sil @test_root_release |
| // CHECK: bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thick RootClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_partial_ref %0 : $RootClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick RootClassWithNontrivialStoredProperties.Type |
| sil @test_root_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| %4 = mark_uninitialized [rootself] %0 : $RootClassWithNontrivialStoredProperties |
| strong_release %4 : $RootClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_root_partial_release |
| // CHECK: bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: alloc_ref |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: store |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: destroy_addr |
| // CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thick RootClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_partial_ref %0 : $RootClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick RootClassWithNontrivialStoredProperties.Type |
| sil @test_root_partial_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| %4 = mark_uninitialized [rootself] %0 : $RootClassWithNontrivialStoredProperties |
| |
| %1 = alloc_ref $SomeClass |
| %2 = ref_element_addr %4 : $RootClassWithNontrivialStoredProperties, #RootClassWithNontrivialStoredProperties.x |
| assign %1 to %2 : $*SomeClass |
| |
| strong_release %4 : $RootClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_derived_release |
| // CHECK: bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_stack |
| // CHECK-NEXT: store |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]] |
| // CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thick DerivedClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_partial_ref [[SELF]] : $DerivedClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick DerivedClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_stack [[SELFBOX]] |
| |
| sil @test_derived_release : $@convention(method) (@owned DerivedClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| %1 = alloc_stack $DerivedClassWithNontrivialStoredProperties |
| %4 = mark_uninitialized [derivedself] %1 : $*DerivedClassWithNontrivialStoredProperties |
| store %0 to %4 : $*DerivedClassWithNontrivialStoredProperties |
| |
| destroy_addr %4 : $*DerivedClassWithNontrivialStoredProperties |
| dealloc_stack %1 : $*DerivedClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| |
| // CHECK-LABEL: sil @test_derived_partial_release |
| // CHECK: bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_stack |
| // CHECK-NEXT: store |
| // CHECK-NEXT: alloc_ref |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]] |
| // CHECK-NEXT: ref_element_addr [[SELF]] |
| // CHECK-NEXT: store |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]] |
| // CHECK-NEXT: ref_element_addr [[SELF]] |
| // CHECK-NEXT: destroy_addr |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]] |
| // CHECK-NEXT: [[METATYPE:%[0-9]+]] = metatype $@thick DerivedClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_partial_ref [[SELF]] : $DerivedClassWithNontrivialStoredProperties, [[METATYPE]] : $@thick DerivedClassWithNontrivialStoredProperties.Type |
| // CHECK-NEXT: dealloc_stack [[SELFBOX]] |
| |
| sil @test_derived_partial_release : $@convention(method) (@owned DerivedClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| %1 = alloc_stack $DerivedClassWithNontrivialStoredProperties |
| %4 = mark_uninitialized [derivedself] %1 : $*DerivedClassWithNontrivialStoredProperties |
| store %0 to %4 : $*DerivedClassWithNontrivialStoredProperties |
| |
| %8 = alloc_ref $SomeClass |
| %9 = load %4 : $*DerivedClassWithNontrivialStoredProperties |
| %10 = ref_element_addr %9 : $DerivedClassWithNontrivialStoredProperties, #DerivedClassWithNontrivialStoredProperties.a |
| assign %8 to %10 : $*SomeClass |
| |
| destroy_addr %4 : $*DerivedClassWithNontrivialStoredProperties |
| dealloc_stack %1 : $*DerivedClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_delegating_box_release |
| // CHECK: bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_box $RootClassWithNontrivialStoredProperties |
| // CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELFBOX]] |
| // CHECK-NEXT: store %0 to [[PB]] |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[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 @test_delegating_box_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| %2 = alloc_box $RootClassWithNontrivialStoredProperties |
| %2a = project_box %2 : $@box RootClassWithNontrivialStoredProperties |
| %4 = mark_uninitialized [delegatingself] %2a : $*RootClassWithNontrivialStoredProperties |
| store %0 to %4 : $*RootClassWithNontrivialStoredProperties |
| strong_release %2 : $@box RootClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_delegating_rvalue_release |
| // CHECK: bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_box $RootClassWithNontrivialStoredProperties |
| // CHECK-NEXT: [[PB:%[0-9]+]] = project_box [[SELFBOX]] |
| // CHECK-NEXT: store %0 to [[PB]] |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[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 [[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 @test_delegating_rvalue_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $RootClassWithNontrivialStoredProperties): |
| %2 = alloc_box $RootClassWithNontrivialStoredProperties |
| %2a = project_box %2 : $@box RootClassWithNontrivialStoredProperties |
| %4 = mark_uninitialized [delegatingself] %2a : $*RootClassWithNontrivialStoredProperties |
| store %0 to %4 : $*RootClassWithNontrivialStoredProperties |
| %6 = load %4 : $*RootClassWithNontrivialStoredProperties |
| strong_release %6 : $RootClassWithNontrivialStoredProperties |
| strong_release %2 : $@box RootClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_delegating_derived_release |
| // CHECK: bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| // CHECK-NEXT: [[SELFBOX:%[0-9]+]] = alloc_stack $DerivedClassWithNontrivialStoredProperties |
| // CHECK-NEXT: store %0 to [[SELFBOX]] |
| // CHECK-NEXT: [[SELF:%[0-9]+]] = load [[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 @test_delegating_derived_release : $@convention(method) (@owned DerivedClassWithNontrivialStoredProperties) -> () { |
| bb0(%0 : $DerivedClassWithNontrivialStoredProperties): |
| %2 = alloc_stack $DerivedClassWithNontrivialStoredProperties |
| %4 = mark_uninitialized [delegatingself] %2 : $*DerivedClassWithNontrivialStoredProperties |
| store %0 to %4 : $*DerivedClassWithNontrivialStoredProperties |
| |
| destroy_addr %4 : $*DerivedClassWithNontrivialStoredProperties |
| dealloc_stack %2 : $*DerivedClassWithNontrivialStoredProperties |
| |
| %13 = tuple () |
| return %13 : $() |
| } |
| |
| |
| // <rdar://problem/18199087> DI doesn't catch use of super properties lexically inside super.init call |
| sil @super_init_out_of_order : $@convention(method) (@owned DerivedClassWithIVars, Int) -> @owned DerivedClassWithIVars { |
| bb0(%0 : $DerivedClassWithIVars, %i : $Int): |
| %1 = alloc_box $DerivedClassWithIVars |
| %1a = project_box %1 : $@box DerivedClassWithIVars |
| %3 = mark_uninitialized [derivedself] %1a : $*DerivedClassWithIVars |
| store %0 to %3 : $*DerivedClassWithIVars |
| |
| // Initialize properties in derived class. |
| %8 = load %3 : $*DerivedClassWithIVars |
| %9 = ref_element_addr %8 : $DerivedClassWithIVars, #DerivedClassWithIVars.a |
| assign %i to %9 : $*Int |
| |
| |
| // Get the super.init function information, but don't apply it. |
| %11 = load %3 : $*DerivedClassWithIVars |
| %13 = upcast %11 : $DerivedClassWithIVars to $RootClassWithIVars |
| %14 = function_ref @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| |
| // Access a super property before super.init is called. |
| %a = load %3 : $*DerivedClassWithIVars |
| %b = upcast %11 : $DerivedClassWithIVars to $RootClassWithIVars |
| %c = ref_element_addr %b : $RootClassWithIVars, #RootClassWithIVars.x // expected-error {{use of 'self' in property access 'x' before super.init initializes self}} |
| load %c : $*Int |
| |
| // Call super.init. |
| %15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars |
| |
| %16 = unconditional_checked_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars |
| assign %16 to %3 : $*DerivedClassWithIVars |
| %18 = load %3 : $*DerivedClassWithIVars |
| strong_retain %18 : $DerivedClassWithIVars |
| strong_release %1 : $@box DerivedClassWithIVars |
| return %18 : $DerivedClassWithIVars |
| } |
| |
| |
| // <rdar://problem/20608881> DI miscompiles this testcase into a memory leak |
| struct MyStruct3 { |
| @sil_stored var c: C |
| } |
| sil @selfinit_mystruct3 : $@convention(thin) () -> @owned MyStruct3 |
| |
| // CHECK-LABEL: sil hidden @test_conditional_destroy_delegating_init |
| sil hidden @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 [[CONTROL]] : $*Builtin.Int1 |
| // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*MyStruct3 |
| |
| // CHECK-NEXT: br [[CHECK:bb[0-9]+]] |
| br bb2 |
| |
| // CHECK: [[CHECK]]: |
| bb2: |
| |
| // CHECK-NEXT: [[BIT:%[0-9]+]] = load [[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 @test_conditional_destroy_class_delegating_init |
| sil hidden @test_conditional_destroy_class_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 $MyClass3 |
| |
| %2 = alloc_stack $MyClass3 |
| %3 = mark_uninitialized [delegatingself] %2 : $*MyClass3 |
| |
| // CHECK: cond_br %0, [[SUCCESS:bb[0-9]+]], [[EXIT:bb[0-9]+]] |
| cond_br %0, bb1, bb2 |
| |
| // CHECK: [[SUCCESS]]: |
| bb1: |
| %4 = load %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 %3 : $*MyClass3 |
| |
| // CHECK: [[SET:%[0-9]+]] = integer_literal $Builtin.Int1, -1 |
| // CHECK-NEXT: store [[SET]] to [[CONTROL]] : $*Builtin.Int1 |
| // CHECK: [[NEW_SELF:%[0-9]+]] = apply {{.*}}({{.*}}) : $@convention(thin) (@owned MyClass3) -> @owned MyClass3 |
| // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*MyClass3 |
| |
| // CHECK-NEXT: br [[CHECK:bb[0-9]+]] |
| br bb2 |
| |
| // CHECK: [[CHECK]]: |
| bb2: |
| |
| // CHECK-NEXT: [[BIT:%[0-9]+]] = load [[CONTROL]] : $*Builtin.Int1 |
| // CHECK-NEXT: cond_br [[BIT]], [[INITIALIZED:bb[0-9]+]], [[UNINITIALIZED:bb[0-9]+]] |
| |
| // CHECK: [[INITIALIZED]]: |
| // CHECK-NEXT: destroy_addr [[SELF_BOX]] : $*MyClass3 |
| // CHECK-NEXT: br [[EXIT:bb[0-9]+]] |
| |
| // CHECK: [[UNINITIALIZED]]: |
| // CHECK-NEXT: [[OLD_SELF:%[0-9]+]] = load [[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]] |
| |
| // CHECK: [[EXIT]]: |
| |
| destroy_addr %3 : $*MyClass3 |
| dealloc_stack %2 : $*MyClass3 |
| %7 = tuple () |
| return %7 : $() |
| } |