<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br><div><div>On Jan 15, 2013, at 14:43 , Douglas Gregor <<a href="mailto:dgregor@apple.com">dgregor@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">Author: dgregor<br>Date: Tue Jan 15 16:43:08 2013<br>New Revision: 172567<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=172567&view=rev">http://llvm.org/viewvc/llvm-project?rev=172567&view=rev</a><br>Log:<br>When checking availability attributes for consistency between an<br>overriding and overridden method, allow the overridden method to have<br>a narrower contract (introduced earlier, deprecated/obsoleted later)<br>than the overriding method. Fixes <<a href="rdar://problem/12992023">rdar://problem/12992023</a>>.<br></blockquote><div><br></div><div>I think you mean "allow the <i>overridding</i> method…" I spent five minutes trying to figure out if the comment as written really made sense. Unfortunately, the test case seems backwards as well for warn_mismatched_availability_override_unavail, but correct for both variants of warn_mismatched_availability_override.</div><div><br></div><br><blockquote type="cite">Modified:<br> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br> cfe/trunk/include/clang/Sema/Sema.h<br> cfe/trunk/lib/Sema/SemaDecl.cpp<br> cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br> cfe/trunk/lib/Sema/SemaDeclObjC.cpp<br> cfe/trunk/test/SemaObjC/attr-availability.m<br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 15 16:43:08 2013<br>@@ -1879,6 +1879,16 @@<br> "attribute ignored">, InGroup<Availability>;<br> def warn_mismatched_availability: Warning<<br> "availability does not match previous declaration">, InGroup<Availability>;<br>+def warn_mismatched_availability_override : Warning<<br>+ "overriding method %select{introduced after|"<br>+ "deprecated before|obsoleted before}0 overridden method on %1 (%2 vs. %3)">, <br>+ InGroup<Availability>;<br>+def warn_mismatched_availability_override_unavail : Warning<<br>+ "overriding method cannot be unavailable on %0 when its overridden method is "<br>+ "available">,<br>+ InGroup<Availability>;<br>+def note_overridden_method : Note<<br>+ "overridden method is here">;<br><br> // Thread Safety Attributes<br> def warn_thread_attribute_ignored : Warning<<br><br>Modified: cfe/trunk/include/clang/Sema/Sema.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>+++ cfe/trunk/include/clang/Sema/Sema.h Tue Jan 15 16:43:08 2013<br>@@ -1677,7 +1677,8 @@<br> VersionTuple Deprecated,<br> VersionTuple Obsoleted,<br> bool IsUnavailable,<br>- StringRef Message);<br>+ StringRef Message,<br>+ bool Override);<br> VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range,<br> VisibilityAttr::VisibilityType Vis);<br> DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range);<br>@@ -1685,10 +1686,24 @@<br> FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,<br> int FormatIdx, int FirstArg);<br> SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name);<br>- bool mergeDeclAttribute(NamedDecl *New, InheritableAttr *Attr);<br>+ bool mergeDeclAttribute(NamedDecl *New, InheritableAttr *Attr,<br>+ bool Override);<br>+<br>+ /// \brief Describes the kind of merge to perform for availability<br>+ /// attributes (including "deprecated", "unavailable", and "availability").<br>+ enum AvailabilityMergeKind {<br>+ /// \brief Don't merge availability attributes at all.<br>+ AMK_None,<br>+ /// \brief Merge availability attributes for a redeclaration, which requires<br>+ /// an exact match.<br>+ AMK_Redeclaration,<br>+ /// \brief Merge availability attributes for an override, which requires<br>+ /// an exact match or a weakening of constraints.<br>+ AMK_Override<br>+ };<br><br> void mergeDeclAttributes(NamedDecl *New, Decl *Old,<br>- bool MergeDeprecation = true);<br>+ AvailabilityMergeKind AMK = AMK_Redeclaration);<br> void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);<br> bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S);<br> bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,<br>@@ -6383,8 +6398,7 @@<br> /// \brief Check whether the given new method is a valid override of the<br> /// given overridden method, and set any properties that should be inherited.<br> void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,<br>- const ObjCMethodDecl *Overridden,<br>- bool IsImplementation);<br>+ const ObjCMethodDecl *Overridden);<br><br> /// \brief Describes the compatibility of a result type with its method.<br> enum ResultTypeCompatibilityKind {<br><br>Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jan 15 16:43:08 2013<br>@@ -1822,13 +1822,14 @@<br> return false;<br> }<br><br>-bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr) {<br>+bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr,<br>+ bool Override) {<br> InheritableAttr *NewAttr = NULL;<br> if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))<br> NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),<br> AA->getIntroduced(), AA->getDeprecated(),<br> AA->getObsoleted(), AA->getUnavailable(),<br>- AA->getMessage());<br>+ AA->getMessage(), Override);<br> else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))<br> NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());<br> else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))<br>@@ -1902,7 +1903,7 @@<br><br> /// mergeDeclAttributes - Copy attributes from the Old decl to the New one.<br> void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,<br>- bool MergeDeprecation) {<br>+ AvailabilityMergeKind AMK) {<br> // attributes declared post-definition are currently ignored<br> checkNewAttributesAfterDef(*this, New, Old);<br><br>@@ -1919,14 +1920,25 @@<br> i = Old->specific_attr_begin<InheritableAttr>(),<br> e = Old->specific_attr_end<InheritableAttr>(); <br> i != e; ++i) {<br>+ bool Override = false;<br> // Ignore deprecated/unavailable/availability attributes if requested.<br>- if (!MergeDeprecation &&<br>- (isa<DeprecatedAttr>(*i) || <br>- isa<UnavailableAttr>(*i) ||<br>- isa<AvailabilityAttr>(*i)))<br>- continue;<br>+ if (isa<DeprecatedAttr>(*i) ||<br>+ isa<UnavailableAttr>(*i) ||<br>+ isa<AvailabilityAttr>(*i)) {<br>+ switch (AMK) {<br>+ case AMK_None:<br>+ continue;<br>+<br>+ case AMK_Redeclaration:<br>+ break;<br>+<br>+ case AMK_Override:<br>+ Override = true;<br>+ break;<br>+ }<br>+ }<br><br>- if (mergeDeclAttribute(New, *i))<br>+ if (mergeDeclAttribute(New, *i, Override))<br> foundAny = true;<br> }<br><br>@@ -2475,7 +2487,7 @@<br> ObjCMethodDecl *oldMethod) {<br><br> // Merge the attributes, including deprecated/unavailable<br>- mergeDeclAttributes(newMethod, oldMethod, /* mergeDeprecation */true);<br>+ mergeDeclAttributes(newMethod, oldMethod, AMK_Override);<br><br> // Merge attributes from the parameters.<br> ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(),<br>@@ -2485,7 +2497,7 @@<br> ni != ne && oi != oe; ++ni, ++oi)<br> mergeParamDeclAttributes(*ni, *oi, Context);<br><br>- CheckObjCMethodOverride(newMethod, oldMethod, true);<br>+ CheckObjCMethodOverride(newMethod, oldMethod);<br> }<br><br> /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Jan 15 16:43:08 2013<br>@@ -2001,13 +2001,32 @@<br> return false;<br> }<br><br>+/// \brief Check whether the two versions match.<br>+///<br>+/// If either version tuple is empty, then they are assumed to match. If<br>+/// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y.<br>+static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,<br>+ bool BeforeIsOkay) {<br>+ if (X.empty() || Y.empty())<br>+ return true;<br>+<br>+ if (X == Y)<br>+ return true;<br>+<br>+ if (BeforeIsOkay && X < Y)<br>+ return true;<br>+<br>+ return false;<br>+}<br>+<br> AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,<br> IdentifierInfo *Platform,<br> VersionTuple Introduced,<br> VersionTuple Deprecated,<br> VersionTuple Obsoleted,<br> bool IsUnavailable,<br>- StringRef Message) {<br>+ StringRef Message,<br>+ bool Override) {<br> VersionTuple MergedIntroduced = Introduced;<br> VersionTuple MergedDeprecated = Deprecated;<br> VersionTuple MergedObsoleted = Obsoleted;<br>@@ -2033,18 +2052,47 @@<br> VersionTuple OldDeprecated = OldAA->getDeprecated();<br> VersionTuple OldObsoleted = OldAA->getObsoleted();<br> bool OldIsUnavailable = OldAA->getUnavailable();<br>- StringRef OldMessage = OldAA->getMessage();<br><br>- if ((!OldIntroduced.empty() && !Introduced.empty() &&<br>- OldIntroduced != Introduced) ||<br>- (!OldDeprecated.empty() && !Deprecated.empty() &&<br>- OldDeprecated != Deprecated) ||<br>- (!OldObsoleted.empty() && !Obsoleted.empty() &&<br>- OldObsoleted != Obsoleted) ||<br>- (OldIsUnavailable != IsUnavailable) ||<br>- (OldMessage != Message)) {<br>- Diag(OldAA->getLocation(), diag::warn_mismatched_availability);<br>- Diag(Range.getBegin(), diag::note_previous_attribute);<br>+ if (!versionsMatch(OldIntroduced, Introduced, Override) ||<br>+ !versionsMatch(Deprecated, OldDeprecated, Override) ||<br>+ !versionsMatch(Obsoleted, OldObsoleted, Override) ||<br>+ !(OldIsUnavailable == IsUnavailable ||<br>+ (Override && OldIsUnavailable && !IsUnavailable))) {<br>+ if (Override) {<br>+ int Which = -1;<br>+ VersionTuple FirstVersion;<br>+ VersionTuple SecondVersion;<br>+ if (!versionsMatch(OldIntroduced, Introduced, Override)) {<br>+ Which = 0;<br>+ FirstVersion = OldIntroduced;<br>+ SecondVersion = Introduced;<br>+ } else if (!versionsMatch(Deprecated, OldDeprecated, Override)) {<br>+ Which = 1;<br>+ FirstVersion = Deprecated;<br>+ SecondVersion = OldDeprecated;<br>+ } else if (!versionsMatch(Obsoleted, OldObsoleted, Override)) {<br>+ Which = 2;<br>+ FirstVersion = Obsoleted;<br>+ SecondVersion = OldObsoleted;<br>+ }<br>+<br>+ if (Which == -1) {<br>+ Diag(OldAA->getLocation(),<br>+ diag::warn_mismatched_availability_override_unavail)<br>+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName());<br>+ } else {<br>+ Diag(OldAA->getLocation(),<br>+ diag::warn_mismatched_availability_override)<br>+ << Which<br>+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName())<br>+ << FirstVersion.getAsString() << SecondVersion.getAsString();<br>+ }<br>+ Diag(Range.getBegin(), diag::note_overridden_method);<br>+ } else {<br>+ Diag(OldAA->getLocation(), diag::warn_mismatched_availability);<br>+ Diag(Range.getBegin(), diag::note_previous_attribute);<br>+ }<br>+<br> Attrs.erase(Attrs.begin() + i);<br> --e;<br> continue;<br>@@ -2121,7 +2169,8 @@<br> Introduced.Version,<br> Deprecated.Version,<br> Obsoleted.Version,<br>- IsUnavailable, Str);<br>+ IsUnavailable, Str,<br>+ /*Override=*/false);<br> if (NewAttr)<br> D->addAttr(NewAttr);<br> }<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Jan 15 16:43:08 2013<br>@@ -109,8 +109,7 @@<br> }<br><br> void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, <br>- const ObjCMethodDecl *Overridden,<br>- bool IsImplementation) {<br>+ const ObjCMethodDecl *Overridden) {<br> if (Overridden->hasRelatedResultType() && <br> !NewMethod->hasRelatedResultType()) {<br> // This can only happen when the method follows a naming convention that<br><br>Modified: cfe/trunk/test/SemaObjC/attr-availability.m<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/attr-availability.m?rev=172567&r1=172566&r2=172567&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/attr-availability.m?rev=172567&r1=172566&r2=172567&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaObjC/attr-availability.m (original)<br>+++ cfe/trunk/test/SemaObjC/attr-availability.m Tue Jan 15 16:43:08 2013<br>@@ -6,11 +6,24 @@<br><br> @interface A <P><br> - (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{method 'method' declared here}}<br>+<br>+- (void)overridden __attribute__((availability(macosx,introduced=10.3))); // expected-note{{overridden method is here}}<br>+- (void)overridden2 __attribute__((availability(macosx,introduced=10.3)));<br>+- (void)overridden3 __attribute__((availability(macosx,deprecated=10.3)));<br>+- (void)overridden4 __attribute__((availability(macosx,deprecated=10.3))); // expected-note{{overridden method is here}}<br>+- (void)overridden5 __attribute__((availability(macosx,unavailable))); // expected-note{{overridden method is here}}<br>+- (void)overridden6 __attribute__((availability(macosx,introduced=10.3)));<br> @end<br><br> // <a href="rdar://11475360">rdar://11475360</a><br> @interface B : A<br> - (void)method; // expected-note {{method 'method' declared here}}<br>+- (void)overridden __attribute__((availability(macosx,introduced=10.4))); // expected-warning{{overriding method introduced after overridden method on OS X (10.4 vs. 10.3)}}<br>+- (void)overridden2 __attribute__((availability(macosx,introduced=10.2)));<br>+- (void)overridden3 __attribute__((availability(macosx,deprecated=10.4)));<br>+- (void)overridden4 __attribute__((availability(macosx,deprecated=10.2))); // expected-warning{{overriding method deprecated before overridden method on OS X (10.3 vs. 10.2)}}<br>+- (void)overridden5 __attribute__((availability(macosx,introduced=10.3))); // expected-warning{{overriding method cannot be unavailable on OS X when its overridden method is available}}<br>+- (void)overridden6 __attribute__((availability(macosx,unavailable)));<br> @end<br><br> void f(A *a, B *b) {<br><br><br>_______________________________________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits<br></blockquote></div><br></body></html>