Skip to content

Commit 184d25e

Browse files
Merge pull request #80856 from nate-chandler/cherrypick/release/6.2/rdar148783895
6.2: [CoroutineAccessors] Only reference when available
2 parents 15ecd66 + de1d5ae commit 184d25e

13 files changed

+511
-57
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6242,10 +6242,16 @@ class AbstractStorageDecl : public ValueDecl {
62426242
bool forConformance=false) const;
62436243

62446244
/// Determine how this storage declaration should actually be accessed.
6245-
AccessStrategy getAccessStrategy(AccessSemantics semantics,
6246-
AccessKind accessKind, ModuleDecl *module,
6247-
ResilienceExpansion expansion,
6248-
bool useOldABI) const;
6245+
AccessStrategy getAccessStrategy(
6246+
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
6247+
ResilienceExpansion expansion,
6248+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
6249+
bool useOldABI) const;
6250+
6251+
/// Whether access is via physical storage.
6252+
bool isAccessedViaPhysicalStorage(AccessSemantics semantics,
6253+
AccessKind accessKind, ModuleDecl *module,
6254+
ResilienceExpansion expansion) const;
62496255

62506256
/// Do we need to use resilient access patterns outside of this
62516257
/// property's resilience domain?

lib/AST/Decl.cpp

Lines changed: 95 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
//===--- Decl.cpp - Swift Language Decl ASTs ------------------------------===//
32
//
43
// This source file is part of the Swift.org open source project
@@ -15,7 +14,6 @@
1514
//
1615
//===----------------------------------------------------------------------===//
1716

18-
#include "swift/Strings.h"
1917
#include "swift/AST/Decl.h"
2018
#include "swift/AST/ASTContext.h"
2119
#include "swift/AST/ASTMangler.h"
@@ -24,6 +22,7 @@
2422
#include "swift/AST/AccessRequests.h"
2523
#include "swift/AST/AccessScope.h"
2624
#include "swift/AST/Attr.h"
25+
#include "swift/AST/AvailabilityContext.h"
2726
#include "swift/AST/AvailabilityInference.h"
2827
#include "swift/AST/CaptureInfo.h"
2928
#include "swift/AST/ConformanceLookup.h"
@@ -64,6 +63,7 @@
6463
#include "swift/ClangImporter/ClangModule.h"
6564
#include "swift/Demangling/ManglingMacros.h"
6665
#include "swift/Parse/Lexer.h" // FIXME: Bad dependency
66+
#include "swift/Strings.h"
6767
#include "clang/Lex/MacroInfo.h"
6868
#include "llvm/ADT/DenseMap.h"
6969
#include "llvm/ADT/SmallPtrSet.h"
@@ -3022,9 +3022,11 @@ getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) {
30223022
llvm_unreachable("bad impl kind");
30233023
}
30243024

3025-
static AccessStrategy
3026-
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
3027-
bool useOldABI);
3025+
static AccessStrategy getOpaqueReadAccessStrategy(
3026+
const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module,
3027+
ResilienceExpansion expansion,
3028+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
3029+
bool useOldABI);
30283030
static AccessStrategy
30293031
getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch);
30303032

@@ -3039,7 +3041,9 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
30393041
// If the storage isDynamic (and not @objc) use the accessors.
30403042
if (storage->shouldUseNativeDynamicDispatch())
30413043
return AccessStrategy::getMaterializeToTemporary(
3042-
getOpaqueReadAccessStrategy(storage, false, false),
3044+
getOpaqueReadAccessStrategy(storage, false, nullptr,
3045+
ResilienceExpansion::Minimal,
3046+
std::nullopt, false),
30433047
getOpaqueWriteAccessStrategy(storage, false));
30443048
return AccessStrategy::getStorage();
30453049
}
@@ -3076,15 +3080,61 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
30763080
llvm_unreachable("bad impl kind");
30773081
}
30783082

3079-
static AccessStrategy
3080-
getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch,
3081-
bool useOldABI) {
3083+
static bool mayReferenceUseCoroutineAccessorOnStorage(
3084+
ModuleDecl *module, ResilienceExpansion expansion,
3085+
std::optional<std::pair<SourceRange, const DeclContext *>> reference,
3086+
const AbstractStorageDecl *storage) {
3087+
assert(storage);
3088+
ASTContext &ctx = storage->getASTContext();
3089+
assert(ctx.LangOpts.hasFeature(Feature::CoroutineAccessors));
3090+
3091+
// For triples without platforms, coroutine accessors are always available.
3092+
auto domain = ctx.getTargetAvailabilityDomain();
3093+
if (domain.isUniversal())
3094+
return true;
3095+
3096+
// A non-resilient access to storage can always use the coroutine accessor,
3097+
// provided it exists. Such an access is compiled with the version of the
3098+
// module that includes the accessor.
3099+
bool resilient = [&] {
3100+
if (module)
3101+
return storage->isResilient(module, expansion);
3102+
else
3103+
return storage->isResilient();
3104+
}();
3105+
if (!resilient)
3106+
return true;
3107+
3108+
// Without knowing where the storage is referenced, it can't be known that
3109+
// a coroutine accessor is available.
3110+
if (!reference) {
3111+
return false;
3112+
}
3113+
3114+
// A resilient access to storage may only use a coroutine accessor if the
3115+
// storage became available no earlier than the feature.
3116+
auto referenceAvailability = AvailabilityContext::forLocation(
3117+
reference->first.Start, reference->second)
3118+
.getPlatformRange();
3119+
auto featureAvailability =
3120+
storage->getASTContext().getCoroutineAccessorsAvailability();
3121+
3122+
return referenceAvailability.isContainedIn(featureAvailability);
3123+
}
3124+
3125+
static AccessStrategy getOpaqueReadAccessStrategy(
3126+
const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module,
3127+
ResilienceExpansion expansion,
3128+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
3129+
bool useOldABI) {
30823130
if (useOldABI) {
30833131
assert(storage->requiresOpaqueRead2Coroutine());
30843132
assert(storage->requiresOpaqueReadCoroutine());
30853133
return AccessStrategy::getAccessor(AccessorKind::Read, dispatch);
30863134
}
3087-
if (storage->requiresOpaqueRead2Coroutine())
3135+
if (storage->requiresOpaqueRead2Coroutine() &&
3136+
mayReferenceUseCoroutineAccessorOnStorage(module, expansion, location,
3137+
storage))
30883138
return AccessStrategy::getAccessor(AccessorKind::Read2, dispatch);
30893139
if (storage->requiresOpaqueReadCoroutine())
30903140
return AccessStrategy::getAccessor(AccessorKind::Read, dispatch);
@@ -3098,41 +3148,53 @@ getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch)
30983148
return AccessStrategy::getAccessor(AccessorKind::Set, dispatch);
30993149
}
31003150

3101-
static AccessStrategy
3102-
getOpaqueReadWriteAccessStrategy(const AbstractStorageDecl *storage,
3103-
bool dispatch, bool useOldABI) {
3151+
static AccessStrategy getOpaqueReadWriteAccessStrategy(
3152+
const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module,
3153+
ResilienceExpansion expansion,
3154+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
3155+
bool useOldABI) {
31043156
if (useOldABI) {
31053157
assert(storage->requiresOpaqueModify2Coroutine());
31063158
assert(storage->requiresOpaqueModifyCoroutine());
31073159
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
31083160
}
3109-
if (storage->requiresOpaqueModify2Coroutine())
3161+
if (storage->requiresOpaqueModify2Coroutine() &&
3162+
mayReferenceUseCoroutineAccessorOnStorage(module, expansion, location,
3163+
storage))
31103164
return AccessStrategy::getAccessor(AccessorKind::Modify2, dispatch);
31113165
if (storage->requiresOpaqueModifyCoroutine())
31123166
return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch);
31133167
return AccessStrategy::getMaterializeToTemporary(
3114-
getOpaqueReadAccessStrategy(storage, dispatch, false),
3168+
getOpaqueReadAccessStrategy(storage, dispatch, nullptr,
3169+
ResilienceExpansion::Minimal, location,
3170+
false),
31153171
getOpaqueWriteAccessStrategy(storage, dispatch));
31163172
}
31173173

3118-
static AccessStrategy
3119-
getOpaqueAccessStrategy(const AbstractStorageDecl *storage,
3120-
AccessKind accessKind, bool dispatch, bool useOldABI) {
3174+
static AccessStrategy getOpaqueAccessStrategy(
3175+
const AbstractStorageDecl *storage, AccessKind accessKind, bool dispatch,
3176+
ModuleDecl *module, ResilienceExpansion expansion,
3177+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
3178+
bool useOldABI) {
31213179
switch (accessKind) {
31223180
case AccessKind::Read:
3123-
return getOpaqueReadAccessStrategy(storage, dispatch, useOldABI);
3181+
return getOpaqueReadAccessStrategy(storage, dispatch, module, expansion,
3182+
location, useOldABI);
31243183
case AccessKind::Write:
31253184
assert(!useOldABI);
31263185
return getOpaqueWriteAccessStrategy(storage, dispatch);
31273186
case AccessKind::ReadWrite:
3128-
return getOpaqueReadWriteAccessStrategy(storage, dispatch, useOldABI);
3187+
return getOpaqueReadWriteAccessStrategy(storage, dispatch, module,
3188+
expansion, location, useOldABI);
31293189
}
31303190
llvm_unreachable("bad access kind");
31313191
}
31323192

31333193
AccessStrategy AbstractStorageDecl::getAccessStrategy(
31343194
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
3135-
ResilienceExpansion expansion, bool useOldABI) const {
3195+
ResilienceExpansion expansion,
3196+
std::optional<std::pair<SourceRange, const DeclContext *>> location,
3197+
bool useOldABI) const {
31363198
switch (semantics) {
31373199
case AccessSemantics::DirectToStorage:
31383200
assert(hasStorage() || getASTContext().Diags.hadAnyError());
@@ -3149,11 +3211,11 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
31493211
// accessors are dynamically dispatched, and we cannot do direct access.
31503212
if (isPolymorphic(this))
31513213
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true,
3152-
useOldABI);
3214+
module, expansion, location, useOldABI);
31533215

31543216
if (shouldUseNativeDynamicDispatch())
31553217
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
3156-
useOldABI);
3218+
module, expansion, location, useOldABI);
31573219

31583220
// If the storage is resilient from the given module and resilience
31593221
// expansion, we cannot use direct access.
@@ -3176,7 +3238,7 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
31763238

31773239
if (resilient)
31783240
return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false,
3179-
useOldABI);
3241+
module, expansion, location, useOldABI);
31803242
}
31813243

31823244
LLVM_FALLTHROUGH;
@@ -3196,6 +3258,15 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
31963258
llvm_unreachable("bad access semantics");
31973259
}
31983260

3261+
bool AbstractStorageDecl::isAccessedViaPhysicalStorage(
3262+
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
3263+
ResilienceExpansion expansion) const {
3264+
return getAccessStrategy(semantics, accessKind, module, expansion,
3265+
/*location=*/std::nullopt,
3266+
/*useOldABI=*/false)
3267+
.getKind() == AccessStrategy::Kind::Storage;
3268+
}
3269+
31993270
bool AbstractStorageDecl::requiresOpaqueAccessors() const {
32003271
// Subscripts always require opaque accessors, so don't even kick off
32013272
// a request.

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,7 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
19741974
auto strategy = decl->getAccessStrategy(
19751975
AccessSemantics::Ordinary,
19761976
decl->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
1977-
M.getSwiftModule(), expansion,
1977+
M.getSwiftModule(), expansion, std::nullopt,
19781978
/*useOldABI=*/false);
19791979
switch (strategy.getKind()) {
19801980
case AccessStrategy::Storage: {

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3335,12 +3335,15 @@ Expr *SILGenFunction::findStorageReferenceExprForMoveOnly(Expr *argExpr,
33353335

33363336
if (!storage)
33373337
return nullptr;
3338+
33383339
// This should match the strategy computation used in
33393340
// SILGenLValue::visit{DeclRef,Member}RefExpr.
3340-
auto strategy = storage->getAccessStrategy(accessSemantics,
3341-
AccessKind::Read, SGM.M.getSwiftModule(), F.getResilienceExpansion(),
3342-
/* old abi*/ false);
3343-
3341+
auto strategy = storage->getAccessStrategy(
3342+
accessSemantics, AccessKind::Read, SGM.M.getSwiftModule(),
3343+
F.getResilienceExpansion(),
3344+
std::make_pair<>(argExpr->getSourceRange(), FunctionDC),
3345+
/* old abi*/ false);
3346+
33443347
switch (strategy.getKind()) {
33453348
case AccessStrategy::Storage:
33463349
// Storage can benefit from direct borrowing/consumption.

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3815,6 +3815,7 @@ static SILFunction *getOrCreateKeyPathSetter(
38153815
auto semantics = AccessSemantics::Ordinary;
38163816
auto strategy = property->getAccessStrategy(semantics, AccessKind::Write,
38173817
SGM.M.getSwiftModule(), expansion,
3818+
std::nullopt,
38183819
/*useOldABI=*/false);
38193820

38203821
LValueOptions lvOptions;
@@ -4634,7 +4635,7 @@ KeyPathPatternComponent SILGenModule::emitKeyPathComponentForDecl(
46344635
auto strategy = storage->getAccessStrategy(
46354636
AccessSemantics::Ordinary,
46364637
storage->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
4637-
M.getSwiftModule(), expansion,
4638+
M.getSwiftModule(), expansion, std::nullopt,
46384639
/*useOldABI=*/false);
46394640

46404641
AbstractStorageDecl *externalDecl = nullptr;

lib/SILGen/SILGenLValue.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,10 +3115,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
31153115

31163116
assert(!e->getType()->is<LValueType>());
31173117

3118+
auto pair = std::make_pair<>(e->getSourceRange(), SGF.FunctionDC);
3119+
31183120
auto accessSemantics = e->getAccessSemantics();
31193121
AccessStrategy strategy = var->getAccessStrategy(
31203122
accessSemantics, getFormalAccessKind(accessKind),
3121-
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
3123+
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(), pair,
31223124
/*useOldABI=*/false);
31233125

31243126
auto baseFormalType = getBaseFormalType(e->getBase());
@@ -3396,7 +3398,7 @@ static LValue emitLValueForNonMemberVarDecl(
33963398
auto access = getFormalAccessKind(accessKind);
33973399
auto strategy = var->getAccessStrategy(
33983400
semantics, access, SGF.SGM.M.getSwiftModule(),
3399-
SGF.F.getResilienceExpansion(), /*useOldABI=*/false);
3401+
SGF.F.getResilienceExpansion(), std::nullopt, /*useOldABI=*/false);
34003402

34013403
lv.addNonMemberVarComponent(SGF, loc, var, subs, options, accessKind,
34023404
strategy, formalRValueType, actorIso);
@@ -4032,6 +4034,7 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
40324034
AccessStrategy strategy = var->getAccessStrategy(
40334035
accessSemantics, getFormalAccessKind(accessKind),
40344036
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4037+
std::make_pair<>(e->getSourceRange(), SGF.FunctionDC),
40354038
/*useOldABI=*/isSynthesizedDefaultImplementionThunk(SGF));
40364039

40374040
bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);
@@ -4053,6 +4056,7 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
40534056
strategy = var->getAccessStrategy(
40544057
accessSemantics, getFormalAccessKind(accessKind),
40554058
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4059+
std::make_pair<>(e->getSourceRange(), SGF.FunctionDC),
40564060
/*useOldABI=*/false);
40574061
}
40584062
}
@@ -4254,6 +4258,7 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
42544258
auto strategy = decl->getAccessStrategy(
42554259
accessSemantics, getFormalAccessKind(accessKind),
42564260
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4261+
std::make_pair<>(e->getSourceRange(), SGF.FunctionDC),
42574262
/*useOldABI=*/isSynthesizedDefaultImplementionThunk(SGF));
42584263

42594264
bool isOnSelfParameter = isCallToSelfOfCurrentFunction(SGF, e);
@@ -4274,6 +4279,7 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
42744279
strategy = decl->getAccessStrategy(
42754280
accessSemantics, getFormalAccessKind(accessKind),
42764281
SGF.SGM.M.getSwiftModule(), SGF.F.getResilienceExpansion(),
4282+
std::make_pair<>(e->getSourceRange(), SGF.FunctionDC),
42774283
/*useOldABI=*/false);
42784284
}
42794285
}
@@ -4744,7 +4750,7 @@ LValue SILGenFunction::emitPropertyLValue(SILLocation loc, ManagedValue base,
47444750

47454751
AccessStrategy strategy = ivar->getAccessStrategy(
47464752
semantics, getFormalAccessKind(accessKind), SGM.M.getSwiftModule(),
4747-
F.getResilienceExpansion(), /*useOldABI=*/false);
4753+
F.getResilienceExpansion(), std::nullopt, /*useOldABI=*/false);
47484754

47494755
auto baseAccessKind =
47504756
getBaseAccessKind(SGM, ivar, accessKind, strategy, baseFormalType,
@@ -5460,7 +5466,7 @@ RValue SILGenFunction::emitRValueForStorageLoad(
54605466
bool isBaseGuaranteed) {
54615467
AccessStrategy strategy = storage->getAccessStrategy(
54625468
semantics, AccessKind::Read, SGM.M.getSwiftModule(),
5463-
F.getResilienceExpansion(), /*useOldABI=*/false);
5469+
F.getResilienceExpansion(), std::nullopt, /*useOldABI=*/false);
54645470

54655471
// If we should call an accessor of some kind, do so.
54665472
if (strategy.getKind() != AccessStrategy::Storage) {

lib/SILGen/SILGenPattern.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,11 +3323,13 @@ static bool isBorrowableSubject(SILGenFunction &SGF,
33233323
if (!storage) {
33243324
return false;
33253325
}
3326-
3326+
3327+
auto pair = std::make_pair<>(subjectExpr->getSourceRange(), SGF.FunctionDC);
3328+
33273329
// Check the access strategy used to read the storage.
33283330
auto strategy =
33293331
storage->getAccessStrategy(access, AccessKind::Read, SGF.SGM.SwiftModule,
3330-
SGF.F.getResilienceExpansion(),
3332+
SGF.F.getResilienceExpansion(), pair,
33313333
/*useOldABI=*/false);
33323334

33333335
switch (strategy.getKind()) {

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,11 +4407,9 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
44074407

44084408
// Check what access strategy is used for a read-write access. It must be
44094409
// direct-to-storage in order for the conversion to be non-ephemeral.
4410-
auto access = asd->getAccessStrategy(
4410+
return asd->isAccessedViaPhysicalStorage(
44114411
AccessSemantics::Ordinary, AccessKind::ReadWrite,
4412-
DC->getParentModule(), DC->getResilienceExpansion(),
4413-
/*useOldABI=*/false);
4414-
return access.getKind() == AccessStrategy::Storage;
4412+
DC->getParentModule(), DC->getResilienceExpansion());
44154413
};
44164414

44174415
SourceRange range;

0 commit comments

Comments
 (0)