]> granicus.if.org Git - clang/commitdiff
[analyzer] pr34404: Fix a crash on modeling pointers to indirect members.
authorArtem Dergachev <artem.dergachev@gmail.com>
Mon, 27 Nov 2017 17:31:16 +0000 (17:31 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Mon, 27 Nov 2017 17:31:16 +0000 (17:31 +0000)
We were crashing whenever a C++ pointer-to-member was taken, that was pointing
to a member of an anonymous structure field within a class, eg.

  struct A {
    struct {
     int x;
    };
  };
  // ...
  &A::x;

Differential Revision: https://reviews.llvm.org/D39800

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/pointer-to-member.cpp

index 0126e03d60d25c89b008a1473d9859f725fd39b0..31e21232408b6d7decc5d4651a1385635a8b1c2a 100644 (file)
@@ -2108,10 +2108,12 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
                       ProgramPoint::PostLValueKind);
     return;
   }
-  if (isa<FieldDecl>(D)) {
+  if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
     // FIXME: Compute lvalue of field pointers-to-member.
     // Right now we just use a non-null void pointer, so that it gives proper
     // results in boolean contexts.
+    // FIXME: Maybe delegate this to the surrounding operator&.
+    // Note how this expression is lvalue, however pointer-to-member is NonLoc.
     SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
                                           currBldrCtx->blockCount());
     state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true);
index 0fbb992dd82a7d7ea8c5ec05015ca366b35a0cb9..65882527d2da2574757970a0dac4d52d9061c87c 100644 (file)
@@ -230,3 +230,42 @@ void double_diamond() {
   clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int R1::*>(&B::f)))) == 4); // expected-warning {{TRUE}}
 }
 } // end of testPointerToMemberDiamond namespace
+
+namespace testAnonymousMember {
+struct A {
+  struct {
+    int x;
+  };
+  struct {
+    struct {
+      int y;
+    };
+  };
+  struct {
+    union {
+      int z;
+    };
+  };
+};
+
+void test() {
+  clang_analyzer_eval(&A::x); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::y); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::z); // expected-warning{{TRUE}}
+
+  // FIXME: These should be true.
+  int A::*l = &A::x, A::*m = &A::y, A::*n = &A::z;
+  clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(m); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(n); // expected-warning{{UNKNOWN}}
+
+  // FIXME: These should be true as well.
+  A a;
+  a.x = 1;
+  clang_analyzer_eval(a.*l == 1); // expected-warning{{UNKNOWN}}
+  a.y = 2;
+  clang_analyzer_eval(a.*m == 2); // expected-warning{{UNKNOWN}}
+  a.z = 3;
+  clang_analyzer_eval(a.*n == 3); // expected-warning{{UNKNOWN}}
+}
+} // end of testAnonymousMember namespace