<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 3:25 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><meta http-equiv="Content-Type" content="text/html charset=windows-1252"><div 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.</div></div></div></blockquote><div><br></div><div>Yep, my apologies for the typo.</div><br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div><div> 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></div></blockquote><div><br></div>Good eye, thanks! r172586.</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">   </span>- Doug</div><div><br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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><a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br></blockquote></div><br></div></blockquote></div><br></body></html>