summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-09-30 21:27:42 +0000
committerDouglas Gregor <dgregor@apple.com>2015-09-30 21:27:42 +0000
commitd2a713e41bd362125ba80a3eecc7e05876e06adb (patch)
tree17c9fe147727c3d80269947aa6dd383e9f2da0b7 /clang
parentb1ff6e4260dfe4cce64a2ebb425360f706aeb42b (diff)
downloadbcm5719-llvm-d2a713e41bd362125ba80a3eecc7e05876e06adb.tar.gz
bcm5719-llvm-d2a713e41bd362125ba80a3eecc7e05876e06adb.zip
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. llvm-svn: 248949
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td12
-rw-r--r--clang/include/clang/Sema/Sema.h31
-rw-r--r--clang/lib/Sema/SemaDecl.cpp27
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp47
-rw-r--r--clang/test/ARCMT/checking.m6
-rw-r--r--clang/test/SemaObjC/attr-availability.m72
6 files changed, 149 insertions, 46 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cac97ce05fa..fa1a6ff8fc5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2410,15 +2410,19 @@ def warn_availability_version_ordering : Warning<
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<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 09b46ce77b6..1cf57ca36de 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -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);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 571c9baa048..a359ef49311 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2175,14 +2175,15 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
}
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, NamedDecl *D,
// 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 *New, Decl *Old,
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 *New, Decl *Old,
continue;
case AMK_Redeclaration:
- break;
-
case AMK_Override:
- Override = true;
+ case AMK_ProtocolImplementation:
+ LocalAMK = AMK;
break;
}
}
@@ -2388,7 +2392,7 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
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(ObjCMethodDecl *newMethod,
// 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.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 8218c20696d..3cf9567889f 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1821,12 +1821,24 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
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::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
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::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
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::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
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 &S, Decl *D,
Deprecated.Version,
Obsoleted.Version,
IsUnavailable, Str,
- /*Override=*/false,
+ Sema::AMK_None,
Index);
if (NewAttr)
D->addAttr(NewAttr);
diff --git a/clang/test/ARCMT/checking.m b/clang/test/ARCMT/checking.m
index 6a7cf76c386..11a57538d73 100644
--- a/clang/test/ARCMT/checking.m
+++ b/clang/test/ARCMT/checking.m
@@ -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;
diff --git a/clang/test/SemaObjC/attr-availability.m b/clang/test/SemaObjC/attr-availability.m
index ea97e0e472d..8323139e590 100644
--- a/clang/test/SemaObjC/attr-availability.m
+++ b/clang/test/SemaObjC/attr-availability.m
@@ -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@+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.
+@protocol AvailabilityP2
+@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;
+@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}}
+}
+
+@interface ImplementsAvailabilityP2a <AvailabilityP2>
+-(void)methodA;
+-(void)methodB;
+@end
+
+void testImplementsAvailabilityP2a(ImplementsAvailabilityP2a *obj) {
+ [obj methodA]; // okay: availability not inherited
+ [obj methodB]; // okay: unavailability not inherited
+}
+
+__attribute__((objc_root_class))
+@interface ImplementsAvailabilityP2b <AvailabilityP2>
+@end
+
+@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}}
+}
+
+@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))
+@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));
+@end
+
+__attribute__((objc_root_class))
+@interface ImplementsAvailabilityP2d <AvailabilityP2>
+@end
+
+@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)) {
+}
+@end
OpenPOWER on IntegriCloud