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"
@@ -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);
30283030static AccessStrategy
30293031getOpaqueWriteAccessStrategy (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
31333193AccessStrategy 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+
31993270bool AbstractStorageDecl::requiresOpaqueAccessors () const {
32003271 // Subscripts always require opaque accessors, so don't even kick off
32013272 // a request.
0 commit comments