Skip to content

[stdlib] Start adopting noncopyable generics in the stdlib (phase 1) #72125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3093778
[stdlib] MemoryLayout: Add support for non-copyable type arguments
lorentey Feb 16, 2024
b3064f5
[stdlib] Unsafe[Mutable]Pointer: Add support for non-copyable Pointee…
lorentey Feb 16, 2024
51925c5
[stdlib] Optional: Initial support for noncopyable payloads
lorentey Feb 29, 2024
8adc6aa
[stdlib] UnsafeRawPointer: new interactions with noncopyable types
lorentey Mar 5, 2024
904d20b
[stdlib] OpaquePointer: new interactions with noncopyable types
lorentey Mar 5, 2024
17808ba
[build] Enable noncopyable generics; disable anything that prevents t…
lorentey Feb 20, 2024
2128686
[stdlib] MemoryLayout: Adopt @_preInverseGenerics
lorentey Mar 6, 2024
27471da
[stdlib] UnsafePointer: Adopt @_preInverseGenerics
lorentey Mar 6, 2024
063758a
[stdlib] Optional: Adopt @_preInverseGenerics
lorentey Mar 6, 2024
3760c9b
[stdlib] UnsafeRawPointer: Adopt @_preInverseGenerics
lorentey Mar 6, 2024
47ce63e
[stdlib] OpaquePointer: Adopt @_preInverseGenerics
lorentey Mar 6, 2024
0441805
[stdlib] Generalize swap(_:_:) for noncopyable types
lorentey Mar 6, 2024
cdc3f3d
[stdlib] UnsafePointer: Add @_preInverseGenerics to stored properties
lorentey Mar 7, 2024
af5ab90
[stdlib] UnsafePointer: Add @_preInverseGenerics to _Pointer conformance
lorentey Mar 7, 2024
d60387a
[stdlib] Optional: Add @_preInverseGenerics to ExpressibleByNilLitera…
lorentey Mar 7, 2024
3ea98dc
[stdlib] UnsafePointer: Don’t let the compiler synthesize `hashValue`
lorentey Mar 7, 2024
9b3dec7
[stdlib] UnsafePointer: Resolve most of the symbol mismatches
lorentey Mar 7, 2024
fb84071
[Synchronization] Update symbol expectations
lorentey Mar 7, 2024
817642a
fix typo in benchmarks cmake
airspeedswift Mar 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ include(AddSwiftBenchmarkSuite)
# Declarative Description of Benchmarks
#===-----------------------------------------------------------------------===#

set(SWIFT_BENCH_MODULES
set(SWIFT_BENCH_MODULES)

# FIXME(NCG): Temporarily disabled
set(SWIFT_BENCH_MODULES_DISABLED
single-source/Ackermann
single-source/AngryPhonebook
single-source/AnyHashableWithAClass
Expand Down Expand Up @@ -213,7 +216,9 @@ set(SWIFT_BENCH_MODULES
cxx-source/ReadAccessor
)

set(SWIFT_MULTISOURCE_SWIFT_BENCHES
set(SWIFT_MULTISOURCE_SWIFT_BENCHES)
# FIXME(NCG): Temporarily disabled
set(SWIFT_MULTISOURCE_SWIFT_BENCHES_DISABLED
multi-source/PrimsSplit
)

Expand Down
3 changes: 3 additions & 0 deletions benchmark/utils/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import TestsUtils
import DriverUtils

#if false // FIXME(NCG): Temporarily disabled to enable dev toolchain generation
import Ackermann
import AngryPhonebook
import AnyHashableWithAClass
Expand Down Expand Up @@ -406,5 +408,6 @@ register(UTF16Decode.benchmarks)
register(Walsh.benchmarks)
register(WordCount.benchmarks)
register(XorLoop.benchmarks)
#endif

main()
33 changes: 22 additions & 11 deletions stdlib/public/Cxx/UnsafeCxxIterators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
///
/// - SeeAlso: https://en.cppreference.com/w/cpp/named_req/InputIterator
public protocol UnsafeCxxInputIterator: Equatable {
associatedtype Pointee
associatedtype Pointee: ~Copyable

/// Returns the unwrapped result of C++ `operator*()`.
///
/// Generally, Swift creates this property automatically for C++ types that
/// define `operator*()`.
@_borrowed
var pointee: Pointee { get }

/// Returns an iterator pointing to the next item in the sequence.
Expand All @@ -33,19 +34,23 @@ public protocol UnsafeCxxInputIterator: Equatable {
func successor() -> Self
}

extension UnsafePointer: UnsafeCxxInputIterator {}
extension UnsafePointer: UnsafeCxxInputIterator
where Pointee: ~Copyable {}

extension UnsafeMutablePointer: UnsafeCxxInputIterator {}
extension UnsafeMutablePointer: UnsafeCxxInputIterator
where Pointee: ~Copyable {}

extension Optional: UnsafeCxxInputIterator where Wrapped: UnsafeCxxInputIterator {
public typealias Pointee = Wrapped.Pointee

@inlinable
public var pointee: Pointee {
if let value = self {
return value.pointee
_read {
guard let value = self else {
fatalError("Could not dereference nullptr")
}
yield value.pointee
}
fatalError("Could not dereference nullptr")
}

@inlinable
Expand All @@ -58,10 +63,12 @@ extension Optional: UnsafeCxxInputIterator where Wrapped: UnsafeCxxInputIterator
}

public protocol UnsafeCxxMutableInputIterator: UnsafeCxxInputIterator {
@_borrowed
override var pointee: Pointee { get set }
}

extension UnsafeMutablePointer: UnsafeCxxMutableInputIterator {}
extension UnsafeMutablePointer: UnsafeCxxMutableInputIterator
where Pointee: ~Copyable {}

/// Bridged C++ iterator that allows computing the distance between two of its
/// instances, and advancing an instance by a given number of elements.
Expand All @@ -77,10 +84,14 @@ public protocol UnsafeCxxRandomAccessIterator: UnsafeCxxInputIterator {
static func +=(lhs: inout Self, rhs: Distance)
}

extension UnsafePointer: UnsafeCxxRandomAccessIterator {}
extension UnsafePointer: UnsafeCxxRandomAccessIterator
where Pointee: ~Copyable {}

extension UnsafeMutablePointer: UnsafeCxxRandomAccessIterator {}
extension UnsafeMutablePointer: UnsafeCxxRandomAccessIterator
where Pointee: ~Copyable {}

public protocol UnsafeCxxMutableRandomAccessIterator: UnsafeCxxRandomAccessIterator, UnsafeCxxMutableInputIterator {}
public protocol UnsafeCxxMutableRandomAccessIterator:
UnsafeCxxRandomAccessIterator, UnsafeCxxMutableInputIterator {}

extension UnsafeMutablePointer: UnsafeCxxMutableRandomAccessIterator {}
extension UnsafeMutablePointer: UnsafeCxxMutableRandomAccessIterator
where Pointee: ~Copyable {}
9 changes: 5 additions & 4 deletions stdlib/public/Synchronization/AtomicPointers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===//

@available(SwiftStdlib 6.0, *)
extension UnsafePointer: AtomicRepresentable {
extension UnsafePointer: AtomicRepresentable where Pointee: ~Copyable {
/// The storage representation type that `Self` encodes to and decodes from
/// which is a suitable type when used in atomic operations.
@available(SwiftStdlib 6.0, *)
Expand Down Expand Up @@ -65,7 +65,7 @@ extension UnsafePointer: AtomicRepresentable {
}

@available(SwiftStdlib 6.0, *)
extension UnsafePointer: AtomicOptionalRepresentable {
extension UnsafePointer: AtomicOptionalRepresentable where Pointee: ~Copyable {
/// The storage representation type that encodes to and decodes from
/// `Optional<Self>` which is a suitable type when used in atomic operations
/// on `Optional`.
Expand Down Expand Up @@ -121,7 +121,7 @@ extension UnsafePointer: AtomicOptionalRepresentable {
//===----------------------------------------------------------------------===//

@available(SwiftStdlib 6.0, *)
extension UnsafeMutablePointer: AtomicRepresentable {
extension UnsafeMutablePointer: AtomicRepresentable where Pointee: ~Copyable {
/// The storage representation type that `Self` encodes to and decodes from
/// which is a suitable type when used in atomic operations.
@available(SwiftStdlib 6.0, *)
Expand Down Expand Up @@ -171,7 +171,8 @@ extension UnsafeMutablePointer: AtomicRepresentable {
}

@available(SwiftStdlib 6.0, *)
extension UnsafeMutablePointer: AtomicOptionalRepresentable {
extension UnsafeMutablePointer: AtomicOptionalRepresentable
where Pointee: ~Copyable {
/// The storage representation type that encodes to and decodes from
/// `Optional<Self>` which is a suitable type when used in atomic operations
/// on `Optional`.
Expand Down
1 change: 1 addition & 0 deletions stdlib/public/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Macros")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "FreestandingMacros")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable")
list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BorrowingSwitch")

if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "")
set(swift_bin_dir "${CMAKE_BINARY_DIR}/bin")
Expand Down
34 changes: 26 additions & 8 deletions stdlib/public/core/CTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2024 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
Expand Down Expand Up @@ -150,38 +150,58 @@ public struct OpaquePointer {
internal init(_ v: Builtin.RawPointer) {
self._rawValue = v
}
}

@available(*, unavailable)
extension OpaquePointer: Sendable {}

/// Creates an `OpaquePointer` from a given address in memory.
extension OpaquePointer {
/// Creates a new `OpaquePointer` from the given address, specified as a bit
/// pattern.
///
/// - Parameter bitPattern: A bit pattern to use for the address of the new
/// pointer. If `bitPattern` is zero, the result is `nil`.
@_transparent
public init?(bitPattern: Int) {
if bitPattern == 0 { return nil }
self._rawValue = Builtin.inttoptr_Word(bitPattern._builtinWordValue)
}

/// Creates an `OpaquePointer` from a given address in memory.
/// Creates a new `OpaquePointer` from the given address, specified as a bit
/// pattern.
///
/// - Parameter bitPattern: A bit pattern to use for the address of the new
/// pointer. If `bitPattern` is zero, the result is `nil`.
@_transparent
public init?(bitPattern: UInt) {
if bitPattern == 0 { return nil }
self._rawValue = Builtin.inttoptr_Word(bitPattern._builtinWordValue)
}
}

extension OpaquePointer {
/// Converts a typed `UnsafePointer` to an opaque C pointer.
@_transparent
public init<T>(@_nonEphemeral _ from: UnsafePointer<T>) {
@_preInverseGenerics
public init<T: ~Copyable>(@_nonEphemeral _ from: UnsafePointer<T>) {
self._rawValue = from._rawValue
}

/// Converts a typed `UnsafePointer` to an opaque C pointer.
///
/// The result is `nil` if `from` is `nil`.
@_transparent
public init?<T>(@_nonEphemeral _ from: UnsafePointer<T>?) {
@_preInverseGenerics
public init?<T: ~Copyable>(@_nonEphemeral _ from: UnsafePointer<T>?) {
guard let unwrapped = from else { return nil }
self.init(unwrapped)
}
}

extension OpaquePointer {
/// Converts a typed `UnsafeMutablePointer` to an opaque C pointer.
@_transparent
@_preInverseGenerics
public init<T>(@_nonEphemeral _ from: UnsafeMutablePointer<T>) {
self._rawValue = from._rawValue
}
Expand All @@ -190,6 +210,7 @@ public struct OpaquePointer {
///
/// The result is `nil` if `from` is `nil`.
@_transparent
@_preInverseGenerics
public init?<T>(@_nonEphemeral _ from: UnsafeMutablePointer<T>?) {
guard let unwrapped = from else { return nil }
self.init(unwrapped)
Expand All @@ -215,9 +236,6 @@ extension OpaquePointer: Hashable {
}
}

@available(*, unavailable)
extension OpaquePointer : Sendable { }

@_unavailableInEmbedded
extension OpaquePointer: CustomDebugStringConvertible {
/// A textual representation of the pointer, suitable for debugging.
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/core/CompilerProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public protocol CaseIterable {
/// `Optional` type conforms to `ExpressibleByNilLiteral`.
/// `ExpressibleByNilLiteral` conformance for types that use `nil` for other
/// purposes is discouraged.
public protocol ExpressibleByNilLiteral {
public protocol ExpressibleByNilLiteral: ~Copyable {
/// Creates an instance initialized with `nil`.
init(nilLiteral: ())
}
Expand Down
33 changes: 23 additions & 10 deletions stdlib/public/core/MemoryLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2024 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
Expand Down Expand Up @@ -40,7 +40,12 @@
/// byteCount: count * MemoryLayout<Point>.stride,
/// alignment: MemoryLayout<Point>.alignment)
@frozen // namespace
public enum MemoryLayout<T> {
public enum MemoryLayout<T: ~Copyable> {}

@available(*, unavailable)
extension MemoryLayout : _BitwiseCopyable {}

extension MemoryLayout where T: ~Copyable {
/// The contiguous memory footprint of `T`, in bytes.
///
/// A type's size does not include any dynamically allocated or out of line
Expand All @@ -50,6 +55,7 @@ public enum MemoryLayout<T> {
/// When allocating memory for multiple instances of `T` using an unsafe
/// pointer, use a multiple of the type's stride instead of its size.
@_transparent
@_preInverseGenerics
public static var size: Int {
return Int(Builtin.sizeof(T.self))
}
Expand All @@ -62,6 +68,7 @@ public enum MemoryLayout<T> {
/// trades runtime performance for space efficiency. This value is always
/// positive.
@_transparent
@_preInverseGenerics
public static var stride: Int {
return Int(Builtin.strideof(T.self))
}
Expand All @@ -71,15 +78,13 @@ public enum MemoryLayout<T> {
/// Use the `alignment` property for a type when allocating memory using an
/// unsafe pointer. This value is always positive.
@_transparent
@_preInverseGenerics
public static var alignment: Int {
return Int(Builtin.alignof(T.self))
}
}

@available(*, unavailable)
extension MemoryLayout : _BitwiseCopyable {}

extension MemoryLayout {
extension MemoryLayout where T: ~Copyable {
/// Returns the contiguous memory footprint of the given instance.
///
/// The result does not include any dynamically allocated or out of line
Expand All @@ -103,7 +108,8 @@ extension MemoryLayout {
/// - Parameter value: A value representative of the type to describe.
/// - Returns: The size, in bytes, of the given value's type.
@_transparent
public static func size(ofValue value: T) -> Int {
@_preInverseGenerics
public static func size(ofValue value: borrowing T) -> Int {
return MemoryLayout.size
}

Expand Down Expand Up @@ -131,7 +137,8 @@ extension MemoryLayout {
/// - Parameter value: A value representative of the type to describe.
/// - Returns: The stride, in bytes, of the given value's type.
@_transparent
public static func stride(ofValue value: T) -> Int {
@_preInverseGenerics
public static func stride(ofValue value: borrowing T) -> Int {
return MemoryLayout.stride
}

Expand All @@ -156,10 +163,13 @@ extension MemoryLayout {
/// - Returns: The default memory alignment, in bytes, of the given value's
/// type. This value is always positive.
@_transparent
public static func alignment(ofValue value: T) -> Int {
@_preInverseGenerics
public static func alignment(ofValue value: borrowing T) -> Int {
return MemoryLayout.alignment
}
}

extension MemoryLayout {
/// Returns the offset of an inline stored property within a type's in-memory
/// representation.
///
Expand Down Expand Up @@ -229,12 +239,15 @@ extension MemoryLayout {
@_transparent
@_unavailableInEmbedded
public static func offset(of key: PartialKeyPath<T>) -> Int? {
// FIXME(noncopyableGenerics): The new (implicit) `where T: Copyable`
// extension constraint currently changes the mangling of this from a
// standalone function to an extension method.
return key._storedInlineOffset
}
}

// Not-yet-public alignment conveniences
extension MemoryLayout {
extension MemoryLayout where T: ~Copyable {
internal static var _alignmentMask: Int { return alignment - 1 }

internal static func _roundingUpToAlignment(_ value: Int) -> Int {
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/core/MigrationSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2024 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
Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/core/MutableCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,8 @@ extension MutableCollection {
/// - a: The first value to swap.
/// - b: The second value to swap.
@inlinable
public func swap<T>(_ a: inout T, _ b: inout T) {
@_preInverseGenerics
public func swap<T: ~Copyable>(_ a: inout T, _ b: inout T) {
// Semantically equivalent to (a, b) = (b, a).
// Microoptimized to avoid retain/release traffic.
#if $BuiltinUnprotectedAddressOf
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/core/NFC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ extension Unicode._InternalNFC.Iterator: IteratorProtocol {
}

// If we have a leftover composee, make sure to return it.
return composee._take()
return composee.take()
}
}

Expand Down
Loading