r307175 - [Sema] Don't allow -Wunguarded-availability to be silenced with redecls

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 5 10:08:56 PDT 2017


Author: epilk
Date: Wed Jul  5 10:08:56 2017
New Revision: 307175

URL: http://llvm.org/viewvc/llvm-project?rev=307175&view=rev
Log:
[Sema] Don't allow -Wunguarded-availability to be silenced with redecls

Differential revision: https://reviews.llvm.org/D33816

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/DelayedDiagnostic.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/DelayedDiagnostic.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Sema/attr-availability.c
    cfe/trunk/test/Sema/attr-deprecated.c
    cfe/trunk/test/Sema/attr-unavailable-message.c
    cfe/trunk/test/SemaCXX/attr-deprecated.cpp
    cfe/trunk/test/SemaObjC/attr-availability.m
    cfe/trunk/test/SemaObjC/unguarded-availability-new.m
    cfe/trunk/test/SemaObjC/unguarded-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=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul  5 10:08:56 2017
@@ -2880,7 +2880,7 @@ def warn_partial_availability : Warning<
 def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
   InGroup<UnguardedAvailabilityNew>;
 def note_partial_availability_silence : Note<
-  "explicitly redeclare %0 to silence this warning">;
+  "annotate %select{%1|anonymous %1}0 with an availability attribute to silence">;
 def note_unguarded_available_silence : Note<
   "enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
   " this warning">;

Modified: cfe/trunk/include/clang/Sema/DelayedDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DelayedDiagnostic.h?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DelayedDiagnostic.h (original)
+++ cfe/trunk/include/clang/Sema/DelayedDiagnostic.h Wed Jul  5 10:08:56 2017
@@ -124,7 +124,8 @@ public:
 
   static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
                                             SourceLocation Loc,
-                                            const NamedDecl *D,
+                                            const NamedDecl *ReferringDecl,
+                                            const NamedDecl *OffendingDecl,
                                             const ObjCInterfaceDecl *UnknownObjCClass,
                                             const ObjCPropertyDecl  *ObjCProperty,
                                             StringRef Msg,
@@ -164,9 +165,13 @@ public:
     return *reinterpret_cast<const AccessedEntity*>(AccessData);
   }
 
-  const NamedDecl *getAvailabilityDecl() const {
+  const NamedDecl *getAvailabilityReferringDecl() const {
     assert(Kind == Availability && "Not an availability diagnostic.");
-    return AvailabilityData.Decl;
+    return AvailabilityData.ReferringDecl;
+  }
+
+  const NamedDecl *getAvailabilityOffendingDecl() const {
+    return AvailabilityData.OffendingDecl;
   }
 
   StringRef getAvailabilityMessage() const {
@@ -213,7 +218,8 @@ public:
 private:
 
   struct AD {
-    const NamedDecl *Decl;
+    const NamedDecl *ReferringDecl;
+    const NamedDecl *OffendingDecl;
     const ObjCInterfaceDecl *UnknownObjCClass;
     const ObjCPropertyDecl  *ObjCProperty;
     const char *Message;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jul  5 10:08:56 2017
@@ -3881,7 +3881,9 @@ public:
 
   void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
 
-  void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D,
+  void EmitAvailabilityWarning(AvailabilityResult AR,
+                               const NamedDecl *ReferringDecl,
+                               const NamedDecl *OffendingDecl,
                                StringRef Message, SourceLocation Loc,
                                const ObjCInterfaceDecl *UnknownObjCClass,
                                const ObjCPropertyDecl *ObjCProperty,
@@ -10413,16 +10415,14 @@ public:
     return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
   }
 
-  /// \brief The diagnostic we should emit for \c D, or \c AR_Available.
-  ///
-  /// \param D The declaration to check. Note that this may be altered to point
-  /// to another declaration that \c D gets it's availability from. i.e., we
-  /// walk the list of typedefs to find an availability attribute.
+  /// The diagnostic we should emit for \c D, and the declaration that
+  /// originated it, or \c AR_Available.
   ///
+  /// \param D The declaration to check.
   /// \param Message If non-null, this will be populated with the message from
   /// the availability attribute that is selected.
-  AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D,
-                                                      std::string *Message);
+  std::pair<AvailabilityResult, const NamedDecl *>
+  ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message);
 
   const DeclContext *getCurObjCLexicalContext() const {
     const DeclContext *DC = getCurLexicalContext();

Modified: cfe/trunk/lib/Sema/DelayedDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DelayedDiagnostic.cpp?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DelayedDiagnostic.cpp (original)
+++ cfe/trunk/lib/Sema/DelayedDiagnostic.cpp Wed Jul  5 10:08:56 2017
@@ -22,7 +22,8 @@ using namespace sema;
 DelayedDiagnostic
 DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
                                     SourceLocation Loc,
-                                    const NamedDecl *D,
+                                    const NamedDecl *ReferringDecl,
+                                    const NamedDecl *OffendingDecl,
                                     const ObjCInterfaceDecl *UnknownObjCClass,
                                     const ObjCPropertyDecl  *ObjCProperty,
                                     StringRef Msg,
@@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(Avai
   DD.Kind = Availability;
   DD.Triggered = false;
   DD.Loc = Loc;
-  DD.AvailabilityData.Decl = D;
+  DD.AvailabilityData.ReferringDecl = ReferringDecl;
+  DD.AvailabilityData.OffendingDecl = OffendingDecl;
   DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
   DD.AvailabilityData.ObjCProperty = ObjCProperty;
   char *MessageData = nullptr;

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Jul  5 10:08:56 2017
@@ -6929,8 +6929,34 @@ shouldDiagnoseAvailabilityByDefault(cons
          DeclVersion >= ForceAvailabilityFromVersion;
 }
 
+static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
+  for (Decl *Ctx = OrigCtx; Ctx;
+       Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
+    if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
+      return cast<NamedDecl>(Ctx);
+    if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
+      if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
+        return Imp->getClassInterface();
+      return CD;
+    }
+  }
+
+  return dyn_cast<NamedDecl>(OrigCtx);
+}
+
+/// Actually emit an availability diagnostic for a reference to an unavailable
+/// decl.
+///
+/// \param Ctx The context that the reference occurred in
+/// \param ReferringDecl The exact declaration that was referenced.
+/// \param OffendingDecl A related decl to \c ReferringDecl that has an
+/// availability attribute corrisponding to \c K attached to it. Note that this
+/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
+/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
+/// and OffendingDecl is the EnumDecl.
 static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
-                                      Decl *Ctx, const NamedDecl *D,
+                                      Decl *Ctx, const NamedDecl *ReferringDecl,
+                                      const NamedDecl *OffendingDecl,
                                       StringRef Message, SourceLocation Loc,
                                       const ObjCInterfaceDecl *UnknownObjCClass,
                                       const ObjCPropertyDecl *ObjCProperty,
@@ -6938,7 +6964,7 @@ static void DoEmitAvailabilityWarning(Se
   // Diagnostics for deprecated or unavailable.
   unsigned diag, diag_message, diag_fwdclass_message;
   unsigned diag_available_here = diag::note_availability_specified_here;
-  SourceLocation NoteLocation = D->getLocation();
+  SourceLocation NoteLocation = OffendingDecl->getLocation();
 
   // Matches 'diag::note_property_attribute' options.
   unsigned property_note_select;
@@ -6947,7 +6973,7 @@ static void DoEmitAvailabilityWarning(Se
   unsigned available_here_select_kind;
 
   VersionTuple DeclVersion;
-  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
+  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
     DeclVersion = AA->getIntroduced();
 
   if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
@@ -6961,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Se
     diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
     property_note_select = /* deprecated */ 0;
     available_here_select_kind = /* deprecated */ 2;
-    if (const auto *attr = D->getAttr<DeprecatedAttr>())
+    if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>())
       NoteLocation = attr->getLocation();
     break;
 
@@ -6973,13 +6999,14 @@ static void DoEmitAvailabilityWarning(Se
     property_note_select = /* unavailable */ 1;
     available_here_select_kind = /* unavailable */ 0;
 
-    if (auto attr = D->getAttr<UnavailableAttr>()) {
+    if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
       if (attr->isImplicit() && attr->getImplicitReason()) {
         // Most of these failures are due to extra restrictions in ARC;
         // reflect that in the primary diagnostic when applicable.
         auto flagARCError = [&] {
           if (S.getLangOpts().ObjCAutoRefCount &&
-              S.getSourceManager().isInSystemHeader(D->getLocation()))
+              S.getSourceManager().isInSystemHeader(
+                  OffendingDecl->getLocation()))
             diag = diag::err_unavailable_in_arc;
         };
 
@@ -7022,7 +7049,8 @@ static void DoEmitAvailabilityWarning(Se
     // not specified for deployment targets >= to iOS 11 or equivalent or
     // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
     // later.
-    const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D);
+    const AvailabilityAttr *AA =
+        getAttrForPlatform(S.getASTContext(), OffendingDecl);
     VersionTuple Introduced = AA->getIntroduced();
     bool NewWarning = shouldDiagnoseAvailabilityByDefault(
         S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
@@ -7045,9 +7073,9 @@ static void DoEmitAvailabilityWarning(Se
   CharSourceRange UseRange;
   StringRef Replacement;
   if (K == AR_Deprecated) {
-    if (auto attr = D->getAttr<DeprecatedAttr>())
+    if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
       Replacement = attr->getReplacement();
-    if (auto attr = getAttrForPlatform(S.Context, D))
+    if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
       Replacement = attr->getReplacement();
 
     if (!Replacement.empty())
@@ -7056,21 +7084,21 @@ static void DoEmitAvailabilityWarning(Se
   }
 
   if (!Message.empty()) {
-    S.Diag(Loc, diag_message) << D << Message
+    S.Diag(Loc, diag_message) << ReferringDecl << Message
       << (UseRange.isValid() ?
           FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
     if (ObjCProperty)
       S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
           << ObjCProperty->getDeclName() << property_note_select;
   } else if (!UnknownObjCClass) {
-    S.Diag(Loc, diag) << D
+    S.Diag(Loc, diag) << ReferringDecl
       << (UseRange.isValid() ?
           FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
     if (ObjCProperty)
       S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
           << ObjCProperty->getDeclName() << property_note_select;
   } else {
-    S.Diag(Loc, diag_fwdclass_message) << D
+    S.Diag(Loc, diag_fwdclass_message) << ReferringDecl
       << (UseRange.isValid() ?
           FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
     S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
@@ -7078,16 +7106,16 @@ static void DoEmitAvailabilityWarning(Se
 
   // The declaration can have multiple availability attributes, we are looking
   // at one of them.
-  const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
+  const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
   if (A && A->isInherited()) {
-    for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
+    for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
          Redecl = Redecl->getPreviousDecl()) {
       const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
                                                               Redecl);
       if (AForRedecl && !AForRedecl->isInherited()) {
         // If D is a declaration with inherited attributes, the note should
         // point to the declaration with actual attributes.
-        S.Diag(Redecl->getLocation(), diag_available_here) << D
+        S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
             << available_here_select_kind;
         break;
       }
@@ -7095,10 +7123,19 @@ static void DoEmitAvailabilityWarning(Se
   }
   else
     S.Diag(NoteLocation, diag_available_here)
-        << D << available_here_select_kind;
+        << OffendingDecl << available_here_select_kind;
 
   if (K == AR_NotYetIntroduced)
-    S.Diag(Loc, diag::note_partial_availability_silence) << D;
+    if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
+      if (auto *TD = dyn_cast<TagDecl>(Enclosing))
+        if (TD->getDeclName().isEmpty()) {
+          S.Diag(TD->getLocation(), diag::note_partial_availability_silence)
+              << /*Anonymous*/1 << TD->getKindName();
+          return;
+        }
+      S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence)
+          << /*Named*/0 << Enclosing;
+    }
 }
 
 static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
@@ -7108,9 +7145,9 @@ static void handleDelayedAvailabilityChe
 
   DD.Triggered = true;
   DoEmitAvailabilityWarning(
-      S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(),
-      DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
-      DD.getObjCProperty(), false);
+      S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
+      DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
+      DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
 }
 
 void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@@ -7169,22 +7206,25 @@ void Sema::redelayDiagnostics(DelayedDia
 }
 
 void Sema::EmitAvailabilityWarning(AvailabilityResult AR,
-                                   NamedDecl *D, StringRef Message,
-                                   SourceLocation Loc,
+                                   const NamedDecl *ReferringDecl,
+                                   const NamedDecl *OffendingDecl,
+                                   StringRef Message, SourceLocation Loc,
                                    const ObjCInterfaceDecl *UnknownObjCClass,
-                                   const ObjCPropertyDecl  *ObjCProperty,
+                                   const ObjCPropertyDecl *ObjCProperty,
                                    bool ObjCPropertyAccess) {
   // Delay if we're currently parsing a declaration.
   if (DelayedDiagnostics.shouldDelayDiagnostics()) {
-    DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
-        AR, Loc, D, UnknownObjCClass, ObjCProperty, Message,
-        ObjCPropertyAccess));
+    DelayedDiagnostics.add(
+        DelayedDiagnostic::makeAvailability(
+            AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
+            ObjCProperty, Message, ObjCPropertyAccess));
     return;
   }
 
   Decl *Ctx = cast<Decl>(getCurLexicalContext());
-  DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass,
-                            ObjCProperty, ObjCPropertyAccess);
+  DoEmitAvailabilityWarning(*this, AR, Ctx, ReferringDecl, OffendingDecl,
+                            Message, Loc, UnknownObjCClass, ObjCProperty,
+                            ObjCPropertyAccess);
 }
 
 namespace {
@@ -7336,19 +7376,21 @@ public:
 
 void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
     NamedDecl *D, SourceRange Range) {
-
-  VersionTuple ContextVersion = AvailabilityStack.back();
-  if (AvailabilityResult Result =
-          SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
+  AvailabilityResult Result;
+  const NamedDecl *OffendingDecl;
+  std::tie(Result, OffendingDecl) =
+      SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
+  if (Result != AR_Available) {
     // All other diagnostic kinds have already been handled in
     // DiagnoseAvailabilityOfDecl.
     if (Result != AR_NotYetIntroduced)
       return;
 
-    const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
+    const AvailabilityAttr *AA =
+      getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
     VersionTuple Introduced = AA->getIntroduced();
 
-    if (ContextVersion >= Introduced)
+    if (AvailabilityStack.back() >= Introduced)
       return;
 
     // If the context of this function is less available than D, we should not
@@ -7373,8 +7415,9 @@ void DiagnoseUnguardedAvailability::Diag
                SemaRef.getASTContext().getTargetInfo().getPlatformName())
         << Introduced.getAsString();
 
-    SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
-        << D << /* partial */ 3;
+    SemaRef.Diag(OffendingDecl->getLocation(),
+                 diag::note_availability_specified_here)
+        << OffendingDecl << /* partial */ 3;
 
     auto FixitDiag =
         SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jul  5 10:08:56 2017
@@ -87,24 +87,9 @@ static void DiagnoseUnusedOfDecl(Sema &S
   }
 }
 
-static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
-  const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
-  if (!OMD)
-    return false;
-  const ObjCInterfaceDecl *OID = OMD->getClassInterface();
-  if (!OID)
-    return false;
-
-  for (const ObjCCategoryDecl *Cat : OID->visible_categories())
-    if (ObjCMethodDecl *CatMeth =
-            Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
-      if (!CatMeth->hasAttr<AvailabilityAttr>())
-        return true;
-  return false;
-}
-
-AvailabilityResult
-Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
+std::pair<AvailabilityResult, const NamedDecl *>
+Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D,
+                                       std::string *Message) {
   AvailabilityResult Result = D->getAvailability(Message);
 
   // For typedefs, if the typedef declaration appears available look
@@ -121,45 +106,23 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(N
   }
 
   // Forward class declarations get their attributes from their definition.
-  if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+  if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
     if (IDecl->getDefinition()) {
       D = IDecl->getDefinition();
       Result = D->getAvailability(Message);
     }
   }
 
-  if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
+  if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
     if (Result == AR_Available) {
       const DeclContext *DC = ECD->getDeclContext();
-      if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
+      if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
         Result = TheEnumDecl->getAvailability(Message);
+        D = TheEnumDecl;
+      }
     }
 
-  if (Result == AR_NotYetIntroduced) {
-    // Don't do this for enums, they can't be redeclared.
-    if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
-      return AR_Available;
-
-    bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
-    // Objective-C method declarations in categories are not modelled as
-    // redeclarations, so manually look for a redeclaration in a category
-    // if necessary.
-    if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
-      Warn = false;
-    // In general, D will point to the most recent redeclaration. However,
-    // for `@class A;` decls, this isn't true -- manually go through the
-    // redecl chain in that case.
-    if (Warn && isa<ObjCInterfaceDecl>(D))
-      for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
-           Redecl = Redecl->getPreviousDecl())
-        if (!Redecl->hasAttr<AvailabilityAttr>() ||
-            Redecl->getAttr<AvailabilityAttr>()->isInherited())
-          Warn = false;
-
-    return Warn ? AR_NotYetIntroduced : AR_Available;
-  }
-
-  return Result;
+  return {Result, D};
 }
 
 static void
@@ -167,32 +130,34 @@ DiagnoseAvailabilityOfDecl(Sema &S, Name
                            const ObjCInterfaceDecl *UnknownObjCClass,
                            bool ObjCPropertyAccess) {
   std::string Message;
+  AvailabilityResult Result;
+  const NamedDecl* OffendingDecl;
   // See if this declaration is unavailable, deprecated, or partial.
-  if (AvailabilityResult Result =
-          S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
+  std::tie(Result, OffendingDecl) = S.ShouldDiagnoseAvailabilityOfDecl(D, &Message);
+  if (Result == AR_Available)
+    return;
 
-    if (Result == AR_NotYetIntroduced) {
-      if (S.getCurFunctionOrMethodDecl()) {
-        S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
-        return;
-      } else if (S.getCurBlock() || S.getCurLambda()) {
-        S.getCurFunction()->HasPotentialAvailabilityViolations = true;
-        return;
-      }
+  if (Result == AR_NotYetIntroduced) {
+    if (S.getCurFunctionOrMethodDecl()) {
+      S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+      return;
+    } else if (S.getCurBlock() || S.getCurLambda()) {
+      S.getCurFunction()->HasPotentialAvailabilityViolations = true;
+      return;
     }
+  }
 
-    const ObjCPropertyDecl *ObjCPDecl = nullptr;
-    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
-      if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
-        AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
-        if (PDeclResult == Result)
-          ObjCPDecl = PD;
-      }
+  const ObjCPropertyDecl *ObjCPDecl = nullptr;
+  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+      AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
+      if (PDeclResult == Result)
+        ObjCPDecl = PD;
     }
-
-    S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass,
-                              ObjCPDecl, ObjCPropertyAccess);
   }
+
+  S.EmitAvailabilityWarning(Result, D, OffendingDecl, Message, Loc,
+                            UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
 }
 
 /// \brief Emit a note explaining that this function is deleted.

Modified: cfe/trunk/test/Sema/attr-availability.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-availability.c?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-availability.c (original)
+++ cfe/trunk/test/Sema/attr-availability.c Wed Jul  5 10:08:56 2017
@@ -21,6 +21,9 @@ ATSFontGetPostScriptName(int flags) __at
 extern void
 PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
 
+#ifdef WARN_PARTIAL
+// expected-note at +2 2 {{marked partial here}}
+#endif
 enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum {
   kPartialEnumConstant,
 };
@@ -35,11 +38,19 @@ void test_10095131() {
   PartiallyAvailable();
 }
 
+#ifdef WARN_PARTIAL
+// FIXME: This note should point to the declaration with the availability
+// attribute.
+// expected-note at +2 {{marked partial here}}
+#endif
 extern void PartiallyAvailable() ;
 void with_redeclaration() {
-  PartiallyAvailable();  // Don't warn.
-
-  // enums should never warn.
+#ifdef WARN_PARTIAL
+  // expected-warning at +4 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note at +4 {{__builtin_available}}
+  // expected-warning at +4 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note at +4 {{__builtin_available}}
+  // expected-warning at +3 {{'kPartialEnumConstant' is only available on macOS 10.8 or newer}} expected-note at +3 {{__builtin_available}}
+#endif
+  PartiallyAvailable();
   enum PartialEnum p = kPartialEnumConstant;
 }
 
@@ -86,13 +97,13 @@ enum Original {
   OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}}
 };
 
-enum AllDeprecated {
-  AllDeprecatedCase, // expected-note + {{'AllDeprecatedCase' has been explicitly marked deprecated here}}
+enum AllDeprecated { // expected-note + {{'AllDeprecated' has been explicitly marked deprecated here}}
+  AllDeprecatedCase,
   AllDeprecatedUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'AllDeprecatedUnavailable' has been explicitly marked unavailable here}}
 } __attribute__((availability(macosx, deprecated=10.2)));
 
-enum AllUnavailable {
-  AllUnavailableCase, // expected-note + {{'AllUnavailableCase' has been explicitly marked unavailable here}}
+enum AllUnavailable { // expected-note + {{'AllUnavailable' has been explicitly marked unavailable here}}
+  AllUnavailableCase,
 } __attribute__((availability(macosx, unavailable)));
 
 enum User {

Modified: cfe/trunk/test/Sema/attr-deprecated.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-deprecated.c?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-deprecated.c (original)
+++ cfe/trunk/test/Sema/attr-deprecated.c Wed Jul  5 10:08:56 2017
@@ -104,9 +104,9 @@ foo_dep test17, // expected-warning {{'f
         test19;
 
 // rdar://problem/8518751
-enum __attribute__((deprecated)) Test20 { // expected-note {{'Test20' has been explicitly marked deprecated here}}
+enum __attribute__((deprecated)) Test20 { // expected-note 2 {{'Test20' has been explicitly marked deprecated here}}
   test20_a __attribute__((deprecated)), // expected-note {{'test20_a' has been explicitly marked deprecated here}}
-  test20_b // expected-note {{'test20_b' has been explicitly marked deprecated here}}
+  test20_b
 };
 void test20() {
   enum Test20 f; // expected-warning {{'Test20' is deprecated}}

Modified: cfe/trunk/test/Sema/attr-unavailable-message.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-unavailable-message.c?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-unavailable-message.c (original)
+++ cfe/trunk/test/Sema/attr-unavailable-message.c Wed Jul  5 10:08:56 2017
@@ -36,13 +36,13 @@ void unavail(void) {
 
 // rdar://10201690
 enum foo {
-    a = 1, // expected-note {{'a' has been explicitly marked deprecated here}}
+    a = 1,
     b __attribute__((deprecated())) = 2, // expected-note {{'b' has been explicitly marked deprecated here}}
     c = 3
-}__attribute__((deprecated()));
+}__attribute__((deprecated())); // expected-note {{'foo' has been explicitly marked deprecated here}}
 
-enum fee { // expected-note {{'fee' has been explicitly marked unavailable here}}
-    r = 1, // expected-note {{'r' has been explicitly marked unavailable here}}
+enum fee { // expected-note 2 {{'fee' has been explicitly marked unavailable here}}
+    r = 1,
     s = 2,
     t = 3
 }__attribute__((unavailable()));

Modified: cfe/trunk/test/SemaCXX/attr-deprecated.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-deprecated.cpp?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-deprecated.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-deprecated.cpp Wed Jul  5 10:08:56 2017
@@ -199,8 +199,8 @@ namespace test5 {
 
 // rdar://problem/8518751
 namespace test6 {
-  enum __attribute__((deprecated)) A { // expected-note {{'A' has been explicitly marked deprecated here}}
-    a0 // expected-note {{'a0' has been explicitly marked deprecated here}}
+  enum __attribute__((deprecated)) A { // expected-note 2 {{'A' has been explicitly marked deprecated here}}
+    a0
   };
   void testA() {
     A x; // expected-warning {{'A' is deprecated}}
@@ -218,8 +218,8 @@ namespace test6 {
   }
 
   template <class T> struct C {
-    enum __attribute__((deprecated)) Enum { // expected-note {{'Enum' has been explicitly marked deprecated here}}
-      c0 // expected-note {{'c0' has been explicitly marked deprecated here}}
+    enum __attribute__((deprecated)) Enum { // expected-note 2 {{'Enum' has been explicitly marked deprecated here}}
+      c0
     };
   };
   void testC() {

Modified: cfe/trunk/test/SemaObjC/attr-availability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/attr-availability.m?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/attr-availability.m (original)
+++ cfe/trunk/test/SemaObjC/attr-availability.m Wed Jul  5 10:08:56 2017
@@ -13,7 +13,7 @@
 @interface A <P>
 - (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}}
 #if defined(WARN_PARTIAL)
-  // expected-note at +2 {{'partialMethod' has been explicitly marked partial here}}
+  // expected-note at +2 2 {{'partialMethod' has been explicitly marked partial here}}
 #endif
 - (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 
@@ -66,7 +66,10 @@ void f(A *a, B *b) {
 @end
 
 void f_after_redecl(A *a, B *b) {
-  [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning at +2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note at +2 {{@available}}
+#endif
+  [a partialMethod];
   [b partialMethod]; // no warning
   [a partial_proto_method]; // no warning
   [b partial_proto_method]; // no warning
@@ -133,6 +136,10 @@ id NSNibOwner, topNibObjects;
 @end
 
 @interface PartialI <PartialProt>
+#ifdef WARN_PARTIAL
+// expected-note at +3{{marked partial here}}
+// expected-note at +3{{marked partial here}}
+#endif
 - (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 + (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 @end
@@ -160,14 +167,20 @@ id NSNibOwner, topNibObjects;
 @end
 
 void partialfun(PartialI* a) {
-  [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning at +2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note at +2{{@available}}
+#endif
+  [a partialMethod];
   [a ipartialMethod1]; // no warning
 #if defined(WARN_PARTIAL)
   // expected-warning at +2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note at +2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
 #endif
   [a ipartialMethod2];
   [a ppartialMethod]; // no warning
-  [PartialI partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning at +2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note at +2 {{@available}}
+#endif
+  [PartialI partialMethod];
   [PartialI ipartialMethod1]; // no warning
 #if defined(WARN_PARTIAL)
   // expected-warning at +2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note at +2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
@@ -177,20 +190,23 @@ void partialfun(PartialI* a) {
 }
 
 #if defined(WARN_PARTIAL)
-  // expected-note at +2 {{'PartialI2' has been explicitly marked partial here}}
+  // expected-note at +2 2 {{'PartialI2' has been explicitly marked partial here}}
 #endif
 __attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2
 @end
 
 #if defined(WARN_PARTIAL)
-  // expected-warning at +2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note at +2 {{explicitly redeclare 'PartialI2' to silence this warning}}
+// expected-warning at +2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note at +2 {{annotate 'partialinter1' with an availability attribute to silence}}
 #endif
 void partialinter1(PartialI2* p) {
 }
 
 @class PartialI2;
 
-void partialinter2(PartialI2* p) { // no warning
+#ifdef WARN_PARTIAL
+// expected-warning at +2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note at +2 {{annotate 'partialinter2' with an availability attribute to silence}}
+#endif
+void partialinter2(PartialI2* p) {
 }
 
 

Modified: cfe/trunk/test/SemaObjC/unguarded-availability-new.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/unguarded-availability-new.m?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/unguarded-availability-new.m (original)
+++ cfe/trunk/test/SemaObjC/unguarded-availability-new.m Wed Jul  5 10:08:56 2017
@@ -96,16 +96,16 @@ typedef int AVAILABLE_NEXT new_int;
 FUNC_AVAILABLE new_int x;
 #ifndef NO_WARNING
 #ifdef MAC
-  // expected-warning at -3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note at -3 {{explicitly redeclare 'new_int' to silence this warning}}
+  // expected-warning at -3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note at -3 {{annotate 'x' with an availability attribute to silence}}
 #endif
 #ifdef IOS
-  // expected-warning at -6 {{'new_int' is partial: introduced in iOS 12}} expected-note at -6 {{explicitly redeclare 'new_int' to silence this warning}}
+  // expected-warning at -6 {{'new_int' is partial: introduced in iOS 12}} expected-note at -6 {{annotate 'x' with an availability attribute to silence}}
 #endif
 #ifdef TVOS
-  // expected-warning at -9 {{'new_int' is partial: introduced in tvOS 13}} expected-note at -9 {{explicitly redeclare 'new_int' to silence this warning}}
+  // expected-warning at -9 {{'new_int' is partial: introduced in tvOS 13}} expected-note at -9 {{annotate 'x' with an availability attribute to silence}}
 #endif
 #ifdef WATCHOS
-  // expected-warning at -12 {{'new_int' is partial: introduced in watchOS 5}} expected-note at -12 {{explicitly redeclare 'new_int' to silence this warning}}
+  // expected-warning at -12 {{'new_int' is partial: introduced in watchOS 5}} expected-note at -12 {{annotate 'x' with an availability attribute to silence}}
 #endif
 #endif
 

Modified: cfe/trunk/test/SemaObjC/unguarded-availability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/unguarded-availability.m?rev=307175&r1=307174&r2=307175&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/unguarded-availability.m (original)
+++ cfe/trunk/test/SemaObjC/unguarded-availability.m Wed Jul  5 10:08:56 2017
@@ -5,6 +5,8 @@
 #define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11)))
 #define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12)))
 
+typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}}
+
 int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}}
 
 #ifdef OBJCPP
@@ -70,9 +72,9 @@ void use_typedef() {
 }
 
 __attribute__((objc_root_class))
-AVAILABLE_10_11 @interface Class_10_11 {
+AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}}
   int_10_11 foo;
-  int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
+  int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}}
 }
 - (void)method1;
 - (void)method2;
@@ -125,7 +127,7 @@ void test_blocks() {
   };
 }
 
-void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}}
+void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{annotate 'test_params' with an availability attribute to silence}}
 
 void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn
 
@@ -234,3 +236,30 @@ void functionInFunction() {
 }
 
 #endif
+
+struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}}
+  new_int mem; // expected-warning{{'new_int' is partial}}
+
+  struct { new_int mem; } anon; // expected-warning{{'new_int' is partial}} expected-note{{annotate anonymous struct with an availability attribute}}
+};
+
+#ifdef OBJCPP
+static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}}
+typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}}
+  SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is partial}} 
+} SomeEnum;
+#endif
+
+ at interface InInterface
+-(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}}
+ at end
+
+ at interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
+ at property (class) new_int x; // expected-warning{{'new_int' is partial}}
+ at end
+
+void with_local_struct() {
+  struct local { // expected-note{{annotate 'local' with an availability attribute}}
+    new_int x; // expected-warning{{'new_int' is partial}}
+  };
+}




More information about the cfe-commits mailing list