1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// RUN: %empty-directory(%t)
// RUN: %gyb %s -o %t/UnsafeAtomicInitializers.swift
// RUN: %line-directive %t/UnsafeAtomicInitializers.swift -- %target-swift-frontend -typecheck -verify %t/UnsafeAtomicInitializers.swift
%{
from gyb_utils import autogenerated_warning
types = [
# id type initial
("Int", "Int", "0"),
("Int64", "Int64", "0"),
("Int32", "Int32", "0"),
("Int16", "Int16", "0"),
("Int8", "Int8", "0"),
("UInt", "UInt", "0"),
("UInt64", "UInt64", "0"),
("UInt32", "UInt32", "0"),
("UInt16", "UInt16", "0"),
("UInt8", "UInt8", "0"),
# id type initial
("URP", "UnsafeRawPointer", "UnsafeRawPointer(UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 8))"),
("UP", "UnsafePointer<Bar>", "UnsafePointer(UnsafeMutablePointer<Bar>.allocate(capacity: 1))"),
("UMRP", "UnsafeMutableRawPointer", ".allocate(byteCount: 8, alignment: 8)"),
("UMP", "UnsafeMutablePointer<Bar>", ".allocate(capacity: 1)"),
("Unmanaged", "Unmanaged<Foo>", "Unmanaged.passRetained(Foo())"),
# id type initial
("URPOpt", "UnsafeRawPointer?", "nil"),
("UPOpt", "UnsafePointer<Bar>?", "nil"),
("UMRPOpt", "UnsafeMutableRawPointer?", "nil"),
("UMPOpt", "UnsafeMutablePointer<Bar>?", "nil"),
("UnmanagedOpt", "Unmanaged<Foo>?", "nil"),
]
}%
${autogenerated_warning()}
import Atomics
class Foo {
var value = 0
}
struct Bar {
var value = 0
}
% for (id, type, initial) in types:
func test_${id}() -> UnsafeAtomic<${type}> {
var storage = UnsafeAtomic<${type}>.Storage(${initial})
let atomic = UnsafeAtomic<${type}>(at: &storage) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}}
// expected-note@-1 {{implicit argument conversion from 'UnsafeAtomic<${type}>.Storage' to 'UnsafeMutablePointer<UnsafeAtomic<${type}>.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}}
// expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
return atomic
}
% end
func test_UnsafeAtomicLazyReference() -> UnsafeAtomicLazyReference<Foo> {
var value = UnsafeAtomicLazyReference<Foo>.Storage()
let atomic = UnsafeAtomicLazyReference(at: &value) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}}
// expected-note@-1 {{implicit argument conversion from 'UnsafeAtomicLazyReference<Foo>.Storage' to 'UnsafeMutablePointer<UnsafeAtomicLazyReference<Foo>.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}}
// expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
return atomic
}
class BrokenAtomicCounter { // THIS IS BROKEN; DO NOT USE
private var _storage = UnsafeAtomic<Int>.Storage(0)
private var _value: UnsafeAtomic<Int>?
init() {
// This escapes the ephemeral pointer generated by the inout expression,
// so it leads to undefined behavior when the pointer gets dereferenced
// in the atomic operations below. DO NOT DO THIS.
_value = UnsafeAtomic(at: &_storage) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}}
// expected-note@-1 {{implicit argument conversion from 'UnsafeAtomic<Int>.Storage' to 'UnsafeMutablePointer<UnsafeAtomic<Int>.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}}
// expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
}
func increment() {
_value!.wrappingIncrement(by: 1, ordering: .relaxed)
}
func get() -> Int {
_value!.load(ordering: .relaxed)
}
}
struct AtomicCounter {
typealias Value = Int
typealias Header = UnsafeAtomic<Value>.Storage
class Buffer: ManagedBuffer<Header, Void> {
deinit {
withUnsafeMutablePointerToHeader { header in
_ = header.pointee.dispose()
}
}
}
let buffer: Buffer
init() {
buffer = Buffer.create(minimumCapacity: 0) { _ in
Header(0)
} as! Buffer
}
private func _withAtomicPointer<R>(
_ body: (UnsafeAtomic<Int>) throws -> R
) rethrows -> R {
try buffer.withUnsafeMutablePointerToHeader { header in
try body(UnsafeAtomic<Int>(at: header))
}
}
func increment() {
_withAtomicPointer { $0.wrappingIncrement(ordering: .relaxed) }
}
func load() -> Int {
_withAtomicPointer { $0.load(ordering: .relaxed) }
}
}
struct AtomicUnmanagedRef<Instance: AnyObject> {
typealias Value = Unmanaged<Instance>?
typealias Header = UnsafeAtomic<Value>.Storage
class Buffer: ManagedBuffer<Header, Void> {
deinit {
withUnsafeMutablePointerToHeader { header in
_ = header.pointee.dispose()
}
}
}
let buffer: Buffer
init() {
buffer = Buffer.create(minimumCapacity: 0) { _ in
Header(nil)
} as! Buffer
}
private func _withAtomicPointer<R>(
_ body: (UnsafeAtomic<Value>) throws -> R
) rethrows -> R {
try buffer.withUnsafeMutablePointerToHeader { header in
try body(UnsafeAtomic<Value>(at: header))
}
}
func store(_ desired: Value) {
_withAtomicPointer { $0.store(desired, ordering: .sequentiallyConsistent) }
}
func load() -> Value {
_withAtomicPointer { $0.load(ordering: .sequentiallyConsistent) }
}
}
|