@@ -3752,8 +3752,12 @@ bool HasStorageRequest::evaluate(Evaluator &evaluator,
3752
3752
return false ;
3753
3753
3754
3754
// @_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
+ }
3757
3761
3758
3762
// Protocol requirements never have storage.
3759
3763
if (isa<ProtocolDecl>(storage->getDeclContext ()))
@@ -3847,10 +3851,21 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
3847
3851
: StorageIsMutable);
3848
3852
}
3849
3853
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
+
3851
3866
// Allow the @_hasStorage attribute to override all the accessors we parsed
3852
3867
// when making the final classification.
3853
- if (var-> getParsedAttrs (). hasAttribute <HasStorageAttr>( )) {
3868
+ } else if (auto * var = dyn_cast<VarDecl>(storage )) {
3854
3869
// The SIL rules for @_hasStorage are slightly different from the non-SIL
3855
3870
// rules. In SIL mode, @_hasStorage marks that the type is simply stored,
3856
3871
// and the only thing that determines mutability is the existence of the
@@ -3945,7 +3960,6 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
3945
3960
bool hasMutableAddress = storage->getParsedAccessor (AccessorKind::MutableAddress);
3946
3961
bool hasInit = storage->getParsedAccessor (AccessorKind::Init);
3947
3962
3948
- auto *DC = storage->getDeclContext ();
3949
3963
// 'get', 'read', and a non-mutable addressor are all exclusive.
3950
3964
ReadImplKind readImpl;
3951
3965
if (storage->getParsedAccessor (AccessorKind::Get)) {
0 commit comments