Tweak availability checking to look through typedef declarations.
authorTed Kremenek <kremenek@apple.com>
Thu, 14 May 2015 22:07:25 +0000 (22:07 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 14 May 2015 22:07:25 +0000 (22:07 +0000)
llvm-svn: 237396

clang/lib/Sema/SemaExpr.cpp
clang/test/SemaObjC/attr-availability.m

index 8dee0ee..0c5c23a 100644 (file)
@@ -104,13 +104,29 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
                            bool ObjCPropertyAccess) {
   // See if this declaration is unavailable or deprecated.
   std::string Message;
+  AvailabilityResult Result = D->getAvailability(&Message);
+
+  // For typedefs, if the typedef declaration appears available look
+  // to the underlying type to see if it is more restrictive.
+  while (const TypedefNameDecl *TD = TD = dyn_cast<TypedefNameDecl>(D)) {
+    if (Result == AR_Available) {
+      if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+        D = TT->getDecl();
+        Result = D->getAvailability(&Message);
+        continue;
+      }
+    }
+    break;
+  }
     
   // Forward class declarations get their attributes from their definition.
   if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
-    if (IDecl->getDefinition())
+    if (IDecl->getDefinition()) {
       D = IDecl->getDefinition();
+      Result = D->getAvailability(&Message);
+    }
   }
-  AvailabilityResult Result = D->getAvailability(&Message);
+
   if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
     if (Result == AR_Available) {
       const DeclContext *DC = ECD->getDeclContext();
index bac4be2..ea97e0e 100644 (file)
@@ -190,3 +190,19 @@ void partialinter1(PartialI2* p) {
 
 void partialinter2(PartialI2* p) { // no warning
 }
+
+
+// Test that both the use of the 'typedef' and the enum constant
+// produces an error. rdar://problem/20903588
+#define UNAVAILABLE __attribute__((unavailable("not available")))
+
+typedef enum MyEnum : int MyEnum;
+enum MyEnum : int { // expected-note {{'MyEnum' has been explicitly marked unavailable here}}
+  MyEnum_Blah UNAVAILABLE, // expected-note {{'MyEnum_Blah' has been explicitly marked unavailable here}}
+} UNAVAILABLE;
+
+void use_myEnum() {
+  // expected-error@+2 {{'MyEnum' is unavailable: not available}}
+  // expected-error@+1 {{MyEnum_Blah' is unavailable: not available}}
+  MyEnum e = MyEnum_Blah; 
+}