]> granicus.if.org Git - clang/commitdiff
[analyzer] Handle C++11 member initializer expressions.
authorJordan Rose <jordan_rose@apple.com>
Wed, 17 Jul 2013 17:16:42 +0000 (17:16 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 17 Jul 2013 17:16:42 +0000 (17:16 +0000)
Previously, we would simply abort the path when we saw a default member
initialization; now, we actually attempt to evaluate it. Like default
arguments, the contents of these expressions are not actually part of the
current function, so we fall back to constant evaluation.

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/initializer.cpp

index ff8a9e8661372a98d81d65d3c08ccd0c8cc72607..0b31495c8401461575ecdfd3c9c2c7aa51fb7996 100644 (file)
@@ -612,7 +612,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
   switch (S->getStmtClass()) {
     // C++ and ARC stuff we don't support yet.
     case Expr::ObjCIndirectCopyRestoreExprClass:
-    case Stmt::CXXDefaultInitExprClass:
     case Stmt::CXXDependentScopeMemberExprClass:
     case Stmt::CXXPseudoDestructorExprClass:
     case Stmt::CXXTryStmtClass:
@@ -737,7 +736,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
     }
 
-    case Stmt::CXXDefaultArgExprClass: {
+    case Stmt::CXXDefaultArgExprClass:
+    case Stmt::CXXDefaultInitExprClass: {
       Bldr.takeNodes(Pred);
       ExplodedNodeSet PreVisit;
       getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
@@ -745,9 +745,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       ExplodedNodeSet Tmp;
       StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
 
-      const LocationContext *LCtx = Pred->getLocationContext();
-      const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
-      const Expr *ArgE = DefaultE->getExpr();
+      const Expr *ArgE;
+      if (const CXXDefaultArgExpr *DefE = dyn_cast<CXXDefaultArgExpr>(S))
+        ArgE = DefE->getExpr();
+      else if (const CXXDefaultInitExpr *DefE = dyn_cast<CXXDefaultInitExpr>(S))
+        ArgE = DefE->getExpr();
+      else
+        llvm_unreachable("unknown constant wrapper kind");
 
       bool IsTemporary = false;
       if (const MaterializeTemporaryExpr *MTE =
@@ -760,13 +764,15 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       if (!ConstantVal)
         ConstantVal = UnknownVal();
 
+      const LocationContext *LCtx = Pred->getLocationContext();
       for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
            I != E; ++I) {
         ProgramStateRef State = (*I)->getState();
-        State = State->BindExpr(DefaultE, LCtx, *ConstantVal);
+        State = State->BindExpr(S, LCtx, *ConstantVal);
         if (IsTemporary)
-          State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
-                                                DefaultE);
+          State = createTemporaryRegionIfNeeded(State, LCtx,
+                                                cast<Expr>(S),
+                                                cast<Expr>(S));
         Bldr2.generateNode(S, *I, State);
       }
 
index 3f7802c56d29e239d5f6c90494141a9a822adc92..a71e35dc63c6c75bd227818b787c568f394ddae5 100644 (file)
@@ -109,3 +109,37 @@ namespace DefaultConstructorWithCleanups {
     return w.arr[0].value; // no-warning
   }
 }
+
+namespace DefaultMemberInitializers {
+  struct Wrapper {
+    int value = 42;
+
+    Wrapper() {}
+    Wrapper(int x) : value(x) {}
+    Wrapper(bool) {}
+  };
+
+  void test() {
+    Wrapper w1;
+    clang_analyzer_eval(w1.value == 42); // expected-warning{{TRUE}}
+
+    Wrapper w2(50);
+    clang_analyzer_eval(w2.value == 50); // expected-warning{{TRUE}}
+
+    Wrapper w3(false);
+    clang_analyzer_eval(w3.value == 42); // expected-warning{{TRUE}}
+  }
+
+  struct StringWrapper {
+    const char s[4] = "abc";
+    const char *p = "xyz";
+
+    StringWrapper(bool) {}
+  };
+
+  void testString() {
+    StringWrapper w(true);
+    clang_analyzer_eval(w.s[1] == 'b'); // expected-warning{{TRUE}}
+    clang_analyzer_eval(w.p[1] == 'y'); // expected-warning{{TRUE}}
+  }
+}