blob: 409611ee0a70140a8443560b77cc6a624d5184a3 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -enforce-exclusivity=unchecked -diagnose-static-exclusivity -verify | %FileCheck %s
sil_stage raw
import Builtin
import Swift
sil @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
sil @takesOneInout : $@convention(thin) (@inout Int) -> ()
sil @makesInt : $@convention(thin) () -> Int
sil @takesInoutAndNoEscapeClosure : $@convention(thin) (@inout Int, @noescape @owned @callee_owned () -> ()) -> ()
sil @takesInoutAndNoEscapeClosureTakingArgument : $@convention(thin) (@inout Int, @noescape @owned @callee_owned (Int) -> ()) -> ()
sil @takesInoutAndNoEscapeGuaranteedClosureTakingArgument : $@convention(thin) (@inout Int, @noescape @guaranteed @callee_guaranteed (Int) -> ()) -> ()
sil @takesInoutAndNoEscapeClosureWithGenericReturn : $@convention(thin) <T> (@inout Int, @noescape @callee_owned (Int) -> @out T) -> ()
sil @takesInoutAndNoEscapeBlockClosure : $@convention(thin) (@inout Int, @owned @convention(block) @noescape () -> ()) -> ()
sil @takesInoutAndNoEscapeOptionalBlockClosure : $@convention(thin) (@inout Int, @owned Optional<@convention(block) @noescape () -> ()>) -> ()
// CHECK-LABEL: sil hidden [ossa] @twoLocalInoutsDisaliased
sil hidden [ossa] @twoLocalInoutsDisaliased : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%5 = alloc_box ${ var Int }
%6 = project_box %5 : ${ var Int }, 0
store %0 to [trivial] %6 : $*Int
%8 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%9 = begin_access [modify] [unknown] %3 : $*Int
%10 = begin_access [modify] [unknown] %6 : $*Int // no-error
%11 = apply %8(%9, %10) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %10 : $*Int
end_access %9: $*Int
destroy_value %5 : ${ var Int }
destroy_value %2 : ${ var Int }
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: sil hidden [ossa] @twoLocalInoutsSimpleAliasing
sil hidden [ossa] @twoLocalInoutsSimpleAliasing : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = begin_access [modify] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%7 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil hidden [ossa] @conflictingPriorAccess
sil hidden [ossa] @conflictingPriorAccess : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = begin_access [modify] [unknown] %5 : $*Int
%7 = begin_access [modify] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%8 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*Int
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: sil hidden [ossa] @twoSequentialInouts
sil hidden [ossa] @twoSequentialInouts : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesOneInout : $@convention(thin) (@inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int
%6 = apply %4(%5) : $@convention(thin) (@inout Int) -> ()
end_access %5 : $*Int
%7 = begin_access [modify] [unknown] %3 : $*Int // no-error
%8 = apply %4(%7) : $@convention(thin) (@inout Int) -> ()
end_access %7: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil hidden [ossa] @unconditionalBranch
sil hidden [ossa] @unconditionalBranch : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = begin_access [modify] [unknown] %3 : $*Int
br finish
finish:
end_access %4: $*Int
destroy_value %2 : ${ var Int }
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil hidden [ossa] @diamondMergeStacks
sil hidden [ossa] @diamondMergeStacks : $@convention(thin) (Int, Builtin.Int1) -> () {
bb0(%0 : $Int, %1 : $Builtin.Int1):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = begin_access [modify] [unknown] %3 : $*Int
cond_br %1, then, else
then:
br finish
else:
br finish
finish:
end_access %4: $*Int
destroy_value %2 : ${ var Int }
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil hidden [ossa] @loopMergeStacks
sil hidden [ossa] @loopMergeStacks : $@convention(thin) (Int, Builtin.Int1) -> () {
bb0(%0 : $Int, %1 : $Builtin.Int1):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = begin_access [modify] [unknown] %3 : $*Int
br bb1
bb1:
cond_br %1, bb1, bb2
bb2:
end_access %4: $*Int
destroy_value %2 : ${ var Int }
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil hidden [ossa] @loopWithError
sil hidden [ossa] @loopWithError : $@convention(thin) (Int, Builtin.Int1) -> () {
bb0(%0 : $Int, %1 : $Builtin.Int1):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
br bb1
bb1:
// Make sure we don't diagnose twice.
%4 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
end_access %5: $*Int
end_access %4: $*Int
cond_br %1, bb1, bb2
bb2:
destroy_value %2 : ${ var Int }
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil hidden [ossa] @modifySubAccessesAreAllowed
sil hidden [ossa] @modifySubAccessesAreAllowed : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int
%6 = begin_access [modify] [unknown] %5 : $*Int // no-error
%7 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%8 = tuple ()
return %8 : $()
}
// Multiple access kinds
// CHECK-LABEL: sil hidden [ossa] @twoLocalReadsSimpleAliasing
sil hidden [ossa] @twoLocalReadsSimpleAliasing : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%2 = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %2 : $*Int
%4 = begin_access [read] [unknown] %2 : $*Int
%5 = begin_access [read] [unknown] %2 : $*Int // no-error
end_access %5 : $*Int
end_access %4: $*Int
destroy_value %1 : ${ var Int }
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil hidden [ossa] @localReadFollowedByModify
sil hidden [ossa] @localReadFollowedByModify : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%2 = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %2 : $*Int
%4 = begin_access [read] [unknown] %2 : $*Int // expected-note {{conflicting access is here}}
%5 = begin_access [modify] [unknown] %2 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
end_access %5 : $*Int
end_access %4: $*Int
destroy_value %1 : ${ var Int }
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: sil hidden [ossa] @localModifyFollowedByRead
sil hidden [ossa] @localModifyFollowedByRead : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%2 = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %2 : $*Int
%4 = begin_access [modify] [unknown] %2 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%5 = begin_access [read] [unknown] %2 : $*Int // expected-note {{conflicting access is here}}
end_access %5 : $*Int
end_access %4: $*Int
destroy_value %1 : ${ var Int }
%6 = tuple ()
return %6 : $()
}
class ClassWithStoredProperty {
@_hasStorage var f: Int
init()
}
// CHECK-LABEL: sil hidden [ossa] @classStoredProperty
sil hidden [ossa] @classStoredProperty : $@convention(thin) (@owned ClassWithStoredProperty) -> () {
bb0(%0 : @owned $ClassWithStoredProperty):
%0a = begin_borrow %0 : $ClassWithStoredProperty
%1 = ref_element_addr %0a : $ClassWithStoredProperty, #ClassWithStoredProperty.f
// expected-error@+1{{overlapping accesses to 'f', but modification requires exclusive access; consider copying to a local variable}}
%2 = begin_access [modify] [dynamic] %1 : $*Int
%3 = ref_element_addr %0a : $ClassWithStoredProperty, #ClassWithStoredProperty.f
// expected-note@+1{{conflicting access is here}}
%4 = begin_access [modify] [dynamic] %3 : $*Int
end_access %4 : $*Int
end_access %2 : $*Int
end_borrow %0a : $ClassWithStoredProperty
destroy_value %0 : $ClassWithStoredProperty
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil hidden [ossa] @lookThroughBeginBorrow
sil hidden [ossa] @lookThroughBeginBorrow : $@convention(thin) (@owned ClassWithStoredProperty) -> () {
bb0(%0 : @owned $ClassWithStoredProperty):
%1 = begin_borrow %0 : $ClassWithStoredProperty
%2 = begin_borrow %0 : $ClassWithStoredProperty
%3 = ref_element_addr %1 : $ClassWithStoredProperty, #ClassWithStoredProperty.f
// expected-error@+1{{overlapping accesses to 'f', but modification requires exclusive access; consider copying to a local variable}}
%4 = begin_access [modify] [dynamic] %3 : $*Int
%5 = ref_element_addr %2 : $ClassWithStoredProperty, #ClassWithStoredProperty.f
// expected-note@+1{{conflicting access is here}}
%6 = begin_access [modify] [dynamic] %5 : $*Int
end_access %6 : $*Int
end_access %4 : $*Int
end_borrow %2 : $ClassWithStoredProperty
end_borrow %1 : $ClassWithStoredProperty
destroy_value %0 : $ClassWithStoredProperty
%7 = tuple ()
return %7 : $()
}
// Tests for address identity
// Treat 'alloc_box' as identity for project_box
// CHECK-LABEL: sil hidden [ossa] @twoAllocBoxProjections
sil hidden [ossa] @twoAllocBoxProjections : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = copy_value %2 : ${ var Int }
%5 = project_box %4 : ${ var Int }, 0
%6 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%7 = begin_access [modify] [unknown] %5 : $*Int // expected-note {{conflicting access is here}}
end_access %7 : $*Int
end_access %6: $*Int
destroy_value %2 : ${ var Int }
destroy_value %4 : ${ var Int }
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil hidden [ossa] @lookThroughMarkUninitialized
sil hidden [ossa] @lookThroughMarkUninitialized : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%2 = mark_uninitialized [rootself] %1 : ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = project_box %2 : ${ var Int }, 0
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = begin_access [modify] [unknown] %4 : $*Int // expected-note {{conflicting access is here}}
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%7 = tuple ()
return %7 : $()
}
// Treat global as identity for global_addr instruction-
sil_global hidden @global1 : $Int
sil_global hidden @global2 : $Int
// CHECK-LABEL: sil hidden [ossa] @modifySameGlobal
sil hidden [ossa] @modifySameGlobal : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = global_addr @global1 :$*Int
%2 = global_addr @global1 :$*Int
%3 = begin_access [modify] [unknown] %1 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%4 = begin_access [modify] [unknown] %2 : $*Int // expected-note {{conflicting access is here}}
end_access %4 : $*Int
end_access %3: $*Int
%5 = tuple ()
return %5 : $()
}
// CHECK-LABEL: sil hidden [ossa] @modifyDifferentGlobal
sil hidden [ossa] @modifyDifferentGlobal : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = global_addr @global1 :$*Int
%2 = global_addr @global2 :$*Int
%3 = begin_access [modify] [unknown] %1 : $*Int
%4 = begin_access [modify] [unknown] %2 : $*Int // no-error
end_access %4 : $*Int
end_access %3: $*Int
%5 = tuple ()
return %5 : $()
}
// Multiple errors accessing the same location
// If we have a sequence of begin read - begin write - begin read accesses make
// sure the second read doesn't report a confusing read-read conflict.
// CHECK-LABEL: sil hidden [ossa] @readWriteReadConflictingThirdAccess
sil hidden [ossa] @readWriteReadConflictingThirdAccess : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [read] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%6 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%7 = begin_access [read] [unknown] %3 : $*Int // no-error
%8 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*Int
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
// If we have a sequence of begin write - begin write - begin write accesses make sure the
// third write doesn't report a conflict.
// CHECK-LABEL: sil hidden [ossa] @writeWriteWriteConflictingThirdAccess
sil hidden [ossa] @writeWriteWriteConflictingThirdAccess : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = begin_access [modify] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%7 = begin_access [modify] [unknown] %3 : $*Int // no-error
%8 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*Int
end_access %6 : $*Int
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
// If we have a sequence of begin write - end write - begin write - begin write
// accesses make sure the it is the second begin write that gets the note
// about the conflict and not the first
// CHECK-LABEL: sil hidden [ossa] @resetFirstAccessForNote
sil hidden [ossa] @resetFirstAccessForNote : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int // no-note
end_access %5 : $*Int
%6 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%7 = begin_access [modify] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%8 = apply %4(%5, %6) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*Int
end_access %6: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
// Check for iterator invalidation issues when the hash from
// basic blocks to analysis state is re-hashed. The number of
// blocks in this test is determined by the initial size of the
// 'BlockOutAccesses' DenseMap in the implementation.
//
// The unreachable block below must branch to bN where
// N = 3/4 * INITIAL_SIZE - 2
sil [ossa] @blockMapRehash : $@convention(method) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
br bb1
bb1:
br bb2
bb2:
br bb3
bb3:
br bb4
bb4:
br bb5
bb5:
br bb6
bb6:
br bb7
bb7:
br bb8
bb8:
br bb9
bb9:
br bb10
bb10:
br bb11
bb11:
br bb12
bb12:
br bb13
bb13:
br bb14
bb14:
br bb15
bb15:
br bb16
bb16:
br bb17
bb17:
br bb18
bb18:
br bb19
bb19:
br bb20
bb20:
br bb21
bb21:
br bb22
bb22:
br bb23 // no-crash
bb23:
%1 = tuple ()
return %1 : $()
bbUnreachable:
br bb22
}
// Check that a pointer_to_address access passes diagnostics.
//
// CHECK-LABEL: sil hidden [ossa] @pointerToAddr
sil hidden [ossa] @pointerToAddr : $@convention(thin) (Builtin.RawPointer) -> Int {
bb0(%0: $Builtin.RawPointer):
%adr = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int
%access = begin_access [read] [dynamic] %adr : $*Int
%val = load [trivial] %access : $*Int
end_access %access : $*Int
return %val : $Int
}
// Helper.
struct S {
var x: Int
}
// Check inlined struct element access.
// This only happens when mandatory passes are applied repeatedly.
// e.g. importing from a debug standard library.
//
// CHECK-LABEL: sil hidden [ossa] @inlinedStructElement
sil hidden [ossa] @inlinedStructElement : $@convention(thin) (@inout S) -> Int {
bb0(%0 : $*S):
%2 = begin_access [modify] [static] %0 : $*S
%3 = struct_element_addr %2 : $*S, #S.x
%4 = begin_access [read] [static] %3 : $*Int
%5 = load [trivial] %4 : $*Int
end_access %4 : $*Int
end_access %2 : $*S
return %5 : $Int
}
// Check inlined tuple element access.
// This only happens when mandatory passes are applied repeatedly.
//
// CHECK-LABEL: sil hidden [ossa] @inlinedTupleElement
sil hidden [ossa] @inlinedTupleElement : $@convention(thin) (@inout (Int, Int)) -> Int {
bb0(%0 : $*(Int, Int)):
%2 = begin_access [modify] [static] %0 : $*(Int, Int)
%3 = tuple_element_addr %2 : $*(Int, Int), 0
%4 = begin_access [read] [static] %3 : $*Int
%5 = load [trivial] %4 : $*Int
end_access %4 : $*Int
end_access %2 : $*(Int, Int)
return %5 : $Int
}
// Check inlined enum access.
// This only happens when mandatory passes are applied repeatedly.
//
// CHECK-LABEL: sil hidden [ossa] @inlinedEnumValue
sil hidden [ossa] @inlinedEnumValue : $@convention(thin) (Int) -> (@out Optional<Int>, Int) {
bb0(%0 : $*Optional<Int>, %1 : $Int):
%6 = unchecked_take_enum_data_addr %0 : $*Optional<Int>, #Optional.some!enumelt.1
%7 = begin_access [read] [static] %6 : $*Int
%8 = load [trivial] %7 : $*Int
end_access %7 : $*Int
return %8 : $Int
}
// Helper.
class Storage {}
// Check inlined array access.
// This only happens when mandatory passes are applied repeatedly.
//
// CHECK-LABEL: sil hidden [ossa] @inlinedArrayProp
sil hidden [ossa] @inlinedArrayProp : $@convention(thin) (@guaranteed Storage, Builtin.Word) -> Int {
bb0(%0 : @guaranteed $Storage, %1 : $Builtin.Word):
%2 = ref_tail_addr %0 : $Storage, $UInt
%3 = begin_access [read] [static] %2 : $*UInt
%4 = tail_addr %3 : $*UInt, %1 : $Builtin.Word, $Int
%5 = begin_access [read] [static] %4 : $*Int
%6 = index_addr %5 : $*Int, %1 : $Builtin.Word
%7 = begin_access [read] [static] %6 : $*Int
%8 = load [trivial] %7 : $*Int
end_access %7 : $*Int
end_access %5 : $*Int
end_access %3 : $*UInt
return %8 : $Int
}
// Conflicts involving noescape closures.
sil hidden [ossa] @closureThatModifiesCaptureAndTakesInout: $@convention(thin) (@inout Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int):
%2 = begin_access [modify] [unknown] %1 : $*Int // expected-note {{conflicting access is here}}
end_access %2 : $*Int
%3 = tuple ()
return %3 : $()
}
// FIXME: We should prevent SILGen from emitting such a thing because the only
// way to distinguish a capture from a regular @inout argument here is by the
// @inout_aliasable convention. When we eliminate that convention we should make
// sure that whenever we promote a closure from a @callee_guaranteed @noescape
// function type to @conventio(thin), we insert access enforcement on the caller
// side for captured variables.
//
// CHECK-LABEL: sil hidden [ossa] @inProgressModifyModifyConflictWithCallToClosure
sil hidden [ossa] @inProgressModifyModifyConflictWithCallToClosure : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @closureThatModifiesCaptureAndTakesInout: $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%8 = apply %4(%5, %3) : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
end_access %5: $*Int
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
sil hidden [ossa] @closureWithArgument_1 : $@convention(thin) (Int, @inout_aliasable Int) -> () {
bb0(%0 : $Int, %1 : $*Int):
%2 = begin_access [modify] [unknown] %1 : $*Int // expected-note 2 {{conflicting access is here}}
end_access %2 : $*Int
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil hidden [ossa] @inProgressConflictWithNoEscapeClosureArgument
sil hidden [ossa] @inProgressConflictWithNoEscapeClosureArgument : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeClosureTakingArgument : $@convention(thin) (@inout Int, @noescape @owned @callee_owned (Int) -> ()) -> ()
%5 = function_ref @closureWithArgument_1 : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%6 = partial_apply %5(%3) : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %6 : $@callee_owned (Int) -> () to $@callee_owned @noescape (Int) -> ()
%7 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%8 = apply %4(%7, %conv) : $@convention(thin) (@inout Int, @noescape @owned @callee_owned (Int) -> ()) -> ()
end_access %7: $*Int
destroy_value %6 : $@callee_owned (Int) -> ()
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: sil hidden [ossa] @inProgressConflictWithNoEscapeGuaranteedClosureArgument : $@convention(thin) (Int) -> () {
sil hidden [ossa] @inProgressConflictWithNoEscapeGuaranteedClosureArgument : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeGuaranteedClosureTakingArgument : $@convention(thin) (@inout Int, @noescape @guaranteed @callee_guaranteed (Int) -> ()) -> ()
%5 = function_ref @closureWithArgument_1 : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%6 = partial_apply [callee_guaranteed] %5(%3) : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %6 : $@callee_guaranteed (Int) -> () to $@callee_guaranteed @noescape (Int) -> ()
%bconv = begin_borrow %conv : $@callee_guaranteed @noescape (Int) -> ()
%7 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%8 = apply %4(%7, %bconv) : $@convention(thin) (@inout Int, @noescape @guaranteed @callee_guaranteed (Int) -> ()) -> ()
end_access %7: $*Int
end_borrow %bconv : $@callee_guaranteed @noescape (Int) -> ()
destroy_value %6 : $@callee_guaranteed (Int) -> ()
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
sil hidden [ossa] @closureThatModifiesCapture_2 : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = begin_access [modify] [unknown] %0 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
end_access %1 : $*Int
%2 = tuple ()
return %2 : $()
}
// CHECK-LABEL: sil hidden [ossa] @inProgressReadModifyConflictWithNoEscapeClosureArgument
sil hidden [ossa] @inProgressReadModifyConflictWithNoEscapeClosureArgument : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeClosure : $@convention(thin) (@inout Int, @noescape @owned @callee_owned () -> ()) -> ()
%5 = function_ref @closureThatModifiesCapture_2 : $@convention(thin) (@inout_aliasable Int) -> ()
%6 = partial_apply %5(%3) : $@convention(thin) (@inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %6 : $@callee_owned () -> () to $@callee_owned @noescape () -> ()
%7 = begin_access [read] [unknown] %3 : $*Int // expected-note {{conflicting access is here}}
%8 = apply %4(%3, %conv) : $@convention(thin) (@inout Int, @noescape @owned @callee_owned () -> ()) -> ()
end_access %7: $*Int
destroy_value %6 : $@callee_owned () -> ()
destroy_value %2 : ${ var Int }
%9 = tuple ()
return %9 : $()
}
sil hidden [ossa] @closureWithConcreteReturn : $@convention(thin) (Int, @inout_aliasable Int) -> (Int) {
bb0(%0 : $Int, %1 : $*Int):
%2 = begin_access [modify] [unknown] %1 : $*Int // expected-note {{conflicting access is here}}
end_access %2 : $*Int
return %0 : $Int
}
sil [reabstraction_thunk] @thunkForClosureWithConcreteReturn : $@convention(thin) (Int, @noescape @callee_owned (Int) -> Int) -> @out Int
// CHECK-LABEL: sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithReabstractionThunk
sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithReabstractionThunk : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeClosureWithGenericReturn : $@convention(thin) <T_0> (@inout Int, @noescape @callee_owned (Int) -> @out T_0) -> ()
%5 = function_ref @closureWithConcreteReturn : $@convention(thin) (Int, @inout_aliasable Int) -> (Int)
%6 = partial_apply %5(%3) : $@convention(thin) (Int, @inout_aliasable Int) -> (Int)
%7 = convert_escape_to_noescape %6 : $@callee_owned (Int) -> Int to $@noescape @callee_owned (Int) -> Int
%8 = function_ref @thunkForClosureWithConcreteReturn : $@convention(thin) (Int, @noescape @callee_owned (Int) -> Int) -> @out Int
%9 = partial_apply %8(%7) : $@convention(thin) (Int, @noescape @callee_owned (Int) -> Int) -> @out Int
%10 = convert_escape_to_noescape %9 : $@callee_owned (Int) -> @out Int to $@noescape @callee_owned (Int) -> @out Int
%11 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%12 = apply %4<Int>(%11, %10) : $@convention(thin) <T_0> (@inout Int, @noescape @callee_owned (Int) -> @out T_0) -> ()
end_access %11: $*Int
destroy_value %9 : $@callee_owned (Int) -> @out Int
destroy_value %6 : $@callee_owned (Int) -> Int
destroy_value %2 : ${ var Int }
%13 = tuple ()
return %13 : $()
}
sil [reabstraction_thunk] @thunkForCalleeGuaranteed : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
sil [reabstraction_thunk] @withoutActuallyEscapingThunk : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
sil hidden [ossa] @closureThatModifiesCapture_1: $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%1 = begin_access [modify] [unknown] %0 : $*Int // expected-note 3{{conflicting access is here}}
end_access %1 : $*Int
%2 = tuple ()
return %2 : $()
}
// CHECK-LABEL: sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithBlockStorage
sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithBlockStorage : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeBlockClosure : $@convention(thin) (@inout Int, @owned @convention(block) @noescape () -> ()) -> ()
%5 = function_ref @closureThatModifiesCapture_1 : $@convention(thin) (@inout_aliasable Int) -> ()
%6 = partial_apply [callee_guaranteed] %5(%3) : $@convention(thin) (@inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %6 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%thunk = function_ref @withoutActuallyEscapingThunk : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel = partial_apply [callee_guaranteed] %thunk(%conv) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel2 = mark_dependence %sentinel : $@callee_guaranteed () -> () on %conv : $@noescape @callee_guaranteed () -> ()
%sentinel3 = copy_value %sentinel2 : $@callee_guaranteed () -> ()
%7 = alloc_stack $@block_storage @callee_guaranteed () -> ()
%8 = project_block_storage %7 : $*@block_storage @callee_guaranteed () -> ()
store %sentinel3 to [init] %8 : $*@callee_guaranteed () -> ()
%10 = function_ref @thunkForCalleeGuaranteed : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
%11 = init_block_storage_header %7 : $*@block_storage @callee_guaranteed () -> (), invoke %10 : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) @noescape () -> ()
%12 = copy_block %11 : $@convention(block) @noescape () -> ()
%13 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%14 = apply %4(%13, %12) : $@convention(thin) (@inout Int, @owned @convention(block) @noescape () -> ()) -> ()
end_access %13 : $*Int
destroy_addr %8 : $*@callee_guaranteed() -> ()
dealloc_stack %7 : $*@block_storage @callee_guaranteed () -> ()
destroy_value %sentinel2 : $@callee_guaranteed () -> ()
destroy_value %6 : $@callee_guaranteed () -> ()
destroy_value %2 : ${ var Int }
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithOptionalBlockStorage
sil hidden [ossa] @inProgressConflictWithNoEscapeClosureWithOptionalBlockStorage : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeOptionalBlockClosure : $@convention(thin) (@inout Int, @owned Optional<@convention(block) @noescape () -> ()>) -> ()
%5 = function_ref @closureThatModifiesCapture_1 : $@convention(thin) (@inout_aliasable Int) -> ()
%6 = partial_apply [callee_guaranteed] %5(%3) : $@convention(thin) (@inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %6 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%thunk = function_ref @withoutActuallyEscapingThunk : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel = partial_apply [callee_guaranteed] %thunk(%conv) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel2 = mark_dependence %sentinel : $@callee_guaranteed () -> () on %conv : $@noescape @callee_guaranteed () -> ()
%sentinel3 = copy_value %sentinel2 : $@callee_guaranteed () -> ()
%7 = alloc_stack $@block_storage @callee_guaranteed () -> ()
%8 = project_block_storage %7 : $*@block_storage @callee_guaranteed () -> ()
store %sentinel3 to [init] %8 : $*@callee_guaranteed () -> ()
%10 = function_ref @thunkForCalleeGuaranteed : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
%11 = init_block_storage_header %7 : $*@block_storage @callee_guaranteed () -> (), invoke %10 : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) @noescape () -> ()
%12 = copy_block %11 : $@convention(block) @noescape () -> ()
%13 = enum $Optional<@convention(block) @noescape () -> ()>, #Optional.some!enumelt.1, %12 : $@convention(block) @noescape () -> ()
%14 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%15 = apply %4(%14, %13) : $@convention(thin) (@inout Int, @owned Optional<@convention(block) @noescape () -> ()>) -> ()
end_access %14 : $*Int
destroy_addr %8 : $*@callee_guaranteed () -> ()
dealloc_stack %7 : $*@block_storage @callee_guaranteed () -> ()
destroy_value %sentinel2 : $@callee_guaranteed () -> ()
destroy_value %6 : $@callee_guaranteed () -> ()
destroy_value %2 : ${ var Int }
%ret = tuple ()
return %ret : $()
}
// Stored property relaxation.
struct NestedStructWithStoredProps {
var a: Int
var b: Int
}
struct StructWithStoredProps {
var x: Int
var y: Int
var n: NestedStructWithStoredProps
}
sil [ossa] @takesInoutIntAndStructWithStoredProps : $@convention(thin) (@inout Int, @inout StructWithStoredProps) -> ()
// CHECK-LABEL: sil hidden [ossa] @twoSeparateStoredProperties
sil hidden [ossa] @twoSeparateStoredProperties : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var StructWithStoredProps }
%3 = project_box %2 : ${ var StructWithStoredProps }, 0
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps
%6 = struct_element_addr %5 : $*StructWithStoredProps, #StructWithStoredProps.x
%7 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // no-error
%8 = struct_element_addr %7 : $*StructWithStoredProps, #StructWithStoredProps.y
%9 = apply %4(%6, %8) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*StructWithStoredProps
end_access %5: $*StructWithStoredProps
destroy_value %2 : ${ var StructWithStoredProps }
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil hidden [ossa] @twoSeparateNestedStoredProperties
sil hidden [ossa] @twoSeparateNestedStoredProperties : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var StructWithStoredProps }
%3 = project_box %2 : ${ var StructWithStoredProps }, 0
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps
%6 = struct_element_addr %5 : $*StructWithStoredProps, #StructWithStoredProps.n
%7 = struct_element_addr %6 : $*NestedStructWithStoredProps, #NestedStructWithStoredProps.a
%8 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // no-error
%9 = struct_element_addr %8 : $*StructWithStoredProps, #StructWithStoredProps.n
%10 = struct_element_addr %9 : $*NestedStructWithStoredProps, #NestedStructWithStoredProps.b
%11 = apply %4(%7, %10) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %8 : $*StructWithStoredProps
end_access %5: $*StructWithStoredProps
destroy_value %2 : ${ var StructWithStoredProps }
%12 = tuple ()
return %12 : $()
}
// CHECK-LABEL: sil hidden [ossa] @theSameStoredProperty
sil hidden [ossa] @theSameStoredProperty : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var StructWithStoredProps }
%3 = project_box %2 : ${ var StructWithStoredProps }, 0
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = struct_element_addr %5 : $*StructWithStoredProps, #StructWithStoredProps.x
%7 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-note {{conflicting access is here}}
%8 = struct_element_addr %7 : $*StructWithStoredProps, #StructWithStoredProps.x
%9 = apply %4(%6, %8) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*StructWithStoredProps
end_access %5: $*StructWithStoredProps
destroy_value %2 : ${ var StructWithStoredProps }
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil hidden [ossa] @storedPropertyAndAggregate
sil hidden [ossa] @storedPropertyAndAggregate : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var StructWithStoredProps }
%3 = project_box %2 : ${ var StructWithStoredProps }, 0
%4 = function_ref @takesInoutIntAndStructWithStoredProps : $@convention(thin) (@inout Int, @inout StructWithStoredProps) -> ()
%5 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = struct_element_addr %5 : $*StructWithStoredProps, #StructWithStoredProps.x
%7 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-note {{conflicting access is here}}
%8 = apply %4(%6, %7) : $@convention(thin) (@inout Int, @inout StructWithStoredProps) -> ()
end_access %7 : $*StructWithStoredProps
end_access %5: $*StructWithStoredProps
destroy_value %2 : ${ var StructWithStoredProps }
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: sil hidden [ossa] @nestedStoredPropertyAndAggregate
sil hidden [ossa] @nestedStoredPropertyAndAggregate : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var StructWithStoredProps }
%3 = project_box %2 : ${ var StructWithStoredProps }, 0
%4 = function_ref @takesInoutIntAndStructWithStoredProps : $@convention(thin) (@inout Int, @inout StructWithStoredProps) -> ()
%5 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = struct_element_addr %5 : $*StructWithStoredProps, #StructWithStoredProps.n
%7 = struct_element_addr %6 : $*NestedStructWithStoredProps, #NestedStructWithStoredProps.a
%8 = begin_access [modify] [unknown] %3 : $*StructWithStoredProps // expected-note {{conflicting access is here}}
%9 = struct_element_addr %8 : $*StructWithStoredProps, #StructWithStoredProps.n
end_access %8 : $*StructWithStoredProps
end_access %5: $*StructWithStoredProps
destroy_value %2 : ${ var StructWithStoredProps }
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil hidden [ossa] @twoSeparateTupleElements
sil hidden [ossa] @twoSeparateTupleElements : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var (Int, Int) }
%3 = project_box %2 : ${ var (Int, Int) }, 0
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*(Int, Int)
%6 = tuple_element_addr %5 : $*(Int, Int), 0
%7 = begin_access [modify] [unknown] %3 : $*(Int, Int) // no-error
%8 = tuple_element_addr %7 : $*(Int, Int), 1
%9 = apply %4(%6, %8) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*(Int, Int)
end_access %5: $*(Int, Int)
destroy_value %2 : ${ var (Int, Int) }
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil hidden [ossa] @sameTupleElement
sil hidden [ossa] @sameTupleElement : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var (Int, Int) }
%3 = project_box %2 : ${ var (Int, Int) }, 0
%4 = function_ref @takesTwoInouts : $@convention(thin) (@inout Int, @inout Int) -> ()
%5 = begin_access [modify] [unknown] %3 : $*(Int, Int) // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%6 = tuple_element_addr %5 : $*(Int, Int), 0
%7 = begin_access [modify] [unknown] %3 : $*(Int, Int) // expected-note {{conflicting access is here}}
%8 = tuple_element_addr %7 : $*(Int, Int), 0
%9 = apply %4(%6, %8) : $@convention(thin) (@inout Int, @inout Int) -> ()
end_access %7 : $*(Int, Int)
end_access %5: $*(Int, Int)
destroy_value %2 : ${ var (Int, Int) }
%10 = tuple ()
return %10 : $()
}
sil hidden [ossa] @passNilToNoEscape : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
%4 = enum $Optional<@convention(block) @noescape () -> ()>, #Optional.none!enumelt
%5 = function_ref @takesInoutAndNoEscapeOptionalBlockClosure : $@convention(thin) (@inout Int, @owned Optional<@convention(block) @noescape () -> ()>) -> ()
%6 = apply %5(%3, %4) : $@convention(thin) (@inout Int, @owned Optional<@convention(block) @noescape () -> ()>) -> ()
destroy_value %2 : ${ var Int }
%7 = tuple ()
return %7 : $()
}
sil private [ossa] @closureForDirectPartialApplyTakingInout : $@convention(thin) (@inout Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $*Int):
%access = begin_access [read] [unknown] %1 : $*Int // expected-note 3 {{conflicting access is here}}
%val = load [trivial] %access : $*Int
end_access %access : $*Int
%v = tuple ()
return %v : $()
}
sil hidden [ossa] @directPartialApplyTakingInout : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%box = alloc_box ${ var Int }, var, name "i"
%boxadr = project_box %box : ${ var Int }, 0
store %0 to [trivial] %boxadr : $*Int
%f = function_ref @closureForDirectPartialApplyTakingInout : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
%pa = partial_apply [callee_guaranteed] %f(%boxadr) : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
%nepa = convert_escape_to_noescape %pa : $@callee_guaranteed (@inout Int) -> () to $@noescape @callee_guaranteed (@inout Int) -> ()
%access = begin_access [modify] [unknown] %boxadr : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%call = apply %nepa(%access) : $@noescape @callee_guaranteed (@inout Int) -> ()
end_access %access : $*Int
destroy_value %pa : $@callee_guaranteed (@inout Int) -> ()
destroy_value %box : ${ var Int }
%v = tuple ()
return %v : $()
}
sil private [ossa] @closureForDirectPartialApplyChain : $@convention(thin) (@inout Int, Int, @inout_aliasable Int) -> () {
bb0(%0 : $*Int, %1 : $Int, %2 : $*Int):
%access = begin_access [read] [unknown] %2 : $*Int // expected-note {{conflicting access is here}}
%val = load [trivial] %access : $*Int
end_access %access : $*Int
%v = tuple ()
return %v : $()
}
sil hidden [ossa] @directPartialApplyChain : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%box = alloc_box ${ var Int }, var, name "i"
%boxadr = project_box %box : ${ var Int }, 0
store %0 to [trivial] %boxadr : $*Int
%f = function_ref @closureForDirectPartialApplyChain : $@convention(thin) (@inout Int, Int, @inout_aliasable Int) -> ()
%pa1 = partial_apply [callee_guaranteed] %f(%boxadr) : $@convention(thin) (@inout Int, Int, @inout_aliasable Int) -> ()
%pa2 = partial_apply [callee_guaranteed] %pa1(%0) : $@callee_guaranteed (@inout Int, Int) -> ()
%nepa = convert_escape_to_noescape %pa2 : $@callee_guaranteed (@inout Int) -> () to $@noescape @callee_guaranteed (@inout Int) -> ()
%access = begin_access [modify] [unknown] %boxadr : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%call = apply %nepa(%access) : $@noescape @callee_guaranteed (@inout Int) -> ()
end_access %access : $*Int
destroy_value %pa2 : $@callee_guaranteed (@inout Int) -> ()
destroy_value %box : ${ var Int }
%v = tuple ()
return %v : $()
}
sil private [ossa] @closureForPartialApplyArgChain : $@convention(thin) (Int, @inout_aliasable Int) -> () {
bb0(%0 : $Int, %1 : $*Int):
%access = begin_access [read] [unknown] %1 : $*Int // expected-note {{conflicting access is here}}
%val = load [trivial] %access : $*Int
end_access %access : $*Int
%v = tuple ()
return %v : $()
}
sil hidden [ossa] @partialApplyArgChain : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = alloc_box ${ var Int }
%3 = project_box %2 : ${ var Int }, 0
store %0 to [trivial] %3 : $*Int
%4 = function_ref @takesInoutAndNoEscapeClosure : $@convention(thin) (@inout Int, @noescape @owned @callee_owned () -> ()) -> ()
%5 = function_ref @closureForPartialApplyArgChain : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%6 = partial_apply %5(%3) : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%7 = partial_apply %6(%0) : $@callee_owned (Int) -> ()
%conv = convert_escape_to_noescape %7 : $@callee_owned () -> () to $@callee_owned @noescape () -> ()
%8 = begin_access [modify] [unknown] %3 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%9 = apply %4(%8, %conv) : $@convention(thin) (@inout Int, @noescape @owned @callee_owned () -> ()) -> ()
end_access %8: $*Int
destroy_value %7 : $@callee_owned () -> ()
destroy_value %2 : ${ var Int }
%v = tuple ()
return %v : $()
}
class SomeClass {}
// 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 that this doesn't trigger the DiagnoseStaticExclusivity
// assert that all accesses have a valid AccessedStorage source.
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 : $()
}
sil [ossa] @addressor : $@convention(thin) () -> UnsafeMutablePointer<Int32>
// An addressor produces an unsafely accessed RawPointer. Pass the
// address to an inout can result in an enforced (unknown) access on
// the unsafe address. We need to handle this case without asserting.
sil [ossa] @addressorAccess : $@convention(thin) (@guaranteed ClassWithStoredProperty, Int32) -> () {
bb0(%0 : @guaranteed $ClassWithStoredProperty, %1 : $Int32):
%f = function_ref @addressor : $@convention(thin) () -> UnsafeMutablePointer<Int32>
%up = apply %f() : $@convention(thin) () -> UnsafeMutablePointer<Int32>
%o = unchecked_ref_cast %0 : $ClassWithStoredProperty to $Builtin.NativeObject
%ptr = struct_extract %up : $UnsafeMutablePointer<Int32>, #UnsafeMutablePointer._rawValue
%adr = pointer_to_address %ptr : $Builtin.RawPointer to [strict] $*Int32
%dep = mark_dependence %adr : $*Int32 on %o : $Builtin.NativeObject
%a1 = begin_access [modify] [unsafe] %dep : $*Int32
%a2 = begin_access [modify] [static] %a1 : $*Int32
store %1 to [trivial] %a2 : $*Int32
end_access %a2 : $*Int32
end_access %a1 : $*Int32
%v = tuple ()
return %v : $()
}
// <rdar://problem/41976355> [SR-8201]: Swift 4.2 Crash in DiagnoseStaticExclusivity (llvm_unreachable)
// mutatingNoescapeWithThunk and mutatingNoescapeConflictWithThunk.
// Test that noescape closure verification allows a closure with @inout_aliasable argument convention,
// which may only be used as a nonescaping closure, can be passed to a reabstraction thunk
// without the @noescape function-type argument convention.
sil [ossa] @mutatingNoescapeHelper : $@convention(thin) (Optional<UnsafePointer<Int32>>, @inout_aliasable Int32) -> () {
bb0(%0 : $Optional<UnsafePointer<Int32>>, %1 : $*Int32):
%up = unchecked_enum_data %0 : $Optional<UnsafePointer<Int32>>, #Optional.some!enumelt.1
%p = struct_extract %up : $UnsafePointer<Int32>, #UnsafePointer._rawValue
%adr = pointer_to_address %p : $Builtin.RawPointer to [strict] $*Int32
%val = load [trivial] %adr : $*Int32
%access = begin_access [modify] [unknown] %1 : $*Int32 // expected-note {{conflicting access is here}}
store %val to [trivial] %access : $*Int32
end_access %access : $*Int32
%v = tuple ()
return %v : $()
}
sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @mutatingNoescapeThunk : $@convention(thin) (UnsafePointer<Int32>, @guaranteed @callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()) -> () {
bb0(%0 : $UnsafePointer<Int32>, %1 : @guaranteed $@callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()):
%e = enum $Optional<UnsafePointer<Int32>>, #Optional.some!enumelt.1, %0 : $UnsafePointer<Int32>
%c = apply %1(%e) : $@callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()
%v = tuple ()
return %v : $()
}
sil [ossa] @takeMutatingNoescapeClosure : $@convention(thin) <Ï„_0_0> (UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
// A (mutating) closure taking an @inout_aliasable argument may be
// passed to a reabstraction_thunk as an escaping function type. This
// is valid as long as the thunk is only used as a @nosecape type.
sil [ossa] @mutatingNoescapeWithThunk : $@convention(method) (UnsafePointer<Int32>, @inout Int32) -> () {
bb0(%0 : $UnsafePointer<Int32>, %1 : $*Int32):
%f1 = function_ref @mutatingNoescapeHelper : $@convention(thin) (Optional<UnsafePointer<Int32>>, @inout_aliasable Int32) -> ()
%pa1 = partial_apply [callee_guaranteed] %f1(%1) : $@convention(thin) (Optional<UnsafePointer<Int32>>, @inout_aliasable Int32) -> ()
%thunk = function_ref @mutatingNoescapeThunk : $@convention(thin) (UnsafePointer<Int32>, @guaranteed @callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()) -> ()
%pa2 = partial_apply [callee_guaranteed] %thunk(%pa1) : $@convention(thin) (UnsafePointer<Int32>, @guaranteed @callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()) -> ()
%closure = convert_escape_to_noescape [not_guaranteed] %pa2 : $@callee_guaranteed (UnsafePointer<Int32>) -> () to $@noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()
%f2 = function_ref @takeMutatingNoescapeClosure : $@convention(thin) <Ï„_0_0> (UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
%call = apply %f2<Int32>(%0, %closure) : $@convention(thin) <Ï„_0_0> (UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
destroy_value %pa2 : $@callee_guaranteed (UnsafePointer<Int32>) -> ()
%v = tuple ()
return %v : $()
}
sil [ossa] @takeInoutAndMutatingNoescapeClosure : $@convention(thin) <Ï„_0_0> (@inout Int32, UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
sil [ossa] @mutatingNoescapeConflictWithThunk : $@convention(method) (UnsafePointer<Int32>, @inout Int32) -> () {
bb0(%0 : $UnsafePointer<Int32>, %1 : $*Int32):
%f1 = function_ref @mutatingNoescapeHelper : $@convention(thin) (Optional<UnsafePointer<Int32>>, @inout_aliasable Int32) -> ()
%pa1 = partial_apply [callee_guaranteed] %f1(%1) : $@convention(thin) (Optional<UnsafePointer<Int32>>, @inout_aliasable Int32) -> ()
%thunk = function_ref @mutatingNoescapeThunk : $@convention(thin) (UnsafePointer<Int32>, @guaranteed @callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()) -> ()
%pa2 = partial_apply [callee_guaranteed] %thunk(%pa1) : $@convention(thin) (UnsafePointer<Int32>, @guaranteed @callee_guaranteed (Optional<UnsafePointer<Int32>>) -> ()) -> ()
%closure = convert_escape_to_noescape [not_guaranteed] %pa2 : $@callee_guaranteed (UnsafePointer<Int32>) -> () to $@noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()
%f2 = function_ref @takeInoutAndMutatingNoescapeClosure : $@convention(thin) <Ï„_0_0> (@inout Int32, UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
%access = begin_access [modify] [unknown] %1 : $*Int32 // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%call = apply %f2<Int32>(%access, %0, %closure) : $@convention(thin) <Ï„_0_0> (@inout Int32, UnsafePointer<Ï„_0_0>, @noescape @callee_guaranteed (UnsafePointer<Int32>) -> ()) -> ()
destroy_value %pa2 : $@callee_guaranteed (UnsafePointer<Int32>) -> ()
end_access %access : $*Int32
%v = tuple ()
return %v : $()
}
// <rdar://problem/41660554> Swift CI (macOS release master, OSS): SIL verification failed: Unknown formal access pattern: storage
// Test access marker verification of a KeyPath projection with nested @inout access after inlining.
sil @takeInoutInt : $@convention(thin) (@inout Int) -> ()
// The compiler intrinsic _projectXXXKeyPath returns a tuple of
// UnsafePointer and Optional AnyObject. After inlining, the unsafe
// pointer may appear to originate from anywhere, including a phi.
// There's currently no way to tell that the UnsafePointer originated
// from a KeyPath projection. This pattern could occur with any
// addressor. In either case, the nested access is valid but
// unidentified. Addressors that require enforcement must start a
// dynamic access within the addressor itself, before returning an
// UnsafePointer.
sil [ossa] @testNestedKeypathAccess : $@convention(thin) (@guaranteed (UnsafeMutablePointer<Int>, Optional<AnyObject>)) -> () {
bb0(%0 : @guaranteed $(UnsafeMutablePointer<Int>, Optional<AnyObject>)):
%up = tuple_extract %0 : $(UnsafeMutablePointer<Int>, Optional<AnyObject>), 0
%o = tuple_extract %0 : $(UnsafeMutablePointer<Int>, Optional<AnyObject>), 1
%p = struct_extract %up : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
%adr = pointer_to_address %p : $Builtin.RawPointer to [strict] $*Int
%dep = mark_dependence %adr : $*Int on %o : $Optional<AnyObject>
%access = begin_access [modify] [static] %dep : $*Int
%f = function_ref @takeInoutInt : $@convention(thin) (@inout Int) -> ()
%call = apply %f(%access) : $@convention(thin) (@inout Int) -> ()
end_access %access : $*Int
%v = tuple ()
return %v : $()
}
// Test a conflict on a noescape closure where multiple closures may be conditionally stored in an ObjC block.
sil hidden [ossa] @noEscapeClosureWithConditionalBlockStorage : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%box = alloc_box ${ var Int }
%boxadr = project_box %box : ${ var Int }, 0
store %0 to [trivial] %boxadr : $*Int
%closure = function_ref @closureThatModifiesCapture_1 : $@convention(thin) (@inout_aliasable Int) -> ()
%pa = partial_apply [callee_guaranteed] %closure(%boxadr) : $@convention(thin) (@inout_aliasable Int) -> ()
%conv = convert_escape_to_noescape %pa : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%thunk = function_ref @withoutActuallyEscapingThunk : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel = partial_apply [callee_guaranteed] %thunk(%conv) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
%sentinel2 = mark_dependence %sentinel : $@callee_guaranteed () -> () on %conv : $@noescape @callee_guaranteed () -> ()
%sentinel3 = copy_value %sentinel2 : $@callee_guaranteed () -> ()
%calleethunk = function_ref @thunkForCalleeGuaranteed : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
cond_br undef, bb1, bb2
bb1:
%bs1 = alloc_stack $@block_storage @callee_guaranteed () -> ()
%pbs1 = project_block_storage %bs1 : $*@block_storage @callee_guaranteed () -> ()
store %sentinel3 to [init] %pbs1 : $*@callee_guaranteed () -> ()
%initblock1 = init_block_storage_header %bs1 : $*@block_storage @callee_guaranteed () -> (), invoke %calleethunk : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) @noescape () -> ()
%copyblock1 = copy_block %initblock1 : $@convention(block) @noescape () -> ()
destroy_addr %pbs1 : $*@callee_guaranteed() -> ()
dealloc_stack %bs1 : $*@block_storage @callee_guaranteed () -> ()
destroy_value %sentinel2 : $@callee_guaranteed () -> ()
br bb3(%copyblock1 : $@convention(block) @noescape () -> ())
bb2:
%bs2 = alloc_stack $@block_storage @callee_guaranteed () -> ()
%pbs2 = project_block_storage %bs2 : $*@block_storage @callee_guaranteed () -> ()
store %sentinel3 to [init] %pbs2 : $*@callee_guaranteed () -> ()
%initblock2 = init_block_storage_header %bs2 : $*@block_storage @callee_guaranteed () -> (), invoke %calleethunk : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) @noescape () -> ()
%copyblock2 = copy_block %initblock2 : $@convention(block) @noescape () -> ()
destroy_addr %pbs2 : $*@callee_guaranteed() -> ()
dealloc_stack %bs2 : $*@block_storage @callee_guaranteed () -> ()
destroy_value %sentinel2 : $@callee_guaranteed () -> ()
br bb3(%copyblock2 : $@convention(block) @noescape () -> ())
bb3(%block : @owned $@convention(block) @noescape () -> ()):
%access = begin_access [modify] [unknown] %boxadr : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%f = function_ref @takesInoutAndNoEscapeBlockClosure : $@convention(thin) (@inout Int, @owned @convention(block) @noescape () -> ()) -> ()
%call = apply %f(%access, %block) : $@convention(thin) (@inout Int, @owned @convention(block) @noescape () -> ()) -> ()
end_access %access : $*Int
destroy_value %pa : $@callee_guaranteed () -> ()
destroy_value %box : ${ var Int }
%ret = tuple ()
return %ret : $()
}
// -----------------------------------------------------------------------------
// <rdar://problem/42242406> [SR-8266]: Compiler crash when checking
// exclusivity of inout alias:
// closureWithNoCapture
// closureWithConflict,
// partialApplyPhiThunk
// testPartialApplyPhi.
// testDirectPartialApplyPhi.
//
// Test that 'checkNoEscapePartialApply' does not assert on a noescape
// closure passed through a block argument.
sil hidden [ossa] @closureWithNoCapture : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%2 = tuple ()
return %2 : $()
}
sil hidden [ossa] @closureWithConflict : $@convention(thin) (Int, @inout_aliasable Int) -> () {
bb0(%0 : $Int, %1 : $*Int):
%2 = begin_access [modify] [unknown] %1 : $*Int // expected-note {{conflicting access is here}}
end_access %2 : $*Int
%v = tuple ()
return %v : $()
}
sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @partialApplyPhiThunk : $@convention(thin) (@in_guaranteed Int, @guaranteed @noescape @callee_guaranteed (Int) -> (@error Error)) -> (@error Error) {
bb0(%0 : $*Int, %1 : $@noescape @callee_guaranteed (Int) -> (@error Error)):
%val = load [trivial] %0 : $*Int
try_apply %1(%val) : $@noescape @callee_guaranteed (Int) -> (@error Error), normal bb1, error bb2
bb1(%v : $()):
return %v : $()
bb2(%5 : @owned $Error):
throw %5 : $Error
}
sil [ossa] @takeGenericNoEscapeFunction : $@convention(method) <Ï„_0_0> (@inout Ï„_0_0, @noescape @callee_guaranteed (@in_guaranteed Ï„_0_0) -> (@error Error)) -> (@error Error)
// CHECK-LABEL: sil [ossa] @testPartialApplyPhi
sil [ossa] @testPartialApplyPhi : $@convention(thin) (Int, @inout Int) -> (@error Error) {
bb0(%0 : $Int, %1 : $*Int):
cond_br undef, bb1, bb2
bb1:
%f1 = function_ref @closureWithNoCapture : $@convention(thin) (Int) -> ()
%pa1 = partial_apply [callee_guaranteed] %f1() : $@convention(thin) (Int) -> ()
br bb3(%pa1 : $@callee_guaranteed (Int) -> ())
bb2:
%f2 = function_ref @closureWithConflict : $@convention(thin) (Int, @inout_aliasable Int) -> ()
%pa2 = partial_apply [callee_guaranteed] %f2(%1) : $@convention(thin) (Int, @inout_aliasable Int) -> ()
br bb3(%pa2 : $@callee_guaranteed (Int) -> ())
bb3(%pa3 : @owned $@callee_guaranteed (Int) -> ()):
%cvt3 = convert_function %pa3 : $@callee_guaranteed (Int) -> () to $@callee_guaranteed (Int) -> (@error Error)
%esc3 = convert_escape_to_noescape [not_guaranteed] %cvt3 : $@callee_guaranteed (Int) -> (@error Error) to $@noescape @callee_guaranteed (Int) -> (@error Error)
%f3 = function_ref @partialApplyPhiThunk : $@convention(thin) (@in_guaranteed Int, @guaranteed @noescape @callee_guaranteed (Int) -> (@error Error)) -> (@error Error)
%pa4 = partial_apply [callee_guaranteed] %f3(%esc3) : $@convention(thin) (@in_guaranteed Int, @guaranteed @noescape @callee_guaranteed (Int) -> (@error Error)) -> (@error Error)
%esc4 = convert_escape_to_noescape [not_guaranteed] %pa4 : $@callee_guaranteed (@in_guaranteed Int) -> (@error Error) to $@noescape @callee_guaranteed (@in_guaranteed Int) -> (@error Error)
// ClosureLifetimeFixup has not run yet, so these destroys are "incorrect".
destroy_value %pa4 : $@callee_guaranteed (@in_guaranteed Int) -> (@error Error)
destroy_value %cvt3 : $@callee_guaranteed (Int) -> (@error Error)
%access = begin_access [modify] [static] %1 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%f4 = function_ref @takeGenericNoEscapeFunction : $@convention(method) <Ï„_0_0> (@inout Ï„_0_0, @noescape @callee_guaranteed (@in_guaranteed Ï„_0_0) -> (@error Error)) -> (@error Error)
try_apply %f4<Int>(%access, %esc4) : $@convention(method) <Ï„_0_0> (@inout Ï„_0_0, @noescape @callee_guaranteed (@in_guaranteed Ï„_0_0) -> (@error Error)) -> (@error Error), normal bb4, error bb5
bb4(%v : $()):
end_access %access : $*Int
return %v : $()
bb5(%e : @owned $Error):
end_access %access : $*Int
throw %e : $Error
}
// CHECK-LABEL: sil [ossa] @testDirectPartialApplyPhi
sil [ossa] @testDirectPartialApplyPhi : $@convention(thin) (@inout Int) -> (@error Error) {
bb0(%0 : $*Int):
cond_br undef, bb1, bb2
bb1:
%f1 = function_ref @closureForDirectPartialApplyTakingInout : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
%pa1 = partial_apply [callee_guaranteed] %f1(%0) : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
br bb3(%pa1 : $@callee_guaranteed (@inout Int) -> ())
bb2:
%f2 = function_ref @closureForDirectPartialApplyTakingInout : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
%pa2 = partial_apply [callee_guaranteed] %f2(%0) : $@convention(thin) (@inout Int, @inout_aliasable Int) -> ()
br bb3(%pa2 : $@callee_guaranteed (@inout Int) -> ())
bb3(%pa3 : @owned $@callee_guaranteed (@inout Int) -> ()):
%esc3 = convert_escape_to_noescape [not_guaranteed] %pa3 : $@callee_guaranteed (@inout Int) -> () to $@noescape @callee_guaranteed (@inout Int) -> ()
destroy_value %pa3 : $@callee_guaranteed (@inout Int) -> ()
%access = begin_access [modify] [static] %0 : $*Int // expected-error 2 {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
%call = apply %esc3(%access) : $@noescape @callee_guaranteed (@inout Int) -> ()
end_access %access : $*Int
%v = tuple ()
return %v : $()
}
// -----------------------------------------------------------------------------
// Test withoutActuallyEscaping thunk.
// <rdar://problem/43059088> Assertion in DiagnoseStaticExclusivity
// Noescape closure verification should not assert.
sil @takeEscapingClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
sil private [ossa] @nestedInWithoutActuallyEscapingVerify : $@convention(thin) (@inout_aliasable Int) -> () {
bb0(%0 : $*Int):
%a = begin_access [modify] [unknown] %0 : $*Int
end_access %a : $*Int
%v = tuple ()
return %v : $()
}
// CHECK-LABEL: sil hidden [ossa] @testWithoutActuallyEscapingVerify : $@convention(thin) (@inout Int) -> () {
sil hidden [ossa] @testWithoutActuallyEscapingVerify : $@convention(thin) (@inout Int) -> () {
bb0(%0 : $*Int):
%2 = function_ref @nestedInWithoutActuallyEscapingVerify : $@convention(thin) (@inout_aliasable Int) -> ()
%3 = partial_apply [callee_guaranteed] %2(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
%4 = function_ref @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%3a = copy_value %3 : $@callee_guaranteed () -> ()
%5 = partial_apply [callee_guaranteed] %4(%3a) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%6 = mark_dependence %5 : $@callee_guaranteed () -> () on %3 : $@callee_guaranteed () -> ()
%8 = function_ref @closureForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%9 = apply %8(%6) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%10 = is_escaping_closure %6 : $@callee_guaranteed () -> ()
cond_fail %10 : $Builtin.Int1
destroy_value %3 : $@callee_guaranteed () -> ()
destroy_value %6 : $@callee_guaranteed () -> ()
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] [ossa] @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] [ossa] @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
%1 = apply %0() : $@callee_guaranteed () -> ()
return %1 : $()
}
sil private [ossa] @closureForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
%2 = function_ref @takeEscapingClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%3 = apply %2(%0) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
%4 = tuple ()
return %4 : $()
}
// -----------------------------------------------------------------------------
// Test withoutActuallyEscaping convert_function.
// <rdar://problem/43059088> Assertion in DiagnoseStaticExclusivity
// Noescape closure verification should not assert.
// CHECK-LABEL: sil hidden [ossa] @testWithoutActuallyEscapingBlockVerify : $@convention(thin) (Int) -> () {
// CHECK: convert_function %{{.*}} : $@convention(block) () -> () to [without_actually_escaping] $@convention(block) () -> ()
sil hidden [ossa] @testWithoutActuallyEscapingBlockVerify : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%box = alloc_box ${ var Int }, var, name "localVal"
%projbox = project_box %box : ${ var Int }, 0
store %0 to [trivial] %projbox : $*Int
%closureF = function_ref @testWithoutActuallyEscapingBlockVerifyClosure : $@convention(thin) (@inout_aliasable Int) -> ()
%closure = partial_apply [callee_guaranteed] %closureF(%projbox) : $@convention(thin) (@inout_aliasable Int) -> ()
%block = alloc_stack $@block_storage @callee_guaranteed () -> ()
%blockproj = project_block_storage %block : $*@block_storage @callee_guaranteed () -> ()
store %closure to [init] %blockproj : $*@callee_guaranteed () -> ()
// function_ref thunk for @escaping @callee_guaranteed () -> ()
%thunkF = function_ref @$sIeg_IeyB_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
%initblock_unowned = init_block_storage_header %block : $*@block_storage @callee_guaranteed () -> (), invoke %thunkF : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) () -> ()
%initblock = copy_block %initblock_unowned : $@convention(block) () -> ()
destroy_addr %blockproj : $*@callee_guaranteed () -> ()
dealloc_stack %block : $*@block_storage @callee_guaranteed () -> ()
%borrow = begin_borrow %initblock : $@convention(block) () -> ()
%copy = copy_value %borrow : $@convention(block) () -> ()
%escapingF = convert_function %copy : $@convention(block) () -> () to [without_actually_escaping] $@convention(block) () -> ()
%clauseF = function_ref @testWithoutActuallyEscapingBlockVerifyClause : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
%call = apply %clauseF(%escapingF) : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
destroy_value %escapingF : $@convention(block) () -> ()
end_borrow %borrow : $@convention(block) () -> ()
destroy_value %initblock : $@convention(block) () -> ()
destroy_value %box : ${ var Int }
%v = tuple ()
return %v : $()
}
sil [ossa] @testWithoutActuallyEscapingBlockVerifyClosure : $@convention(thin) (@inout_aliasable Int) -> ()
// thunk for @escaping @callee_guaranteed () -> ()
sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sIeg_IeyB_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> () {
// %0
bb0(%0 : $*@block_storage @callee_guaranteed () -> ()):
%1 = project_block_storage %0 : $*@block_storage @callee_guaranteed () -> ()
%2 = load [copy] %1 : $*@callee_guaranteed () -> ()
%3 = begin_borrow %2 : $@callee_guaranteed () -> ()
%4 = apply %3() : $@callee_guaranteed () -> ()
end_borrow %3 : $@callee_guaranteed () -> ()
%6 = tuple ()
destroy_value %2 : $@callee_guaranteed () -> ()
return %6 : $()
} // end sil function '$sIeg_IeyB_TR'
sil private [ossa] @testWithoutActuallyEscapingBlockVerifyClause : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> () {
bb0(%0 : @guaranteed $@convention(block) () -> ()):
%1 = copy_block %0 : $@convention(block) () -> ()
%3 = begin_borrow %1 : $@convention(block) () -> ()
%4 = copy_value %3 : $@convention(block) () -> ()
%5 = apply %4() : $@convention(block) () -> ()
destroy_value %4 : $@convention(block) () -> ()
end_borrow %3 : $@convention(block) () -> ()
destroy_value %1 : $@convention(block) () -> ()
%v = tuple ()
return %v : $()
}