Skip to content

Commit d311b7e

Browse files
authored
Merge branch 'main' into swift-6-release-note
2 parents 55fd62b + 2d0b194 commit d311b7e

File tree

96 files changed

+2461
-689
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+2461
-689
lines changed

CHANGELOG.md

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
## Swift 6.0
77

8+
89
* Swift 6 comes with a new language mode that prevents the risk of data races
910
at compile time. This guarantee is accomplished through _data isolation_; the
1011
compiler will validate that data passed over a boundary between concurrently
@@ -21,6 +22,34 @@
2122
You can enable the Swift 6 language mode using the `-swift-version 6`
2223
compiler flag.
2324

25+
* [SE-0431][]:
26+
You can now require a function value to carry its actor isolation
27+
dynamically in a way that can be directly read by clients:
28+
29+
```swift
30+
func apply<R>(count: Int,
31+
operation: @isolated(any) async () -> R) async -> [R]
32+
where R: Sendable {
33+
// implementation
34+
}
35+
```
36+
37+
The isolation can read with the `.isolation` property, which has type
38+
`(any Actor)?`:
39+
40+
```swift
41+
let iso = operation.isolation
42+
```
43+
44+
This capability has been adopted by the task-creation APIs in the
45+
standard library. As a result, creating a task with an actor-isolated
46+
function will now synchronously enqueue the task on the actor, which
47+
can be used for transitive event-ordering guarantees if the actor
48+
guarantees that jobs will be run in the order they are enqueued, as
49+
`@MainActor` does. If the function is not explicitly isolated, Swift
50+
still retains the right to optimize enqueues for functions that actually
51+
start by doing work with different isolation from their formal isolation.
52+
2453
* [SE-0423][]:
2554
You can now use `@preconcurrency` attribute to replace static actor isolation
2655
checking with dynamic checks for witnesses of synchronous nonisolated protocol
@@ -61,6 +90,21 @@
6190
The dynamic actor isolation checks can be disabled using the flag
6291
`-disable-dynamic-actor-isolation`.
6392

93+
* [SE-0420][]:
94+
`async` functions can now explicitly inherit the isolation of their caller
95+
by declaring an `isolated` parameter with the default value of `#isolation`:
96+
97+
```swift
98+
func poll(isolation: isolated (any Actor)? = #isolation) async -> [Item] {
99+
// implementation
100+
}
101+
```
102+
103+
When the caller is actor-isolated, this allows it to pass isolated state
104+
to the function, which would otherwise have concurrency problems. The
105+
function may also be able to eliminate unwanted scheduling changes, such
106+
as when it can quickly return in a fast path without needing to suspend.
107+
64108
* [SE-0418][]:
65109

66110
The compiler would now automatically employ `Sendable` on functions
@@ -10458,17 +10502,19 @@ using the `.dynamicType` member to retrieve the type of an expression should mig
1045810502
[SE-0407]: https://github.com/apple/swift-evolution/blob/main/proposals/0407-member-macro-conformances.md
1045910503
[SE-0408]: https://github.com/apple/swift-evolution/blob/main/proposals/0408-pack-iteration.md
1046010504
[SE-0411]: https://github.com/apple/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
10461-
[SE-0417]: https://github.com/apple/swift-evolution/blob/main/proposals/0417-task-executor-preference.md
1046210505
[SE-0412]: https://github.com/apple/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
1046310506
[SE-0413]: https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md
10507+
[SE-0414]: https://github.com/apple/swift-evolution/blob/main/proposals/0414-region-based-isolation.md
10508+
[SE-0417]: https://github.com/apple/swift-evolution/blob/main/proposals/0417-task-executor-preference.md
10509+
[SE-0418]: https://github.com/apple/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md
10510+
[SE-0420]: https://github.com/apple/swift-evolution/blob/main/proposals/0420-inheritance-of-actor-isolation.md
1046410511
[SE-0422]: https://github.com/apple/swift-evolution/blob/main/proposals/0422-caller-side-default-argument-macro-expression.md
10512+
[SE-0423]: https://github.com/apple/swift-evolution/blob/main/proposals/0423-dynamic-actor-isolation.md
1046510513
[SE-0427]: https://github.com/apple/swift-evolution/blob/main/proposals/0427-noncopyable-generics.md
1046610514
[SE-0429]: https://github.com/apple/swift-evolution/blob/main/proposals/0429-partial-consumption.md
1046710515
[SE-0432]: https://github.com/apple/swift-evolution/blob/main/proposals/0432-noncopyable-switch.md
10468-
[SE-0414]: https://github.com/apple/swift-evolution/blob/main/proposals/0414-region-based-isolation.md
1046910516
[SE-0430]: https://github.com/apple/swift-evolution/blob/main/proposals/0430-transferring-parameters-and-results.md
10470-
[SE-0418]: https://github.com/apple/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md
10471-
[SE-0423]: https://github.com/apple/swift-evolution/blob/main/proposals/0423-dynamic-actor-isolation.md
10517+
[SE-0431]: https://github.com/apple/swift-evolution/blob/main/proposals/0431-isolated-any-functions.md
1047210518
[#64927]: <https://github.com/apple/swift/issues/64927>
1047310519
[#42697]: <https://github.com/apple/swift/issues/42697>
1047410520
[#42728]: <https://github.com/apple/swift/issues/42728>

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,34 @@ extension Type {
433433
// Builder initialization
434434
//===----------------------------------------------------------------------===//
435435

436+
private extension Instruction {
437+
/// Returns self, unless self is a meta instruction, in which case the next
438+
/// non-meta instruction is returned. Returns nil if there are no non-meta
439+
/// instructions in the basic block.
440+
var nextNonMetaInstruction: Instruction? {
441+
for inst in InstructionList(first: self) where !(inst is MetaInstruction) {
442+
return inst
443+
}
444+
return nil
445+
}
446+
447+
/// Returns the next interesting location. As it is impossible to set a
448+
/// breakpoint on a meta instruction, those are skipped.
449+
/// However, we don't want to take a location with different inlining
450+
/// information than this instruction, so in that case, we will return the
451+
/// location of the meta instruction. If the meta instruction is the only
452+
/// instruction in the basic block, we also take its location.
453+
var locationOfNextNonMetaInstruction: Location {
454+
let location = self.location
455+
guard !location.isInlined,
456+
let nextLocation = nextNonMetaInstruction?.location,
457+
!nextLocation.isInlined else {
458+
return location
459+
}
460+
return nextLocation
461+
}
462+
}
463+
436464
extension Builder {
437465
/// Creates a builder which inserts _before_ `insPnt`, using a custom `location`.
438466
init(before insPnt: Instruction, location: Location, _ context: some MutatingContext) {
@@ -441,8 +469,23 @@ extension Builder {
441469
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
442470
}
443471

444-
/// Creates a builder which inserts _before_ `insPnt`, using the location of `insPnt`.
472+
/// Creates a builder which inserts before `insPnt`, using `insPnt`'s next
473+
/// non-meta instruction's location.
474+
/// This function should be used when moving code to an unknown insert point,
475+
/// when we want to inherit the location of the closest non-meta instruction.
476+
/// For replacing an existing meta instruction with another, use
477+
/// ``Builder.init(replacing:_:)``.
445478
init(before insPnt: Instruction, _ context: some MutatingContext) {
479+
context.verifyIsTransforming(function: insPnt.parentFunction)
480+
self.init(insertAt: .before(insPnt),
481+
location: insPnt.locationOfNextNonMetaInstruction,
482+
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
483+
}
484+
485+
/// Creates a builder which inserts _before_ `insPnt`, using the exact location of `insPnt`,
486+
/// for the purpose of replacing that meta instruction with an equivalent instruction.
487+
/// This function does not delete `insPnt`.
488+
init(replacing insPnt: MetaInstruction, _ context: some MutatingContext) {
446489
context.verifyIsTransforming(function: insPnt.parentFunction)
447490
self.init(insertAt: .before(insPnt), location: insPnt.location,
448491
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
@@ -460,10 +503,10 @@ extension Builder {
460503
}
461504
}
462505

463-
/// Creates a builder which inserts _after_ `insPnt`, using the location of `insPnt`.
506+
/// Creates a builder which inserts _after_ `insPnt`, using `insPnt`'s next
507+
/// non-meta instruction's location.
464508
init(after insPnt: Instruction, _ context: some MutatingContext) {
465-
context.verifyIsTransforming(function: insPnt.parentFunction)
466-
self.init(after: insPnt, location: insPnt.location, context)
509+
self.init(after: insPnt, location: insPnt.locationOfNextNonMetaInstruction, context)
467510
}
468511

469512
/// Creates a builder which inserts at the end of `block`, using a custom `location`.
@@ -482,11 +525,12 @@ extension Builder {
482525
}
483526

484527
/// Creates a builder which inserts at the begin of `block`, using the location of the first
485-
/// instruction of `block`.
528+
/// non-meta instruction of `block`.
486529
init(atBeginOf block: BasicBlock, _ context: some MutatingContext) {
487530
context.verifyIsTransforming(function: block.parentFunction)
488531
let firstInst = block.instructions.first!
489-
self.init(insertAt: .before(firstInst), location: firstInst.location,
532+
self.init(insertAt: .before(firstInst),
533+
location: firstInst.locationOfNextNonMetaInstruction,
490534
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
491535
}
492536

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,16 @@ public protocol DebugVariableInstruction : VarDeclInstruction {
418418
var debugVariable: DebugVariable { get }
419419
}
420420

421-
final public class DebugValueInst : Instruction, UnaryInstruction, DebugVariableInstruction {
421+
/// A meta instruction is an instruction whose location is not interesting as
422+
/// it is impossible to set a breakpoint on it.
423+
/// That could be because the instruction does not generate code (such as
424+
/// `debug_value`), or because the generated code would be in the prologue
425+
/// (`alloc_stack`).
426+
/// When we are moving code onto an unknown instruction (such as the start of a
427+
/// basic block), we want to ignore any meta instruction that might be there.
428+
public protocol MetaInstruction: Instruction {}
429+
430+
final public class DebugValueInst : Instruction, UnaryInstruction, DebugVariableInstruction, MetaInstruction {
422431
public var varDecl: VarDecl? {
423432
VarDecl(bridged: bridged.DebugValue_getDecl())
424433
}
@@ -1127,7 +1136,7 @@ final public class InitBlockStorageHeaderInst: SingleValueInstruction {}
11271136

11281137
public protocol Allocation : SingleValueInstruction { }
11291138

1130-
final public class AllocStackInst : SingleValueInstruction, Allocation, DebugVariableInstruction {
1139+
final public class AllocStackInst : SingleValueInstruction, Allocation, DebugVariableInstruction, MetaInstruction {
11311140
public var hasDynamicLifetime: Bool { bridged.AllocStackInst_hasDynamicLifetime() }
11321141

11331142
public var varDecl: VarDecl? {

SwiftCompilerSources/Sources/SIL/Location.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public struct Location: Equatable, CustomStringConvertible {
3030

3131
public var hasValidLineNumber: Bool { bridged.hasValidLineNumber() }
3232
public var isAutoGenerated: Bool { bridged.isAutoGenerated() }
33+
public var isInlined: Bool { bridged.isInlined() }
3334

3435
public var isDebugSteppable: Bool { hasValidLineNumber && !isAutoGenerated }
3536

cmake/modules/DarwinSDKs.cmake

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
option(SWIFT_ENABLE_IOS32
2-
"Build 32-bit variants of iOS"
3-
TRUE)
4-
5-
if(SWIFT_ENABLE_IOS32)
6-
set(SUPPORTED_IOS_ARCHS "arm64;arm64e")
7-
set(SUPPORTED_IOS_SIMULATOR_ARCHS "x86_64;arm64")
8-
else()
91
set(SUPPORTED_IOS_ARCHS "arm64;arm64e")
102
set(SUPPORTED_IOS_SIMULATOR_ARCHS "x86_64;arm64")
11-
endif()
12-
133
set(SUPPORTED_TVOS_ARCHS "arm64")
144
set(SUPPORTED_TVOS_SIMULATOR_ARCHS "x86_64;arm64")
155
set(SUPPORTED_WATCHOS_ARCHS "armv7k;arm64_32")

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -955,12 +955,16 @@ the memory of the annotated type:
955955
threads, writes don't overlap with reads or writes coming from the same
956956
thread, and that the pointer is not used after the value is moved or
957957
consumed.
958-
- When the value is moved, a bitwise copy of its memory is performed to the new
959-
address of the value in its new owner. As currently implemented, raw storage
960-
types are not suitable for storing values which are not bitwise-movable, such
961-
as nontrivial C++ types, Objective-C weak references, and data structures
962-
such as `pthread_mutex_t` which are implemented in C as always requiring a
963-
fixed address.
958+
- By default, when the value is moved a bitwise copy of its memory is performed
959+
to the new address of the value in its new owner. This makes it unsuitable to
960+
store not bitwise-movable types such as nontrivial C++ types, Objective-C weak
961+
references, and data structures such as `pthread_mutex_t` which are
962+
implemented in C as always requiring a fixed address. However, you can provide
963+
`movesAsLike` to the `like:` version of this attribute to enforce that moving
964+
the value will defer its move semantics to the type it's like. This makes it
965+
suitable for storing such values that are not bitwise-movable. Note that the
966+
raw storage for this variant must always be properly initialized after
967+
initialization because foreign moves will assume an initialized state.
964968

965969
Using the `@_rawLayout` attribute will suppress the annotated type from
966970
being implicitly `Sendable`. If the type is safe to access across threads, it
@@ -987,6 +991,11 @@ forms are currently accepted:
987991
- `@_rawLayout(likeArrayOf: T, count: N)` specifies the type's size should be
988992
`MemoryLayout<T>.stride * N` and alignment should match `T`'s, like an
989993
array of N contiguous elements of `T` in memory.
994+
- `@_rawLayout(like: T, movesAsLike)` specifies the type's size and alignment
995+
should be equal to the type `T`'s. It also guarantees that moving a value of
996+
this raw layout type will have the same move semantics as the type it's like.
997+
This is important for things like ObjC weak references and non-trivial move
998+
constructors in C++.
990999

9911000
A notable difference between `@_rawLayout(like: T)` and
9921001
`@_rawLayout(likeArrayOf: T, count: 1)` is that the latter will pad out the

include/swift/ABI/TaskLocal.h

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ class TaskLocal {
4444
/// lookups by skipping empty parent tasks during get(), and explained
4545
/// in depth in `createParentLink`.
4646
IsParent = 0b01,
47+
/// The task local binding was created inside the body of a `withTaskGroup`,
48+
/// and therefore must either copy it, or crash when a child task is created
49+
/// using 'group.addTask' and it would refer to this task local.
50+
///
51+
/// Items of this kind must be copied by a group child task for access
52+
/// safety reasons, as otherwise the pop would happen before the child task
53+
/// has completed.
54+
IsNextCreatedInTaskGroupBody = 0b10,
4755
};
4856

4957
class Item {
@@ -101,20 +109,55 @@ class TaskLocal {
101109
/// the Item linked list into the appropriate parent.
102110
static Item *createParentLink(AsyncTask *task, AsyncTask *parent);
103111

112+
static Item *createLink(AsyncTask *task,
113+
const HeapObject *key,
114+
const Metadata *valueType,
115+
bool inTaskGroupBody);
116+
104117
static Item *createLink(AsyncTask *task,
105118
const HeapObject *key,
106119
const Metadata *valueType);
107120

121+
static Item *createLinkInTaskGroup(
122+
AsyncTask *task,
123+
const HeapObject *key,
124+
const Metadata *valueType);
125+
108126
void destroy(AsyncTask *task);
109127

110128
Item *getNext() {
111129
return reinterpret_cast<Item *>(next & ~statusMask);
112130
}
113131

132+
void relinkNext(Item* nextOverride) {
133+
assert(!getNext() &&
134+
"Can only relink task local item that was not pointing at anything yet");
135+
assert(nextOverride->isNextLinkPointer() ||
136+
nextOverride->isParentPointer() &&
137+
"Currently relinking is only done within a task group to "
138+
"avoid within-taskgroup next pointers; attempted to point at "
139+
"task local declared within task group body though!");
140+
141+
next = reinterpret_cast<uintptr_t>(nextOverride) |
142+
static_cast<uintptr_t>((nextOverride->isNextLinkPointer()
143+
? NextLinkType::IsNextCreatedInTaskGroupBody
144+
: NextLinkType::IsParent));
145+
}
146+
114147
NextLinkType getNextLinkType() const {
115148
return static_cast<NextLinkType>(next & statusMask);
116149
}
117150

151+
bool isNextLinkPointer() const {
152+
return static_cast<NextLinkType>(next & statusMask) ==
153+
NextLinkType::IsNext;
154+
}
155+
156+
bool isNextLinkPointerCreatedInTaskGroupBody() const {
157+
return static_cast<NextLinkType>(next & statusMask) ==
158+
NextLinkType::IsNextCreatedInTaskGroupBody;
159+
}
160+
118161
/// Item does not contain any actual value, and is only used to point at
119162
/// a specific parent item.
120163
bool isEmpty() const {
@@ -127,7 +170,7 @@ class TaskLocal {
127170
reinterpret_cast<char *>(this) + storageOffset(valueType));
128171
}
129172

130-
void copyTo(AsyncTask *task);
173+
TaskLocal::Item* copyTo(AsyncTask *task);
131174

132175
/// Compute the offset of the storage from the base of the item.
133176
static size_t storageOffset(const Metadata *valueType) {
@@ -136,9 +179,9 @@ class TaskLocal {
136179
if (valueType) {
137180
size_t alignment = valueType->vw_alignment();
138181
return (offset + alignment - 1) & ~(alignment - 1);
139-
} else {
140-
return offset;
141182
}
183+
184+
return offset;
142185
}
143186

144187
/// Determine the size of the item given a particular value type.
@@ -200,6 +243,9 @@ class TaskLocal {
200243
/// can be safely disposed of.
201244
bool popValue(AsyncTask *task);
202245

246+
/// Peek at the head item and get its type.
247+
std::optional<NextLinkType> peekHeadLinkType() const;
248+
203249
/// Copy all task-local bindings to the target task.
204250
///
205251
/// The new bindings allocate their own items and can out-live the current task.
@@ -212,6 +258,8 @@ class TaskLocal {
212258
/// "pop" of the `B` value - it was spawned from a scope where only B was observable.
213259
void copyTo(AsyncTask *target);
214260

261+
void copyToOnlyOnlyFromCurrent(AsyncTask *target);
262+
215263
/// Destroy and deallocate all items stored by this specific task.
216264
///
217265
/// Items owned by a parent task are left untouched, since we do not own them.

0 commit comments

Comments
 (0)