]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't warn for returning void expressions in void blocks.
authorJordan Rose <jordan_rose@apple.com>
Wed, 17 Apr 2013 18:03:48 +0000 (18:03 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 17 Apr 2013 18:03:48 +0000 (18:03 +0000)
This was slightly tricky because BlockDecls don't currently store an
inferred return type. However, we can rely on the fact that blocks with
inferred return types will have return statements that match the inferred
type.

<rdar://problem/13665798>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179699 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
lib/StaticAnalyzer/Core/CallEvent.cpp
test/Analysis/uninit-vals-ps.c

index 7a5d9936010868c90afd8b77d146cc64214ef159..ed96c401a7aa710371a739729f19035149622de2 100644 (file)
@@ -55,8 +55,17 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
     //   void test() {
     //     return foo();
     //   }
-    if (RT.isNull() || !RT->isVoidType())
-      emitUndef(C, RetE);
+    if (!RT.isNull() && RT->isVoidType())
+      return;
+
+    // Not all blocks have explicitly-specified return types; if the return type
+    // is not available, but the return value expression has 'void' type, assume
+    // Sema already checked it.
+    if (RT.isNull() && isa<BlockDecl>(SFC->getDecl()) &&
+        RetE->getType()->isVoidType())
+      return;
+
+    emitUndef(C, RetE);
     return;
   }
 
index 45b2e219d9e35d08fef262a5f9a150e85cd704ea..dfd20b8b332b30da1004428fe04163b539a23fe6 100644 (file)
@@ -239,8 +239,20 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
   assert(D);
   if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
     return FD->getResultType();
-  else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D))
+  if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D))
     return MD->getResultType();
+  if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+    // Blocks are difficult because the return type may not be stored in the
+    // BlockDecl itself. The AST should probably be enhanced, but for now we
+    // just do what we can.
+    QualType Ty = BD->getSignatureAsWritten()->getType();
+    if (const FunctionType *FT = Ty->getAs<FunctionType>())
+      if (!FT->getResultType()->isDependentType())
+        return FT->getResultType();
+
+    return QualType();
+  }
+  
   return QualType();
 }
 
index 09736ef1e35e07e7a610d8fe784fee0dc16466b8..ad40b15502e46a32465e808f3ee824f359705bfe 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
 
 struct FPRec {
   void (*my_func)(int * x);  
@@ -122,6 +122,8 @@ int pr4631_f1_b(void)
   return x;  // no-warning
 }
 
+// <rdar://problem/12278788> - FP when returning a void-valued expression from
+// a void function...or block.
 void foo_radar12278788() { return; }
 void test_radar12278788() {
   return foo_radar12278788(); // no-warning
@@ -134,3 +136,16 @@ int test_radar12278788_FP() {
   RetVoidFuncType f = foo_radar12278788_fp;
   return ((RetIntFuncType)f)(); //expected-warning {{Undefined or garbage value returned to caller}}
 }
+
+void rdar13665798() {
+  ^() {
+    return foo_radar12278788(); // no-warning
+  }();
+  ^void() {
+    return foo_radar12278788(); // no-warning
+  }();
+  ^int() {
+    RetVoidFuncType f = foo_radar12278788_fp;
+    return ((RetIntFuncType)f)(); //expected-warning {{Undefined or garbage value returned to caller}}
+  }();
+}