| // 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 @twoLocalInoutsDisaliased |
| sil hidden @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 @twoLocalInoutsSimpleAliasing |
| sil hidden @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 @conflictingPriorAccess |
| sil hidden @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 @twoSequentialInouts |
| sil hidden @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 @unconditionalBranch |
| sil hidden @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 @diamondMergeStacks |
| sil hidden @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 @loopMergeStacks |
| sil hidden @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 @loopWithError |
| sil hidden @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 @modifySubAccessesAreAllowed |
| sil hidden @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 @twoLocalReadsSimpleAliasing |
| sil hidden @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 @localReadFollowedByModify |
| sil hidden @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 @localModifyFollowedByRead |
| sil hidden @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 { |
| @sil_stored var f: Int |
| init() |
| } |
| // CHECK-LABEL: sil hidden @classStoredProperty |
| sil hidden @classStoredProperty : $@convention(thin) (ClassWithStoredProperty) -> () { |
| bb0(%0 : $ClassWithStoredProperty): |
| %1 = ref_element_addr %0 : $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 %0 : $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 |
| destroy_value %0 : $ClassWithStoredProperty |
| %5 = tuple () |
| return %5 : $() |
| } |
| |
| // CHECK-LABEL: sil hidden @lookThroughBeginBorrow |
| sil hidden @lookThroughBeginBorrow : $@convention(thin) (ClassWithStoredProperty) -> () { |
| bb0(%0 : $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 from %0 : $ClassWithStoredProperty, $ClassWithStoredProperty |
| end_borrow %1 from %0 : $ClassWithStoredProperty, $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 @twoAllocBoxProjections |
| sil hidden @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 @lookThroughMarkUninitialized |
| sil hidden @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 @modifySameGlobal |
| sil hidden @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 @modifyDifferentGlobal |
| sil hidden @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 @readWriteReadConflictingThirdAccess |
| sil hidden @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 @writeWriteWriteConflictingThirdAccess |
| sil hidden @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 @resetFirstAccessForNote |
| sil hidden @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 @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 @pointerToAddr |
| sil hidden @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 @inlinedStructElement |
| sil hidden @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 @inlinedTupleElement |
| sil hidden @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 @inlinedEnumValue |
| sil hidden @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 @inlinedArrayProp |
| sil hidden @inlinedArrayProp : $@convention(thin) (@guaranteed Storage, Builtin.Word) -> Int { |
| bb0(%0 : $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 @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 @inProgressModifyModifyConflictWithCallToClosure |
| sil hidden @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 @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 @inProgressConflictWithNoEscapeClosureArgument |
| sil hidden @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 %2 : ${ var Int } |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| // CHECK-LABEL: sil hidden @inProgressConflictWithNoEscapeGuaranteedClosureArgument : $@convention(thin) (Int) -> () { |
| sil hidden @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 from %conv : $@callee_guaranteed @noescape (Int) -> (), $@callee_guaranteed @noescape (Int) -> () |
| destroy_value %2 : ${ var Int } |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| sil hidden @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 @inProgressReadModifyConflictWithNoEscapeClosureArgument |
| sil hidden @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 %2 : ${ var Int } |
| %9 = tuple () |
| return %9 : $() |
| } |
| |
| sil hidden @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 @inProgressConflictWithNoEscapeClosureWithReabstractionThunk |
| sil hidden @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 %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 @closureThatModifiesCapture_1: $@convention(thin) (@inout_aliasable Int) -> () { |
| bb0(%0 : $*Int): |
| %1 = begin_access [modify] [unknown] %0 : $*Int // expected-note 2{{conflicting access is here}} |
| end_access %1 : $*Int |
| %2 = tuple () |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil hidden @inProgressConflictWithNoEscapeClosureWithBlockStorage |
| sil hidden @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 %2 : ${ var Int } |
| %ret = tuple () |
| return %ret : $() |
| } |
| |
| // CHECK-LABEL: sil hidden @inProgressConflictWithNoEscapeClosureWithOptionalBlockStorage |
| sil hidden @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 %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 @takesInoutIntAndStructWithStoredProps : $@convention(thin) (@inout Int, @inout StructWithStoredProps) -> () |
| |
| // CHECK-LABEL: sil hidden @twoSeparateStoredProperties |
| sil hidden @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 @twoSeparateNestedStoredProperties |
| sil hidden @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 @theSameStoredProperty |
| sil hidden @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 @storedPropertyAndAggregate |
| sil hidden @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 @nestedStoredPropertyAndAggregate |
| sil hidden @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 @twoSeparateTupleElements |
| sil hidden @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 @sameTupleElement |
| sil hidden @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 @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 () -> ()>) -> () |
| %7 = tuple () |
| return %7 : $() |
| } |
| |
| sil private @closureForDirectPartialApplyTakingInout : $@convention(thin) (@inout 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 @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 %box : ${ var Int } |
| %v = tuple () |
| return %v : $() |
| } |
| |
| sil private @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 @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 %box : ${ var Int } |
| %v = tuple () |
| return %v : $() |
| } |
| |
| sil private @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 @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 %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 @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 @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 @addressorAccess : $@convention(thin) (@guaranteed ClassWithStoredProperty, Int32) -> () { |
| bb0(%0 : $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 : $() |
| } |