diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 582d5f94c3404..1b8cb8e5c3544 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3658,11 +3658,27 @@ void Sema::copyFeatureAvailability(Decl *Dst, Decl *Src) { } } +static bool isForwardDeclaration(Decl *Prev, Decl *D) { + if (Prev->getCanonicalDecl() != D->getCanonicalDecl()) + return false; + if (auto *ID = dyn_cast(Prev)) + return !ID->getPreviousDecl(); + if (auto *PD = dyn_cast(Prev)) + return !PD->getPreviousDecl(); + return false; +} + void Sema::copyFeatureAvailabilityCheck(Decl *Dst, NamedDecl *Src, bool Redeclaration) { if (Dst->isInvalidDecl()) return; + // Don't check whether a new feature is being added if Src is a + // forward declaration of classes and protocols as they cannnot be + // annotated with attributes. + if (isForwardDeclaration(Src, Dst)) + return; + llvm::SmallDenseMap DstToAttr; for (auto *AA : Dst->specific_attrs()) diff --git a/clang/test/SemaObjC/feature-availability.m b/clang/test/SemaObjC/feature-availability.m index 586b60b24fb65..622b4cab11778 100644 --- a/clang/test/SemaObjC/feature-availability.m +++ b/clang/test/SemaObjC/feature-availability.m @@ -34,6 +34,8 @@ -(struct S1)m2 __attribute__((availability(domain:feature1, AVAIL))); -(struct S1)m3 __attribute__((availability(domain:feature1, UNAVAIL))); // expected-error {{use of 'S1' requires feature 'feature1' to be available}} @end +@class Base0; + __attribute__((availability(domain:feature1, AVAIL))) // expected-note 2 {{is incompatible with __attribute__((availability(domain:feature1, 0)))}} @interface Base0 { struct S0 ivar0; // expected-error {{use of 'S0' requires feature 'feature1' to be unavailable}} @@ -134,6 +136,8 @@ @interface Derived2(Cat1) @implementation Derived2(Cat1) @end +@protocol P1; + __attribute__((availability(domain:feature1, UNAVAIL))) @protocol P1 @end