[cfe-commits] r164829 - in /cfe/trunk: lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/array-struct-region.cpp

Jordan Rose jordan_rose at apple.com
Fri Sep 28 10:15:21 PDT 2012


Author: jrose
Date: Fri Sep 28 12:15:21 2012
New Revision: 164829

URL: http://llvm.org/viewvc/llvm-project?rev=164829&view=rev
Log:
[analyzer] Create a temp region when a method is called on a struct rvalue.

An rvalue has no address, but calling a C++ member function requires a
'this' pointer. This commit makes the analyzer create a temporary region
in which to store the struct rvalue and use as a 'this' pointer whenever
a member function is called on an rvalue, which is essentially what
CodeGen does.

More of <rdar://problem/12137950>. The last part is tracking down the
C++ FIXME in array-struct-region.cpp.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/Analysis/array-struct-region.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=164829&r1=164828&r2=164829&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Sep 28 12:15:21 2012
@@ -1470,6 +1470,23 @@
   }
 }
 
+/// If the value of the given expression is a NonLoc, copy it into a new
+/// temporary region, and replace the value of the expression with that.
+static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
+                                                     const LocationContext *LC,
+                                                     const Expr *E) {
+  SVal V = State->getSVal(E, LC);
+
+  if (isa<NonLoc>(V)) {
+    MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
+    const MemRegion *R  = MRMgr.getCXXTempObjectRegion(E, LC);
+    State = State->bindLoc(loc::MemRegionVal(R), V);
+    State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+  }
+
+  return State;
+}
+
 /// VisitMemberExpr - Transfer function for member expressions.
 void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
                                  ExplodedNodeSet &TopDst) {
@@ -1478,6 +1495,7 @@
   ExplodedNodeSet Dst;
   Decl *member = M->getMemberDecl();
 
+  // Handle static member variables accessed via member syntax.
   if (VarDecl *VD = dyn_cast<VarDecl>(member)) {
     assert(M->isGLValue());
     Bldr.takeNodes(Pred);
@@ -1486,36 +1504,27 @@
     return;
   }
 
+  ProgramStateRef state = Pred->getState();
+  const LocationContext *LCtx = Pred->getLocationContext();
+  Expr *BaseExpr = M->getBase()->IgnoreParens();
+
   // Handle C++ method calls.
   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(member)) {
-    Bldr.takeNodes(Pred);
+    if (MD->isInstance())
+      state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+
     SVal MDVal = svalBuilder.getFunctionPointer(MD);
-    ProgramStateRef state =
-      Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal);
+    state = state->BindExpr(M, LCtx, MDVal);
+
     Bldr.generateNode(M, Pred, state);
     return;
   }
 
+  // Handle regular struct fields / member variables.
+  state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+  SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
 
-  FieldDecl *field = dyn_cast<FieldDecl>(member);
-  if (!field) // FIXME: skipping member expressions for non-fields
-    return;
-
-  Expr *baseExpr = M->getBase()->IgnoreParens();
-  ProgramStateRef state = Pred->getState();
-  const LocationContext *LCtx = Pred->getLocationContext();
-  SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext());
-
-  // If we're accessing a field of an rvalue, we need to treat it like a
-  // temporary object.
-  if (isa<NonLoc>(baseExprVal)) {
-    const MemRegion *R  =
-      svalBuilder.getRegionManager().getCXXTempObjectRegion(baseExpr, LCtx);
-    SVal L = loc::MemRegionVal(R);
-    state = state->bindLoc(L, baseExprVal);
-    baseExprVal = L;
-  }
-
+  FieldDecl *field = cast<FieldDecl>(member);
   SVal L = state->getLValue(field, baseExprVal);
   if (M->isGLValue()) {
     ExplodedNodeSet Tmp;

Modified: cfe/trunk/test/Analysis/array-struct-region.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/array-struct-region.cpp?rev=164829&r1=164828&r2=164829&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/array-struct-region.cpp (original)
+++ cfe/trunk/test/Analysis/array-struct-region.cpp Fri Sep 28 12:15:21 2012
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
 
 void clang_analyzer_eval(int);
 
@@ -11,7 +13,14 @@
 #endif
 };
 
+#ifdef INLINE
+struct S getS() {
+  struct S s = { 42 };
+  return s;
+}
+#else
 struct S getS();
+#endif
 
 
 void testAssignment() {





More information about the cfe-commits mailing list