Skip to content

Commit c849ae2

Browse files
authored
Merge pull request swiftlang#83963 from owenv/exclusivity-docs
Add documentation to static exclusivity diagnostics
2 parents ff62407 + 6bcaa0a commit c849ae2

File tree

4 files changed

+67
-4
lines changed

4 files changed

+67
-4
lines changed

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ GROUP(ConformanceIsolation, "conformance-isolation")
4747
GROUP(DeprecatedDeclaration, "deprecated-declaration")
4848
GROUP(DynamicCallable, "dynamic-callable-requirements")
4949
GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version")
50+
GROUP(ExclusivityViolation, "exclusivity-violation")
5051
GROUP(ExistentialAny, "existential-any")
5152
GROUP(ExistentialMemberAccess, "existential-member-access-limitations")
5253
GROUP(ImplementationOnlyDeprecated, "implementation-only-deprecated")

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,26 @@ ERROR(unimplemented_generator_witnesses,none,
8484
"protocol conformance emission for generator coroutines is unimplemented",
8585
())
8686

87-
ERROR(exclusivity_access_required,none,
87+
GROUPED_ERROR(exclusivity_access_required,ExclusivityViolation,none,
8888
"overlapping accesses to %0, but "
8989
"%select{initialization|read|modification|deinitialization}1 requires "
9090
"exclusive access; "
9191
"%select{consider copying to a local variable|"
9292
"consider calling MutableCollection.swapAt(_:_:)}2",
9393
(StringRef, unsigned, bool))
9494

95-
ERROR(exclusivity_access_required_unknown_decl,none,
95+
GROUPED_ERROR(exclusivity_access_required_unknown_decl,ExclusivityViolation,none,
9696
"overlapping accesses, but "
9797
"%select{initialization|read|modification|deinitialization}0 requires "
9898
"exclusive access; consider copying to a local variable", (unsigned))
9999

100-
ERROR(exclusivity_access_required_moveonly,none,
100+
GROUPED_ERROR(exclusivity_access_required_moveonly,ExclusivityViolation,none,
101101
"overlapping accesses to %0, but "
102102
"%select{initialization|read|modification|deinitialization}1 requires "
103103
"exclusive access",
104104
(StringRef, unsigned))
105105

106-
ERROR(exclusivity_access_required_unknown_decl_moveonly,none,
106+
GROUPED_ERROR(exclusivity_access_required_unknown_decl_moveonly,ExclusivityViolation,none,
107107
"overlapping accesses, but "
108108
"%select{initialization|read|modification|deinitialization}0 requires "
109109
"exclusive access", (unsigned))

userdocs/diagnostics/diagnostic-descriptions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ presented specially within your IDE of choice. See below for the full list of th
2929
- <doc:nominal-types>
3030
- <doc:property-wrapper-requirements>
3131
- <doc:protocol-type-non-conformance>
32+
- <doc:exclusivity-violation>
3233
- <doc:conformance-isolation>
3334
- <doc:result-builder-methods>
3435
- <doc:sendable-metatypes>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Overlapping accesses, but operation requires exclusive access
2+
3+
Swift requires exclusive access to a variable in order to modify that variable. An error is reported if a program attempts to access a variable while it is already in the process of being accessed via another name. These issues can often be resolved by making a local copy of a variable before modifying it.
4+
5+
In the following example, `count` is accessed for modification by passing it as an `inout` argument to `modifyTwice`. This `inout` access to `count` lasts for the entire duration of the `modifyTwice` function call. The exclusivity violation occurs because the `modifier` closure also accesses `count` via the name `$0` while the first access is in progress.
6+
7+
```swift
8+
func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
9+
modifier(&value)
10+
modifier(&value)
11+
}
12+
13+
func testCount() {
14+
var count = 1
15+
modifyTwice(&count) { $0 += count } // error: overlapping accesses to 'count', but modification requires exclusive access; consider copying to a local variable
16+
print(count)
17+
}
18+
```
19+
20+
This exclusivity violation can be fixed by introducing a local variable to track the value the `modifier` closure should add to its argument.
21+
22+
```swift
23+
func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
24+
modifier(&value)
25+
modifier(&value)
26+
}
27+
28+
func testCount() {
29+
var count = 1
30+
let incrementBy = count
31+
modifyTwice(&count) { $0 += incrementBy }
32+
print(count)
33+
}
34+
```
35+
36+
In this updated program, `count` and `$0` no longer refer to the same variable, so accessing them at the same time does not violate exclusivity.
37+
38+
Another common source of exclusivity violations occurs when a `mutating` method modifies `self`:
39+
40+
```swift
41+
extension Array {
42+
mutating func append(removingFrom other: inout Array<Element>) {
43+
while !other.isEmpty {
44+
self.append(other.removeLast())
45+
}
46+
}
47+
}
48+
49+
var numbers = [1, 2, 3]
50+
numbers.append(removingFrom: &numbers) // error: overlapping accesses to 'x', but modification requires exclusive access; consider copying to a local variable
51+
```
52+
53+
A `mutating` method accesses `self` for the duration of the method call, so in this example `numbers` has two conflicting long-lived accesses, one as `self` and one as an `inout` argument to the method. Again, a local variable can be introduced to eliminate the conflict:
54+
55+
```swift
56+
var numbers = [1, 2, 3]
57+
var toAppend = numbers
58+
numbers.append(removingFrom: &toAppend)
59+
```
60+
61+
Exclusivity checks play an important role in enforcing memory safety and enabling compiler optimizations. To learn more, see [Swift 5 Exclusivity Enforcement](https://www.swift.org/blog/swift-5-exclusivity/) on the Swift.org blog.

0 commit comments

Comments
 (0)