erik.pilkington created this revision.

This patch drops support for suppressing -Wunguarded-availability with 
redeclarations. This was behavior left over from the -Wpartial-availability 
days, where it was the only way of silencing the diagnostic. Now that we have 
@available and better support for annotating contexts with availability 
attributes, this behavior should be dropped. 
This would emit warnings on code that used the old way of silencing the 
diagnostic, but this method:

- Didn't have many users; it was clunky to use
- Has a simple upgrade path that is mentioned in the diagnostics we emit
- Allows for availability violations to go undetected

@thakis: I know the chromium project uses this warning, is this OK with you?

rdar://32388777

Thanks for taking a look,
Erik


https://reviews.llvm.org/D33816

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaExpr.cpp
  test/Sema/attr-availability.c
  test/Sema/attr-deprecated.c
  test/Sema/attr-unavailable-message.c
  test/SemaCXX/attr-deprecated.cpp
  test/SemaObjC/attr-availability.m
  test/SemaObjC/unguarded-availability.m

Index: test/SemaObjC/unguarded-availability.m
===================================================================
--- test/SemaObjC/unguarded-availability.m
+++ test/SemaObjC/unguarded-availability.m
@@ -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 @@
 }
 
 __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_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,23 @@
 }
 
 #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 '' with an availability attribute}}
+};
+
+@interface InInterface
+-(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}}
+@end
+
+@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}}
+@property (class) new_int x; // expected-warning{{'new_int' is partial}}
+@end
+
+void with_local_struct() {
+  struct local { // expected-note{{annotate 'local' with an availability attribute}}
+    new_int x; // expected-warning{{'new_int' is partial}}
+  };
+}
Index: test/SemaObjC/attr-availability.m
===================================================================
--- test/SemaObjC/attr-availability.m
+++ test/SemaObjC/attr-availability.m
@@ -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@+2 {{'partialMethod' has been explicitly marked partial here}}
+  // expected-note@+2 2 {{'partialMethod' has been explicitly marked partial here}}
 #endif
 - (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 
@@ -66,7 +66,10 @@
 @end
 
 void f_after_redecl(A *a, B *b) {
-  [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning@+2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+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 @@
 @end
 
 @interface PartialI <PartialProt>
+#ifdef WARN_PARTIAL
+// expected-note@+3{{marked partial here}}
+// expected-note@+3{{marked partial here}}
+#endif
 - (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 + (void)partialMethod __attribute__((availability(macosx,introduced=10.8)));
 @end
@@ -160,13 +167,19 @@
 @end
 
 void partialfun(PartialI* a) {
-  [a partialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2{{@available}}
+#endif
+  [a partialMethod];
   [a ipartialMethod1]; // no warning
 #if defined(WARN_PARTIAL)
   // expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}}
 #endif
   [a ipartialMethod2];
   [a ppartialMethod]; // no warning
+#ifdef WARN_PARTIAL
+  // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}}
+#endif
   [PartialI partialMethod]; // no warning
   [PartialI ipartialMethod1]; // no warning
 #if defined(WARN_PARTIAL)
@@ -177,20 +190,23 @@
 }
 
 #if defined(WARN_PARTIAL)
-  // expected-note@+2 {{'PartialI2' has been explicitly marked partial here}}
+  // expected-note@+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@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}}
+// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+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@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}}
+#endif
+void partialinter2(PartialI2* p) {
 }
 
 
Index: test/SemaCXX/attr-deprecated.cpp
===================================================================
--- test/SemaCXX/attr-deprecated.cpp
+++ test/SemaCXX/attr-deprecated.cpp
@@ -199,12 +199,12 @@
 
 // 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}}
-    x = a0; // expected-warning {{'a0' is deprecated}}
+    x = a0; // expected-warning {{'A' is deprecated}}
   }
   
   enum B {
@@ -218,13 +218,13 @@
   }
 
   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() {
     C<int>::Enum x; // expected-warning {{'Enum' is deprecated}}
-    x = C<int>::c0; // expected-warning {{'c0' is deprecated}}
+    x = C<int>::c0; // expected-warning {{'Enum' is deprecated}}
   }
 
   template <class T> struct D {
Index: test/Sema/attr-unavailable-message.c
===================================================================
--- test/Sema/attr-unavailable-message.c
+++ test/Sema/attr-unavailable-message.c
@@ -36,21 +36,21 @@
 
 // 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()));
 
 enum fee f() { // expected-error {{'fee' is unavailable}}
-    int i = a; // expected-warning {{'a' is deprecated}}
+    int i = a; // expected-warning {{'foo' is deprecated}}
 
     i = b; // expected-warning {{'b' is deprecated}}
 
-    return r; // expected-error {{'r' is unavailable}}
+    return r; // expected-error {{'fee' is unavailable}}
 }
Index: test/Sema/attr-deprecated.c
===================================================================
--- test/Sema/attr-deprecated.c
+++ test/Sema/attr-deprecated.c
@@ -104,14 +104,14 @@
         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}}
   f = test20_a; // expected-warning {{'test20_a' is deprecated}}
-  f = test20_b; // expected-warning {{'test20_b' is deprecated}}
+  f = test20_b; // expected-warning {{'Test20' is deprecated}}
 }
 
 char test21[__has_feature(attribute_deprecated_with_message) ? 1 : -1];
Index: test/Sema/attr-availability.c
===================================================================
--- test/Sema/attr-availability.c
+++ test/Sema/attr-availability.c
@@ -21,6 +21,9 @@
 extern void
 PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8)));
 
+#ifdef WARN_PARTIAL
+// expected-note@+2 2 {{marked partial here}}
+#endif
 enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum {
   kPartialEnumConstant,
 };
@@ -35,11 +38,18 @@
   PartiallyAvailable();
 }
 
+#ifdef WARN_PARTIAL
+// FIXME: This note should point to the declaration with the availability
+// attribute.
+// expected-note@+2 {{marked partial here}}
+#endif
 extern void PartiallyAvailable() ;
 void with_redeclaration() {
-  PartiallyAvailable();  // Don't warn.
-
-  // enums should never warn.
+#ifdef WARN_PARTIAL
+  // expected-warning@+3 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}}
+  // expected-warning@+3 2 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+3 2 {{__builtin_available}}
+#endif
+  PartiallyAvailable();
   enum PartialEnum p = kPartialEnumConstant;
 }
 
@@ -86,13 +96,13 @@
   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 {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -87,22 +87,6 @@
   }
 }
 
-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) {
   AvailabilityResult Result = D->getAvailability(Message);
@@ -128,37 +112,15 @@
     }
   }
 
-  if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
+  if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
     if (Result == AR_Available) {
-      const DeclContext *DC = ECD->getDeclContext();
-      if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
+      DeclContext *DC = ECD->getDeclContext();
+      if (EnumDecl *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;
 }
 
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6901,6 +6901,23 @@
   return true;
 }
 
+static NamedDecl *findEnclosingDeclToAnnotate(Decl *Ctx) {
+  while (Ctx) {
+    if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx))
+      return cast<NamedDecl>(Ctx);
+    if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
+      if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
+        return Imp->getClassInterface();
+      return CD;
+    }
+    if (auto *MD = dyn_cast<ObjCMethodDecl>(Ctx))
+      return MD;
+    Ctx = cast_or_null<Decl>(Ctx->getDeclContext());
+  }
+
+  return nullptr;
+}
+
 static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
                                       Decl *Ctx, const NamedDecl *D,
                                       StringRef Message, SourceLocation Loc,
@@ -7057,7 +7074,9 @@
         << D << available_here_select_kind;
 
   if (K == AR_NotYetIntroduced)
-    S.Diag(Loc, diag::note_partial_availability_silence) << D;
+    if (NamedDecl *Enclosing = findEnclosingDeclToAnnotate(Ctx))
+      S.Diag(Enclosing->getLocStart(), diag::note_partial_availability_silence)
+          << Enclosing;
 }
 
 static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2873,7 +2873,7 @@
 def warn_partial_availability : Warning<"%0 is only available conditionally">,
     InGroup<UnguardedAvailability>, DefaultIgnore;
 def note_partial_availability_silence : Note<
-  "explicitly redeclare %0 to silence this warning">;
+  "annotate %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">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to