From: Zhongxing Xu Date: Sat, 9 Jan 2010 09:16:47 +0000 (+0000) Subject: When binding an rvalue to a reference, create a temporary object. Use X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bc37b8dd9914e02580f531fa6e5e72be34d9675e;p=clang When binding an rvalue to a reference, create a temporary object. Use CXXObjectRegion to represent it. In Environment, lookup a literal expression before make up a value for it. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93047 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 1a420e41d1..fb0e88301f 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -353,6 +353,10 @@ protected: void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst); + /// Create a C++ temporary object for an rvalue. + void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) /// with those assumptions. diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 99aa3e15d7..3bcedbefd6 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -752,21 +752,21 @@ public: } }; +// C++ temporary object associated with an expression. class CXXObjectRegion : public TypedRegion { friend class MemRegionManager; - // T - The object type. - QualType T; + Expr const *Ex; - CXXObjectRegion(QualType t, const MemRegion *sReg) - : TypedRegion(sReg, CXXObjectRegionKind), T(t) {} + CXXObjectRegion(Expr const *E, MemRegion const *sReg) + : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {} static void ProfileRegion(llvm::FoldingSetNodeID &ID, - QualType T, const MemRegion *sReg); + Expr const *E, const MemRegion *sReg); public: QualType getValueType(ASTContext& C) const { - return T; + return Ex->getType(); } void Profile(llvm::FoldingSetNodeID &ID) const; @@ -901,7 +901,8 @@ public: const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - const CXXObjectRegion *getCXXObjectRegion(QualType T); + const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex, + LocationContext const *LC); const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index dd2f08b48f..f04cf7b05f 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { } case Stmt::IntegerLiteralClass: { - return ValMgr.makeIntVal(cast(E)); + // In C++, this expression may have been bound to a temporary object. + SVal const *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast(E)); } // Casts where the source and target type are the same diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 0336ae5ada..ed3dc8abac 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -887,6 +887,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast(Ex), Pred, Dst, true); return; + + // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::IntegerLiteralClass: + CreateCXXTemporaryObject(Ex, Pred, Dst); + return; default: // Arbitrary subexpressions can return aggregate temporaries that @@ -2992,6 +2997,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 5be882ad54..c17e4e83ee 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -304,14 +304,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, - QualType T, + Expr const *Ex, const MemRegion *sReg) { - ID.AddPointer(T.getTypePtr()); + ID.AddPointer(Ex); ID.AddPointer(sReg); } void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ProfileRegion(ID, T, getSuperRegion()); + ProfileRegion(ID, Ex, getSuperRegion()); } //===----------------------------------------------------------------------===// @@ -580,8 +580,11 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, } const CXXObjectRegion* -MemRegionManager::getCXXObjectRegion(QualType T) { - return getSubRegion(T, getUnknownRegion()); +MemRegionManager::getCXXObjectRegion(Expr const *E, + LocationContext const *LC) { + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + assert(SFC); + return getSubRegion(E, getStackLocalsRegion(SFC)); } const CXXThisRegion* diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp new file mode 100644 index 0000000000..941147b9b2 --- /dev/null +++ b/test/Analysis/reference.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s + +void f1() { + int const &i = 3; + int b = i; +}