Raw File
definite_init.sil
// 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
  %1 = mark_uninitialized [var] %0#1 : $*Int // expected-note {{variable defined here}}
  %4 = load %1 : $*Int                // expected-error {{variable '<unknown>' used before being initialized}}
  strong_release %0#0 : $@box Int
  %9 = return %4 : $Int
}


// CHECK-LABEL: @inout_uninit
sil @inout_uninit : $@convention(thin) () -> () {
bb0:
  %0 = alloc_box $Int
  %1 = mark_uninitialized [var] %0#1 : $*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#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
  %1 = mark_uninitialized [var] %91#1 : $*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#0 : $@box Int
  %11 = return %8 : $(Int, Int)
}


struct AddressOnlyStruct {
  var a : protocol<>
  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
  %1 = mark_uninitialized [var] %0#1 : $*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#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)
  %3 = mark_uninitialized [var] %2#1 : $*(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#0 : $@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)
  %3 = mark_uninitialized [var] %2#1 : $*(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#0 : $@box (Int, Int)
  return %23 : $(Int, Int)
}



// CHECK-LABEL: sil @copy_addr1
sil @copy_addr1 : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
  %3 = alloc_box $T
  %4 = mark_uninitialized [var] %3#1 : $*T
  copy_addr [take] %1 to [initialization] %4 : $*T
  copy_addr %4 to [initialization] %0 : $*T
  strong_release %3#0 : $@box T
  %9 = tuple ()
  return %9 : $()
}

// CHECK-LABEL: sil @copy_addr2
sil @copy_addr2 : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
  %3 = alloc_box $T
  %4 = mark_uninitialized [var] %3#1 : $*T // expected-note {{variable defined here}}
  copy_addr %4 to [initialization] %0 : $*T   // expected-error {{variable '<unknown>' used before being initialized}}
  strong_release %3#0 : $@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
  %0 = mark_uninitialized [var] %1#1 : $*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#0 : $@box Int
  mark_function_escape %0 : $*Int // expected-error {{variable '<unknown>' used by function definition before being initialized}}
  %8 = partial_apply %6(%1#0) : $@convention(thin) (@owned @box Int) -> ()  
  %9 = apply %5(%8) : $@convention(thin) (@callee_owned () -> ()) -> ()
  strong_release %1#0 : $@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
  %1 = mark_uninitialized [var] %7#1 : $*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#0 : $@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
  %c = mark_uninitialized [var] %b#1 : $*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#0 : $@box SomeClass

  %11 = tuple ()
  return %11 : $()
}


// CHECK-LABEL: sil @assign_test_addressonly
sil @assign_test_addressonly : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
  %b = alloc_box $T
  %2 = mark_uninitialized [var] %b#1 : $*T

  // CHECK: alloc_box

  // This should become an initialization of %4
  copy_addr %1 to %2 : $*T
  // CHECK-NEXT: copy_addr %1 to [initialization] %2#1 : $*T

  // This should stay an assignment of %4
  copy_addr [take] %1 to %2 : $*T
  // CHECK-NEXT: copy_addr [take] %1 to %2#1 : $*T
  
  // This is a load, and shouldn't be changed.
  copy_addr %2 to [initialization] %0 : $*T
  // CHECK-NEXT: copy_addr %2#1 to [initialization] %0 : $*T

  strong_release %b#0 : $@box T
  // CHECK-NEXT: strong_release %2#0
  %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>
  %c = mark_uninitialized [var] %b#1 : $*@sil_weak Optional<SomeClass> // expected-note {{variable defined here}}

  // Invalid load to keep the alloc_box around so we can check init semantics.
  load %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] %0#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 %0#1

  release_value %8 : $Optional<SomeClass>
  // CHECK-NEXT: release_value [[C2]]

  strong_release %b#0 : $@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
  %c = mark_uninitialized [var] %b#1 : $*@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#0 : $@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
  %c = mark_uninitialized [var] %b#1 : $*ContainsNativeObject
  %1 = load %0 : $*ContainsNativeObject
  assign %1 to %c : $*ContainsNativeObject
  
  strong_release %b#0 : $@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
  %3 = mark_uninitialized [derivedself] %1#1 : $*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#0 : $@box DerivedClassWithIVars
  return %18 : $DerivedClassWithIVars
}

sil @derived_test2 :  $@convention(method) (@owned DerivedClassWithIVars) -> @owned DerivedClassWithIVars {
bb0(%0 : $DerivedClassWithIVars):
  %1 = alloc_box $DerivedClassWithIVars
  %3 = mark_uninitialized [derivedself] %1#1 : $*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#0 : $@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) (@out MyStruct2, @thin MyStruct2.Type) -> ()

  // <rdar://problem/18089574> Protocol member in struct + delegating init miscompilation
  // CHECK-LABEL: @self_init_copyaddr
  sil @self_init_copyaddr : $@convention(thin) (@out MyStruct2, @thin MyStruct2.Type) -> () {
    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) (@out MyStruct2, @thin MyStruct2.Type) -> ()
       %8 = alloc_stack $MyStruct2

       // Make sure this copy_addr ends up being an initialization.
       apply %7(%8, %6) : $@convention(thin) (@out MyStruct2, @thin MyStruct2.Type) -> ()
  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: store %0 to [[SELFBOX]]#1
// CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]]#1
// 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]]#0
sil @test_delegating_box_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () {
bb0(%0 : $RootClassWithNontrivialStoredProperties):
  %2 = alloc_box $RootClassWithNontrivialStoredProperties
  %4 = mark_uninitialized [delegatingself] %2#1 : $*RootClassWithNontrivialStoredProperties
  store %0 to %4 : $*RootClassWithNontrivialStoredProperties
  strong_release %2#0 : $@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: store %0 to [[SELFBOX]]#1
// CHECK-NEXT: [[SELF:%[0-9]+]] = load [[SELFBOX]]#1
// 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 [[SELFBOX]]#1
// 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]]#0
sil @test_delegating_rvalue_release : $@convention(method) (@owned RootClassWithNontrivialStoredProperties) -> () {
bb0(%0 : $RootClassWithNontrivialStoredProperties):
  %2 = alloc_box $RootClassWithNontrivialStoredProperties
  %4 = mark_uninitialized [delegatingself] %2#1 : $*RootClassWithNontrivialStoredProperties
  store %0 to %4 : $*RootClassWithNontrivialStoredProperties
  %6 = load %4 : $*RootClassWithNontrivialStoredProperties
  strong_release %6 : $RootClassWithNontrivialStoredProperties
  strong_release %2#0 : $@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
  %3 = mark_uninitialized [derivedself] %1#1 : $*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#0 : $@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 : $()
}
back to top