]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't assert when combining using .* on a temporary.
authorJordan Rose <jordan_rose@apple.com>
Tue, 29 Apr 2014 17:08:12 +0000 (17:08 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 29 Apr 2014 17:08:12 +0000 (17:08 +0000)
While we don't model pointer-to-member operators yet (neither .* nor ->*),
CallAndMessageChecker still checks to make sure the 'this' object is not
null or undefined first. However, it also expects that the object should
always have a valid MemRegion, something that's generally important elsewhere
in the analyzer as well. Ensure this is true ahead of time, just like we do
for member access.

PR19531

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

lib/StaticAnalyzer/Core/ExprEngineC.cpp
test/Analysis/member-expr.cpp

index 91b072f66c4ed0831a6fff785f8462a580c76f5c..b754ecbffee3a888fde6c62725eba7ea8083a76c 100644 (file)
@@ -81,6 +81,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
         }
       }
 
+      // Although we don't yet model pointers-to-members, we do need to make
+      // sure that the members of temporaries have a valid 'this' pointer for
+      // other checks.
+      if (B->getOpcode() == BO_PtrMemD)
+        state = createTemporaryRegionIfNeeded(state, LCtx, LHS);
+
       // Process non-assignments except commas or short-circuited
       // logical expressions (LAnd and LOr).
       SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());      
index cf437387d6a64012c62de4b772af0f37d37d4ee8..f8dd324e985720861d39e227d32c71dedc1ef794 100644 (file)
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -verify
 
+void clang_analyzer_checkInlined(bool);
 void clang_analyzer_eval(int);
 
 namespace EnumsViaMemberExpr {
@@ -20,4 +21,21 @@ namespace EnumsViaMemberExpr {
   void testEnumPtr(Foo *Baz) {
     clang_analyzer_eval(Baz->Bar == Foo::Bar); // expected-warning{{TRUE}}
   }
-}
\ No newline at end of file
+}
+
+namespace PR19531 {
+  struct A {
+    A() : x(0) {}
+    bool h() const;
+    int x;
+  };
+
+  struct B {
+    void g(bool (A::*mp_f)() const) {
+      // This used to trigger an assertion because the 'this' pointer is a
+      // temporary.
+      (A().*mp_f)();
+    }
+    void f() { g(&A::h); }
+  };
+}