diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-12-18 20:13:39 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-12-18 20:13:39 +0000 |
commit | 53287518f69b8f06f82a6cdbd13e4e3a13b58186 (patch) | |
tree | ed4668c21c79b378704b7fdea3675cad5764fd7f | |
parent | 5231eaa5f58c49860d5446d5269685cd9c063ccb (diff) | |
download | clang-53287518f69b8f06f82a6cdbd13e4e3a13b58186.tar.gz |
Enhance GRExprEngine::VisitCallExpr() to be used in an lvalue context. Uncovered a new failing test case along the way, but we're making progress on handling C++ references in the analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91710 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRExprEngine.h | 2 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 57 | ||||
-rw-r--r-- | test/Analysis/misc-ps-region-store.cpp | 8 |
3 files changed, 60 insertions, 7 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 6c422edff9..21031a488e 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -265,7 +265,7 @@ protected: /// VisitCall - Transfer function for function calls. void VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst); + ExplodedNodeSet& Dst, bool asLValue); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 9b00d1e64a..4295e9a1ae 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -46,6 +46,23 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { return Ctx.Selectors.getSelector(0, &II); } +static bool CalleeReturnsReference(const CallExpr *CE) { + const Expr *Callee = CE->getCallee(); + QualType T = Callee->getType(); + + + if (const PointerType *PT = T->getAs<PointerType>()) { + const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>(); + T = FT->getResultType(); + } + else { + const BlockPointerType *BT = T->getAs<BlockPointerType>(); + T = BT->getPointeeType()->getAs<FunctionType>()->getResultType(); + } + + return T->isReferenceType(); +} + //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// @@ -228,7 +245,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); } - + void *tag = I->first; Checker *checker = I->second; @@ -593,7 +610,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr* C = cast<CallExpr>(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false); break; } @@ -745,6 +762,14 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true); return; + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: { + CallExpr* C = cast<CallExpr>(Ex); + assert(CalleeReturnsReference(C)); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); + break; + } + case Stmt::CompoundLiteralExprClass: VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); return; @@ -1563,7 +1588,7 @@ public: void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; @@ -1577,7 +1602,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, WorkList.push_back(CallExprWLItem(AI, Pred)); ExplodedNodeSet ArgsEvaluated; - + while (!WorkList.empty()) { CallExprWLItem Item = WorkList.back(); WorkList.pop_back(); @@ -1623,6 +1648,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Finally, evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { @@ -1664,7 +1690,28 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - CheckerVisit(CE, Dst, DstTmp3, false); + + if (!(!asLValue && CalleeReturnsReference(CE))) { + CheckerVisit(CE, Dst, DstTmp3, false); + return; + } + + // Handle the case where the called function returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of CallExpr is consumed by another expression. + ExplodedNodeSet DstTmp4; + CheckerVisit(CE, DstTmp4, DstTmp3, false); + QualType LoadTy = CE->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, CE, *NI, state, state->getSVal(CE), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp index c1e03bb0d9..838ac39d5c 100644 --- a/test/Analysis/misc-ps-region-store.cpp +++ b/test/Analysis/misc-ps-region-store.cpp @@ -2,8 +2,14 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s // XFAIL: * -// This test case currently crashes because of an assertion failure. +// Test basic handling of references. char &test1_aux(); char *test1() { return &test1_aux(); } + +// This test currently crasehs because test1_aux() evaluates to a 'char' instead of a char& in CFRefCount.cpp. +char test1_as_rvalue() { + return test1_aux(); +} + |