mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
220 lines
8.5 KiB
Plaintext
220 lines
8.5 KiB
Plaintext
// RUN: %target-sil-opt -module-name moveonly_addresschecker -emit-verbose-sil -sil-move-only-checker -enable-sil-verify-all %s | %FileCheck %s
|
|
|
|
sil_stage raw
|
|
|
|
public class CopyableKlass {}
|
|
|
|
@_moveOnly
|
|
public struct NonTrivialStruct {
|
|
var k: CopyableKlass
|
|
}
|
|
|
|
sil @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
sil @use_nontrivial_struct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
sil @consume_nontrivial_struct : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
sil @consume_nontrivial_struct_addr : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_lifetime_ending_use_test_inst : $@convention(thin) () -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack $NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC:.*]]
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: [[BORROW:%.*]] = load_borrow [[STACK]]
|
|
// CHECK: apply {{%.*}}([[BORROW]])
|
|
// CHECK-NEXT: end_borrow [[BORROW]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK: } // end sil function 'non_lifetime_ending_use_test_inst'
|
|
sil [ossa] @non_lifetime_ending_use_test_inst : $@convention(thin) () -> () {
|
|
%f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%1 = alloc_stack $NonTrivialStruct, let, name "v"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
br bb1
|
|
|
|
bb1:
|
|
%3 = load [copy] %2 : $*NonTrivialStruct
|
|
%f2 = function_ref @use_nontrivial_struct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
apply %f2(%3) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
destroy_value %3 : $NonTrivialStruct
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_lifetime_ending_use_test_boundary_edge : $@convention(thin) () -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack $NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC:.*]]
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: cond_br undef, bb1, bb2
|
|
|
|
// CHECK: bb1:
|
|
// CHECK: [[BORROW:%.*]] = load_borrow [[STACK]]
|
|
// CHECK: apply {{%.*}}([[BORROW]])
|
|
// CHECK-NEXT: end_borrow [[BORROW]]
|
|
// CHECK: br bb3
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK-NEXT: destroy_addr [[STACK]]
|
|
// CHECK: } // end sil function 'non_lifetime_ending_use_test_boundary_edge'
|
|
sil [ossa] @non_lifetime_ending_use_test_boundary_edge : $@convention(thin) () -> () {
|
|
%f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%1 = alloc_stack $NonTrivialStruct, let, name "v"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = load [copy] %2 : $*NonTrivialStruct
|
|
%f2 = function_ref @use_nontrivial_struct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
apply %f2(%3) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
destroy_value %3 : $NonTrivialStruct
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @lifetime_ending_use : $@convention(thin) () -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack $NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC:.*]]
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: cond_br undef, bb1, bb2
|
|
|
|
// CHECK: bb1:
|
|
//
|
|
// TODO: We should be smarter here and redefine the debug_value to be on the
|
|
// take value and then when that value is destroyed, insert the actual
|
|
// debug_value undef.
|
|
//
|
|
// CHECK: [[TAKE:%.*]] = load [take] [[STACK]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply {{%.*}}([[TAKE]])
|
|
// CHECK: br bb3
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: destroy_addr [[STACK]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK: } // end sil function 'lifetime_ending_use'
|
|
sil [ossa] @lifetime_ending_use : $@convention(thin) () -> () {
|
|
%f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%1 = alloc_stack $NonTrivialStruct, let, name "v"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = load [copy] %2 : $*NonTrivialStruct
|
|
%f2 = function_ref @consume_nontrivial_struct : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
apply %f2(%3) : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @lifetime_ending_use_addr : $@convention(thin) () -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack $NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC:.*]]
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: cond_br undef, bb1, bb2
|
|
|
|
// CHECK: bb1:
|
|
// CHECK: apply {{%.*}}([[STACK]])
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK: br bb3
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: destroy_addr [[STACK]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK: } // end sil function 'lifetime_ending_use_addr'
|
|
sil [ossa] @lifetime_ending_use_addr : $@convention(thin) () -> () {
|
|
%f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%1 = alloc_stack $NonTrivialStruct, let, name "v"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%f2 = function_ref @consume_nontrivial_struct_addr : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
apply %f2(%2) : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dead_def_test_inst : $@convention(thin) () -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack $NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC:.*]]
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: cond_br undef, bb1, bb3
|
|
//
|
|
// CHECK: bb1:
|
|
// CHECK: apply {{%.*}}([[STACK]])
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK-NEXT: br bb2
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK: [[NEW_VAL:%.*]] = apply {{%.*}}() :
|
|
// CHECK-NEXT: store [[NEW_VAL]] to [init] [[STACK]]
|
|
// CHECK-NEXT: destroy_addr [[STACK]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK-NEXT: br bb4
|
|
//
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: destroy_addr [[STACK]]
|
|
// CHECK-NEXT: debug_value undef : $*NonTrivialStruct, let, name "v" // {{.*}}; line:[[DEBUG_LOC]]
|
|
// CHECK: br bb4
|
|
// CHECK: } // end sil function 'dead_def_test_inst'
|
|
sil [ossa] @dead_def_test_inst : $@convention(thin) () -> () {
|
|
%f = function_ref @get_nontrivial_struct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%1 = alloc_stack $NonTrivialStruct, let, name "v"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
// TODO: Fix bug where we do not propagate this use to bb0 and thus think that
|
|
// store %0 is a dead def.
|
|
%f2 = function_ref @consume_nontrivial_struct_addr : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
apply %f2(%2) : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
br bb1a
|
|
|
|
bb1a:
|
|
%0a = apply %f() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
store %0a to [init] %2 : $*NonTrivialStruct
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|