Skip to content

Commit bbee754

Browse files
committed
ManagedAtomic[LazyReference]: Always access ivar through pointer
The deinit implementations used to access the ivar directly, but that can confuse the compiler into assuming the value never changes after its initialization, because it doesn’t see accesses that are done via the pointer. Stop accessing the ivar directly once it has been initialized.
1 parent 951d3b2 commit bbee754

File tree

5 files changed

+27
-5
lines changed

5 files changed

+27
-5
lines changed

Sources/Atomics/AtomicLazyReference.swift.gyb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ public class ManagedAtomicLazyReference<Instance: AnyObject> {
139139
@usableFromInline
140140
internal typealias _Rep = Optional<Unmanaged<Instance>>.AtomicRepresentation
141141

142+
/// The atomic representation of the value stored inside.
143+
///
144+
/// Warning: This ivar must only ever be accessed via `_ptr` after
145+
/// its initialization.
142146
@usableFromInline
143147
internal let _storage: _Rep
144148

@@ -149,7 +153,7 @@ public class ManagedAtomicLazyReference<Instance: AnyObject> {
149153
}
150154

151155
deinit {
152-
if let unmanaged = _storage.dispose() {
156+
if let unmanaged = _ptr.pointee.dispose() {
153157
unmanaged.release()
154158
}
155159
}

Sources/Atomics/HighLevelTypes.swift.gyb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ where Value.AtomicRepresentation.Value == Value {
9797
@usableFromInline
9898
internal typealias _Storage = Value.AtomicRepresentation
9999

100+
/// The atomic representation of the value stored inside.
101+
///
102+
/// Warning: This ivar must only ever be accessed via `_ptr` after
103+
/// its initialization.
100104
@usableFromInline
101105
internal var _storage: _Storage
102106

@@ -108,7 +112,7 @@ where Value.AtomicRepresentation.Value == Value {
108112
}
109113

110114
deinit {
111-
_ = _storage.dispose()
115+
_ = _ptr.pointee.dispose()
112116
}
113117

114118
@_alwaysEmitIntoClient @inline(__always)

Sources/Atomics/autogenerated/AtomicLazyReference.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ public class ManagedAtomicLazyReference<Instance: AnyObject> {
142142
@usableFromInline
143143
internal typealias _Rep = Optional<Unmanaged<Instance>>.AtomicRepresentation
144144

145+
/// The atomic representation of the value stored inside.
146+
///
147+
/// Warning: This ivar must only ever be accessed via `_ptr` after
148+
/// its initialization.
145149
@usableFromInline
146150
internal let _storage: _Rep
147151

@@ -152,7 +156,7 @@ public class ManagedAtomicLazyReference<Instance: AnyObject> {
152156
}
153157

154158
deinit {
155-
if let unmanaged = _storage.dispose() {
159+
if let unmanaged = _ptr.pointee.dispose() {
156160
unmanaged.release()
157161
}
158162
}

Sources/Atomics/autogenerated/HighLevelTypes.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ where Value.AtomicRepresentation.Value == Value {
9999
@usableFromInline
100100
internal typealias _Storage = Value.AtomicRepresentation
101101

102+
/// The atomic representation of the value stored inside.
103+
///
104+
/// Warning: This ivar must only ever be accessed via `_ptr` after
105+
/// its initialization.
102106
@usableFromInline
103107
internal var _storage: _Storage
104108

@@ -110,7 +114,7 @@ where Value.AtomicRepresentation.Value == Value {
110114
}
111115

112116
deinit {
113-
_ = _storage.dispose()
117+
_ = _ptr.pointee.dispose()
114118
}
115119

116120
@_alwaysEmitIntoClient @inline(__always)

Tests/AtomicsTests/AtomicLazyReference.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ import Atomics
1515

1616
class AtomicLazyReferenceTests: XCTestCase {
1717
func test_unsafe_create_destroy() {
18+
XCTAssertEqual(LifetimeTracked.instances, 0)
1819
let v = UnsafeAtomicLazyReference<LifetimeTracked>.create()
19-
defer { v.destroy() }
20+
defer {
21+
v.destroy()
22+
XCTAssertEqual(LifetimeTracked.instances, 0)
23+
}
2024
XCTAssertNil(v.load())
2125
}
2226

2327
func test_unsafe_storeIfNilThenLoad() {
28+
XCTAssertEqual(LifetimeTracked.instances, 0)
2429
do {
2530
let v = UnsafeAtomicLazyReference<LifetimeTracked>.create()
2631
XCTAssertNil(v.load())
@@ -39,6 +44,7 @@ class AtomicLazyReferenceTests: XCTestCase {
3944
}
4045

4146
func test_managed_storeIfNilThenLoad() {
47+
XCTAssertEqual(LifetimeTracked.instances, 0)
4248
do {
4349
let v = ManagedAtomicLazyReference<LifetimeTracked>()
4450
XCTAssertNil(v.load())

0 commit comments

Comments
 (0)