@@ -3752,8 +3752,12 @@ bool HasStorageRequest::evaluate(Evaluator &evaluator,
37523752 return false ;
37533753
37543754 // @_hasStorage implies that it... has storage.
3755- if (var->getAttrs ().hasAttribute <HasStorageAttr>())
3756- return true ;
3755+ if (var->getAttrs ().hasAttribute <HasStorageAttr>()) {
3756+ // Except in contexts where it would be invalid. This is diagnosed in
3757+ // StorageImplInfoRequest.
3758+ return !isa<ProtocolDecl, ExtensionDecl, EnumDecl>(
3759+ storage->getDeclContext ()->getImplementedObjCContext ());
3760+ }
37573761
37583762 // Protocol requirements never have storage.
37593763 if (isa<ProtocolDecl>(storage->getDeclContext ()))
@@ -3847,10 +3851,21 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
38473851 : StorageIsMutable);
38483852 }
38493853
3850- if (auto *var = dyn_cast<VarDecl>(storage)) {
3854+ // If we're in an @implementation extension, we care about the semantics of
3855+ // the decl it implements.
3856+ auto *DC = storage->getDeclContext ()->getImplementedObjCContext ();
3857+
3858+ if (auto attr = storage->getParsedAttrs ().getAttribute <HasStorageAttr>()) {
3859+ // If we see `@_hasStorage` in a context with no stored properties, diagnose
3860+ // and ignore it.
3861+ if (isa<ExtensionDecl, EnumDecl, ProtocolDecl>(DC)) {
3862+ storage->diagnose (diag::attr_invalid_in_context, attr,
3863+ DC->getAsDecl ()->getDescriptiveKind ())
3864+ .warnInSwiftInterface (storage->getDeclContext ());
3865+
38513866 // Allow the @_hasStorage attribute to override all the accessors we parsed
38523867 // when making the final classification.
3853- if (var-> getParsedAttrs (). hasAttribute <HasStorageAttr>( )) {
3868+ } else if (auto * var = dyn_cast<VarDecl>(storage )) {
38543869 // The SIL rules for @_hasStorage are slightly different from the non-SIL
38553870 // rules. In SIL mode, @_hasStorage marks that the type is simply stored,
38563871 // and the only thing that determines mutability is the existence of the
@@ -3945,7 +3960,6 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
39453960 bool hasMutableAddress = storage->getParsedAccessor (AccessorKind::MutableAddress);
39463961 bool hasInit = storage->getParsedAccessor (AccessorKind::Init);
39473962
3948- auto *DC = storage->getDeclContext ();
39493963 // 'get', 'read', and a non-mutable addressor are all exclusive.
39503964 ReadImplKind readImpl;
39513965 if (storage->getParsedAccessor (AccessorKind::Get)) {
0 commit comments