1-
21// ===--- Decl.cpp - Swift Language Decl ASTs ------------------------------===//
32//
43// This source file is part of the Swift.org open source project
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"
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"
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"
@@ -3026,9 +3026,11 @@ getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) {
30263026 llvm_unreachable (" bad impl kind" );
30273027}
30283028
3029- static AccessStrategy
3030- getOpaqueReadAccessStrategy (const AbstractStorageDecl *storage, bool dispatch,
3031- bool useOldABI);
3029+ static AccessStrategy getOpaqueReadAccessStrategy (
3030+ const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module ,
3031+ ResilienceExpansion expansion,
3032+ std::optional<std::pair<SourceRange, const DeclContext *>> location,
3033+ bool useOldABI);
30323034static AccessStrategy
30333035getOpaqueWriteAccessStrategy (const AbstractStorageDecl *storage, bool dispatch);
30343036
@@ -3043,7 +3045,9 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
30433045 // If the storage isDynamic (and not @objc) use the accessors.
30443046 if (storage->shouldUseNativeDynamicDispatch ())
30453047 return AccessStrategy::getMaterializeToTemporary (
3046- getOpaqueReadAccessStrategy (storage, false , false ),
3048+ getOpaqueReadAccessStrategy (storage, false , nullptr ,
3049+ ResilienceExpansion::Minimal,
3050+ std::nullopt , false ),
30473051 getOpaqueWriteAccessStrategy (storage, false ));
30483052 return AccessStrategy::getStorage ();
30493053 }
@@ -3080,15 +3084,61 @@ getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) {
30803084 llvm_unreachable (" bad impl kind" );
30813085}
30823086
3083- static AccessStrategy
3084- getOpaqueReadAccessStrategy (const AbstractStorageDecl *storage, bool dispatch,
3085- bool useOldABI) {
3087+ static bool mayReferenceUseCoroutineAccessorOnStorage (
3088+ ModuleDecl *module , ResilienceExpansion expansion,
3089+ std::optional<std::pair<SourceRange, const DeclContext *>> reference,
3090+ const AbstractStorageDecl *storage) {
3091+ assert (storage);
3092+ ASTContext &ctx = storage->getASTContext ();
3093+ assert (ctx.LangOpts .hasFeature (Feature::CoroutineAccessors));
3094+
3095+ // For triples without platforms, coroutine accessors are always available.
3096+ auto domain = ctx.getTargetAvailabilityDomain ();
3097+ if (domain.isUniversal ())
3098+ return true ;
3099+
3100+ // A non-resilient access to storage can always use the coroutine accessor,
3101+ // provided it exists. Such an access is compiled with the version of the
3102+ // module that includes the accessor.
3103+ bool resilient = [&] {
3104+ if (module )
3105+ return storage->isResilient (module , expansion);
3106+ else
3107+ return storage->isResilient ();
3108+ }();
3109+ if (!resilient)
3110+ return true ;
3111+
3112+ // Without knowing where the storage is referenced, it can't be known that
3113+ // a coroutine accessor is available.
3114+ if (!reference) {
3115+ return false ;
3116+ }
3117+
3118+ // A resilient access to storage may only use a coroutine accessor if the
3119+ // storage became available no earlier than the feature.
3120+ auto referenceAvailability = AvailabilityContext::forLocation (
3121+ reference->first .Start , reference->second )
3122+ .getPlatformRange ();
3123+ auto featureAvailability =
3124+ storage->getASTContext ().getCoroutineAccessorsAvailability ();
3125+
3126+ return referenceAvailability.isContainedIn (featureAvailability);
3127+ }
3128+
3129+ static AccessStrategy getOpaqueReadAccessStrategy (
3130+ const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module ,
3131+ ResilienceExpansion expansion,
3132+ std::optional<std::pair<SourceRange, const DeclContext *>> location,
3133+ bool useOldABI) {
30863134 if (useOldABI) {
30873135 assert (storage->requiresOpaqueRead2Coroutine ());
30883136 assert (storage->requiresOpaqueReadCoroutine ());
30893137 return AccessStrategy::getAccessor (AccessorKind::Read, dispatch);
30903138 }
3091- if (storage->requiresOpaqueRead2Coroutine ())
3139+ if (storage->requiresOpaqueRead2Coroutine () &&
3140+ mayReferenceUseCoroutineAccessorOnStorage (module , expansion, location,
3141+ storage))
30923142 return AccessStrategy::getAccessor (AccessorKind::Read2, dispatch);
30933143 if (storage->requiresOpaqueReadCoroutine ())
30943144 return AccessStrategy::getAccessor (AccessorKind::Read, dispatch);
@@ -3102,41 +3152,53 @@ getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch)
31023152 return AccessStrategy::getAccessor (AccessorKind::Set, dispatch);
31033153}
31043154
3105- static AccessStrategy
3106- getOpaqueReadWriteAccessStrategy (const AbstractStorageDecl *storage,
3107- bool dispatch, bool useOldABI) {
3155+ static AccessStrategy getOpaqueReadWriteAccessStrategy (
3156+ const AbstractStorageDecl *storage, bool dispatch, ModuleDecl *module ,
3157+ ResilienceExpansion expansion,
3158+ std::optional<std::pair<SourceRange, const DeclContext *>> location,
3159+ bool useOldABI) {
31083160 if (useOldABI) {
31093161 assert (storage->requiresOpaqueModify2Coroutine ());
31103162 assert (storage->requiresOpaqueModifyCoroutine ());
31113163 return AccessStrategy::getAccessor (AccessorKind::Modify, dispatch);
31123164 }
3113- if (storage->requiresOpaqueModify2Coroutine ())
3165+ if (storage->requiresOpaqueModify2Coroutine () &&
3166+ mayReferenceUseCoroutineAccessorOnStorage (module , expansion, location,
3167+ storage))
31143168 return AccessStrategy::getAccessor (AccessorKind::Modify2, dispatch);
31153169 if (storage->requiresOpaqueModifyCoroutine ())
31163170 return AccessStrategy::getAccessor (AccessorKind::Modify, dispatch);
31173171 return AccessStrategy::getMaterializeToTemporary (
3118- getOpaqueReadAccessStrategy (storage, dispatch, false ),
3172+ getOpaqueReadAccessStrategy (storage, dispatch, nullptr ,
3173+ ResilienceExpansion::Minimal, location,
3174+ false ),
31193175 getOpaqueWriteAccessStrategy (storage, dispatch));
31203176}
31213177
3122- static AccessStrategy
3123- getOpaqueAccessStrategy (const AbstractStorageDecl *storage,
3124- AccessKind accessKind, bool dispatch, bool useOldABI) {
3178+ static AccessStrategy getOpaqueAccessStrategy (
3179+ const AbstractStorageDecl *storage, AccessKind accessKind, bool dispatch,
3180+ ModuleDecl *module , ResilienceExpansion expansion,
3181+ std::optional<std::pair<SourceRange, const DeclContext *>> location,
3182+ bool useOldABI) {
31253183 switch (accessKind) {
31263184 case AccessKind::Read:
3127- return getOpaqueReadAccessStrategy (storage, dispatch, useOldABI);
3185+ return getOpaqueReadAccessStrategy (storage, dispatch, module , expansion,
3186+ location, useOldABI);
31283187 case AccessKind::Write:
31293188 assert (!useOldABI);
31303189 return getOpaqueWriteAccessStrategy (storage, dispatch);
31313190 case AccessKind::ReadWrite:
3132- return getOpaqueReadWriteAccessStrategy (storage, dispatch, useOldABI);
3191+ return getOpaqueReadWriteAccessStrategy (storage, dispatch, module ,
3192+ expansion, location, useOldABI);
31333193 }
31343194 llvm_unreachable (" bad access kind" );
31353195}
31363196
31373197AccessStrategy AbstractStorageDecl::getAccessStrategy (
31383198 AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module ,
3139- ResilienceExpansion expansion, bool useOldABI) const {
3199+ ResilienceExpansion expansion,
3200+ std::optional<std::pair<SourceRange, const DeclContext *>> location,
3201+ bool useOldABI) const {
31403202 switch (semantics) {
31413203 case AccessSemantics::DirectToStorage:
31423204 assert (hasStorage () || getASTContext ().Diags .hadAnyError ());
@@ -3153,11 +3215,11 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
31533215 // accessors are dynamically dispatched, and we cannot do direct access.
31543216 if (isPolymorphic (this ))
31553217 return getOpaqueAccessStrategy (this , accessKind, /* dispatch*/ true ,
3156- useOldABI);
3218+ module , expansion, location, useOldABI);
31573219
31583220 if (shouldUseNativeDynamicDispatch ())
31593221 return getOpaqueAccessStrategy (this , accessKind, /* dispatch*/ false ,
3160- useOldABI);
3222+ module , expansion, location, useOldABI);
31613223
31623224 // If the storage is resilient from the given module and resilience
31633225 // expansion, we cannot use direct access.
@@ -3180,7 +3242,7 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
31803242
31813243 if (resilient)
31823244 return getOpaqueAccessStrategy (this , accessKind, /* dispatch*/ false ,
3183- useOldABI);
3245+ module , expansion, location, useOldABI);
31843246 }
31853247
31863248 LLVM_FALLTHROUGH;
@@ -3200,6 +3262,15 @@ AccessStrategy AbstractStorageDecl::getAccessStrategy(
32003262 llvm_unreachable (" bad access semantics" );
32013263}
32023264
3265+ bool AbstractStorageDecl::isAccessedViaPhysicalStorage (
3266+ AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module ,
3267+ ResilienceExpansion expansion) const {
3268+ return getAccessStrategy (semantics, accessKind, module , expansion,
3269+ /* location=*/ std::nullopt ,
3270+ /* useOldABI=*/ false )
3271+ .getKind () == AccessStrategy::Kind::Storage;
3272+ }
3273+
32033274bool AbstractStorageDecl::requiresOpaqueAccessors () const {
32043275 // Subscripts always require opaque accessors, so don't even kick off
32053276 // a request.
0 commit comments