diff options
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp | 13 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 14 | ||||
-rw-r--r-- | clang/test/Analysis/uninit-vals-ps.c | 17 |
3 files changed, 40 insertions, 4 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 7a5d9936010..ed96c401a7a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -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; } diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 45b2e219d9e..dfd20b8b332 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -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(); } diff --git a/clang/test/Analysis/uninit-vals-ps.c b/clang/test/Analysis/uninit-vals-ps.c index 09736ef1e35..ad40b15502e 100644 --- a/clang/test/Analysis/uninit-vals-ps.c +++ b/clang/test/Analysis/uninit-vals-ps.c @@ -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}} + }(); +} |