Files
swift-mirror/test/SIL/OwnershipVerifier/borrow_validate.sil
Erik Eckstein e14c1d1f62 SIL, Optimizer: update and handle borrowed-from instructions
Compute, update and handle borrowed-from instruction in various utilities and passes.
Also, used borrowed-from to simplify `gatherBorrowIntroducers` and `gatherEnclosingValues`.
Replace those utilities by `Value.getBorrowIntroducers` and `Value.getEnclosingValues`, which return a lazily computed Sequence of borrowed/enclosing values.
2024-04-10 13:38:10 +02:00

811 lines
31 KiB
Plaintext

// RUN: %target-sil-opt -disable-swift-verification -sil-ownership-verifier-enable-testing -ownership-verifier-textual-error-dumper -enable-sil-verify-all=0 %s -o /dev/null 2>&1 | %FileCheck %s
// REQUIRES: asserts
import Builtin
//////////////////
// Declarations //
//////////////////
class SuperKlass {}
class Klass : SuperKlass {}
struct WrapperStruct {
var cls : Klass
}
enum FakeOptional<T> {
case none
case some(T)
}
sil shared [noinline] @blackhole_spl : $@convention(thin) (@guaranteed WrapperStruct) -> () {
bb0(%0 : $WrapperStruct):
%1 = tuple ()
return %1 : $()
}
// owned val dominates the end_borrow
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrowed_owned_val_dominates_incorrect'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %1 = copy_value %0 : $WrapperStruct
// CHECK: Consuming User: destroy_value %1 : $WrapperStruct
// CHECK: Non Consuming User: end_borrow %4 : $WrapperStruct
// CHECK: Block: bb1
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrowed_owned_val_dominates_incorrect'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'borrowed_owned_val_dominates_incorrect'
sil [ossa] @borrowed_owned_val_dominates_correct : $@convention(thin) (@guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct):
%1 = copy_value %0 : $WrapperStruct
%borrow = begin_borrow %1 : $WrapperStruct
br bb1(%borrow : $WrapperStruct)
bb1(%2 : @guaranteed $WrapperStruct):
%func = function_ref @blackhole_spl : $@convention(thin) (@guaranteed WrapperStruct) -> ()
%call1 = apply %func(%2) : $@convention(thin) (@guaranteed WrapperStruct) -> ()
end_borrow %2 : $WrapperStruct
destroy_value %1 : $WrapperStruct
%res = tuple ()
return %res : $()
}
// CHECK-NOT: Function: 'borrowed_owned_val_dominates_incorrect'
sil [ossa] @borrowed_owned_val_dominates_incorrect : $@convention(thin) (@guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct):
%1 = copy_value %0 : $WrapperStruct
%borrow = begin_borrow %1 : $WrapperStruct
br bb1(%borrow : $WrapperStruct)
bb1(%2 : @guaranteed $WrapperStruct):
%func = function_ref @blackhole_spl : $@convention(thin) (@guaranteed WrapperStruct) -> ()
%call1 = apply %func(%2) : $@convention(thin) (@guaranteed WrapperStruct) -> ()
destroy_value %1 : $WrapperStruct
end_borrow %2 : $WrapperStruct
%res = tuple ()
return %res : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrowed_owned_val_dominates_and_is_phi_incorrect'
// CHECK: Function: 'borrowed_owned_val_dominates_and_is_phi_incorrect'
// CHECK: Found non consuming use outside of the lifetime being verified.
// CHECK: Value: %1 = copy_value %0 : $WrapperStruct
// CHECK: User: end_borrow %2 : $WrapperStruct
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrowed_owned_val_dominates_and_is_phi_incorrect'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'borrowed_owned_val_dominates_and_is_phi_incorrect'
sil [ossa] @borrowed_owned_val_dominates_and_is_phi_incorrect : $@convention(thin) (@guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct):
%1 = copy_value %0 : $WrapperStruct
%borrow = begin_borrow %1 : $WrapperStruct
br bb1(%1 : $WrapperStruct)
bb1(%newowned : @owned $WrapperStruct):
%func = function_ref @blackhole_spl : $@convention(thin) (@guaranteed WrapperStruct) -> ()
%call1 = apply %func(%borrow) : $@convention(thin) (@guaranteed WrapperStruct) -> ()
end_borrow %borrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
%res = tuple ()
return %res : $()
}
// borrowed operand dominates the end_borrow
// CHECK-NOT: Function: 'borrowed_owned_val_dominates_diamond_correct'
sil [ossa] @borrowed_owned_val_dominates_diamond_correct : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
cond_br undef, bb1, bb2
bb1:
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct)
bb2:
%borrow1a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
end_borrow %borrow0 : $WrapperStruct
destroy_value %copy0 : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect1'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %2 = copy_value %0 : $WrapperStruct
// CHECK: Consuming User: destroy_value %2 : $WrapperStruct
// CHECK: Non Consuming User: end_borrow %3 : $WrapperStruct
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect1'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect1'
sil [ossa] @borrowed_owned_val_dominates_diamond_incorrect1 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
cond_br undef, bb1, bb2
bb1:
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct)
bb2:
%borrow1a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
destroy_value %copy0 : $WrapperStruct
end_borrow %borrow0 : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect2'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %2 = copy_value %0 : $WrapperStruct
// CHECK: Consuming User: destroy_value %2 : $WrapperStruct
// CHECK: Non Consuming User: end_borrow %3 : $WrapperStruct
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect2'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'borrowed_owned_val_dominates_diamond_incorrect2'
sil [ossa] @borrowed_owned_val_dominates_diamond_incorrect2 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
cond_br undef, bb1, bb2
bb1:
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct)
bb2:
%borrow1a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct):
destroy_value %copy0 : $WrapperStruct
end_borrow %newborrowi : $WrapperStruct
end_borrow %borrow0 : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// guaranteed val borrowed
// CHECK-NOT: Function: 'borrowed_guaranteed_val_dominates'
sil [ossa] @borrowed_guaranteed_val_dominates : $@convention(thin) (@guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct):
%borrow = begin_borrow %0 : $WrapperStruct
br bb1(%borrow : $WrapperStruct)
bb1(%2 : @guaranteed $WrapperStruct):
%func = function_ref @blackhole_spl : $@convention(thin) (@guaranteed WrapperStruct) -> ()
%call1 = apply %func(%2) : $@convention(thin) (@guaranteed WrapperStruct) -> ()
end_borrow %2 : $WrapperStruct
%res = tuple ()
return %res : $()
}
// owned val does not dominate the end_borrow
// CHECK-NOT: Function: 'borrowed_owned_val_not_dominate_correct'
sil [ossa] @borrowed_owned_val_not_dominate_correct : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
end_borrow %newborrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrowed_owned_val_not_dominate_incorrect'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %10 = argument of bb3 : $WrapperStruct
// CHECK: Consuming User: destroy_value %10 : $WrapperStruct
// CHECK: Non Consuming User: end_borrow %9 : $WrapperStruct
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrowed_owned_val_not_dominate_incorrect'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'borrowed_owned_val_not_dominate_incorrect'
sil [ossa] @borrowed_owned_val_not_dominate_incorrect : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
destroy_value %newowned : $WrapperStruct
end_borrow %newborrow : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrow_lifetime_discrepency'
sil [ossa] @borrow_lifetime_discrepency : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
cond_br undef, bb1, bb2
bb1:
%borrow0 = begin_borrow %copy0 : $WrapperStruct
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct, %borrow0 : $WrapperStruct)
bb2:
%borrow1 = begin_borrow %copy0 : $WrapperStruct
%borrow1a = begin_borrow %borrow1 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct, %borrow1 : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct, %newborrowo : @guaranteed $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
end_borrow %newborrowo : $WrapperStruct
destroy_value %copy0 : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrow_lifetime_discrepency_2'
sil [ossa] @borrow_lifetime_discrepency_2 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct, %borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %0 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
%borrow1a = begin_borrow %borrow1 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct, %borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct, %newborrowo : @guaranteed $WrapperStruct, %base : @owned $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
end_borrow %newborrowo : $WrapperStruct
destroy_value %base : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrow_lifetime_discrepency_incorrect_1'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %13 = argument of bb3 : $WrapperStruct // user: %15
// CHECK: Consuming User: destroy_value %13 : $WrapperStruct // id: %15
// CHECK: Non Consuming User: end_borrow %12 : $WrapperStruct // id: %16
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrow_lifetime_discrepency_incorrect_1'
// CHECK-NOT: Error#: 1.
sil [ossa] @borrow_lifetime_discrepency_incorrect_1 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct, %borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %0 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
%borrow1a = begin_borrow %borrow1 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct, %borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct, %newborrowo : @guaranteed $WrapperStruct, %base : @owned $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
destroy_value %base : $WrapperStruct
end_borrow %newborrowo : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'borrow_lifetime_discrepency_incorrect_2'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %12 = argument of bb3 : $WrapperStruct // user: %14
// CHECK: Consuming User: end_borrow %12 : $WrapperStruct // id: %14
// CHECK: Non Consuming User: end_borrow %11 : $WrapperStruct // id: %15
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'borrow_lifetime_discrepency_incorrect_2'
// CHECK-NOT: Error#: 1.
sil [ossa] @borrow_lifetime_discrepency_incorrect_2 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
%borrow0a = begin_borrow %borrow0 : $WrapperStruct
br bb3(%borrow0a : $WrapperStruct, %borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %0 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
%borrow1a = begin_borrow %borrow1 : $WrapperStruct
br bb3(%borrow1a : $WrapperStruct, %borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrowi : @guaranteed $WrapperStruct, %newborrowo : @guaranteed $WrapperStruct, %base : @owned $WrapperStruct):
end_borrow %newborrowo : $WrapperStruct
end_borrow %newborrowi : $WrapperStruct
destroy_value %base : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrow_lifetime_nodiscrepency'
sil [ossa] @borrow_lifetime_nodiscrepency : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%borrow0 = begin_borrow %0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct)
bb2:
%borrow1 = begin_borrow %1 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct):
end_borrow %newborrow : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrowed_owned_val_dominates_one_path'
sil [ossa] @borrowed_owned_val_dominates_one_path : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy1 = copy_value %1 : $WrapperStruct
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy2 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy2 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
end_borrow %newborrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
destroy_value %copy1 : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrowed_owned_val_dominates_one_path_loop'
sil [ossa] @borrowed_owned_val_dominates_one_path_loop : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1a = begin_borrow %0 : $Builtin.NativeObject
%1b = copy_value %0 : $Builtin.NativeObject
br bb1(%1a : $Builtin.NativeObject, %1b : $Builtin.NativeObject)
bb1(%2a : @guaranteed $Builtin.NativeObject, %2b : @owned $Builtin.NativeObject):
cond_br undef, bb2, bb3
bb2:
%3 = copy_value %2a : $Builtin.NativeObject
%3a = begin_borrow %3 : $Builtin.NativeObject
end_borrow %2a : $Builtin.NativeObject
destroy_value %2b : $Builtin.NativeObject
br bb1(%3a : $Builtin.NativeObject, %3 : $Builtin.NativeObject)
bb3:
end_borrow %2a : $Builtin.NativeObject
destroy_value %2b : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-NOT: Function: 'not_all_incoming_reborrows_have_owned_value'
sil [ossa] @not_all_incoming_reborrows_have_owned_value : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy2 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %0 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy2 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
end_borrow %newborrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// test to show we need to insert reborrow's of reborrows's into the worklist during validation of reborrows
// CHECK-NOT: Function: 'chain_of_reborrows1'
sil [ossa] @chain_of_reborrows1 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy2 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %0 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy2 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
br bb4(%newborrow : $WrapperStruct, %newowned : $WrapperStruct)
bb4(%newnewborrow : @guaranteed $WrapperStruct, %newnewowned : @owned $WrapperStruct):
end_borrow %newnewborrow : $WrapperStruct
destroy_value %newnewowned : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'chain_of_reborrows2'
sil [ossa] @chain_of_reborrows2 : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy1 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %copy1 : $WrapperStruct
br bb3(%borrow1 : $WrapperStruct, %copy1 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
cond_br undef, bb4, bb5
bb4:
%borrow2 = begin_borrow %newborrow : $WrapperStruct
br bb6(%borrow2 : $WrapperStruct)
bb5:
%borrow3 = begin_borrow %newborrow : $WrapperStruct
br bb6(%borrow3 : $WrapperStruct)
bb6(%newnewborrow : @guaranteed $WrapperStruct):
end_borrow %newnewborrow : $WrapperStruct
end_borrow %newborrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrowed_owned_val_not_a_phiarg'
// test to show that we cannot assume the owned val is dominating if it is not passed an owned phi arg in a branch where the reborrow happens
sil [ossa] @borrowed_owned_val_not_a_phiarg : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb2
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb2:
%copy2 = copy_value %1 : $WrapperStruct
%borrow1 = begin_borrow %0 : $WrapperStruct
br bb2a(%borrow1 : $WrapperStruct)
bb2a(%borrow1a : @guaranteed $WrapperStruct):
br bb3(%borrow1a : $WrapperStruct, %copy2 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
end_borrow %newborrow : $WrapperStruct
destroy_value %newowned : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'infinite_loop'
sil [ossa] @infinite_loop : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
cond_br undef, bb1, bb4
bb1:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0 = begin_borrow %copy0 : $WrapperStruct
br bb3(%borrow0 : $WrapperStruct, %copy0 : $WrapperStruct)
bb3(%newborrow : @guaranteed $WrapperStruct, %newowned : @owned $WrapperStruct):
br bb3(%newborrow : $WrapperStruct, %newowned : $WrapperStruct)
bb4:
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'diamond_within_loop'
sil [ossa] @diamond_within_loop : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
br bb1
bb1:
cond_br undef, bb2, bb5
bb2:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0a = begin_borrow %copy0 : $WrapperStruct
br bb4(%borrow0a : $WrapperStruct, %copy0 : $WrapperStruct)
bb3:
%copy1 = copy_value %1 : $WrapperStruct
%borrow1a = begin_borrow %copy1 : $WrapperStruct
br bb4(%borrow1a : $WrapperStruct, %copy1 : $WrapperStruct)
bb4(%newborrowi : @guaranteed $WrapperStruct, %copy : @owned $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
destroy_value %copy : $WrapperStruct
br bb1
bb5:
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'chain_diamond_within_loop'
sil [ossa] @chain_diamond_within_loop : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
br bb1
bb1:
cond_br undef, bb2, bbret
bb2:
cond_br undef, bb3, bb4
bb3:
%copy0 = copy_value %0 : $WrapperStruct
%borrow0a = begin_borrow %copy0 : $WrapperStruct
br bb5(%borrow0a : $WrapperStruct, %copy0 : $WrapperStruct)
bb4:
%copy1 = copy_value %1 : $WrapperStruct
%borrow1a = begin_borrow %copy1 : $WrapperStruct
br bb5(%borrow1a : $WrapperStruct, %copy1 : $WrapperStruct)
bb5(%newborrowo : @guaranteed $WrapperStruct, %copy : @owned $WrapperStruct):
cond_br undef, bb6, bb7
bb6:
%borrowi1 = begin_borrow %newborrowo : $WrapperStruct
br bb8(%borrowi1 : $WrapperStruct)
bb7:
%borrowi2 = begin_borrow %newborrowo : $WrapperStruct
br bb8(%borrowi2 : $WrapperStruct)
bb8(%newborrowi : @guaranteed $WrapperStruct):
end_borrow %newborrowi : $WrapperStruct
end_borrow %newborrowo : $WrapperStruct
destroy_value %copy : $WrapperStruct
br bb1
bbret:
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'reborrow_at_loop_head'
sil [ossa] @reborrow_at_loop_head : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
%borrow0a = begin_borrow %copy0 : $WrapperStruct
br bb1(%borrow0a : $WrapperStruct, %copy0 : $WrapperStruct)
bb1(%borrow : @guaranteed $WrapperStruct, %copy : @owned $WrapperStruct):
cond_br undef, bb2, bb3
bb2:
%copyagain = copy_value %copy : $WrapperStruct
%borrowagain = begin_borrow %copyagain : $WrapperStruct
end_borrow %borrow : $WrapperStruct
destroy_value %copy : $WrapperStruct
br bb1(%borrowagain : $WrapperStruct, %copyagain : $WrapperStruct)
bb3:
end_borrow %borrow : $WrapperStruct
destroy_value %copy : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'reborrow_at_loop_head_incorrect'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %6 = argument of bb1 : $WrapperStruct
// CHECK: Consuming User: destroy_value %6 : $WrapperStruct
// CHECK: Non Consuming User: end_borrow %5 : $WrapperStruct
// CHECK: Block: bb2
// CHECK-LABEL: Error#: 0. End Error in Function: 'reborrow_at_loop_head_incorrect'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'reborrow_at_loop_head_incorrect'
sil [ossa] @reborrow_at_loop_head_incorrect : $@convention(thin) (@guaranteed WrapperStruct, @guaranteed WrapperStruct) -> () {
bb0(%0 : @guaranteed $WrapperStruct, %1 : @guaranteed $WrapperStruct):
%copy0 = copy_value %0 : $WrapperStruct
%borrow0a = begin_borrow %copy0 : $WrapperStruct
br bb1(%borrow0a : $WrapperStruct, %copy0 : $WrapperStruct)
bb1(%borrow : @guaranteed $WrapperStruct, %copy : @owned $WrapperStruct):
cond_br undef, bb2, bb3
bb2:
%copyagain = copy_value %copy : $WrapperStruct
%borrowagain = begin_borrow %copyagain : $WrapperStruct
destroy_value %copy : $WrapperStruct
end_borrow %borrow : $WrapperStruct
br bb1(%borrowagain : $WrapperStruct, %copyagain : $WrapperStruct)
bb3:
end_borrow %borrow : $WrapperStruct
destroy_value %copy : $WrapperStruct
%ret = tuple ()
return %ret : $()
}
// CHECK-NOT: Function: 'borrow_unreachable_correct'
sil [ossa] @borrow_unreachable_correct : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
end_borrow %1 : $Builtin.NativeObject
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
bb2:
unreachable
}
// CHECK-NOT: Function: 'test_borrow_checked_cast_switch_enum_control_flow'
sil [ossa] @test_borrow_checked_cast_switch_enum_control_flow : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
checked_cast_br Klass in %0 : $Klass to SuperKlass, bb1, bb2
bb1(%1 : @owned $SuperKlass):
destroy_value %1 : $SuperKlass
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%borrownone = begin_borrow %none : $FakeOptional<Klass>
br bb3(%borrownone : $FakeOptional<Klass>, %none : $FakeOptional<Klass>)
bb2(%2 : @owned $Klass):
%some = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %2 : $Klass
%borrowsome = begin_borrow %some : $FakeOptional<Klass>
br bb3(%borrowsome : $FakeOptional<Klass>, %some : $FakeOptional<Klass>)
bb3(%borrow : @guaranteed $FakeOptional<Klass>, %mKlass : @owned $FakeOptional<Klass>):
end_borrow %borrow : $FakeOptional<Klass>
destroy_value %mKlass : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'test_borrow_checked_cast_switch_enum_control_flow_incorrect'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %12 = argument of bb3 : $FakeOptional<Klass>
// CHECK: Consuming User: destroy_value %12 : $FakeOptional<Klass>
// CHECK: Non Consuming User: end_borrow %11 : $FakeOptional<Klass>
// CHECK: Block: bb3
// CHECK-LABEL: Error#: 0. End Error in Function: 'test_borrow_checked_cast_switch_enum_control_flow_incorrect'
// CHECK-NOT: Error#: {{[0-9][0-9]*}}. End Error in Function: 'test_borrow_checked_cast_switch_enum_control_flow_incorrect'
sil [ossa] @test_borrow_checked_cast_switch_enum_control_flow_incorrect : $@convention(thin) (@owned Klass) -> () {
bb0(%0 : @owned $Klass):
checked_cast_br Klass in %0 : $Klass to SuperKlass, bb1, bb2
bb1(%1 : @owned $SuperKlass):
destroy_value %1 : $SuperKlass
%none = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
%borrownone = begin_borrow %none : $FakeOptional<Klass>
br bb3(%borrownone : $FakeOptional<Klass>, %none : $FakeOptional<Klass>)
bb2(%2 : @owned $Klass):
%some = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %2 : $Klass
%borrowsome = begin_borrow %some : $FakeOptional<Klass>
br bb3(%borrowsome : $FakeOptional<Klass>, %some : $FakeOptional<Klass>)
bb3(%borrow : @guaranteed $FakeOptional<Klass>, %mKlass : @owned $FakeOptional<Klass>):
destroy_value %mKlass : $FakeOptional<Klass>
end_borrow %borrow : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// Test copying a borrowed value after it has been reborrowed in a different block.
//
// CHECK-LABEL: Error#: 0. Begin Error in Function: 'test_copy_borrow_after_reborrow'
// CHECK: Found outside of lifetime use!
// CHECK: Value: %1 = begin_borrow %0 : $Klass
// CHECK: User: %6 = copy_value %1 : $Klass
// CHECK: Block: bb3
// CHECK-LABEL: End Error in Function: 'test_copy_borrow_after_reborrow'
sil [ossa] @test_copy_borrow_after_reborrow : $@convention(thin) () -> () {
bb0:
%alloc = alloc_ref $Klass
%borrow = begin_borrow %alloc : $Klass
cond_br undef, bb1, bb2
bb1:
br bb3(%borrow: $Klass)
bb2:
br bb3(%borrow: $Klass)
bb3(%borrowphi : @guaranteed $Klass):
%innercopy = copy_value %borrow : $Klass
end_borrow %borrowphi : $Klass
%outercopy = copy_value %innercopy : $Klass
destroy_value %innercopy : $Klass
destroy_value %outercopy : $Klass
destroy_value %alloc : $Klass
%99 = tuple ()
return %99 : $()
}
// CHECK: Error#: 0. Begin Error in Function: 'test_scope_end_order1'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %3 = begin_borrow %1 : $Klass // users: %5, %4
// CHECK: Consuming User: end_borrow %3 : $Klass // id: %5
// CHECK: Non Consuming User: end_borrow %4 : $*Klass // id: %6
// CHECK: Block: bb0
// CHECK: Error#: 0. End Error in Function: 'test_scope_end_order1'
sil [ossa] @test_scope_end_order1 : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
%copy = copy_value %0 : $Klass
%stk = alloc_stack $Klass
%borrow = begin_borrow %copy : $Klass
%ra = store_borrow %borrow to %stk : $*Klass
end_borrow %borrow : $Klass
end_borrow %ra : $*Klass
destroy_value %copy : $Klass
dealloc_stack %stk : $*Klass
%1 = tuple ()
return %1 : $()
}
// CHECK: Error#: 0. Begin Error in Function: 'test_scope_end_order2'
// CHECK: Found outside of lifetime use?!
// CHECK: Value: %2 = load_borrow %0 : $*Klass // users: %4, %3
// CHECK: Consuming User: end_borrow %2 : $Klass // id: %4
// CHECK: Non Consuming User: end_borrow %3 : $*Klass // id: %5
// CHECK: Block: bb0
// CHECK: Error#: 0. End Error in Function: 'test_scope_end_order2'
sil [ossa] @test_scope_end_order2 : $@convention(thin) (@in_guaranteed Klass) -> () {
bb0(%0 : $*Klass):
%stk = alloc_stack $Klass
%borrow = load_borrow %0 : $*Klass
%ra = store_borrow %borrow to %stk : $*Klass
end_borrow %borrow : $Klass
end_borrow %ra : $*Klass
dealloc_stack %stk : $*Klass
%1 = tuple ()
return %1 : $()
}