r248949 - Don't inherit availability information when implementing a protocol requirement.
Douglas Gregor via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 30 14:27:43 PDT 2015
Author: dgregor
Date: Wed Sep 30 16:27:42 2015
New Revision: 248949
URL: http://llvm.org/viewvc/llvm-project?rev=248949&view=rev
Log:
Don't inherit availability information when implementing a protocol requirement.
When an Objective-C method implements a protocol requirement, do not
inherit any availability information from the protocol
requirement. Rather, check that the implementation is not less
available than the protocol requirement, as we do when overriding a
method that has availability. Fixes rdar://problem/22734745.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/ARCMT/checking.m
cfe/trunk/test/SemaObjC/attr-availability.m
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Sep 30 16:27:42 2015
@@ -2410,15 +2410,19 @@ def warn_availability_version_ordering :
def warn_mismatched_availability: Warning<
"availability does not match previous declaration">, InGroup<Availability>;
def warn_mismatched_availability_override : Warning<
- "overriding method %select{introduced after|"
- "deprecated before|obsoleted before}0 overridden method on %1 (%2 vs. %3)">,
- InGroup<Availability>;
+ "%select{|overriding }4method %select{introduced after|"
+ "deprecated before|obsoleted before}0 "
+ "%select{the protocol method it implements|overridden method}4 "
+ "on %1 (%2 vs. %3)">, InGroup<Availability>;
def warn_mismatched_availability_override_unavail : Warning<
- "overriding method cannot be unavailable on %0 when its overridden method is "
+ "%select{|overriding }1method cannot be unavailable on %0 when "
+ "%select{the protocol method it implements|its overridden method}1 is "
"available">,
InGroup<Availability>;
def note_overridden_method : Note<
"overridden method is here">;
+def note_protocol_method : Note<
+ "protocol method is here">;
// Thread Safety Attributes
def warn_invalid_capability_name : Warning<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Sep 30 16:27:42 2015
@@ -2062,6 +2062,22 @@ public:
TypeSourceInfo *TInfo);
bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New);
+ /// \brief Describes the kind of merge to perform for availability
+ /// attributes (including "deprecated", "unavailable", and "availability").
+ enum AvailabilityMergeKind {
+ /// \brief Don't merge availability attributes at all.
+ AMK_None,
+ /// \brief Merge availability attributes for a redeclaration, which requires
+ /// an exact match.
+ AMK_Redeclaration,
+ /// \brief Merge availability attributes for an override, which requires
+ /// an exact match or a weakening of constraints.
+ AMK_Override,
+ /// \brief Merge availability attributes for an implementation of
+ /// a protocol requirement.
+ AMK_ProtocolImplementation,
+ };
+
/// Attribute merging methods. Return true if a new attribute was added.
AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
IdentifierInfo *Platform,
@@ -2070,7 +2086,7 @@ public:
VersionTuple Obsoleted,
bool IsUnavailable,
StringRef Message,
- bool Override,
+ AvailabilityMergeKind AMK,
unsigned AttrSpellingListIndex);
TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
TypeVisibilityAttr::VisibilityType Vis,
@@ -2099,19 +2115,6 @@ public:
OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex);
- /// \brief Describes the kind of merge to perform for availability
- /// attributes (including "deprecated", "unavailable", and "availability").
- enum AvailabilityMergeKind {
- /// \brief Don't merge availability attributes at all.
- AMK_None,
- /// \brief Merge availability attributes for a redeclaration, which requires
- /// an exact match.
- AMK_Redeclaration,
- /// \brief Merge availability attributes for an override, which requires
- /// an exact match or a weakening of constraints.
- AMK_Override
- };
-
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Sep 30 16:27:42 2015
@@ -2175,14 +2175,15 @@ static bool mergeAlignedAttrs(Sema &S, N
}
static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
- const InheritableAttr *Attr, bool Override) {
+ const InheritableAttr *Attr,
+ Sema::AvailabilityMergeKind AMK) {
InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
AA->getIntroduced(), AA->getDeprecated(),
AA->getObsoleted(), AA->getUnavailable(),
- AA->getMessage(), Override,
+ AA->getMessage(), AMK,
AttrSpellingListIndex);
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
@@ -2219,7 +2220,11 @@ static bool mergeDeclAttribute(Sema &S,
// AlignedAttrs are handled separately, because we need to handle all
// such attributes on a declaration at the same time.
NewAttr = nullptr;
- else if (isa<DeprecatedAttr>(Attr) && Override)
+ else if (isa<DeprecatedAttr>(Attr) &&
+ (AMK == Sema::AMK_Override ||
+ AMK == Sema::AMK_ProtocolImplementation))
+ NewAttr = nullptr;
+ else if (isa<UnavailableAttr>(Attr) && AMK == Sema::AMK_ProtocolImplementation)
NewAttr = nullptr;
else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
@@ -2366,8 +2371,8 @@ void Sema::mergeDeclAttributes(NamedDecl
if (!foundAny) New->setAttrs(AttrVec());
for (auto *I : Old->specific_attrs<InheritableAttr>()) {
- bool Override = false;
// Ignore deprecated/unavailable/availability attributes if requested.
+ AvailabilityMergeKind LocalAMK = AMK_None;
if (isa<DeprecatedAttr>(I) ||
isa<UnavailableAttr>(I) ||
isa<AvailabilityAttr>(I)) {
@@ -2376,10 +2381,9 @@ void Sema::mergeDeclAttributes(NamedDecl
continue;
case AMK_Redeclaration:
- break;
-
case AMK_Override:
- Override = true;
+ case AMK_ProtocolImplementation:
+ LocalAMK = AMK;
break;
}
}
@@ -2388,7 +2392,7 @@ void Sema::mergeDeclAttributes(NamedDecl
if (isa<UsedAttr>(I))
continue;
- if (mergeDeclAttribute(*this, New, I, Override))
+ if (mergeDeclAttribute(*this, New, I, LocalAMK))
foundAny = true;
}
@@ -3156,8 +3160,11 @@ void Sema::mergeObjCMethodDecls(ObjCMeth
// Merge the attributes, including deprecated/unavailable
AvailabilityMergeKind MergeKind =
- isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration
- : AMK_Override;
+ isa<ObjCProtocolDecl>(oldMethod->getDeclContext())
+ ? AMK_ProtocolImplementation
+ : isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration
+ : AMK_Override;
+
mergeDeclAttributes(newMethod, oldMethod, MergeKind);
// Merge attributes from the parameters.
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Sep 30 16:27:42 2015
@@ -1821,12 +1821,24 @@ AvailabilityAttr *Sema::mergeAvailabilit
VersionTuple Obsoleted,
bool IsUnavailable,
StringRef Message,
- bool Override,
+ AvailabilityMergeKind AMK,
unsigned AttrSpellingListIndex) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
bool FoundAny = false;
+ bool OverrideOrImpl = false;
+ switch (AMK) {
+ case AMK_None:
+ case AMK_Redeclaration:
+ OverrideOrImpl = false;
+ break;
+
+ case AMK_Override:
+ case AMK_ProtocolImplementation:
+ OverrideOrImpl = true;
+ break;
+ }
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
@@ -1849,24 +1861,24 @@ AvailabilityAttr *Sema::mergeAvailabilit
VersionTuple OldObsoleted = OldAA->getObsoleted();
bool OldIsUnavailable = OldAA->getUnavailable();
- if (!versionsMatch(OldIntroduced, Introduced, Override) ||
- !versionsMatch(Deprecated, OldDeprecated, Override) ||
- !versionsMatch(Obsoleted, OldObsoleted, Override) ||
+ if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl) ||
+ !versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl) ||
+ !versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl) ||
!(OldIsUnavailable == IsUnavailable ||
- (Override && !OldIsUnavailable && IsUnavailable))) {
- if (Override) {
+ (OverrideOrImpl && !OldIsUnavailable && IsUnavailable))) {
+ if (OverrideOrImpl) {
int Which = -1;
VersionTuple FirstVersion;
VersionTuple SecondVersion;
- if (!versionsMatch(OldIntroduced, Introduced, Override)) {
+ if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl)) {
Which = 0;
FirstVersion = OldIntroduced;
SecondVersion = Introduced;
- } else if (!versionsMatch(Deprecated, OldDeprecated, Override)) {
+ } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) {
Which = 1;
FirstVersion = Deprecated;
SecondVersion = OldDeprecated;
- } else if (!versionsMatch(Obsoleted, OldObsoleted, Override)) {
+ } else if (!versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl)) {
Which = 2;
FirstVersion = Obsoleted;
SecondVersion = OldObsoleted;
@@ -1875,15 +1887,20 @@ AvailabilityAttr *Sema::mergeAvailabilit
if (Which == -1) {
Diag(OldAA->getLocation(),
diag::warn_mismatched_availability_override_unavail)
- << AvailabilityAttr::getPrettyPlatformName(Platform->getName());
+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
+ << (AMK == AMK_Override);
} else {
Diag(OldAA->getLocation(),
diag::warn_mismatched_availability_override)
<< Which
<< AvailabilityAttr::getPrettyPlatformName(Platform->getName())
- << FirstVersion.getAsString() << SecondVersion.getAsString();
+ << FirstVersion.getAsString() << SecondVersion.getAsString()
+ << (AMK == AMK_Override);
}
- Diag(Range.getBegin(), diag::note_overridden_method);
+ if (AMK == AMK_Override)
+ Diag(Range.getBegin(), diag::note_overridden_method);
+ else
+ Diag(Range.getBegin(), diag::note_protocol_method);
} else {
Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
Diag(Range.getBegin(), diag::note_previous_attribute);
@@ -1926,11 +1943,11 @@ AvailabilityAttr *Sema::mergeAvailabilit
MergedObsoleted == Obsoleted)
return nullptr;
- // Only create a new attribute if !Override, but we want to do
+ // Only create a new attribute if !OverrideOrImpl, but we want to do
// the checking.
if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
MergedDeprecated, MergedObsoleted) &&
- !Override) {
+ !OverrideOrImpl) {
return ::new (Context) AvailabilityAttr(Range, Context, Platform,
Introduced, Deprecated,
Obsoleted, IsUnavailable, Message,
@@ -1971,7 +1988,7 @@ static void handleAvailabilityAttr(Sema
Deprecated.Version,
Obsoleted.Version,
IsUnavailable, Str,
- /*Override=*/false,
+ Sema::AMK_None,
Index);
if (NewAttr)
D->addAttr(NewAttr);
Modified: cfe/trunk/test/ARCMT/checking.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/checking.m?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/checking.m (original)
+++ cfe/trunk/test/ARCMT/checking.m Wed Sep 30 16:27:42 2015
@@ -44,9 +44,9 @@ struct UnsafeS {
};
@interface A : NSObject
-- (id)retain; // expected-note {{'retain' has been explicitly marked unavailable here}}
-- (id)retainCount; // expected-note {{'retainCount' has been explicitly marked unavailable here}}
-- (id)autorelease; // expected-note 2 {{'autorelease' has been explicitly marked unavailable here}}
+- (id)retain __attribute__((unavailable)); // expected-note {{'retain' has been explicitly marked unavailable here}}
+- (id)retainCount __attribute__((unavailable)); // expected-note {{'retainCount' has been explicitly marked unavailable here}}
+- (id)autorelease __attribute__((unavailable)); // expected-note 2 {{'autorelease' has been explicitly marked unavailable here}}
- (id)init;
- (oneway void)release;
- (void)dealloc;
Modified: cfe/trunk/test/SemaObjC/attr-availability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/attr-availability.m?rev=248949&r1=248948&r2=248949&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/attr-availability.m (original)
+++ cfe/trunk/test/SemaObjC/attr-availability.m Wed Sep 30 16:27:42 2015
@@ -23,6 +23,7 @@
- (void)overridden4 __attribute__((availability(macosx,deprecated=10.3))); // expected-note{{overridden method is here}}
- (void)overridden5 __attribute__((availability(macosx,unavailable)));
- (void)overridden6 __attribute__((availability(macosx,introduced=10.3))); // expected-note{{overridden method is here}}
+- (void)unavailableMethod __attribute__((unavailable));
@end
// rdar://11475360
@@ -35,6 +36,7 @@
- (void)overridden4 __attribute__((availability(macosx,deprecated=10.2))); // expected-warning{{overriding method deprecated before overridden method on OS X (10.3 vs. 10.2)}}
- (void)overridden5 __attribute__((availability(macosx,introduced=10.3)));
- (void)overridden6 __attribute__((availability(macosx,unavailable))); // expected-warning{{overriding method cannot be unavailable on OS X when its overridden method is available}}
+- (void)unavailableMethod; // does *not* inherit unavailability
@end
void f(A *a, B *b) {
@@ -206,3 +208,73 @@ void use_myEnum() {
// expected-error at +1 {{MyEnum_Blah' is unavailable: not available}}
MyEnum e = MyEnum_Blah;
}
+
+// Test that the availability of (optional) protocol methods is not
+// inherited be implementations of those protocol methods.
+ at protocol AvailabilityP2
+ at optional
+-(void)methodA __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note 4{{'methodA' has been explicitly marked deprecated here}} \
+// expected-note 2{{protocol method is here}}
+-(void)methodB __attribute__((unavailable)); // expected-note 4{{'methodB' has been explicitly marked unavailable here}}
+-(void)methodC;
+ at end
+
+void testAvailabilityP2(id<AvailabilityP2> obj) {
+ [obj methodA]; // expected-warning{{'methodA' is deprecated: first deprecated in OS X 10.2}}
+ [obj methodB]; // expected-error{{'methodB' is unavailable}}
+}
+
+ at interface ImplementsAvailabilityP2a <AvailabilityP2>
+-(void)methodA;
+-(void)methodB;
+ at end
+
+void testImplementsAvailabilityP2a(ImplementsAvailabilityP2a *obj) {
+ [obj methodA]; // okay: availability not inherited
+ [obj methodB]; // okay: unavailability not inherited
+}
+
+__attribute__((objc_root_class))
+ at interface ImplementsAvailabilityP2b <AvailabilityP2>
+ at end
+
+ at implementation ImplementsAvailabilityP2b
+-(void)methodA {
+ // Make sure we're not inheriting availability.
+ id<AvailabilityP2> obj = self;
+ [obj methodA]; // expected-warning{{'methodA' is deprecated: first deprecated in OS X 10.2}}
+ [obj methodB]; // expected-error{{'methodB' is unavailable}}
+}
+-(void)methodB {
+ // Make sure we're not inheriting unavailability.
+ id<AvailabilityP2> obj = self;
+ [obj methodA]; // expected-warning{{'methodA' is deprecated: first deprecated in OS X 10.2}}
+ [obj methodB]; // expected-error{{'methodB' is unavailable}}
+}
+
+ at end
+
+void testImplementsAvailabilityP2b(ImplementsAvailabilityP2b *obj) {
+ // still get warnings/errors because we see the protocol version.
+
+ [obj methodA]; // expected-warning{{'methodA' is deprecated: first deprecated in OS X 10.2}}
+ [obj methodB]; // expected-error{{'methodB' is unavailable}}
+}
+
+__attribute__((objc_root_class))
+ at interface ImplementsAvailabilityP2c <AvailabilityP2>
+-(void)methodA __attribute__((availability(macosx,introduced=10.2))); // expected-warning{{method introduced after the protocol method it implements on OS X (10.2 vs. 10.1)}}
+-(void)methodB __attribute__((unavailable));
+ at end
+
+__attribute__((objc_root_class))
+ at interface ImplementsAvailabilityP2d <AvailabilityP2>
+ at end
+
+ at implementation ImplementsAvailabilityP2d
+-(void)methodA __attribute__((availability(macosx,introduced=10.2))) // expected-warning{{method introduced after the protocol method it implements on OS X (10.2 vs. 10.1)}}
+{
+}
+-(void)methodB __attribute__((unavailable)) {
+}
+ at end
More information about the cfe-commits
mailing list