Skip to content

Commit fb584f8

Browse files
authored
Merge branch 'main' into async-sequence-fixes
2 parents 220392b + 8c67d15 commit fb584f8

File tree

51 files changed

+1079
-169
lines changed

Some content is hidden

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

51 files changed

+1079
-169
lines changed

docs/ABI/CallConvSummary.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ Register usage
140140
| ``x8`` | | Indirect result | | | |
141141
| | | location register | | | |
142142
+----------+---------+-------------------------+----------+----------+----------+
143-
| ``x16`` | ``ip0`` | Scratch registers (used | | | |
144-
+----------+---------+ by dyld, can be used | | | |
145-
| ``x17`` | ``ip1`` | freely otherwise) | | | |
143+
| ``x16``, | ``ip0``,| Scratch registers (used | | | |
144+
| ``x17`` | ``ip1`` | by dyld, can be used | | | |
145+
| | | freely otherwise) | | | |
146146
+----------+---------+-------------------------+----------+----------+----------+
147147
| ``x18`` | | RESERVED **DO NOT USE** | | | |
148148
+----------+---------+-------------------------+----------+----------+----------+

include/swift/ABI/Executor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,12 @@ class SerialExecutorRef {
155155
return reinterpret_cast<DefaultActor*>(Identity);
156156
}
157157

158+
bool hasSerialExecutorWitnessTable() const {
159+
return !isGeneric() && !isDefaultActor();
160+
}
161+
158162
const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const {
159-
assert(!isGeneric() && !isDefaultActor());
163+
assert(hasSerialExecutorWitnessTable());
160164
auto table = Implementation & WitnessTableMask;
161165
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
162166
}

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4669,7 +4669,7 @@ ERROR(value_of_module_type,none,
46694669
"expected module member name after module name", ())
46704670

46714671
ERROR(value_of_metatype_type,none,
4672-
"expected member name or constructor call after type name%select{|; this "
4672+
"expected member name or initializer call after type name%select{|; this "
46734673
"will be an error in Swift 6}0", (bool))
46744674

46754675
NOTE(add_parens_to_type,none,
@@ -6516,9 +6516,9 @@ ERROR(dynamic_replacement_replaced_not_objc_dynamic, none,
65166516
ERROR(dynamic_replacement_replacement_not_objc_dynamic, none,
65176517
"%0 is marked @objc dynamic", (DeclName))
65186518
ERROR(dynamic_replacement_replaced_constructor_is_convenience, none,
6519-
"replaced constructor %0 is marked as convenience", (DeclNameRef))
6519+
"replaced initializer %0 is marked as convenience", (DeclNameRef))
65206520
ERROR(dynamic_replacement_replaced_constructor_is_not_convenience, none,
6521-
"replaced constructor %0 is not marked as convenience", (DeclNameRef))
6521+
"replaced initializer %0 is not marked as convenience", (DeclNameRef))
65226522

65236523
//------------------------------------------------------------------------------
65246524
// MARK: @_typeEraser()

include/swift/Runtime/Bincompat.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -47,6 +47,38 @@ bool useLegacySwiftValueUnboxingInCasting();
4747
/// if present.
4848
bool useLegacySwiftObjCHashing();
4949

50+
/// Legacy semantics allowed for the `swift_task_reportUnexpectedExecutor` to
51+
/// only log a warning. This changes in future releases and this function
52+
/// will fatal error always.
53+
///
54+
/// Similarly, the internal runtime function
55+
/// `swift_task_isCurrentExecutor(expected)` was previously allowed to return
56+
/// `false`. In future releases it will call into `checkIsolated`, and CRASH
57+
/// when previously it would have returned false.
58+
///
59+
/// Because some applications were running with "isolation warnings" and
60+
/// those call into the `isCurrentExecutor` API and expected warnings to be
61+
/// logged, but they ignored those warnings we cannot make them crashing,
62+
/// and must check if the app was built against a new.
63+
///
64+
/// Old behavior:
65+
/// - `swift_task_isCurrentExecutorImpl` cannot crash and does NOT invoke
66+
/// `SerialExecutor.checkIsolated`
67+
/// - `swift_task_isCurrentExecutorImpl` does not invoke `checkIsolated`
68+
/// - logging a warning on concurrency violation is allowed
69+
///
70+
/// New behavior:
71+
/// - always fatal error in `swift_task_reportUnexpectedExecutor`
72+
/// - `swift_task_isCurrentExecutorImpl` will crash when it would have returned
73+
/// false
74+
/// - `swift_task_isCurrentExecutorImpl` does invoke `checkIsolated` when other
75+
/// checks failed
76+
///
77+
/// This can be overridden by using `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=1`
78+
/// or `SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=crash|nocrash`
79+
SWIFT_RUNTIME_STDLIB_SPI
80+
bool swift_bincompat_useLegacyNonCrashingExecutorChecks();
81+
5082
} // namespace bincompat
5183

5284
} // namespace runtime

include/swift/Runtime/Concurrency.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,11 @@ void swift_task_enqueue(Job *job, SerialExecutorRef executor);
715715
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
716716
void swift_task_enqueueGlobal(Job *job);
717717

718+
/// Invoke an executor's `checkIsolated` or otherwise equivalent API,
719+
/// that will crash if the current executor is NOT the passed executor.
720+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
721+
void swift_task_checkIsolated(SerialExecutorRef executor);
722+
718723
/// A count in nanoseconds.
719724
using JobDelay = unsigned long long;
720725

@@ -729,6 +734,9 @@ void swift_task_enqueueGlobalWithDeadline(long long sec, long long nsec,
729734
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
730735
void swift_task_enqueueMainExecutor(Job *job);
731736

737+
/// WARNING: This method is expected to CRASH when caller is not on the
738+
/// expected executor.
739+
///
732740
/// Return true if the caller is running in a Task on the passed Executor.
733741
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
734742
bool swift_task_isOnExecutor(
@@ -781,6 +789,12 @@ SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_hook)(
781789
int clock, Job *job,
782790
swift_task_enqueueGlobalWithDeadline_original original);
783791

792+
typedef SWIFT_CC(swift) void (*swift_task_checkIsolated_original)(SerialExecutorRef executor);
793+
SWIFT_EXPORT_FROM(swift_Concurrency)
794+
SWIFT_CC(swift) void (*swift_task_checkIsolated_hook)(
795+
SerialExecutorRef executor, swift_task_checkIsolated_original original);
796+
797+
784798
typedef SWIFT_CC(swift) bool (*swift_task_isOnExecutor_original)(
785799
HeapObject *executor,
786800
const Metadata *selfType,

lib/AST/Pattern.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,9 @@ Pattern::getOwnership(
777777
void visitNamedPattern(NamedPattern *p) {
778778
switch (p->getDecl()->getIntroducer()) {
779779
case VarDecl::Introducer::Let:
780+
// `let` defaults to the prevailing ownership of the switch.
781+
break;
782+
780783
case VarDecl::Introducer::Var:
781784
// If the subpattern type is copyable, then we can bind the variable
782785
// by copying without requiring more than a borrow of the original.
@@ -786,7 +789,7 @@ Pattern::getOwnership(
786789
// TODO: An explicit `consuming` binding kind consumes regardless of
787790
// type.
788791

789-
// Noncopyable `let` and `var` consume the bound value to move it into
792+
// Noncopyable `var` consumes the bound value to move it into
790793
// a new independent variable.
791794
increaseOwnership(ValueOwnership::Owned, p);
792795
break;
@@ -797,8 +800,8 @@ Pattern::getOwnership(
797800
break;
798801

799802
case VarDecl::Introducer::Borrowing:
800-
// `borrow` bindings borrow parts of the value in-place so they don't
801-
// need stronger access to the subject value.
803+
// `borrow` bindings borrow parts of the value in-place.
804+
increaseOwnership(ValueOwnership::Shared, p);
802805
break;
803806
}
804807
}

lib/SILGen/SILGenPattern.cpp

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3218,12 +3218,123 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
32183218
SGF.Cleanups.emitBranchAndCleanups(sharedDest, caseBlock, args);
32193219
}
32203220

3221+
// TODO: Integrate this with findStorageExprForMoveOnly, which does almost the
3222+
// same check.
3223+
static bool isBorrowableSubject(SILGenFunction &SGF,
3224+
Expr *subjectExpr) {
3225+
// Look through forwarding expressions.
3226+
for (;;) {
3227+
subjectExpr = subjectExpr->getValueProvidingExpr();
3228+
3229+
// Look through loads.
3230+
if (auto load = dyn_cast<LoadExpr>(subjectExpr)) {
3231+
subjectExpr = load->getSubExpr();
3232+
continue;
3233+
}
3234+
3235+
// Look through optional force-projections.
3236+
// We can't look through optional evaluations here because wrapping the
3237+
// value up in an Optional at the end needs a copy/move to create the
3238+
// temporary optional.
3239+
if (auto force = dyn_cast<ForceValueExpr>(subjectExpr)) {
3240+
subjectExpr = force->getSubExpr();
3241+
continue;
3242+
}
3243+
3244+
// Look through parens.
3245+
if (auto paren = dyn_cast<ParenExpr>(subjectExpr)) {
3246+
subjectExpr = paren->getSubExpr();
3247+
continue;
3248+
}
3249+
3250+
// Look through `try` and `await`.
3251+
if (auto tryExpr = dyn_cast<TryExpr>(subjectExpr)) {
3252+
subjectExpr = tryExpr->getSubExpr();
3253+
continue;
3254+
}
3255+
if (auto awaitExpr = dyn_cast<AwaitExpr>(subjectExpr)) {
3256+
subjectExpr = awaitExpr->getSubExpr();
3257+
continue;
3258+
}
3259+
3260+
break;
3261+
}
3262+
3263+
// An explicit `borrow` expression requires us to do a borrowing access.
3264+
if (isa<BorrowExpr>(subjectExpr)) {
3265+
return true;
3266+
}
3267+
3268+
AbstractStorageDecl *storage;
3269+
AccessSemantics access;
3270+
3271+
// A subject is potentially borrowable if it's some kind of storage reference.
3272+
if (auto declRef = dyn_cast<DeclRefExpr>(subjectExpr)) {
3273+
storage = dyn_cast<AbstractStorageDecl>(declRef->getDecl());
3274+
access = declRef->getAccessSemantics();
3275+
} else if (auto memberRef = dyn_cast<MemberRefExpr>(subjectExpr)) {
3276+
storage = dyn_cast<AbstractStorageDecl>(memberRef->getMember().getDecl());
3277+
access = memberRef->getAccessSemantics();
3278+
} else if (auto subscript = dyn_cast<SubscriptExpr>(subjectExpr)) {
3279+
storage = dyn_cast<AbstractStorageDecl>(subscript->getMember().getDecl());
3280+
access = subscript->getAccessSemantics();
3281+
} else {
3282+
return false;
3283+
}
3284+
3285+
// If the member being referenced isn't storage, there's no benefit to
3286+
// borrowing it.
3287+
if (!storage) {
3288+
return false;
3289+
}
3290+
3291+
// Check the access strategy used to read the storage.
3292+
auto strategy = storage->getAccessStrategy(access,
3293+
AccessKind::Read,
3294+
SGF.SGM.SwiftModule,
3295+
SGF.F.getResilienceExpansion());
3296+
3297+
switch (strategy.getKind()) {
3298+
case AccessStrategy::Kind::Storage:
3299+
// Accessing storage directly benefits from borrowing.
3300+
return true;
3301+
case AccessStrategy::Kind::DirectToAccessor:
3302+
case AccessStrategy::Kind::DispatchToAccessor:
3303+
// If we use an accessor, the kind of accessor affects whether we get
3304+
// a reference we can borrow or a temporary that will be consumed.
3305+
switch (strategy.getAccessor()) {
3306+
case AccessorKind::Get:
3307+
case AccessorKind::DistributedGet:
3308+
// Get returns an owned value.
3309+
return false;
3310+
case AccessorKind::Read:
3311+
case AccessorKind::Modify:
3312+
case AccessorKind::Address:
3313+
case AccessorKind::MutableAddress:
3314+
// Read, modify, and addressors yield a borrowable reference.
3315+
return true;
3316+
case AccessorKind::Init:
3317+
case AccessorKind::Set:
3318+
case AccessorKind::WillSet:
3319+
case AccessorKind::DidSet:
3320+
llvm_unreachable("should not be involved in a read");
3321+
}
3322+
llvm_unreachable("switch not covered?");
3323+
3324+
case AccessStrategy::Kind::MaterializeToTemporary:
3325+
case AccessStrategy::Kind::DispatchToDistributedThunk:
3326+
return false;
3327+
}
3328+
llvm_unreachable("switch not covered?");
3329+
}
3330+
32213331
void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
32223332
LLVM_DEBUG(llvm::dbgs() << "emitting switch stmt\n";
32233333
S->dump(llvm::dbgs());
32243334
llvm::dbgs() << '\n');
32253335

3226-
auto subjectTy = S->getSubjectExpr()->getType();
3336+
auto subjectExpr = S->getSubjectExpr();
3337+
auto subjectTy = subjectExpr->getType();
32273338
auto subjectLoweredTy = getLoweredType(subjectTy);
32283339
auto subjectLoweredAddress =
32293340
silConv.useLoweredAddresses() && subjectLoweredTy.isAddressOnly(F);
@@ -3244,7 +3355,14 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
32443355
if (getASTContext().LangOpts.hasFeature(Feature::BorrowingSwitch)) {
32453356
if (subjectTy->isNoncopyable()) {
32463357
// Determine the overall ownership behavior of the switch, based on the
3247-
// patterns' ownership behavior.
3358+
// subject expression and the patterns' ownership behavior.
3359+
3360+
// If the subject expression is borrowable, then perform the switch as
3361+
// a borrow. (A `consume` expression would render the expression
3362+
// non-borrowable.) Otherwise, perform it as a consume.
3363+
ownership = isBorrowableSubject(*this, subjectExpr)
3364+
? ValueOwnership::Shared
3365+
: ValueOwnership::Owned;
32483366
for (auto caseLabel : S->getCases()) {
32493367
for (auto item : caseLabel->getCaseLabelItems()) {
32503368
ownership = std::max(ownership, item.getPattern()->getOwnership());

0 commit comments

Comments
 (0)