mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
901 lines
42 KiB
Plaintext
901 lines
42 KiB
Plaintext
// RUN: %target-sil-opt -module-name moveonly_addresschecker -sil-move-only-address-checker -enable-experimental-feature MoveOnlyClasses -enable-sil-verify-all %s | %FileCheck %s
|
|
|
|
sil_stage raw
|
|
|
|
import Swift
|
|
import Builtin
|
|
|
|
public class CopyableKlass {}
|
|
|
|
public final class Klass: ~Copyable {
|
|
var intField: Int
|
|
var k: Klass
|
|
init()
|
|
}
|
|
|
|
sil @get_klass : $@convention(thin) () -> @owned Klass
|
|
sil @nonConsumingUseKlass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
|
|
sil @copyableClassConsume : $@convention(thin) (@owned CopyableKlass) -> () // user: %24
|
|
sil @copyableClassUseMoveOnlyWithoutEscaping : $@convention(thin) (@guaranteed CopyableKlass) -> () // user: %16
|
|
|
|
public struct NonTrivialStruct: ~Copyable {
|
|
var k = Klass()
|
|
var copyableK = CopyableKlass()
|
|
var nonTrivialStruct2 = NonTrivialStruct2()
|
|
}
|
|
|
|
sil @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
sil @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
sil @consumeNonTrivialStructAddr : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
sil @consumeNonTrivialStruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
|
|
public struct NonTrivialStructPair: ~Copyable {
|
|
var lhs: NonTrivialStruct
|
|
var rhs: NonTrivialStruct
|
|
}
|
|
|
|
public struct NonTrivialStruct2: ~Copyable {
|
|
var copyableKlass = CopyableKlass()
|
|
}
|
|
|
|
sil @useNonTrivialStruct2 : $@convention(thin) (@guaranteed NonTrivialStruct2) -> ()
|
|
|
|
struct MyBufferView<T>: ~Copyable {
|
|
var ptr: UnsafeBufferPointer<T>
|
|
}
|
|
|
|
final class ClassContainingMoveOnly {
|
|
var value = NonTrivialStruct()
|
|
}
|
|
|
|
struct SingleTrivialFieldAndDeinit: ~Copyable {
|
|
var value: Builtin.IntLiteral
|
|
|
|
consuming func finalize()
|
|
|
|
deinit
|
|
}
|
|
|
|
sil @getSingleTrivialFieldAndDeinit : $@convention(thin) () -> @owned SingleTrivialFieldAndDeinit
|
|
sil @finalizeSingleTrivialFieldAndDeinit : $@convention(thin) (@owned SingleTrivialFieldAndDeinit) -> ()
|
|
|
|
@_hasStorage @_hasInitialValue var varGlobal: NonTrivialStruct { get set }
|
|
@_hasStorage @_hasInitialValue let letGlobal: NonTrivialStruct { get }
|
|
sil_global hidden @$s23moveonly_addresschecker9varGlobalAA16NonTrivialStructVvp : $NonTrivialStruct
|
|
sil_global hidden [let] @$s23moveonly_addresschecker9letGlobalAA16NonTrivialStructVvp : $NonTrivialStruct
|
|
|
|
struct NonCopyableNativeObjectIntPair : ~Copyable {
|
|
var a: Builtin.NativeObject
|
|
var currentPosition: Int
|
|
}
|
|
|
|
struct NonCopyableNativeObjectPair : ~Copyable {
|
|
var a: Builtin.NativeObject
|
|
var currentPosition: Builtin.NativeObject
|
|
}
|
|
|
|
sil @get_nativeobject : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
|
|
///////////
|
|
// Tests //
|
|
///////////
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleInitReturn : $@convention(thin) (@owned NonTrivialStruct) -> @owned NonTrivialStruct {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-NEXT: [[ALLOC_STACK:%.*]] = alloc_stack [lexical]
|
|
// CHECK-NEXT: store [[ARG]] to [init] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'simpleInitReturn'
|
|
sil [ossa] @simpleInitReturn : $@convention(thin) (@owned NonTrivialStruct) -> @owned NonTrivialStruct {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
%3 = load [copy] %2 : $*NonTrivialStruct
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
return %3 : $NonTrivialStruct
|
|
}
|
|
|
|
sil [ossa] @simpleInitReturn2 : $@convention(thin) (@owned NonTrivialStruct, @owned NonTrivialStruct) -> @owned NonTrivialStructPair {
|
|
bb0(%arg1 : @owned $NonTrivialStruct, %arg2 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %arg1 to [init] %2 : $*NonTrivialStruct
|
|
%3 = load [copy] %2 : $*NonTrivialStruct
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
|
|
store %arg2 to [init] %2 : $*NonTrivialStruct
|
|
%3a = load [copy] %2 : $*NonTrivialStruct
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%result = struct $NonTrivialStructPair(%3 : $NonTrivialStruct, %3a : $NonTrivialStruct)
|
|
return %result : $NonTrivialStructPair
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleInitReturnMoveOnlyField : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-NEXT: [[ALLOC_STACK:%.*]] = alloc_stack [lexical]
|
|
// CHECK-NEXT: store [[ARG]] to [init] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[GEP_3:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP_3]]
|
|
// CHECK-NEXT: [[GEP_1:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.copyableK
|
|
// CHECK-NEXT: [[GEP_2:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
// CHECK-NEXT: destroy_addr [[GEP_1]]
|
|
// CHECK-NEXT: destroy_addr [[GEP_2]]
|
|
// CHECK-NEXT: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'simpleInitReturnMoveOnlyField'
|
|
sil [ossa] @simpleInitReturnMoveOnlyField : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
%3a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
%3 = load [copy] %3a : $*Klass
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
return %3 : $Klass
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-NEXT: [[ALLOC_STACK:%.*]] = alloc_stack [lexical]
|
|
// CHECK-NEXT: store [[ARG]] to [init] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: cond_br undef, bb1, bb2
|
|
//
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
|
|
// CHECK: bb3([[RESULT:%.*]] :
|
|
// CHECK-NEXT: [[GEP_1:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.copyableK
|
|
// CHECK-NEXT: [[GEP_2:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
// CHECK-NEXT: destroy_addr [[GEP_1]]
|
|
// CHECK-NEXT: destroy_addr [[GEP_2]]
|
|
// CHECK-NEXT: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'simpleInitReturnMoveOnlyFieldMultiBlock'
|
|
sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
%3 = load [copy] %3a : $*Klass
|
|
br bb3(%3 : $Klass)
|
|
|
|
bb2:
|
|
%4a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
%4 = load [copy] %4a : $*Klass
|
|
br bb3(%4 : $Klass)
|
|
|
|
bb3(%5 : @owned $Klass):
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
return %5 : $Klass
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock2 : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-NEXT: [[ALLOC_STACK:%.*]] = alloc_stack [lexical]
|
|
// CHECK-NEXT: store [[ARG]] to [init] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: cond_br undef, bb1, bb2
|
|
//
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: function_ref get_klass
|
|
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @get_klass :
|
|
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FUNC]]()
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: destroy_addr [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
|
|
// CHECK: bb3([[RESULT:%.*]] :
|
|
// CHECK-NEXT: [[GEP_1:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.copyableK
|
|
// CHECK-NEXT: [[GEP_2:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
// CHECK-NEXT: destroy_addr [[GEP_1]]
|
|
// CHECK-NEXT: destroy_addr [[GEP_2]]
|
|
// CHECK-NEXT: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'simpleInitReturnMoveOnlyFieldMultiBlock2'
|
|
sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock2 : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%f = function_ref @get_klass : $@convention(thin) () -> @owned Klass
|
|
%3 = apply %f() : $@convention(thin) () -> @owned Klass
|
|
br bb3(%3 : $Klass)
|
|
|
|
bb2:
|
|
%4a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
%4 = load [copy] %4a : $*Klass
|
|
br bb3(%4 : $Klass)
|
|
|
|
bb3(%5 : @owned $Klass):
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
return %5 : $Klass
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock3 : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $NonTrivialStruct):
|
|
// CHECK-NEXT: [[ALLOC_STACK:%.*]] = alloc_stack [lexical]
|
|
// CHECK-NEXT: store [[ARG]] to [init] [[ALLOC_STACK]]
|
|
// CHECK-NEXT: cond_br undef, bb1, bb2
|
|
//
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: function_ref get_klass
|
|
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @get_klass :
|
|
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FUNC]]()
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[GEPP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: destroy_addr [[GEPP]]
|
|
// CHECK-NEXT: store [[RESULT]] to [init] [[GEP]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
//
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ALLOC_STACK]]
|
|
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[GEP]]
|
|
// CHECK-NEXT: br bb3([[RESULT]] :
|
|
//
|
|
// CHECK: bb3([[RESULT:%.*]] :
|
|
// CHECK-NEXT: [[GEP_1:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.copyableK
|
|
// CHECK-NEXT: [[GEP_2:%.*]] = struct_element_addr [[ALLOC_STACK]] : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
// CHECK-NEXT: destroy_addr [[GEP_1]]
|
|
// CHECK-NEXT: destroy_addr [[GEP_2]]
|
|
// CHECK-NEXT: dealloc_stack [[ALLOC_STACK]]
|
|
// CHECK-NEXT: return [[RESULT]]
|
|
// CHECK: } // end sil function 'simpleInitReturnMoveOnlyFieldMultiBlock3'
|
|
sil [ossa] @simpleInitReturnMoveOnlyFieldMultiBlock3 : $@convention(thin) (@owned NonTrivialStruct) -> @owned Klass {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack [lexical] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %2 : $*NonTrivialStruct
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%f = function_ref @get_klass : $@convention(thin) () -> @owned Klass
|
|
%3 = apply %f() : $@convention(thin) () -> @owned Klass
|
|
%3a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
store %3 to [assign] %3a : $*Klass
|
|
%3b = load [copy] %3a : $*Klass
|
|
br bb3(%3b : $Klass)
|
|
|
|
bb2:
|
|
%4a = struct_element_addr %2 : $*NonTrivialStruct, #NonTrivialStruct.k
|
|
%4 = load [copy] %4a : $*Klass
|
|
br bb3(%4 : $Klass)
|
|
|
|
bb3(%5 : @owned $Klass):
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
return %5 : $Klass
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @useVarKlassNoErrorSimple : $@convention(thin) (@owned Klass) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $Klass):
|
|
// CHECK: [[PTR:%.*]] = alloc_stack [lexical] $Klass, var, name "k"
|
|
// CHECK: store [[ARG]] to [init] [[PTR]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[PTR]]
|
|
// CHECK: [[LOAD:%.*]] = load [take] [[ACCESS]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: } // end sil function 'useVarKlassNoErrorSimple'
|
|
sil [ossa] @useVarKlassNoErrorSimple : $@convention(thin) (@owned Klass) -> () {
|
|
bb0(%arg : @owned $Klass):
|
|
%0 = alloc_stack [lexical] $Klass, var, name "k"
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*Klass
|
|
store %arg to [init] %1 : $*Klass
|
|
%12 = begin_access [read] [static] %1 : $*Klass
|
|
%13 = load_borrow %12 : $*Klass
|
|
%14 = function_ref @nonConsumingUseKlass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%15 = apply %14(%13) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %13 : $Klass
|
|
end_access %12 : $*Klass
|
|
%18 = begin_access [read] [static] %1 : $*Klass
|
|
%19 = load [copy] %18 : $*Klass
|
|
end_access %18 : $*Klass
|
|
%21 = move_value [lexical] %19 : $Klass
|
|
%22 = mark_unresolved_non_copyable_value [consumable_and_assignable] %21 : $Klass
|
|
debug_value %22 : $Klass, let, name "k2"
|
|
%25 = move_value %22 : $Klass
|
|
destroy_value %25 : $Klass
|
|
destroy_addr %1 : $*Klass
|
|
dealloc_stack %0 : $*Klass
|
|
%30 = tuple ()
|
|
return %30 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @classSimpleNonConsumingUseTest : $@convention(thin) (@owned Klass, @owned Klass) -> () {
|
|
// CHECK: [[STACK:%.*]] = alloc_stack [lexical] $Klass, var, name "x2"
|
|
// CHECK: store {{%.*}} to [init] [[STACK]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[STACK]]
|
|
// CHECK: destroy_addr [[STACK]]
|
|
// CHECK: store {{%.*}} to [init] [[ACCESS]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [static] [[STACK]]
|
|
// CHECK: [[BORROW:%.*]] = load_borrow [[ACCESS]]
|
|
// CHECK: apply {{%.*}}([[BORROW]]) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
// CHECK: end_borrow [[BORROW]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: destroy_addr [[STACK]]
|
|
// CHECK: } // end sil function 'classSimpleNonConsumingUseTest'
|
|
sil [ossa] @classSimpleNonConsumingUseTest : $@convention(thin) (@owned Klass, @owned Klass) -> () {
|
|
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
|
|
%4 = alloc_stack [lexical] $Klass, var, name "x2"
|
|
%5 = mark_unresolved_non_copyable_value [consumable_and_assignable] %4 : $*Klass
|
|
store %0 to [init] %5 : $*Klass
|
|
%9 = begin_access [modify] [static] %5 : $*Klass
|
|
store %1 to [assign] %9 : $*Klass
|
|
end_access %9 : $*Klass
|
|
%12 = begin_access [read] [static] %5 : $*Klass
|
|
%13 = load_borrow %12 : $*Klass
|
|
%14 = function_ref @nonConsumingUseKlass : $@convention(thin) (@guaranteed Klass) -> ()
|
|
%15 = apply %14(%13) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %13 : $Klass
|
|
end_access %12 : $*Klass
|
|
destroy_addr %5 : $*Klass
|
|
dealloc_stack %4 : $*Klass
|
|
%21 = tuple ()
|
|
return %21 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @myBufferViewSetter : $@convention(method) <T> (UnsafeBufferPointer<T>, @inout MyBufferView<T>) -> () {
|
|
// CHECK: bb0([[ARG0:%.*]] : ${{.*}}, [[ARG1:%.*]] :
|
|
// CHECK: debug_value [[ARG0]]
|
|
// CHECK: debug_value [[ARG1]]
|
|
// CHECK: destroy_addr [[ARG1]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ARG1]]
|
|
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
|
|
// CHECK: store [[ARG0]] to [trivial] [[GEP]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: } // end sil function 'myBufferViewSetter'
|
|
sil [ossa] @myBufferViewSetter : $@convention(method) <T> (UnsafeBufferPointer<T>, @inout MyBufferView<T>) -> () {
|
|
bb0(%0 : $UnsafeBufferPointer<T>, %1 : $*MyBufferView<T>):
|
|
debug_value %0 : $UnsafeBufferPointer<T>, let, name "value", argno 1
|
|
%3 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*MyBufferView<T>
|
|
debug_value %3 : $*MyBufferView<T>, var, name "self", argno 2, expr op_deref
|
|
%5 = begin_access [modify] [static] %3 : $*MyBufferView<T>
|
|
%6 = struct_element_addr %5 : $*MyBufferView<T>, #MyBufferView.ptr
|
|
store %0 to [trivial] %6 : $*UnsafeBufferPointer<T>
|
|
end_access %5 : $*MyBufferView<T>
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
// No transformation here, just make sure that we treat the mark_unresolved_non_copyable_value as
|
|
// the def so that we don't crash.
|
|
sil [ossa] @test_ref_element_addr_borrow_use : $@convention(thin) (@guaranteed ClassContainingMoveOnly) -> () {
|
|
bb0(%0 : @guaranteed $ClassContainingMoveOnly):
|
|
%f = function_ref @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%1 = ref_element_addr %0 : $ClassContainingMoveOnly, #ClassContainingMoveOnly.value
|
|
%2 = mark_unresolved_non_copyable_value [no_consume_or_assign] %1 : $*NonTrivialStruct
|
|
%3 = begin_access [read] [dynamic] %2 : $*NonTrivialStruct
|
|
%4 = load_borrow %3 : $*NonTrivialStruct
|
|
apply %f(%4) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
end_borrow %4 : $NonTrivialStruct
|
|
end_access %3 : $*NonTrivialStruct
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// No transformation here, just make sure that we treat the mark_unresolved_non_copyable_value as
|
|
// the def so that we don't crash.
|
|
sil [ossa] @test_global_addr_borrow_use : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = global_addr @$s23moveonly_addresschecker9varGlobalAA16NonTrivialStructVvp : $*NonTrivialStruct
|
|
%1 = mark_unresolved_non_copyable_value [no_consume_or_assign] %0 : $*NonTrivialStruct
|
|
%2 = begin_access [read] [dynamic] %1 : $*NonTrivialStruct
|
|
%3 = load_borrow %2 : $*NonTrivialStruct
|
|
%4 = function_ref @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%5 = apply %4(%3) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
end_borrow %3 : $NonTrivialStruct
|
|
end_access %2 : $*NonTrivialStruct
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// Make sure that we do not emit any errors here.
|
|
sil [ossa] @test_global_addr_multiple_borrow_uses : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = global_addr @$s23moveonly_addresschecker9varGlobalAA16NonTrivialStructVvp : $*NonTrivialStruct
|
|
%1 = mark_unresolved_non_copyable_value [no_consume_or_assign] %0 : $*NonTrivialStruct
|
|
%2 = begin_access [read] [dynamic] %1 : $*NonTrivialStruct
|
|
%3 = load_borrow %2 : $*NonTrivialStruct
|
|
%4 = function_ref @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%5 = apply %4(%3) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
end_borrow %3 : $NonTrivialStruct
|
|
end_access %2 : $*NonTrivialStruct
|
|
%0a = global_addr @$s23moveonly_addresschecker9varGlobalAA16NonTrivialStructVvp : $*NonTrivialStruct
|
|
%8 = begin_access [read] [dynamic] %0a : $*NonTrivialStruct
|
|
%9 = struct_element_addr %8 : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
%10 = load_borrow %9 : $*NonTrivialStruct2
|
|
%11 = function_ref @useNonTrivialStruct2 : $@convention(thin) (@guaranteed NonTrivialStruct2) -> ()
|
|
%12 = apply %11(%10) : $@convention(thin) (@guaranteed NonTrivialStruct2) -> ()
|
|
end_borrow %10 : $NonTrivialStruct2
|
|
end_access %8 : $*NonTrivialStruct
|
|
%15 = tuple ()
|
|
return %15 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @classSimpleChainArgTestHoistDebugValue : $@convention(thin) (@inout Klass) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] :
|
|
// CHECK-NEXT: debug_value [[ARG]]
|
|
sil [ossa] @classSimpleChainArgTestHoistDebugValue : $@convention(thin) (@inout Klass) -> () {
|
|
bb0(%0 : $*Klass):
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*Klass
|
|
%3 = alloc_stack [lexical] $Klass, var, name "y2"
|
|
%4 = mark_unresolved_non_copyable_value [consumable_and_assignable] %3 : $*Klass
|
|
%5 = begin_access [read] [static] %1 : $*Klass
|
|
copy_addr %5 to [init] %4 : $*Klass
|
|
end_access %5 : $*Klass
|
|
// If we do not hoist this to %1, we should crash. Make sure we dont!
|
|
debug_value %1 : $*Klass, var, name "x2", argno 1, expr op_deref
|
|
destroy_addr %4 : $*Klass
|
|
dealloc_stack %3 : $*Klass
|
|
%f = function_ref @get_klass : $@convention(thin) () -> @owned Klass
|
|
%newArg = apply %f() : $@convention(thin) () -> @owned Klass
|
|
store %newArg to [init] %1 : $*Klass
|
|
%27 = tuple ()
|
|
return %27 : $()
|
|
}
|
|
|
|
// Make sure that we treat the move only access below like an inout parameter
|
|
// that is live at the end of its lifetime, rather than like a var.
|
|
//
|
|
// CHECK: sil [ossa] @closure_assignable_but_not_consumable_treated_like_inout : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed
|
|
// CHECK-NEXT: project_box
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: begin_access
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: end_access
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
// CHECK-NEXT: } // end sil function 'closure_assignable_but_not_consumable_treated_like_inout'
|
|
sil [ossa] @closure_assignable_but_not_consumable_treated_like_inout : $@convention(thin) (@guaranteed { var NonTrivialStruct }) -> () {
|
|
bb0(%0 : @closureCapture @guaranteed ${ var NonTrivialStruct }):
|
|
%4 = project_box %0 : ${ var NonTrivialStruct }, 0
|
|
%9 = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%10 = apply %9() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%11 = begin_access [modify] [dynamic] %4 : $*NonTrivialStruct
|
|
%12 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %11 : $*NonTrivialStruct
|
|
store %10 to [assign] %12 : $*NonTrivialStruct
|
|
end_access %11 : $*NonTrivialStruct
|
|
%24 = tuple ()
|
|
return %24 : $()
|
|
}
|
|
|
|
// CHECK: sil hidden [ossa] @ref_element_addr_treated_like_inout : $@convention(method) (@guaranteed ClassContainingMoveOnly) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: ref_element_addr
|
|
// CHECK-NEXT: begin_access
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: end_access
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'ref_element_addr_treated_like_inout'
|
|
sil hidden [ossa] @ref_element_addr_treated_like_inout : $@convention(method) (@guaranteed ClassContainingMoveOnly) -> () {
|
|
bb0(%0 : @guaranteed $ClassContainingMoveOnly):
|
|
%9 = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%10 = apply %9() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%5 = ref_element_addr %0 : $ClassContainingMoveOnly, #ClassContainingMoveOnly.value
|
|
%6 = begin_access [modify] [dynamic] %5 : $*NonTrivialStruct
|
|
%7 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %6 : $*NonTrivialStruct
|
|
store %10 to [assign] %7 : $*NonTrivialStruct
|
|
end_access %6 : $*NonTrivialStruct
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK: sil [ossa] @test_global_addr_write_use : $@convention(thin) () -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: global_addr
|
|
// CHECK-NEXT: begin_access
|
|
// CHECK-NEXT: destroy_addr
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: end_access
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
// CHECK: } // end sil function 'test_global_addr_write_use'
|
|
sil [ossa] @test_global_addr_write_use : $@convention(thin) () -> () {
|
|
bb0:
|
|
%9 = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%10 = apply %9() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = global_addr @$s23moveonly_addresschecker9varGlobalAA16NonTrivialStructVvp : $*NonTrivialStruct
|
|
%1 = begin_access [modify] [dynamic] %0 : $*NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %1 : $*NonTrivialStruct
|
|
store %10 to [assign] %2 : $*NonTrivialStruct
|
|
end_access %1 : $*NonTrivialStruct
|
|
%8 = tuple ()
|
|
return %8 : $()
|
|
}
|
|
|
|
// Make sure we do not crash on this.
|
|
sil [ossa] @test_in_use : $@convention(thin) () -> () {
|
|
%9 = function_ref @getNonTrivialStruct : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%10 = apply %9() : $@convention(thin) () -> @owned NonTrivialStruct
|
|
%0 = alloc_stack [moveable_value_debuginfo] $NonTrivialStruct
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*NonTrivialStruct
|
|
store %10 to [init] %2 : $*NonTrivialStruct
|
|
%f2 = function_ref @consumeNonTrivialStructAddr : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
apply %f2(%2) : $@convention(thin) (@in NonTrivialStruct) -> ()
|
|
destroy_addr %2 : $*NonTrivialStruct
|
|
dealloc_stack %0 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
//////////////////////////////////////////
|
|
// MARK: Load Take As Borrow/Copy Tests //
|
|
//////////////////////////////////////////
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_take_as_load_borrow : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
// CHECK: [[ALLOC:%.*]] = alloc_stack $NonTrivialStruct
|
|
// CHECK: [[BORROW:%.*]] = load_borrow [[ALLOC]]
|
|
// CHECK: end_borrow [[BORROW]]
|
|
// CHECK: } // end sil function 'load_take_as_load_borrow'
|
|
sil [ossa] @load_take_as_load_borrow : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack $NonTrivialStruct
|
|
%1a = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %1a : $*NonTrivialStruct
|
|
%2 = load [take] %1a : $*NonTrivialStruct
|
|
destroy_value %2 : $NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_take_as_load_take : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
// CHECK: [[ALLOC:%.*]] = alloc_stack $NonTrivialStruct
|
|
// CHECK: [[LOAD:%.*]] = load [take] [[ALLOC]]
|
|
// CHECK: apply {{%.*}}([[LOAD]])
|
|
// CHECK: } // end sil function 'load_take_as_load_take'
|
|
sil [ossa] @load_take_as_load_take : $@convention(thin) (@owned NonTrivialStruct) -> () {
|
|
bb0(%0 : @owned $NonTrivialStruct):
|
|
%1 = alloc_stack $NonTrivialStruct
|
|
%1a = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*NonTrivialStruct
|
|
store %0 to [init] %1a : $*NonTrivialStruct
|
|
%2 = load [take] %1a : $*NonTrivialStruct
|
|
%f = function_ref @consumeNonTrivialStruct : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
apply %f(%2) : $@convention(thin) (@owned NonTrivialStruct) -> ()
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
struct M: ~Copyable {
|
|
deinit {}
|
|
}
|
|
struct M2: ~Copyable {
|
|
let s1: M
|
|
let s2: M
|
|
}
|
|
|
|
sil @get_M2 : $@convention(thin) () -> @owned M2
|
|
sil @end_addr_see_addr : $@convention(thin) (@in M, @in_guaranteed M) -> ()
|
|
|
|
/// A single instruction, apply @end_addr_see_addr, consumes one field and
|
|
/// borrows another.
|
|
|
|
/// Verify that the consumed value isn't destroyed twice and that the borrowed
|
|
/// value isn't destroyed before it's used.
|
|
///
|
|
/// Note: This test case doesn't have valid SIL (#M2.s1 is consumed twice), but
|
|
/// the invalidity wasn't the cause of the miscompile. With the fix, this
|
|
/// is transformed into valid SIL.
|
|
///
|
|
/// Once verification is enabled, feel free to modify this test case to
|
|
/// have a destroy_addr of %second_addr instead, though not that this will
|
|
/// no longer verify the fix.
|
|
// CHECK-LABEL: sil [ossa] @rdar110909290 : {{.*}} {
|
|
// CHECK: [[STACK:%[^,]+]] = alloc_stack $M2
|
|
// CHECK: [[GET_M2:%[^,]+]] = function_ref @get_M2
|
|
// CHECK: [[M2:%[^,]+]] = apply [[GET_M2]]()
|
|
// CHECK: store [[M2]] to [init] [[STACK]] : $*M2
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: [[S1_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s1
|
|
// CHECK: [[S2_ADDR:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s2
|
|
// CHECK: [[END_ADDR_SEE_ADDR:%[^,]+]] = function_ref @end_addr_see_addr
|
|
// CHECK: apply [[END_ADDR_SEE_ADDR]]([[S1_ADDR]], [[S2_ADDR]])
|
|
// CHECK-NOT: struct_element_addr [[STACK]] : $*M2, #M2.s1
|
|
// CHECK: [[S2_ADDR_2:%[^,]+]] = struct_element_addr [[STACK]] : $*M2, #M2.s2
|
|
// CHECK: destroy_addr [[S2_ADDR_2]] : $*M
|
|
// CHECK-LABEL: } // end sil function 'rdar110909290'
|
|
sil [ossa] @rdar110909290 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $M2
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*M2
|
|
%3 = function_ref @get_M2 : $@convention(thin) () -> @owned M2
|
|
%4 = apply %3() : $@convention(thin) () -> @owned M2
|
|
store %4 to [init] %1 : $*M2
|
|
%first_addr = struct_element_addr %1 : $*M2, #M2.s1
|
|
%second_addr = struct_element_addr %1 : $*M2, #M2.s2
|
|
%end_addr_see_addr = function_ref @end_addr_see_addr : $@convention(thin) (@in M, @in_guaranteed M) -> ()
|
|
apply %end_addr_see_addr(%first_addr, %second_addr) : $@convention(thin) (@in M, @in_guaranteed M) -> ()
|
|
destroy_addr %1 : $*M2
|
|
dealloc_stack %0 : $*M2
|
|
%22 = tuple ()
|
|
return %22 : $()
|
|
}
|
|
|
|
// rdar://110232973 ([move-only] Checker should distinguish in between field of single field struct
|
|
// vs parent field itself (was: mutation of field in noncopyable struct should not trigger deinit))
|
|
//
|
|
// Test that the SingleTrivialFieldAndDeinit aggregate is not
|
|
// deinitialized when it's only field is consumed.
|
|
//
|
|
// CHECK-LABEL: sil hidden [ossa] @testNoFieldReinit : $@convention(thin) () -> () {
|
|
// CHECK: [[ALLOC:%.*]] = alloc_stack [lexical] $SingleTrivialFieldAndDeinit
|
|
// CHECK-NOT: destroy_addr [[ALLOC]]
|
|
// CHECK-LABEL: } // end sil function 'testNoFieldReinit'
|
|
sil hidden [ossa] @testNoFieldReinit : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack [lexical] $SingleTrivialFieldAndDeinit, var
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %0 : $*SingleTrivialFieldAndDeinit
|
|
%3 = function_ref @getSingleTrivialFieldAndDeinit : $@convention(thin) () -> @owned SingleTrivialFieldAndDeinit
|
|
%4 = apply %3() : $@convention(thin) () -> @owned SingleTrivialFieldAndDeinit
|
|
store %4 to [init] %1 : $*SingleTrivialFieldAndDeinit
|
|
%6 = integer_literal $Builtin.IntLiteral, 20
|
|
%10 = begin_access [modify] [static] %1 : $*SingleTrivialFieldAndDeinit
|
|
%11 = struct_element_addr %10 : $*SingleTrivialFieldAndDeinit, #SingleTrivialFieldAndDeinit.value
|
|
store %6 to [trivial] %11 : $*Builtin.IntLiteral
|
|
end_access %10 : $*SingleTrivialFieldAndDeinit
|
|
%14 = begin_access [deinit] [static] %1 : $*SingleTrivialFieldAndDeinit
|
|
%15 = load [take] %14 : $*SingleTrivialFieldAndDeinit
|
|
%16 = function_ref @finalizeSingleTrivialFieldAndDeinit : $@convention(thin) (@owned SingleTrivialFieldAndDeinit) -> ()
|
|
%17 = apply %16(%15) : $@convention(thin) (@owned SingleTrivialFieldAndDeinit) -> ()
|
|
end_access %14 : $*SingleTrivialFieldAndDeinit
|
|
destroy_addr %1 : $*SingleTrivialFieldAndDeinit
|
|
dealloc_stack %0 : $*SingleTrivialFieldAndDeinit
|
|
%21 = tuple ()
|
|
return %21 : $()
|
|
}
|
|
|
|
struct FixedSizeQueue : ~Copyable {
|
|
var ptr: Builtin.Int32
|
|
}
|
|
|
|
sil @get_fixedsize_queue : $@convention(thin) () -> @owned FixedSizeQueue
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_return_trivial_type : $@convention(thin) (@owned FixedSizeQueue) -> Builtin.Int32 {
|
|
// CHECK: bb0([[ARG:%.*]] : @owned $
|
|
// CHECK: [[ALLOC:%.*]] = alloc_stack [lexical] $FixedSizeQueue
|
|
// CHECK: store [[ARG]] to [init] [[ALLOC]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ALLOC]]
|
|
// CHECK: [[ALLOC2:%.*]] = alloc_stack $FixedSizeQueue
|
|
// CHECK: copy_addr [take] [[ACCESS]] to [init] [[ALLOC2]]
|
|
// CHECK: [[LOADED:%.*]] = load_borrow [[ALLOC2]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: [[BORROW:%.*]] = begin_borrow [[LOADED]]
|
|
// CHECK: [[TRIVIAL_VALUE:%.*]] = struct_extract [[BORROW]]
|
|
// CHECK: end_borrow [[BORROW]]
|
|
// CHECK: end_borrow [[LOADED]]
|
|
// CHECK: destroy_addr [[ALLOC2]]
|
|
// CHECK: dealloc_stack [[ALLOC2]]
|
|
// CHECK: [[NEW_VALUE:%.*]] = apply {{%.*}}()
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ALLOC]]
|
|
// CHECK: store [[NEW_VALUE]] to [init] [[ACCESS]]
|
|
// CHECK: end_access [[ACCESS]]
|
|
// CHECK: destroy_addr [[ALLOC]]
|
|
// CHECK: dealloc_stack [[ALLOC]]
|
|
// CHECK: return [[TRIVIAL_VALUE]]
|
|
// CHECK: } // end sil function 'test_return_trivial_type'
|
|
sil [ossa] @test_return_trivial_type : $@convention(thin) (@owned FixedSizeQueue) -> Builtin.Int32 {
|
|
bb0(%0 : @owned $FixedSizeQueue):
|
|
%1 = alloc_stack [lexical] $FixedSizeQueue, var, name "self"
|
|
%2 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1 : $*FixedSizeQueue
|
|
store %0 to [init] %2 : $*FixedSizeQueue
|
|
%4 = begin_access [modify] [static] %2 : $*FixedSizeQueue
|
|
%5 = alloc_stack $FixedSizeQueue
|
|
%6 = mark_unresolved_non_copyable_value [consumable_and_assignable] %5 : $*FixedSizeQueue
|
|
copy_addr %4 to [init] %6 : $*FixedSizeQueue
|
|
%8 = load [take] %6 : $*FixedSizeQueue
|
|
end_access %4 : $*FixedSizeQueue
|
|
%10 = begin_borrow %8 : $FixedSizeQueue
|
|
%11 = struct_extract %10 : $FixedSizeQueue, #FixedSizeQueue.ptr
|
|
end_borrow %10 : $FixedSizeQueue
|
|
destroy_value %8 : $FixedSizeQueue
|
|
dealloc_stack %5 : $*FixedSizeQueue
|
|
%21 = function_ref @get_fixedsize_queue : $@convention(thin) () -> @owned FixedSizeQueue
|
|
%22 = apply %21() : $@convention(thin) () -> @owned FixedSizeQueue
|
|
%23 = begin_access [modify] [static] %2 : $*FixedSizeQueue
|
|
store %22 to [assign] %23 : $*FixedSizeQueue
|
|
end_access %23 : $*FixedSizeQueue
|
|
destroy_addr %2 : $*FixedSizeQueue
|
|
dealloc_stack %1 : $*FixedSizeQueue
|
|
return %11 : $Builtin.Int32
|
|
}
|
|
|
|
// Make sure that we set the end_access as the implicit end lifetime use instead
|
|
// of the terminator.
|
|
// CHECK-LABEL: sil [ossa] @assignableButNotConsumableEndAccessImplicitLifetimeTest : $@convention(thin) (@guaranteed ClassContainingMoveOnly, @owned NonTrivialStruct2) -> () {
|
|
// CHECK: bb0([[ARG0:%.*]] : @guaranteed $ClassContainingMoveOnly, [[ARG1:%.*]] : @owned
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: [[ADDR:%.*]] = ref_element_addr [[ARG0]]
|
|
// CHECK-NEXT: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADDR]]
|
|
// CHECK-NEXT: [[GEP1:%.*]] = struct_element_addr [[ACCESS]]
|
|
// CHECK-NEXT: [[GEP2:%.*]] = struct_element_addr [[ACCESS]]
|
|
// CHECK-NEXT: destroy_addr [[GEP2]]
|
|
// CHECK-NEXT: store [[ARG1]] to [init] [[GEP1]]
|
|
// CHECK-NEXT: end_access [[ACCESS]]
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: } // end sil function 'assignableButNotConsumableEndAccessImplicitLifetimeTest'
|
|
sil [ossa] @assignableButNotConsumableEndAccessImplicitLifetimeTest : $@convention(thin) (@guaranteed ClassContainingMoveOnly, @owned NonTrivialStruct2) -> () {
|
|
bb0(%0 : @guaranteed $ClassContainingMoveOnly, %1 : @owned $NonTrivialStruct2):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
destroy_value %1 : $NonTrivialStruct2
|
|
br bb3
|
|
|
|
bb2:
|
|
%2 = ref_element_addr %0 : $ClassContainingMoveOnly, #ClassContainingMoveOnly.value
|
|
%3 = begin_access [modify] [dynamic] %2 : $*NonTrivialStruct
|
|
%4 = mark_unresolved_non_copyable_value [assignable_but_not_consumable] %3 : $*NonTrivialStruct
|
|
%4a = struct_element_addr %4 : $*NonTrivialStruct, #NonTrivialStruct.nonTrivialStruct2
|
|
store %1 to [assign] %4a : $*NonTrivialStruct2
|
|
end_access %3 : $*NonTrivialStruct
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil @testUseCorrectBitsClosureCallee : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectIntPair) -> Bool
|
|
sil @testUseCorrectBitsClosureUser : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Bool) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @testUseCorrectBits : $@convention(method) (Int, @inout NonCopyableNativeObjectIntPair) -> () {
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: } // end sil function 'testUseCorrectBits'
|
|
sil [ossa] @testUseCorrectBits : $@convention(method) (Int, @inout NonCopyableNativeObjectIntPair) -> () {
|
|
bb0(%0 : $Int, %1a : $*NonCopyableNativeObjectIntPair):
|
|
debug_value %0 : $Int, let, name "index", argno 1
|
|
debug_value %1a : $*NonCopyableNativeObjectIntPair, var, name "self", argno 2, expr op_deref
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1a : $*NonCopyableNativeObjectIntPair
|
|
%4 = function_ref @testUseCorrectBitsClosureCallee : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectIntPair) -> Bool
|
|
%5 = partial_apply [callee_guaranteed] [on_stack] %4(%0, %1) : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectIntPair) -> Bool
|
|
%6 = mark_dependence %5 : $@noescape @callee_guaranteed () -> Bool on %1 : $*NonCopyableNativeObjectIntPair
|
|
%7 = function_ref @testUseCorrectBitsClosureUser : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Bool) -> ()
|
|
%8 = apply %7(%6) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Bool) -> ()
|
|
%9 = struct_element_addr %1 : $*NonCopyableNativeObjectIntPair, #NonCopyableNativeObjectIntPair.currentPosition
|
|
debug_value undef : $*NonCopyableNativeObjectIntPair, var, name "self", argno 2, expr op_deref
|
|
destroy_value %6 : $@noescape @callee_guaranteed () -> Bool
|
|
%12 = begin_access [modify] [static] %1 : $*NonCopyableNativeObjectIntPair
|
|
%13 = struct_element_addr %12 : $*NonCopyableNativeObjectIntPair, #NonCopyableNativeObjectIntPair.currentPosition
|
|
store %0 to [trivial] %13 : $*Int
|
|
end_access %12 : $*NonCopyableNativeObjectIntPair
|
|
%16 = tuple ()
|
|
return %16 : $()
|
|
}
|
|
|
|
sil @testUseCorrectBits2ClosureCallee : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectPair) -> Bool
|
|
|
|
// CHECK-LABEL: sil [ossa] @testUseCorrectBits2 : $@convention(method) (Int, @inout NonCopyableNativeObjectPair) -> () {
|
|
// CHECK: bb0({{%.*}} : $Int, [[ARG:%.*]] : $*
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [static] [[ARG]]
|
|
// CHECK-NEXT: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
|
|
// CHECK-NEXT: function_ref get_nativeobject
|
|
// CHECK-NEXT: function_ref @get_nativeobject
|
|
// CHECK-NEXT: apply {{%.*}}
|
|
// CHECK-NEXT: [[GEP2:%.*]] = struct_element_addr [[ARG]] : $*NonCopyableNativeObjectPair, #NonCopyableNativeObjectPair.currentPosition
|
|
// CHECK-NEXT: destroy_addr [[GEP2]]
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK: } // end sil function 'testUseCorrectBits2'
|
|
sil [ossa] @testUseCorrectBits2 : $@convention(method) (Int, @inout NonCopyableNativeObjectPair) -> () {
|
|
bb0(%0 : $Int, %1a : $*NonCopyableNativeObjectPair):
|
|
debug_value %0 : $Int, let, name "index", argno 1
|
|
debug_value %1a : $*NonCopyableNativeObjectPair, var, name "self", argno 2, expr op_deref
|
|
%1 = mark_unresolved_non_copyable_value [consumable_and_assignable] %1a : $*NonCopyableNativeObjectPair
|
|
%4 = function_ref @testUseCorrectBits2ClosureCallee : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectPair) -> Bool
|
|
%5 = partial_apply [callee_guaranteed] [on_stack] %4(%0, %1) : $@convention(thin) (Int, @inout_aliasable NonCopyableNativeObjectPair) -> Bool
|
|
%6 = mark_dependence %5 : $@noescape @callee_guaranteed () -> Bool on %1 : $*NonCopyableNativeObjectPair
|
|
%7 = function_ref @testUseCorrectBitsClosureUser : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Bool) -> ()
|
|
%8 = apply %7(%6) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> Bool) -> ()
|
|
%9 = struct_element_addr %1 : $*NonCopyableNativeObjectPair, #NonCopyableNativeObjectPair.currentPosition
|
|
debug_value undef : $*NonCopyableNativeObjectPair, var, name "self", argno 2, expr op_deref
|
|
destroy_value %6 : $@noescape @callee_guaranteed () -> Bool
|
|
%12 = begin_access [modify] [static] %1 : $*NonCopyableNativeObjectPair
|
|
%13 = struct_element_addr %12 : $*NonCopyableNativeObjectPair, #NonCopyableNativeObjectPair.currentPosition
|
|
%f = function_ref @get_nativeobject : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
%14 = apply %f() : $@convention(thin) () -> @owned Builtin.NativeObject
|
|
store %14 to [assign] %13 : $*Builtin.NativeObject
|
|
end_access %12 : $*NonCopyableNativeObjectPair
|
|
%16 = tuple ()
|
|
return %16 : $()
|
|
}
|
|
|
|
sil [ossa] @testSupportStoreBorrow : $@convention(thin) (@guaranteed NonTrivialStruct) -> () {
|
|
bb0(%0 : @guaranteed $NonTrivialStruct):
|
|
%1 = alloc_stack $NonTrivialStruct
|
|
%1a = mark_unresolved_non_copyable_value [no_consume_or_assign] %1 : $*NonTrivialStruct
|
|
%borrow = store_borrow %0 to %1a : $*NonTrivialStruct
|
|
%f = function_ref @useNonTrivialStruct : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
%l = load_borrow %borrow : $*NonTrivialStruct
|
|
apply %f(%l) : $@convention(thin) (@guaranteed NonTrivialStruct) -> ()
|
|
end_borrow %l : $NonTrivialStruct
|
|
end_borrow %borrow : $*NonTrivialStruct
|
|
dealloc_stack %1 : $*NonTrivialStruct
|
|
%9999 = tuple ()
|
|
return %9999 : $()
|
|
}
|
|
|
|
sil [ossa] @f : $@convention(thin) (@inout NonTrivialStruct, @owned NonTrivialStruct) -> () {
|
|
entry(%out : $*NonTrivialStruct, %s : @owned $NonTrivialStruct):
|
|
%munc = mark_unresolved_non_copyable_value [consumable_and_assignable] %out : $*NonTrivialStruct
|
|
br body
|
|
body:
|
|
store %s to [assign] %munc : $*NonTrivialStruct
|
|
br exit
|
|
exit:
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// Test that we don't crash while attempting to complete reborrow lifetimes.
|
|
sil [ossa] @closure_lifetime_fixup_output : $@convention(thin) (@owned NonTrivialStructPair) -> () {
|
|
bb0(%pair : @owned $NonTrivialStructPair):
|
|
%none = enum $Optional<@callee_guaranteed () -> ()>, #Optional.none!enumelt
|
|
%none_borrow = begin_borrow %none : $Optional<@callee_guaranteed () -> ()>
|
|
%stack = alloc_stack $NonTrivialStructPair, let, name "job", argno 1
|
|
%addr = mark_unresolved_non_copyable_value [consumable_and_assignable] %stack : $*NonTrivialStructPair
|
|
store %pair to [init] %addr : $*NonTrivialStructPair
|
|
cond_br undef, bb1, bb3
|
|
|
|
bb1:
|
|
end_borrow %none_borrow : $Optional<@callee_guaranteed () -> ()>
|
|
%closure = partial_apply [callee_guaranteed] undef() : $@convention(thin) () -> ()
|
|
%some = enum $Optional<@callee_guaranteed () -> ()>, #Optional.some!enumelt, %closure : $@callee_guaranteed () -> ()
|
|
%some_borrow = begin_borrow %some : $Optional<@callee_guaranteed () -> ()>
|
|
br bb2
|
|
|
|
bb2:
|
|
br bb4(%some_borrow : $Optional<@callee_guaranteed () -> ()>, %some : $Optional<@callee_guaranteed () -> ()>)
|
|
|
|
bb3:
|
|
br bb4(%none_borrow : $Optional<@callee_guaranteed () -> ()>, %none : $Optional<@callee_guaranteed () -> ()>)
|
|
|
|
bb4(%reborrow : @reborrow @guaranteed $Optional<@callee_guaranteed () -> ()>, %maybe : @owned $Optional<@callee_guaranteed () -> ()>):
|
|
%borrow = borrowed %reborrow : $Optional<@callee_guaranteed () -> ()> from (%maybe : $Optional<@callee_guaranteed () -> ()>)
|
|
destroy_addr %addr : $*NonTrivialStructPair
|
|
dealloc_stack %stack : $*NonTrivialStructPair
|
|
end_borrow %borrow : $Optional<@callee_guaranteed () -> ()>
|
|
destroy_value %maybe : $Optional<@callee_guaranteed () -> ()>
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|