steven_wu created this revision.
steven_wu added a reviewer: arphaman.

There are some functions/methods that run when the application launches
or the library loads. Those functions will run reguardless the OS
version as long as it satifies the minimum deployment target. Annotate
them with availability attributes doesn't really make sense because they
are essentially available on all targets since minimum deployment
target.

rdar://problem/36093384


Repository:
  rC Clang

https://reviews.llvm.org/D45699

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclObjC.cpp
  test/SemaObjC/unguarded-availability.m

Index: test/SemaObjC/unguarded-availability.m
===================================================================
--- test/SemaObjC/unguarded-availability.m
+++ test/SemaObjC/unguarded-availability.m
@@ -7,7 +7,7 @@
 
 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}}
+int func_10_11() AVAILABLE_10_11; // expected-note 8 {{'func_10_11' has been explicitly marked partial here}}
 
 #ifdef OBJCPP
 // expected-note@+2 6 {{marked partial here}}
@@ -311,3 +311,41 @@
   (void)AK_Cat; // no warning
   (void)AK_CyborgCat; // expected-warning{{'AK_CyborgCat' is only available on macOS 10.12 or newer}} expected-note {{@available}}
 }
+
+
+// test static initializers has the same availability as the deployment target and it cannot be overwritten.
+@interface HasStaticInitializer : BaseClass
++ (void)load AVAILABLE_10_11; // expected-warning{{ignoring availability attribute on '+load' method}}
+@end
+
+@implementation HasStaticInitializer
++ (void)load {
+  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
+}
+@end
+
+// test availability from interface is ignored when checking the unguarded availability in +load method.
+AVAILABLE_10_11
+@interface HasStaticInitializer1 : BaseClass
++ (void)load;
+@end
+
+@implementation HasStaticInitializer1
++ (void)load {
+  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
+}
+@end
+
+__attribute__((constructor))
+void is_constructor();
+
+AVAILABLE_10_11 // expected-warning{{ignoring availability attribute with constructor attribute}}
+void is_constructor() {
+  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
+}
+
+AVAILABLE_10_11 // expected-warning{{ignoring availability attribute with desctructor attribute}}
+__attribute__((destructor))
+void is_destructor() {
+  func_10_11(); // expected-warning{{'func_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'func_10_11' in an @available check to silence this warning}}
+}
Index: lib/Sema/SemaDeclObjC.cpp
===================================================================
--- lib/Sema/SemaDeclObjC.cpp
+++ lib/Sema/SemaDeclObjC.cpp
@@ -4734,6 +4734,20 @@
       Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
     checkObjCMethodX86VectorTypes(*this, ObjCMethod);
 
+  // + load method cannot have availability attributes. It has to be the same
+  // as deployment target.
+  for (const auto& attr: ObjCMethod->attrs()) {
+    if (!isa<AvailabilityAttr>(attr))
+      continue;
+
+    if (ObjCMethod->isClassMethod() &&
+        ObjCMethod->getNameAsString() == "load") {
+      Diag(attr->getLocation(), diag::warn_availability_on_static_initializer)
+          << 0;
+      ObjCMethod->dropAttr<AvailabilityAttr>();
+    }
+  }
+
   ActOnDocumentableDecl(ObjCMethod);
 
   return ObjCMethod;
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6823,6 +6823,11 @@
       return false;
 
     // An implementation implicitly has the availability of the interface.
+    // Unless it is "+load" method.
+    if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
+      if (MethodD->isClassMethod() && MethodD->getNameAsString() == "load")
+        return true;
+
     if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
       if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
         if (CheckContext(Interface))
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -9131,6 +9131,25 @@
     AddToScope = false;
   }
 
+  // Diagnose availability attributes. Availability cannot be used on functions
+  // that are run during load/unload.
+  for (const auto& attr: NewFD->attrs()) {
+    if (!isa<AvailabilityAttr>(attr))
+      continue;
+
+    if (NewFD->hasAttr<ConstructorAttr>()) {
+      Diag(attr->getLocation(), diag::warn_availability_on_static_initializer)
+          << 1;
+      NewFD->dropAttr<AvailabilityAttr>();
+    }
+    if (NewFD->hasAttr<DestructorAttr>()) {
+      Diag(attr->getLocation(), diag::warn_availability_on_static_initializer)
+          << 2;
+      NewFD->dropAttr<AvailabilityAttr>();
+    }
+    break;
+  }
+
   return NewFD;
 }
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2911,6 +2911,10 @@
   "%select{the protocol method it implements|its overridden method}1 is "
   "available">,
   InGroup<Availability>;
+def warn_availability_on_static_initializer : Warning<
+  "ignoring availability attribute %select{on '+load' method|"
+  "with constructor attribute|with desctructor attribute}0">,
+  InGroup<Availability>;
 def note_overridden_method : Note<
   "overridden method is here">;
 def note_protocol_method : Note<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to