[PATCH] D40715: [analyser] different.LabelInsideSwitch checker implementation

2017-12-03 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added a comment.

A few comments.




Comment at: lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp:19
+if (S.second)
+  return S;
+

Maybe I miss something, but do not we return StringRef to temporary string 
going out of scope here? Same below.



Comment at: lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp:24
+
+  class WalkAST : public ConstStmtVisitor {
+const CheckerBase *Checker;

Do you consider using ASTMatchers like in NumberObjectConversionChecker instead 
of manually traversing the AST?



Comment at: lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp:59
+BR.EmitBasicReport(AC->getDecl(), Checker, "Labeled statement inside 
switch",
+   categories::LogicError, OS.str(), Loc, Sr);
+  }

a.sidorin wrote:
> raw_svector_ostream is always synchronized with the string it prints to so we 
> can just pass the message string instead of calling .str().
You could use S->getSourceRange() instead of Sr, as llvm::ArrayRef in 
EmitBasicReport() could be constructed even from the 0 consecutively elements.



Comment at: lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp:80
+  MinSize = ExpSize;
+}
+

Maybe so?
size_t MinSize = std::min(StrSize, ExpSize);
size_t SizeDelta = std::labs(StrSize, ExpSize);


Repository:
  rC Clang

https://reviews.llvm.org/D40715



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-27 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added a comment.

Looks like you run formatter on the whole file, maybe narrow down its scope a 
little? For example, only for the touched function?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95307/new/

https://reviews.llvm.org/D95307

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-27 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:199
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
+  llvm::SmallPtrSet BaseTypes;
+  for (const auto &BaseSpec : PathList)

What if we get the situation of the repeated types in the `PathRange`?

Like `Derived` --(cast to)-> `Base` --(cast to)-> `Derived` --(cast to)-> 
`Base` and so on.

Do we need to store the pair of `QualType` and `PathRange` index for that case 
or only type will be enough?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95307/new/

https://reviews.llvm.org/D95307

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D39800: [analyzer] pr34404: Fix a crash on pointers to members in nested anonymous structures.

2017-11-09 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added a comment.

@NoQ  Do we need to change a `DeclaratorDecl` field in PointerToMember SVal to 
something more common, like `ValueDecl`, to support `IndirectFieldDecl` as well?


https://reviews.llvm.org/D39800



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-12-15 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov updated this revision to Diff 81598.
kromanenkov added a comment.

Fix issues pointed by @dcoughlin and rebase patch on master.


https://reviews.llvm.org/D25475

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  lib/StaticAnalyzer/Core/SValBuilder.cpp
  lib/StaticAnalyzer/Core/SVals.cpp
  lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
  lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  test/Analysis/pointer-to-member.cpp

Index: test/Analysis/pointer-to-member.cpp
===
--- test/Analysis/pointer-to-member.cpp
+++ test/Analysis/pointer-to-member.cpp
@@ -35,8 +35,7 @@
   clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
   clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}}
 }
 
 namespace PR15742 {
@@ -62,21 +61,156 @@
   }
 }
 
-// ---
-// FALSE NEGATIVES
-// ---
-
 bool testDereferencing() {
   A obj;
   obj.m_ptr = 0;
 
   A::MemberPointer member = &A::m_ptr;
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}}
 
   member = 0;
 
-  // FIXME: Should emit a null dereference.
-  return obj.*member; // no-warning
+  return obj.*member; // expected-warning{{The result of the '.*' expression is undefined}}
+}
+
+namespace testPointerToMemberFunction {
+  struct A {
+virtual int foo() { return 1; }
+int bar() { return 2;  }
+  };
+
+  struct B : public A {
+virtual int foo() { return 3; }
+  };
+
+  typedef int (A::*AFnPointer)();
+  typedef int (B::*BFnPointer)();
+
+  void testPointerToMemberCasts() {
+AFnPointer AFP = &A::bar;
+BFnPointer StaticCastedBase2Derived = static_cast(&A::bar),
+   CCastedBase2Derived = (BFnPointer) (&A::bar);
+A a;
+B b;
+
+clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}}
+  }
+
+  void testPointerToMemberVirtualCall() {
+A a;
+B b;
+A *APtr = &a;
+AFnPointer AFP = &A::foo;
+
+clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}}
+
+APtr = &b;
+
+clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberFunction namespace
+
+namespace testPointerToMemberData {
+  struct A {
+int i;
+  };
+
+  void testPointerToMemberData() {
+int A::*AMdPointer = &A::i;
+A a;
+
+a.i = 42;
+a.*AMdPointer += 1;
+
+clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberData namespace
+
+namespace testPointerToMemberMiscCasts {
+struct B {
+  int f;
+};
+
+struct D : public B {
+  int g;
+};
+
+void foo() {
+  D d;
+  d.f = 7;
+
+  int B::* pfb = &B::f;
+  int D::* pfd = pfb;
+  int v = d.*pfd;
+
+  clang_analyzer_eval(v == 7); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMemberMiscCasts namespace
+
+namespace testPointerToMemberMiscCasts2 {
+struct B {
+  int f;
+};
+struct L : public B { };
+struct R : public B { };
+struct D : public L, R { };
+
+void foo() {
+  D d;
+
+  int B::* pb = &B::f;
+  int L::* pl = pb;
+  int R::* pr = pb;
+
+  int D::* pdl = pl;
+  int D::* pdr = pr;
+
+  clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}}
+  clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMemberMiscCasts2 namespace
+
+namespace testPointerToMemberDiamond {
+struct B {
+  int f;
+};
+struct L1 : public B { };
+struct R1 : public B { };
+struct M : public L1, R1 { };
+struct L2 : public M { };
+struct R2 : public M { };
+struct D2 : public L2, R2 { };
+
+void diamond() {
+  M m;
+
+  static_cast(&m)->f = 7;
+  static_cast(&m)->f = 16;
+
+  int L1::* pl1 = &B::f;
+  int M::* pm_via_l1 = pl1;
+
+  int R1::* pr1 = &B::f;
+  int M::* pm_via_r1 = pr1;
+
+  clang_analyzer_eval(m.*(pm_via_l1) == 7); // expected-warning {{TRUE}}
+  clang_analyzer_eval(m.*(pm_via_r1) == 16); // expected-warning {{TRUE}}
+}
+
+void double_diamond() {
+  D2 d2;
+
+  static_cast(static_cast(&d2))->f = 1;
+  static_cast(static_cast(&d2))->f = 2;
+  static_cast(static_cast(&d2))->f = 3;
+  static_cast(static_cast(&d2))->f = 4;
+
+  clang_analyzer_eval(d2.*(static_cast(static_cast(sta

[PATCH] D28033: [analyzer] Treat pointers to static member functions as function pointers

2017-01-10 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov accepted this revision.
kromanenkov added a comment.
This revision is now accepted and ready to land.

Looks good to me, apart from a very small cavil introduced in not even your 
code. Thanks for not leaving pointers to static member functions out of account!




Comment at: test/Analysis/pointer-to-member.cpp:80
 virtual int foo() { return 1; }
 int bar() { return 2;  }
+int static staticMemberFunction(int p) { return p + 1; };

This line is not affected by your patch but would you please delete the extra 
space before the second brace?


https://reviews.llvm.org/D28033



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D31887: [clangd] Add documentation page

2017-04-11 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added inline comments.



Comment at: docs/clangd.rst:10
+
+:program:`clangd` is an implementation of the `Languge Server Protocol 
`_ leveraging Clang.
+Clangd's goal is to provide language "smartness" features like code 
completion, find references, etc. for clients such as C/C++ Editors.

s/Languge/Language



Comment at: docs/clangd.rst:16
+
+Clangd is not meant to be used by C/C++ developpers directly but rather from a 
client implementing the protocol.
+A client would be typically implemented in an IDE or an editor.

s/developpers/developers



Comment at: docs/clangd.rst:34
+Many features could be implemented in Clangd.
+Here is a list of features that could be useful with the satus of whether or
+not they are already implemented in Clangd and specified in the Language 
Server Protocol.

s/satus/status



Comment at: docs/clangd.rst:93
+`LLVM Developer Policy `_ and `Code 
Reviews `_ page.
+Contributions of new features to the `Languge Server Protocol 
`_ itself would also be 
very useful,
+so that Clangd can eventually implement them in a conforming way.

s/Languge/Language


Repository:
  rL LLVM

https://reviews.llvm.org/D31887



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-11-28 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added a comment.

ping


https://reviews.llvm.org/D25475



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-11-29 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov updated this revision to Diff 79560.
kromanenkov added a comment.

Thanks for your comments, Artem! Make function name less ambiguous. Also I take 
liberty to update analogical function name.


https://reviews.llvm.org/D25475

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  lib/StaticAnalyzer/Core/SValBuilder.cpp
  lib/StaticAnalyzer/Core/SVals.cpp
  lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
  lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  test/Analysis/pointer-to-member.cpp

Index: test/Analysis/pointer-to-member.cpp
===
--- test/Analysis/pointer-to-member.cpp
+++ test/Analysis/pointer-to-member.cpp
@@ -35,8 +35,7 @@
   clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
   clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}}
 }
 
 namespace PR15742 {
@@ -62,21 +61,114 @@
   }
 }
 
-// ---
-// FALSE NEGATIVES
-// ---
-
 bool testDereferencing() {
   A obj;
   obj.m_ptr = 0;
 
   A::MemberPointer member = &A::m_ptr;
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}}
 
   member = 0;
 
-  // FIXME: Should emit a null dereference.
-  return obj.*member; // no-warning
+  return obj.*member; // expected-warning{{}}
+}
+
+namespace testPointerToMemberFunction {
+  struct A {
+virtual int foo() { return 1; }
+int bar() { return 2;  }
+  };
+
+  struct B : public A {
+virtual int foo() { return 3; }
+  };
+
+  typedef int (A::*AFnPointer)();
+  typedef int (B::*BFnPointer)();
+
+  void testPointerToMemberCasts() {
+AFnPointer AFP = &A::bar;
+BFnPointer StaticCastedBase2Derived = static_cast(&A::bar),
+   CCastedBase2Derived = (BFnPointer) (&A::bar);
+A a;
+B b;
+
+clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}}
+  }
+
+  void testPointerToMemberVirtualCall() {
+A a;
+B b;
+A *APtr = &a;
+AFnPointer AFP = &A::foo;
+
+clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}}
+
+APtr = &b;
+
+clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberFunction namespace
+
+namespace testPointerToMemberData {
+  struct A {
+int i;
+  };
+
+  void testPointerToMemberData() {
+int A::*AMdPointer = &A::i;
+A a;
+
+a.i = 42;
+a.*AMdPointer += 1;
+
+clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberData namespace
+
+namespace testPointerToMemberMiscCasts {
+struct B {
+  int f;
+};
+
+struct D : public B {
+  int g;
+};
+
+void foo() {
+  D d;
+  d.f = 7;
+
+  int B::* pfb = &B::f;
+  int D::* pfd = pfb;
+  int v = d.*pfd;
+
+  clang_analyzer_eval(v == 7); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMemberMiscCasts namespace
+
+namespace testPointerToMemberMiscCasts2 {
+struct B {
+  int f;
+};
+struct L : public B { };
+struct R : public B { };
+struct D : public L, R { };
+
+void foo() {
+  D d;
+
+  int B::* pb = &B::f;
+  int L::* pl = pb;
+  int R::* pr = pb;
+
+  int D::* pdl = pl;
+  int D::* pdr = pr;
+
+  clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}}
+  clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}}
 }
+} // end of testPointerToMemberMiscCasts2 namespace
Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===
--- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -69,6 +69,9 @@
 
   bool isLocType = Loc::isLocType(castTy);
 
+  if (val.getAs())
+return val;
+
   if (Optional LI = val.getAs()) {
 if (isLocType)
   return LI->getLoc();
@@ -335,6 +338,21 @@
 switch (lhs.getSubKind()) {
 default:
   return makeSymExprValNN(state, op, lhs, rhs, resultTy);
+case nonloc::PointerToMemberKind: {
+  assert(rhs.getSubKind() == nonloc::PointerToMemberKind &&
+ "Both SVals should have pointer-to-member-type");
+  auto LPTM = lhs.castAs(),
+   RPTM = rhs.castAs();
+  auto LPTMD = LPTM.getPTMData(), RPTMD = RPTM.getPTMData();
+  switch (op) {
+case BO_EQ:
+  r

[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-11-29 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov marked an inline comment as done.
kromanenkov added inline comments.



Comment at: 
include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h:217
+
+  llvm::ImmutableList consCXXBase(
+  const CXXBaseSpecifier *CBS,

NoQ wrote:
> Hmm, is it "construct"? Or "constrain"? I think a verbose name wouldn't hurt.
> In fact, i suspect that `consVals` are rather `conSVals`, where `con` stands 
> for "concatenate".
In fact I thought that this entails "consume" :)



Comment at: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp:882
+return UndefinedVal();
+  if (const FieldDecl *FD = PTMSV->getDeclAs())
+return state->getLValue(FD, lhs);

NoQ wrote:
> Hmm, do we need to cover `CXXMethodDecl` here? Or is it modeled as a function 
> pointer anyway, so no action is needed? Worth commenting, i think.
AFAIU CXXMethodDecl is processed in SVal::getAsFunctionDecl() so i'm for no 
action.


https://reviews.llvm.org/D25475



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-12-13 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added inline comments.



Comment at: lib/StaticAnalyzer/Core/ExprEngineC.cpp:899
+case UO_AddrOf: {
+  // Process pointer-to-member address operation
+  const Expr *Ex = U->getSubExpr()->IgnoreParens();

dcoughlin wrote:
> Just sticking this in the middle of a fallthrough cascade seems quite 
> brittle. For example, it relies on the sub expression of a unary deref never 
> being a DeclRefExpr to a field. This may be guaranteed by Sema (?) but if so 
> it is quite a non-obvious invariant to rely upon.
> 
> I think it would be better the restructure this so that the AddrOf case 
> doesn't fall in the the middle of a fallthrough cascade. You could either 
> factor out the default behavior into a function or use a goto.
It seems that UO_Extension case is the default behavior for this case cascade 
(just below UO_AddrOf). AFAIU it would be better to explicitly call the default 
behavior function following by break for each case preceding UO_Extension 
(UO_Plus,UO_Deref and UO_AddrOf). Or i missed something?


https://reviews.llvm.org/D25475



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-12-13 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov added inline comments.



Comment at: lib/StaticAnalyzer/Core/ExprEngineC.cpp:899
+case UO_AddrOf: {
+  // Process pointer-to-member address operation
+  const Expr *Ex = U->getSubExpr()->IgnoreParens();

kromanenkov wrote:
> dcoughlin wrote:
> > Just sticking this in the middle of a fallthrough cascade seems quite 
> > brittle. For example, it relies on the sub expression of a unary deref 
> > never being a DeclRefExpr to a field. This may be guaranteed by Sema (?) 
> > but if so it is quite a non-obvious invariant to rely upon.
> > 
> > I think it would be better the restructure this so that the AddrOf case 
> > doesn't fall in the the middle of a fallthrough cascade. You could either 
> > factor out the default behavior into a function or use a goto.
> It seems that UO_Extension case is the default behavior for this case cascade 
> (just below UO_AddrOf). AFAIU it would be better to explicitly call the 
> default behavior function following by break for each case preceding 
> UO_Extension (UO_Plus,UO_Deref and UO_AddrOf). Or i missed something?
Or maybe just move UO_AddrOf to the beginning of the case cascade and proceed 
with the default behavior if it falls (no need to change UO_Plus and UO_Deref 
in that case)?


https://reviews.llvm.org/D25475



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D25475: [analyzer] Add a new SVal to support pointer-to-member operations.

2016-12-14 Thread Kirill Romanenkov via Phabricator via cfe-commits
kromanenkov updated this revision to Diff 81352.
kromanenkov added a comment.

Thanks for your comments, Devin! You were right about the list of path 
specifiers construction order, so i fix it. Now the base specifier list is 
being used for figuring out the correct subobject field. Also this diff changes 
fallthrough behavior in some cases and renames functions with 'cons' prefix.


https://reviews.llvm.org/D25475

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
  include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  lib/StaticAnalyzer/Core/SValBuilder.cpp
  lib/StaticAnalyzer/Core/SVals.cpp
  lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
  lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  test/Analysis/pointer-to-member.cpp

Index: test/Analysis/pointer-to-member.cpp
===
--- test/Analysis/pointer-to-member.cpp
+++ test/Analysis/pointer-to-member.cpp
@@ -35,8 +35,7 @@
   clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
   clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}}
 }
 
 namespace PR15742 {
@@ -62,21 +61,156 @@
   }
 }
 
-// ---
-// FALSE NEGATIVES
-// ---
-
 bool testDereferencing() {
   A obj;
   obj.m_ptr = 0;
 
   A::MemberPointer member = &A::m_ptr;
 
-  // FIXME: Should be TRUE.
-  clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}}
 
   member = 0;
 
-  // FIXME: Should emit a null dereference.
-  return obj.*member; // no-warning
+  return obj.*member; // expected-warning{{}}
+}
+
+namespace testPointerToMemberFunction {
+  struct A {
+virtual int foo() { return 1; }
+int bar() { return 2;  }
+  };
+
+  struct B : public A {
+virtual int foo() { return 3; }
+  };
+
+  typedef int (A::*AFnPointer)();
+  typedef int (B::*BFnPointer)();
+
+  void testPointerToMemberCasts() {
+AFnPointer AFP = &A::bar;
+BFnPointer StaticCastedBase2Derived = static_cast(&A::bar),
+   CCastedBase2Derived = (BFnPointer) (&A::bar);
+A a;
+B b;
+
+clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}}
+clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}}
+  }
+
+  void testPointerToMemberVirtualCall() {
+A a;
+B b;
+A *APtr = &a;
+AFnPointer AFP = &A::foo;
+
+clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}}
+
+APtr = &b;
+
+clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberFunction namespace
+
+namespace testPointerToMemberData {
+  struct A {
+int i;
+  };
+
+  void testPointerToMemberData() {
+int A::*AMdPointer = &A::i;
+A a;
+
+a.i = 42;
+a.*AMdPointer += 1;
+
+clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+  }
+} // end of testPointerToMemberData namespace
+
+namespace testPointerToMemberMiscCasts {
+struct B {
+  int f;
+};
+
+struct D : public B {
+  int g;
+};
+
+void foo() {
+  D d;
+  d.f = 7;
+
+  int B::* pfb = &B::f;
+  int D::* pfd = pfb;
+  int v = d.*pfd;
+
+  clang_analyzer_eval(v == 7); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMemberMiscCasts namespace
+
+namespace testPointerToMemberMiscCasts2 {
+struct B {
+  int f;
+};
+struct L : public B { };
+struct R : public B { };
+struct D : public L, R { };
+
+void foo() {
+  D d;
+
+  int B::* pb = &B::f;
+  int L::* pl = pb;
+  int R::* pr = pb;
+
+  int D::* pdl = pl;
+  int D::* pdr = pr;
+
+  clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}}
+  clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMemberMiscCasts2 namespace
+
+namespace testPointerToMemberDiamond {
+struct B {
+  int f;
+};
+struct L1 : public B { };
+struct R1 : public B { };
+struct M : public L1, R1 { };
+struct L2 : public M { };
+struct R2 : public M { };
+struct D2 : public L2, R2 { };
+
+void diamond() {
+  M m;
+
+  static_cast(&m)->f = 7;
+  static_cast(&m)->f = 16;
+
+  int L1::* pl1 = &B::f;
+  int M::* pm_via_l1 = pl1;
+
+  int R1::* pr1 = &B::f;
+  int M::* pm_via_r1 = pr1;
+
+  clang_analyzer_eval(m.*(pm_via_l1) == 7); // expected-warning {{TRUE}}
+  clang_analyzer_eval(m.*(pm_via_r1) == 16); // expected-warning {{TRUE}}
+}
+
+void double_diamond() {
+  D2 d2;
+
+  static_cast(static_