r240186 - CF_RETURNS_[NOT_]RETAINED on a param makes the inner pointer __nullable.

Douglas Gregor dgregor at apple.com
Fri Jun 19 16:17:51 PDT 2015


Author: dgregor
Date: Fri Jun 19 18:17:51 2015
New Revision: 240186

URL: http://llvm.org/viewvc/llvm-project?rev=240186&view=rev
Log:
CF_RETURNS_[NOT_]RETAINED on a param makes the inner pointer __nullable.

That is,

  void cf2(CFTypeRef * __nullable p CF_RETURNS_NOT_RETAINED);

is equivalent to

  void cf2(CFTypeRef __nullable * __nullable p CF_RETURNS_NOT_RETAINED);

More rdar://problem/18742441

Modified:
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/Analysis/retain-release.m
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=240186&r1=240185&r2=240186&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Jun 19 18:17:51 2015
@@ -2614,6 +2614,8 @@ namespace {
     SingleLevelPointer,
     // Multi-level pointer (of any pointer kind).
     MultiLevelPointer,
+    // CFFooRef*
+    MaybePointerToCFRef,
     // CFErrorRef*
     CFErrorRefPointer,
     // NSError**
@@ -2754,6 +2756,9 @@ static PointerDeclaratorKind classifyPoi
   case 1:
     return PointerDeclaratorKind::SingleLevelPointer;
 
+  case 2:
+    return PointerDeclaratorKind::MaybePointerToCFRef;
+
   default:
     return PointerDeclaratorKind::MultiLevelPointer;
   }
@@ -2894,6 +2899,8 @@ static TypeSourceInfo *GetFullTypeForDec
   // Determine whether we should infer __nonnull on pointer types.
   Optional<NullabilityKind> inferNullability;
   bool inferNullabilityCS = false;
+  bool inferNullabilityInnerOnly = false;
+  bool inferNullabilityInnerOnlyComplete = false;
 
   // Are we in an assume-nonnull region?
   bool inAssumeNonNullRegion = false;
@@ -3007,6 +3014,31 @@ static TypeSourceInfo *GetFullTypeForDec
         if (isFunctionOrMethod && inAssumeNonNullRegion)
           inferNullability = NullabilityKind::Nullable;
         break;
+
+      case PointerDeclaratorKind::MaybePointerToCFRef:
+        if (isFunctionOrMethod) {
+          // On pointer-to-pointer parameters marked cf_returns_retained or
+          // cf_returns_not_retained, if the outer pointer is explicit then
+          // infer the inner pointer as __nullable.
+          auto hasCFReturnsAttr = [](const AttributeList *NextAttr) -> bool {
+            while (NextAttr) {
+              if (NextAttr->getKind() == AttributeList::AT_CFReturnsRetained ||
+                  NextAttr->getKind() == AttributeList::AT_CFReturnsNotRetained)
+                return true;
+              NextAttr = NextAttr->getNext();
+            }
+            return false;
+          };
+          if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) {
+            if (hasCFReturnsAttr(D.getAttributes()) ||
+                hasCFReturnsAttr(InnermostChunk->getAttrs()) ||
+                hasCFReturnsAttr(D.getDeclSpec().getAttributes().getList())) {
+              inferNullability = NullabilityKind::Nullable;
+              inferNullabilityInnerOnly = true;
+            }
+          }
+        }
+        break;
       }
       break;
 
@@ -3047,9 +3079,10 @@ static TypeSourceInfo *GetFullTypeForDec
       return nullptr;
 
     // If we're supposed to infer nullability, do so now.
-    if (inferNullability) {
-      auto syntax = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword
-                                       : AttributeList::AS_Keyword;
+    if (inferNullability && !inferNullabilityInnerOnlyComplete) {
+      AttributeList::Syntax syntax
+        = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword
+                             : AttributeList::AS_Keyword;
       AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool()
                                          .create(
                                            S.getNullabilityKeyword(
@@ -3059,6 +3092,9 @@ static TypeSourceInfo *GetFullTypeForDec
                                            nullptr, 0, syntax);
 
       spliceAttrIntoList(*nullabilityAttr, attrs);
+
+      if (inferNullabilityInnerOnly)
+        inferNullabilityInnerOnlyComplete = true;
       return nullabilityAttr;
     }
 

Modified: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=240186&r1=240185&r2=240186&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (original)
+++ cfe/trunk/test/Analysis/retain-release.m Fri Jun 19 18:17:51 2015
@@ -2164,6 +2164,13 @@ void testCFReturnsNotRetained() {
   CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
 }
 
+void testCFReturnsNotRetainedAnnotated() {
+  extern void getViaParam2(CFTypeRef * __nonnull CF_RETURNS_NOT_RETAINED outObj);
+  CFTypeRef obj;
+  getViaParam2(&obj);
+  CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
 void testCFReturnsRetained() {
   extern int copyViaParam(CFTypeRef * CF_RETURNS_RETAINED outObj);
   CFTypeRef obj;

Modified: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h?rev=240186&r1=240185&r2=240186&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h (original)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h Fri Jun 19 18:17:51 2015
@@ -9,3 +9,19 @@ void func2(mynonnull i);
 
 void func3(int *); // expected-warning{{pointer is missing a nullability type specifier}}
 
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+typedef void *CFTypeRef;
+void cf1(CFTypeRef * p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}}
+
+void cf2(CFTypeRef * __nullable p CF_RETURNS_NOT_RETAINED);
+void cf3(CFTypeRef * __nonnull p CF_RETURNS_NOT_RETAINED);
+
+void cf4(CFTypeRef __nullable * __nullable p CF_RETURNS_NOT_RETAINED);
+void cf5(CFTypeRef __nonnull * __nullable p CF_RETURNS_NOT_RETAINED);
+
+void cf6(CFTypeRef * __nullable CF_RETURNS_NOT_RETAINED p);
+void cf7(CF_RETURNS_NOT_RETAINED CFTypeRef * __nonnull p);
+
+typedef CFTypeRef __nullable *CFTypeRefPtr;
+void cfp1(CFTypeRefPtr p CF_RETURNS_NOT_RETAINED); // expected-warning {{pointer is missing a nullability type specifier}}
+void cfp2(CFTypeRefPtr __nonnull p CF_RETURNS_NOT_RETAINED);





More information about the cfe-commits mailing list