| // RUN: %target-swift-frontend -enforce-exclusivity=checked -swift-version 4 -emit-sil -primary-file %s -o /dev/null -verify |
| |
| import Swift |
| |
| func takesTwoInouts<T>(_ p1: inout T, _ p2: inout T) { } |
| |
| func simpleInoutDiagnostic() { |
| var i = 7 |
| |
| // FIXME: This diagnostic should be removed if static enforcement is |
| // turned on by default. |
| // expected-error@+4{{inout arguments are not allowed to alias each other}} |
| // expected-note@+3{{previous aliasing argument}} |
| // expected-error@+2{{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesTwoInouts(&i, &i) |
| } |
| |
| func inoutOnInoutParameter(p: inout Int) { |
| // expected-error@+4{{inout arguments are not allowed to alias each other}} |
| // expected-note@+3{{previous aliasing argument}} |
| // expected-error@+2{{overlapping accesses to 'p', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesTwoInouts(&p, &p) |
| } |
| |
| func swapNoSuppression(_ i: Int, _ j: Int) { |
| var a: [Int] = [1, 2, 3] |
| |
| // expected-error@+2{{overlapping accesses to 'a', but modification requires exclusive access; consider calling MutableCollection.swapAt(_:_:)}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&a[i], &a[j]) |
| } |
| |
| class SomeClass { } |
| |
| struct StructWithMutatingMethodThatTakesSelfInout { |
| var f = SomeClass() |
| mutating func mutate(_ other: inout StructWithMutatingMethodThatTakesSelfInout) { } |
| mutating func mutate(_ other: inout SomeClass) { } |
| |
| mutating func callMutatingMethodThatTakesSelfInout() { |
| // expected-error@+4{{inout arguments are not allowed to alias each other}} |
| // expected-note@+3{{previous aliasing argument}} |
| // expected-error@+2{{overlapping accesses to 'self', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| mutate(&self) |
| } |
| |
| mutating func callMutatingMethodThatTakesSelfStoredPropInout() { |
| // expected-error@+2{{overlapping accesses to 'self', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| mutate(&self.f) |
| } |
| } |
| |
| var globalStruct1 = StructWithMutatingMethodThatTakesSelfInout() |
| func callMutatingMethodThatTakesGlobalStoredPropInout() { |
| // expected-error@+2{{overlapping accesses to 'globalStruct1', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| globalStruct1.mutate(&globalStruct1.f) |
| } |
| |
| class ClassWithFinalStoredProp { |
| final var s1: StructWithMutatingMethodThatTakesSelfInout = StructWithMutatingMethodThatTakesSelfInout() |
| final var s2: StructWithMutatingMethodThatTakesSelfInout = StructWithMutatingMethodThatTakesSelfInout() |
| final var i = 7 |
| |
| func callMutatingMethodThatTakesClassStoredPropInout() { |
| s1.mutate(&s2.f) // no-warning |
| |
| // expected-error@+2{{overlapping accesses to 's1', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| s1.mutate(&s1.f) |
| |
| let local1 = self |
| |
| // expected-error@+2{{overlapping accesses to 's1', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| local1.s1.mutate(&local1.s1.f) |
| } |
| } |
| |
| func violationWithGenericType<T>(_ p: T) { |
| var local = p |
| // expected-error@+4{{inout arguments are not allowed to alias each other}} |
| // expected-note@+3{{previous aliasing argument}} |
| // expected-error@+2{{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesTwoInouts(&local, &local) |
| } |
| |
| |
| // Helper. |
| struct StructWithTwoStoredProp { |
| var f1: Int = 7 |
| var f2: Int = 8 |
| } |
| |
| // Take an unsafe pointer to a stored property while accessing another stored property. |
| func violationWithUnsafePointer(_ s: inout StructWithTwoStoredProp) { |
| withUnsafePointer(to: &s.f1) { (ptr) in |
| // expected-error@-1 {{overlapping accesses to 's.f1', but modification requires exclusive access; consider copying to a local variable}} |
| _ = s.f1 |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| |
| // Statically treat accesses to separate stored properties in structs as |
| // accessing separate storage. |
| withUnsafePointer(to: &s.f1) { (ptr) in // no-error |
| _ = s.f2 |
| } |
| } |
| // Tests for Fix-Its to replace swap(&collection[a], &collection[b]) with |
| // collection.swapAt(a, b) |
| |
| struct StructWithField { |
| var f = 12 |
| } |
| |
| struct StructWithFixits { |
| var arrayProp: [Int] = [1, 2, 3] |
| var dictionaryProp: [Int : Int] = [0 : 10, 1 : 11] |
| |
| mutating |
| func shouldHaveFixIts<T>(_ i: Int, _ j: Int, _ param: T, _ paramIndex: T.Index) where T : MutableCollection { |
| var array1 = [1, 2, 3] |
| // expected-error@+2{{overlapping accesses}}{{5-41=array1.swapAt(i + 5, j - 2)}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&array1[i + 5], &array1[j - 2]) |
| |
| // expected-error@+2{{overlapping accesses}}{{5-49=self.arrayProp.swapAt(i, j)}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&self.arrayProp[i], &self.arrayProp[j]) |
| |
| var localOfGenericType = param |
| // expected-error@+2{{overlapping accesses}}{{5-75=localOfGenericType.swapAt(paramIndex, paramIndex)}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&localOfGenericType[paramIndex], &localOfGenericType[paramIndex]) |
| |
| // expected-error@+2{{overlapping accesses}}{{5-39=array1.swapAt(i, j)}} |
| // expected-note@+1{{conflicting access is here}} |
| Swift.swap(&array1[i], &array1[j]) // no-crash |
| } |
| |
| mutating |
| func shouldHaveNoFixIts(_ i: Int, _ j: Int) { |
| var s = StructWithField() |
| // expected-error@+2{{overlapping accesses}}{{none}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&s.f, &s.f) |
| |
| var array1 = [1, 2, 3] |
| var array2 = [1, 2, 3] |
| |
| // Swapping between different arrays should cannot have the |
| // Fix-It. |
| swap(&array1[i], &array2[j]) // no-warning no-fixit |
| swap(&array1[i], &self.arrayProp[j]) // no-warning no-fixit |
| |
| // Dictionaries aren't MutableCollections so don't support swapAt(). |
| // expected-error@+2{{overlapping accesses}}{{none}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&dictionaryProp[i], &dictionaryProp[j]) |
| |
| // We could safely Fix-It this but don't now because the left and |
| // right bases are not textually identical. |
| // expected-error@+2{{overlapping accesses}}{{none}} |
| // expected-note@+1{{conflicting access is here}} |
| swap(&self.arrayProp[i], &arrayProp[j]) |
| |
| // We could safely Fix-It this but we're not that heroic. |
| // We don't suppress when swap() is used as a value |
| let mySwap: (inout Int, inout Int) -> () = swap |
| |
| // expected-error@+2{{overlapping accesses}}{{none}} |
| // expected-note@+1{{conflicting access is here}} |
| mySwap(&array1[i], &array1[j]) |
| |
| func myOtherSwap<T>(_ a: inout T, _ b: inout T) { |
| swap(&a, &b) // no-warning |
| } |
| |
| // expected-error@+2{{overlapping accesses}}{{none}} |
| // expected-note@+1{{conflicting access is here}} |
| mySwap(&array1[i], &array1[j]) |
| } |
| } |
| |
| func takesInoutAndNoEscapeClosure<T>(_ p: inout T, _ c: () -> ()) { } |
| |
| func callsTakesInoutAndNoEscapeClosure() { |
| var local = 5 |
| takesInoutAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| local = 8 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func inoutReadWriteInout(x: inout Int) { |
| // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesInoutAndNoEscapeClosure(&x, { _ = x }) |
| } |
| |
| func inoutWriteWriteInout(x: inout Int) { |
| // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesInoutAndNoEscapeClosure(&x, { x = 42 }) |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWithRead() { |
| var local = 5 |
| takesInoutAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| _ = local // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func takesInoutAndNoEscapeClosureThatThrows<T>(_ p: inout T, _ c: () throws -> ()) { } |
| |
| func callsTakesInoutAndNoEscapeClosureThatThrowsWithNonThrowingClosure() { |
| var local = 5 |
| takesInoutAndNoEscapeClosureThatThrows(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| local = 8 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func takesInoutAndNoEscapeClosureAndThrows<T>(_ p: inout T, _ c: () -> ()) throws { } |
| |
| func callsTakesInoutAndNoEscapeClosureAndThrows() { |
| var local = 5 |
| try! takesInoutAndNoEscapeClosureAndThrows(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| local = 8 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func takesTwoNoEscapeClosures(_ c1: () -> (), _ c2: () -> ()) { } |
| |
| func callsTakesTwoNoEscapeClosures() { |
| var local = 7 |
| takesTwoNoEscapeClosures({local = 8}, {local = 9}) // no-error |
| _ = local |
| } |
| |
| func takesInoutAndEscapingClosure<T>(_ p: inout T, _ c: @escaping () -> ()) { } |
| |
| func callsTakesInoutAndEscapingClosure() { |
| var local = 5 |
| takesInoutAndEscapingClosure(&local) { // no-error |
| local = 8 |
| } |
| } |
| |
| func callsClosureLiteralImmediately() { |
| var i = 7; |
| // Closure literals that are called immediately are considered nonescaping |
| _ = ({ (p: inout Int) in |
| i |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| )(&i) |
| // expected-error@-1 {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| } |
| |
| func callsStoredClosureLiteral() { |
| var i = 7; |
| let c = { (p: inout Int) in i} |
| |
| // Closure literals that are stored and later called are treated as escaping |
| // We don't expect a static exclusivity diagnostic here, but the issue |
| // will be caught at run time |
| _ = c(&i) // no-error |
| } |
| |
| |
| // Calling this with an inout expression for the first parameter performs a |
| // read access for the duration of a call |
| func takesUnsafePointerAndNoEscapeClosure<T>(_ p: UnsafePointer<T>, _ c: () -> ()) { } |
| |
| // Calling this with an inout expression for the first parameter performs a |
| // modify access for the duration of a call |
| func takesUnsafeMutablePointerAndNoEscapeClosure<T>(_ p: UnsafeMutablePointer<T>, _ c: () -> ()) { } |
| |
| |
| func callsTakesUnsafePointerAndNoEscapeClosure() { |
| var local = 1 |
| takesUnsafePointerAndNoEscapeClosure(&local) { // expected-note {{conflicting access is here}} |
| local = 2 // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| } |
| } |
| |
| func callsTakesUnsafePointerAndNoEscapeClosureThatReads() { |
| var local = 1 |
| |
| // Overlapping reads |
| takesUnsafePointerAndNoEscapeClosure(&local) { |
| _ = local // no-error |
| } |
| } |
| |
| func callsTakesUnsafeMutablePointerAndNoEscapeClosureThatReads() { |
| var local = 1 |
| |
| // Overlapping modify and read |
| takesUnsafeMutablePointerAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| _ = local // expected-note {{conflicting access is here}} |
| } |
| |
| } |
| func takesThrowingAutoClosureReturningGeneric<T: Equatable>(_ : @autoclosure () throws -> T) { } |
| func takesInoutAndClosure<T>(_: inout T, _ : () -> ()) { } |
| |
| func callsTakesThrowingAutoClosureReturningGeneric() { |
| var i = 0 |
| takesInoutAndClosure(&i) { // expected-error {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| takesThrowingAutoClosureReturningGeneric(i) // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| struct StructWithMutatingMethodThatTakesAutoclosure { |
| var f = 2 |
| mutating func takesAutoclosure(_ p: @autoclosure () throws -> ()) rethrows { } |
| } |
| |
| func conflictOnSubPathInNoEscapeAutoclosure() { |
| var s = StructWithMutatingMethodThatTakesAutoclosure() |
| s.takesAutoclosure(s.f = 2) |
| // expected-error@-1 {{overlapping accesses to 's', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2 {{conflicting access is here}} |
| } |
| |
| func conflictOnWholeInNoEscapeAutoclosure() { |
| var s = StructWithMutatingMethodThatTakesAutoclosure() |
| takesInoutAndNoEscapeClosure(&s.f) { |
| // expected-error@-1 {{overlapping accesses to 's.f', but modification requires exclusive access; consider copying to a local variable}} |
| s = StructWithMutatingMethodThatTakesAutoclosure() |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| } |
| |
| struct ParameterizedStruct<T> { |
| mutating func takesFunctionWithGenericReturnType(_ f: (Int) -> T) {} |
| } |
| |
| func testReabstractionThunk(p1: inout ParameterizedStruct<Int>, |
| p2: inout ParameterizedStruct<Int>) { |
| // Since takesFunctionWithGenericReturnType() takes a closure with a generic |
| // return type it expects the value to be returned @out. But the closure |
| // here has an 'Int' return type, so the compiler uses a reabstraction thunk |
| // to pass the closure to the method. |
| // This tests that we still detect access violations for closures passed |
| // using a reabstraction thunk. |
| p1.takesFunctionWithGenericReturnType { _ in |
| // expected-error@-1 {{overlapping accesses to 'p1', but modification requires exclusive access; consider copying to a local variable}} |
| p2 = p1 |
| // expected-note@-1 {{conflicting access is here}} |
| return 3 |
| } |
| } |
| |
| |
| func takesNoEscapeBlockClosure |
| ( |
| _ p: inout Int, _ c: @convention(block) () -> () |
| ) { } |
| |
| func takesEscapingBlockClosure |
| ( |
| _ p: inout Int, _ c: @escaping @convention(block) () -> () |
| ) { } |
| |
| func testCallNoEscapeBlockClosure() { |
| var i = 7 |
| takesNoEscapeBlockClosure(&i) { |
| // expected-error@-1 {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| i = 7 |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| } |
| |
| func testCallNoEscapeBlockClosureRead() { |
| var i = 7 |
| takesNoEscapeBlockClosure(&i) { |
| // expected-error@-1 {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| _ = i |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| } |
| |
| func testCallEscapingBlockClosure() { |
| var i = 7 |
| takesEscapingBlockClosure(&i) { // no-warning |
| i = 7 |
| } |
| } |
| |
| |
| |
| func testCallNonEscapingWithEscapedBlock() { |
| var i = 7 |
| let someBlock : @convention(block) () -> () = { |
| i = 8 |
| } |
| |
| takesNoEscapeBlockClosure(&i, someBlock) // no-warning |
| } |
| |
| func takesInoutAndClosureWithGenericArg<T>(_ p: inout Int, _ c: (T) -> Int) { } |
| |
| func callsTakesInoutAndClosureWithGenericArg() { |
| var i = 7 |
| takesInoutAndClosureWithGenericArg(&i) { (p: Int) in |
| // expected-error@-1 {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| return i + p |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| } |
| |
| func takesInoutAndClosureTakingNonOptional(_ p: inout Int, _ c: (Int) -> ()) { } |
| func callsTakesInoutAndClosureTakingNonOptionalWithClosureTakingOptional() { |
| var i = 7 |
| // Test for the thunk converting an (Int?) -> () to an (Int) -> () |
| takesInoutAndClosureTakingNonOptional(&i) { (p: Int?) in |
| // expected-error@-1 {{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}} |
| i = 8 |
| // expected-note@-1 {{conflicting access is here}} |
| } |
| } |
| |
| // Helper. |
| func doOne(_ f: () -> ()) { |
| f() |
| } |
| |
| func noEscapeBlock() { |
| var x = 3 |
| doOne { |
| // expected-error@+2{{overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@+1{{conflicting access is here}} |
| takesInoutAndNoEscapeClosure(&x, { _ = x }) |
| } |
| } |
| |
| func inoutSeparateStructStoredProperties() { |
| var s = StructWithTwoStoredProp() |
| takesTwoInouts(&s.f1, &s.f2) // no-error |
| } |
| |
| func inoutSameStoredProperty() { |
| var s = StructWithTwoStoredProp() |
| takesTwoInouts(&s.f1, &s.f1) |
| // expected-error@-1{{overlapping accesses to 's.f1', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2{{conflicting access is here}} |
| } |
| |
| func inoutSeparateTupleElements() { |
| var t = (1, 4) |
| takesTwoInouts(&t.0, &t.1) // no-error |
| } |
| |
| func inoutSameTupleElement() { |
| var t = (1, 4) |
| takesTwoInouts(&t.0, &t.0) |
| // expected-error@-1{{overlapping accesses to 't.0', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2{{conflicting access is here}} |
| } |
| |
| func inoutSameTupleNamedElement() { |
| var t = (name1: 1, name2: 4) |
| takesTwoInouts(&t.name2, &t.name2) |
| // expected-error@-1{{overlapping accesses to 't.name2', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2{{conflicting access is here}} |
| } |
| |
| func inoutSamePropertyInSameTuple() { |
| var t = (name1: 1, name2: StructWithTwoStoredProp()) |
| takesTwoInouts(&t.name2.f1, &t.name2.f1) |
| // expected-error@-1{{overlapping accesses to 't.name2.f1', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2{{conflicting access is here}} |
| } |
| |
| // Noescape closures and separate stored structs |
| |
| func callsTakesInoutAndNoEscapeClosureNoWarningOnSeparateStored() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local.f1) { |
| local.f2 = 8 // no-error |
| } |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWarningOnSameStoredProp() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local.f1) { // expected-error {{overlapping accesses to 'local.f1', but modification requires exclusive access; consider copying to a local variable}} |
| local.f1 = 8 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWarningOnAggregateAndStoredProp() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| local.f1 = 8 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWarningOnStoredPropAndAggregate() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local.f1) { // expected-error {{overlapping accesses to 'local.f1', but modification requires exclusive access; consider copying to a local variable}} |
| local = StructWithTwoStoredProp() // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWarningOnStoredPropAndBothPropertyAndAggregate() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local.f1) { // expected-error {{overlapping accesses to 'local.f1', but modification requires exclusive access; consider copying to a local variable}} |
| local.f1 = 8 |
| // We want the diagnostic on the access for the aggregate and not the projection. |
| local = StructWithTwoStoredProp() // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func callsTakesInoutAndNoEscapeClosureWarningOnStoredPropAndBothAggregateAndProperty() { |
| var local = StructWithTwoStoredProp() |
| takesInoutAndNoEscapeClosure(&local.f1) { // expected-error {{overlapping accesses to 'local.f1', but modification requires exclusive access; consider copying to a local variable}} |
| // We want the diagnostic on the access for the aggregate and not the projection. |
| local = StructWithTwoStoredProp() // expected-note {{conflicting access is here}} |
| local.f1 = 8 |
| } |
| } |
| |
| |
| struct MyStruct<T> { |
| var prop = 7 |
| mutating func inoutBoundGenericStruct() { |
| takesTwoInouts(&prop, &prop) |
| // expected-error@-1{{overlapping accesses to 'self.prop', but modification requires exclusive access; consider copying to a local variable}} |
| // expected-note@-2{{conflicting access is here}} |
| } |
| } |
| |
| |
| func testForLoopCausesReadAccess() { |
| var a: [Int] = [1] |
| takesInoutAndNoEscapeClosure(&a) { // expected-error {{overlapping accesses to 'a', but modification requires exclusive access; consider copying to a local variable}} |
| for _ in a { // expected-note {{conflicting access is here}} |
| } |
| } |
| } |
| |
| func testKeyPathStructField() { |
| let getF = \StructWithField.f |
| var local = StructWithField() |
| takesInoutAndNoEscapeClosure(&local[keyPath: getF]) { // expected-error {{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}} |
| local.f = 17 // expected-note {{conflicting access is here}} |
| } |
| } |
| |
| func testKeyPathWithClassFinalStoredProperty() { |
| let getI = \ClassWithFinalStoredProp.i |
| let local = ClassWithFinalStoredProp() |
| |
| // Ideally we would diagnose statically here, but it is not required by the |
| // model. |
| takesTwoInouts(&local[keyPath: getI], &local[keyPath: getI]) |
| } |
| |
| func takesInoutAndOptionalClosure(_: inout Int, _ f: (()->())?) { |
| f!() |
| } |
| |
| // An optional closure is not considered @noescape: |
| // This violation will only be caught dynamically. |
| // |
| // apply %takesInoutAndOptionalClosure(%closure) |
| // : $@convention(thin) (@inout Int, @owned Optional<@callee_guaranteed () -> ()>) -> () |
| func testOptionalClosure() { |
| var x = 0 |
| takesInoutAndOptionalClosure(&x) { x += 1 } |
| } |
| |
| func takesInoutAndOptionalBlock(_: inout Int, _ f: (@convention(block) ()->())?) { |
| f!() |
| } |
| |
| // An optional block is not be considered @noescape. |
| // This violation will only be caught dynamically. |
| func testOptionalBlock() { |
| var x = 0 |
| takesInoutAndOptionalBlock(&x) { x += 1 } |
| } |
| |
| // Diagnost a conflict on a noescape closure that is conditionally passed as a function argument. |
| // |
| // <rdar://problem/42560459> [Exclusivity] Failure to statically diagnose a conflict when passing conditional noescape closures. |
| struct S { |
| var x: Int |
| |
| mutating func takeNoescapeClosure(_ f: ()->()) { f() } |
| |
| mutating func testNoescapePartialApplyPhiUse(z : Bool) { |
| func f1() { |
| x = 1 // expected-note {{conflicting access is here}} |
| } |
| func f2() { |
| x = 1 // expected-note {{conflicting access is here}} |
| } |
| takeNoescapeClosure(z ? f1 : f2) |
| // expected-error@-1 2 {{overlapping accesses to 'self', but modification requires exclusive access; consider copying to a local variable}} |
| } |
| } |
| |
| // TODO: A conflict should also be detected here. However, the |
| // typechecker does not allow it. Enable the following test if we ever |
| // remove this case from the typechecker test: |
| // diag_invalid_inout_captures.swift. |
| // public func nestedConflict(x: inout Int) { |
| // doit(x: &x, x == 0 ? { x = 1 } : { x = 2}) |
| // } |