mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
618 lines
22 KiB
Plaintext
618 lines
22 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -definite-init -verify | %FileCheck %s
|
|
|
|
// This file contains tests that test diagnostics emitted for var initialization
|
|
// by DI.
|
|
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
sil @takes_Int_inout : $@convention(thin) (@inout Int) -> ()
|
|
sil @makesInt : $@convention(thin) () -> Int
|
|
|
|
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @use_before_init
|
|
sil [ossa] @use_before_init : $@convention(thin) () -> Int {
|
|
bb0:
|
|
%0 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
|
|
%0a = mark_uninitialized [var] %0 : $<τ_0_0> { var τ_0_0 } <Int> // expected-note {{variable defined here}}
|
|
%1 = project_box %0a : $<τ_0_0> { var τ_0_0 } <Int>, 0
|
|
%4 = load [trivial] %1 : $*Int // expected-error {{variable '<unknown>' used before being initialized}}
|
|
destroy_value %0a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
return %4 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @inout_uninit
|
|
sil [ossa] @inout_uninit : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
|
|
%0a = mark_uninitialized [var] %0 : $<τ_0_0> { var τ_0_0 } <Int> // expected-note {{variable defined here}}
|
|
%1 = project_box %0a : $<τ_0_0> { var τ_0_0 } <Int>, 0
|
|
|
|
%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}}
|
|
|
|
destroy_value %0a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
%t = tuple ()
|
|
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 [ossa] @used_by_inout
|
|
sil [ossa] @used_by_inout : $@convention(thin) (Int) -> (Int, Int) {
|
|
bb0(%0 : $Int):
|
|
%91 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
|
|
%91a = mark_uninitialized [var] %91 : $<τ_0_0> { var τ_0_0 } <Int>
|
|
%1 = project_box %91a : $<τ_0_0> { var τ_0_0 } <Int>, 0
|
|
store %0 to [trivial] %1 : $*Int
|
|
|
|
%3 = load [trivial] %1 : $*Int
|
|
%5 = function_ref @takes_Int_inout : $@convention(thin) (@inout Int) -> ()
|
|
%6 = apply %5(%1) : $@convention(thin) (@inout Int) -> ()
|
|
%7 = load [trivial] %1 : $*Int
|
|
%8 = tuple (%3 : $Int, %7 : $Int)
|
|
destroy_value %91a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
return %8 : $(Int, Int)
|
|
}
|
|
|
|
struct AddressOnlyStruct {
|
|
var a : Any
|
|
var b : Int
|
|
}
|
|
|
|
/// returns_generic_struct - This returns a struct by reference.
|
|
sil [ossa] @returns_generic_struct : $@convention(thin) () -> @out AddressOnlyStruct
|
|
|
|
// There should be no error in this function.
|
|
// CHECK-LABEL: sil [ossa] @call_struct_return_function
|
|
sil [ossa] @call_struct_return_function : $@convention(thin) () -> Int {
|
|
bb0:
|
|
%0 = alloc_box $<τ_0_0> { var τ_0_0 } <AddressOnlyStruct>
|
|
%0a = mark_uninitialized [var] %0 : $<τ_0_0> { var τ_0_0 } <AddressOnlyStruct>
|
|
%1 = project_box %0a : $<τ_0_0> { var τ_0_0 } <AddressOnlyStruct>, 0
|
|
|
|
%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 [trivial] %4 : $*Int
|
|
destroy_value %0a : $<τ_0_0> { var τ_0_0 } <AddressOnlyStruct>
|
|
return %5 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @tuple_elements1
|
|
sil [ossa] @tuple_elements1 : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Int)>
|
|
%2a = mark_uninitialized [var] %2 : $<τ_0_0> { var τ_0_0 } <(Int, Int)> // expected-note {{variable defined here}}
|
|
%3 = project_box %2a : $<τ_0_0> { var τ_0_0 } <(Int, Int)>, 0
|
|
%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}}
|
|
destroy_value %2a : $<τ_0_0> { var τ_0_0 } <(Int, Int)>
|
|
%99 = tuple ()
|
|
return %99 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @tuple_elements2
|
|
sil [ossa] @tuple_elements2 : $@convention(thin) (Int) -> (Int, Int) {
|
|
bb0(%0 : $Int):
|
|
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <(Int, Int)>
|
|
%2a = mark_uninitialized [var] %2 : $<τ_0_0> { var τ_0_0 } <(Int, Int)> // expected-note {{variable defined here}}
|
|
%3 = project_box %2a : $<τ_0_0> { var τ_0_0 } <(Int, Int)>, 0
|
|
%18 = tuple_element_addr %3 : $*(Int, Int), 0
|
|
store %0 to [trivial] %18 : $*Int
|
|
%20 = load [trivial] %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)
|
|
destroy_value %2a : $<τ_0_0> { var τ_0_0 } <(Int, Int)>
|
|
return %23 : $(Int, Int)
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr1
|
|
sil [ossa] @copy_addr1 : $@convention(thin) <T> (@in T) -> @out T {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
|
|
%3a = mark_uninitialized [var] %3 : $<τ_0_0> { var τ_0_0 } <T>
|
|
%4 = project_box %3a : $<τ_0_0> { var τ_0_0 } <T>, 0
|
|
copy_addr [take] %1 to [init] %4 : $*T
|
|
copy_addr %4 to [init] %0 : $*T
|
|
destroy_value %3a : $<τ_0_0> { var τ_0_0 } <T>
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @copy_addr2
|
|
sil [ossa] @copy_addr2 : $@convention(thin) <T> (@in_guaranteed T) -> @out T {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%3 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
|
|
%3a = mark_uninitialized [var] %3 : $<τ_0_0> { var τ_0_0 } <T> // expected-note {{variable defined here}}
|
|
%4 = project_box %3a : $<τ_0_0> { var τ_0_0 } <T>, 0
|
|
copy_addr %4 to [init] %0 : $*T // expected-error {{variable '<unknown>' used before being initialized}}
|
|
destroy_value %3a : $<τ_0_0> { var τ_0_0 } <T>
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
sil [ossa] @takes_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
|
|
sil [ossa] @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
|
|
|
|
// CHECK-LABEL: sil [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @closure_test
|
|
sil [ossa] @closure_test : $@convention(thin) () -> () {
|
|
bb0:
|
|
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
|
|
%1a = mark_uninitialized [var] %1 : $<τ_0_0> { var τ_0_0 } <Int> // expected-note {{variable defined here}}
|
|
%0 = project_box %1a : $<τ_0_0> { var τ_0_0 } <Int>, 0
|
|
|
|
%5 = function_ref @takes_closure : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
|
|
%6 = function_ref @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
|
|
%1copy = copy_value %1a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
mark_function_escape %0 : $*Int // expected-error {{variable '<unknown>' used by function definition before being initialized}}
|
|
%8 = partial_apply %6(%1copy) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
|
|
%9 = apply %5(%8) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
|
|
destroy_value %1a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
|
|
class SomeClass {}
|
|
|
|
sil [ossa] @getSomeClass : $@convention(thin) () -> @owned SomeClass
|
|
sil [ossa] @getSomeOptionalClass : $@convention(thin) () -> @owned Optional<SomeClass>
|
|
|
|
|
|
// CHECK-LABEL: sil [ossa] @assign_test_trivial
|
|
sil [ossa] @assign_test_trivial : $@convention(thin) (Int) -> Int {
|
|
bb0(%0 : $Int):
|
|
%7 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
|
|
%7a = mark_uninitialized [var] %7 : $<τ_0_0> { var τ_0_0 } <Int>
|
|
%1 = project_box %7a : $<τ_0_0> { var τ_0_0 } <Int>, 0
|
|
|
|
// 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 [trivial] %1 : $*Int
|
|
destroy_value %7a : $<τ_0_0> { var τ_0_0 } <Int>
|
|
|
|
return %2 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @assign_test_nontrivial
|
|
sil [ossa] @assign_test_nontrivial : $@convention(thin) () -> () {
|
|
bb0:
|
|
// Assignments of nontrivial types. The first becomes an initialize (i.e.,
|
|
// lone store), the second becomes a reassignment (retain/release dance).
|
|
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
%ba = mark_uninitialized [var] %b : $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
%c = project_box %ba : $<τ_0_0> { var τ_0_0 } <SomeClass>, 0
|
|
|
|
%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: assign [[C1]] to [init]
|
|
|
|
%8 = apply %f() : $@convention(thin) () -> @owned SomeClass
|
|
// CHECK-NEXT: [[C2:%[0-9]+]] = apply
|
|
|
|
assign %8 to %c : $*SomeClass
|
|
// CHECK-NEXT: assign [[C2]] to [reassign]
|
|
|
|
destroy_addr %c : $*SomeClass
|
|
// CHECK-NEXT: destroy_addr
|
|
dealloc_box %ba : $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @assign_test_addressonly
|
|
sil [ossa] @assign_test_addressonly : $@convention(thin) <T> (@in T) -> @out T {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <T>
|
|
%ba = mark_uninitialized [var] %b : $<τ_0_0> { var τ_0_0 } <T>
|
|
%2 = project_box %ba : $<τ_0_0> { var τ_0_0 } <T>, 0
|
|
|
|
// 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 [init] [[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 [init] %0 : $*T
|
|
// CHECK-NEXT: copy_addr [[PB]] to [init] %0 : $*T
|
|
|
|
destroy_value %ba : $<τ_0_0> { var τ_0_0 } <T>
|
|
// CHECK-NEXT: destroy_value %3
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @assign_test_weak
|
|
sil [ossa] @assign_test_weak : $@convention(thin) () -> () {
|
|
bb0:
|
|
// Assignments of weak pointer. The first becomes an initialize, and the
|
|
// second becomes an assignment.
|
|
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>
|
|
%ba = mark_uninitialized [var] %b : $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>
|
|
%c = project_box %ba : $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>, 0
|
|
|
|
%f = function_ref @getSomeOptionalClass : $@convention(thin) () -> @owned Optional<SomeClass>
|
|
|
|
%4 = apply %f() : $@convention(thin) () -> @owned 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 [init] %2
|
|
|
|
destroy_value %4 : $Optional<SomeClass>
|
|
// CHECK-NEXT: destroy_value [[C1]]
|
|
|
|
%8 = apply %f() : $@convention(thin) () -> @owned Optional<SomeClass>
|
|
// CHECK-NEXT: [[C2:%[0-9]+]] = apply
|
|
|
|
store_weak %8 to %c : $*@sil_weak Optional<SomeClass>
|
|
// CHECK-NEXT: store_weak [[C2]] to %2
|
|
|
|
destroy_value %8 : $Optional<SomeClass>
|
|
// CHECK-NEXT: destroy_value [[C2]]
|
|
|
|
destroy_value %ba : $<τ_0_0> { var τ_0_0 } <@sil_weak Optional<SomeClass>>
|
|
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @assign_test_unowned
|
|
sil [ossa] @assign_test_unowned : $@convention(thin) () -> () {
|
|
bb0:
|
|
// Assignments of unowned pointer. The first becomes an initialize, and the
|
|
// second becomes a reassignment.
|
|
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <@sil_unowned SomeClass>
|
|
%ba = mark_uninitialized [var] %b : $<τ_0_0> { var τ_0_0 } <@sil_unowned SomeClass>
|
|
%c = project_box %ba : $<τ_0_0> { var τ_0_0 } <@sil_unowned SomeClass>, 0
|
|
|
|
%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]]
|
|
%5a = copy_value %5 : $@sil_unowned SomeClass
|
|
// CHECK-NEXT: [[C1u_copy:%.*]] = copy_value [[C1u]]
|
|
assign %5a to %c : $*@sil_unowned SomeClass
|
|
// CHECK-NEXT: assign [[C1u_copy]] to [init]
|
|
destroy_value %4 : $SomeClass
|
|
// CHECK-NEXT: destroy_value [[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]]
|
|
|
|
%9a = copy_value %9 : $@sil_unowned SomeClass
|
|
// CHECK-NEXT: [[C2u_copy:%.*]] = copy_value [[C2u]]
|
|
|
|
assign %9a to %c : $*@sil_unowned SomeClass
|
|
// CHECK-NEXT: assign [[C2u_copy]] to [reassign]
|
|
|
|
destroy_value %8 : $SomeClass
|
|
// CHECK-NEXT: destroy_value [[C2]]
|
|
|
|
destroy_addr %c : $*@sil_unowned SomeClass
|
|
dealloc_box %ba : $<τ_0_0> { var τ_0_0 } <@sil_unowned SomeClass>
|
|
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
struct ContainsNativeObject {
|
|
var x : Int
|
|
var y : Builtin.NativeObject
|
|
}
|
|
|
|
sil [ossa] @test_struct : $@convention(thin) (@inout ContainsNativeObject) -> () {
|
|
bb0(%0 : $*ContainsNativeObject):
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <ContainsNativeObject>
|
|
%ba = mark_uninitialized [var] %b : $<τ_0_0> { var τ_0_0 } <ContainsNativeObject>
|
|
%c = project_box %ba : $<τ_0_0> { var τ_0_0 } <ContainsNativeObject>, 0
|
|
%1 = load [copy] %0 : $*ContainsNativeObject
|
|
assign %1 to %c : $*ContainsNativeObject
|
|
|
|
destroy_value %ba : $<τ_0_0> { var τ_0_0 } <ContainsNativeObject>
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_box_assign_trivial
|
|
// CHECK-NOT: load
|
|
// CHECK: assign
|
|
// CHECK: return
|
|
sil [ossa] @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 [ossa] @non_box_assign
|
|
// CHECK-NOT: load
|
|
// CHECK: assign
|
|
// CHECK: return
|
|
sil [ossa] @non_box_assign : $@convention(thin) (@inout SomeClass, @owned SomeClass) -> () {
|
|
bb0(%0 : $*SomeClass, %1 : @owned $SomeClass):
|
|
assign %1 to %0 : $*SomeClass
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
sil_global @int_global : $Int
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_tlc
|
|
// CHECK: mark_uninitialized
|
|
// CHECK: return
|
|
sil [ossa] @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 [ossa] @init_xy_struct : $@convention(thin) () -> XYStruct
|
|
|
|
protocol P {}
|
|
class C : P {}
|
|
sil [ossa] @use : $@convention(thin) (@in P) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @release_not_constructed
|
|
sil [ossa] @release_not_constructed : $@convention(thin) () -> () {
|
|
bb0: // CHECK: bb0:
|
|
// CHECK-NEXT: alloc_stack
|
|
%3 = alloc_stack $SomeClass
|
|
// CHECK-NEXT: mark_uninitialized
|
|
%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 [ossa] @release_some_constructed
|
|
sil [ossa] @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 [init] %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 [ossa] @init_existential_with_class
|
|
sil [ossa] @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 [init] %3 : $*C
|
|
copy_addr %a to [init] %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 [ossa] @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 [ossa] @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 [trivial] [[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 [trivial] [[CONTROL]] : $*Builtin.Int1
|
|
%f = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass
|
|
%6 = apply %f() : $@convention(thin) () -> @owned SomeClass
|
|
assign %6 to %3 : $*SomeClass
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %3 : $*SomeClass
|
|
dealloc_stack %2 : $*SomeClass
|
|
%14 = tuple ()
|
|
return %14 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @conditionalInitOrAssign
|
|
sil [ossa] @conditionalInitOrAssign : $@convention(thin) (Builtin.Int1) -> () {
|
|
bb0(%0 : $Builtin.Int1):
|
|
// CHECK: [[CONTROL:%[0-9]+]] = alloc_stack $Builtin.Int1
|
|
// CHECK: [[CLASSVAL:%[0-9]+]] = alloc_stack [dynamic_lifetime] $SomeClass
|
|
// CHECK: [[MU:%[0-9]+]] = mark_uninitialized [var] [[CLASSVAL]]
|
|
// 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 will become 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 [trivial] [[CONTROL]]
|
|
// CHECK: assign [[V1]] to [init] [[MU]]
|
|
assign %12 to %6 : $*SomeClass // id: %13
|
|
br bb3 // id: %14
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
// 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 a reassign depending on whether %0 is
|
|
// true or not. This gets expanded out to a conditional destroy of the value.
|
|
// CHECK: load [trivial] [[CONTROL]]
|
|
// CHECK: cond_br
|
|
// CHECK: bb4:
|
|
// CHECK: destroy_addr [[MU]]
|
|
// CHECK: br bb6
|
|
// CHECK: bb6:
|
|
// CHECK: assign [[V2]] to [init] [[MU]]
|
|
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
|
|
}
|
|
// CHECK: } // end sil function 'conditionalInitOrAssign'
|
|
|
|
// Make sure that we use a dealloc_box on the path where we do not assign.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @conditionalInitOrAssignAllocBox : $@convention(thin) () -> () {
|
|
// CHECK: bb0:
|
|
// CHECK: [[BOX:%.*]] = alloc_box
|
|
// CHECK: [[MU:%.*]] = mark_uninitialized [var] [[BOX]]
|
|
//
|
|
// CHECK: bb1:
|
|
// CHECK: destroy_value [[MU]]
|
|
// CHECK: br bb3
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK: dealloc_box [[MU]]
|
|
// CHECK: br bb3
|
|
//
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'conditionalInitOrAssignAllocBox'
|
|
sil [ossa] @conditionalInitOrAssignAllocBox : $@convention(thin) () -> () {
|
|
bb0:
|
|
%box = alloc_box $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
%5 = mark_uninitialized [var] %box : $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
%7 = project_box %5 : $<τ_0_0> { var τ_0_0 } <SomeClass>, 0
|
|
%2 = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass
|
|
cond_br undef, bb1, bb2
|
|
|
|
// Value is stored into box and then destroyed.
|
|
bb1:
|
|
%12 = apply %2() : $@convention(thin) () -> @owned SomeClass
|
|
assign %12 to %7 : $*SomeClass
|
|
destroy_value %5 : $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
br bb3
|
|
|
|
bb2:
|
|
dealloc_box %5 : $<τ_0_0> { var τ_0_0 } <SomeClass>
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// LLDB uses mark_uninitialized [var] in an unsupported way via an address to
|
|
// pointer. LLDB shouldn't do this, but until it is removed and validated we
|
|
// need a test for this.
|
|
// CHECK-LABEL: sil [ossa] @lldb_unsupported_markuninitialized_testcase : $@convention(thin) (UnsafeMutablePointer<Any>) -> () {
|
|
// CHECK: mark_uninitialized [var]
|
|
// CHECK: } // end sil function 'lldb_unsupported_markuninitialized_testcase'
|
|
sil [ossa] @lldb_unsupported_markuninitialized_testcase : $@convention(thin) (UnsafeMutablePointer<Any>) -> () {
|
|
bb0(%0 : $UnsafeMutablePointer<Any>):
|
|
%2 = struct_extract %0 : $UnsafeMutablePointer<Any>, #UnsafeMutablePointer._rawValue
|
|
%3 = integer_literal $Builtin.Int64, 8
|
|
%4 = index_raw_pointer %2 : $Builtin.RawPointer, %3 : $Builtin.Int64
|
|
%5 = pointer_to_address %4 : $Builtin.RawPointer to [strict] $*Builtin.RawPointer
|
|
%6 = load [trivial] %5 : $*Builtin.RawPointer
|
|
%7 = pointer_to_address %6 : $Builtin.RawPointer to [strict] $*Error
|
|
%8 = mark_uninitialized [var] %7 : $*Error
|
|
%9 = struct_extract %0 : $UnsafeMutablePointer<Any>, #UnsafeMutablePointer._rawValue
|
|
%10 = integer_literal $Builtin.Int64, 0
|
|
%11 = index_raw_pointer %9 : $Builtin.RawPointer, %10 : $Builtin.Int64
|
|
%12 = pointer_to_address %11 : $Builtin.RawPointer to [strict] $*Builtin.RawPointer
|
|
%13 = load [trivial] %12 : $*Builtin.RawPointer
|
|
%14 = pointer_to_address %13 : $Builtin.RawPointer to [strict] $*@thick SomeClass.Type
|
|
%15 = mark_uninitialized [var] %14 : $*@thick SomeClass.Type
|
|
%16 = metatype $@thick SomeClass.Type
|
|
%17 = begin_access [modify] [unsafe] %15 : $*@thick SomeClass.Type
|
|
assign %16 to %17 : $*@thick SomeClass.Type
|
|
end_access %17 : $*@thick SomeClass.Type
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|