vsavchenko created this revision.
vsavchenko added reviewers: NoQ, xazax.hun, martong, steakhal, Szelethus, 
ASDenysPetrov, manas, RedDocMD.
Herald added subscribers: dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, 
rnkovacs, szepet, baloghadamsoftware.
vsavchenko requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D104647

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/lib/StaticAnalyzer/Core/SVals.cpp
  clang/unittests/StaticAnalyzer/SValTest.cpp

Index: clang/unittests/StaticAnalyzer/SValTest.cpp
===================================================================
--- clang/unittests/StaticAnalyzer/SValTest.cpp
+++ clang/unittests/StaticAnalyzer/SValTest.cpp
@@ -346,6 +346,41 @@
   EXPECT_EQ(Context.VoidPtrTy, *B.getType(Context));
 }
 
+SVAL_TEST(GetMemberPtrType, R"(
+struct A {
+  int a;
+  struct {
+    int b;
+  };
+};
+void foo(int A::*x) {
+  int A::*a = &A::a;
+  int A::*b = &A::b;
+  int A::*c = x;
+}
+)") {
+  SVal A = getByName("a");
+  ASSERT_TRUE(A.getType(Context).hasValue());
+  const auto *AMemberPtrTy = dyn_cast<MemberPointerType>(*A.getType(Context));
+  ASSERT_NE(AMemberPtrTy, nullptr);
+  EXPECT_EQ(Context.IntTy, AMemberPtrTy->getPointeeType());
+  const auto *ARecordType = dyn_cast<RecordType>(AMemberPtrTy->getClass());
+  ASSERT_NE(ARecordType, nullptr);
+  EXPECT_EQ("A", ARecordType->getDecl()->getName());
+
+  SVal B = getByName("b");
+  ASSERT_TRUE(B.getType(Context).hasValue());
+  const auto *BMemberPtrTy = dyn_cast<MemberPointerType>(*B.getType(Context));
+  ASSERT_NE(BMemberPtrTy, nullptr);
+  EXPECT_EQ(Context.IntTy, BMemberPtrTy->getPointeeType());
+  const auto *BRecordType = dyn_cast<RecordType>(BMemberPtrTy->getClass());
+  ASSERT_NE(BRecordType, nullptr);
+  EXPECT_EQ("A", BRecordType->getDecl()->getName());
+
+  SVal C = getByName("c");
+  EXPECT_TRUE(C.isUnknown());
+}
+
 } // namespace
 } // namespace ento
 } // namespace clang
Index: clang/lib/StaticAnalyzer/Core/SVals.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -180,6 +180,14 @@
   Optional<QualType> VisitNonLocSymbolVal(nonloc::SymbolVal SV) {
     return Visit(SV.getSymbol());
   }
+  Optional<QualType> VisitNonLocPointerToMember(nonloc::PointerToMember PTM) {
+    QualType T = PTM.getType();
+
+    if (T.isNull())
+      return None;
+
+    return T;
+  }
   Optional<QualType> VisitSymbolicRegion(const SymbolicRegion *SR) {
     return Visit(SR->getSymbol());
   }
@@ -209,21 +217,21 @@
 }
 
 bool nonloc::PointerToMember::isNullMemberPointer() const {
-  return getPTMData().isNull();
+  return getPTMData() == nullptr;
 }
 
 const NamedDecl *nonloc::PointerToMember::getDecl() const {
-  const auto PTMD = this->getPTMData();
-  if (PTMD.isNull())
+  if (!getPTMData())
     return nullptr;
 
-  const NamedDecl *ND = nullptr;
-  if (PTMD.is<const NamedDecl *>())
-    ND = PTMD.get<const NamedDecl *>();
-  else
-    ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
+  return getPTMData()->getDeclaratorDecl();
+}
+
+QualType nonloc::PointerToMember::getType() const {
+  if (!getPTMData())
+    return {};
 
-  return ND;
+  return getPTMData()->getType();
 }
 
 //===----------------------------------------------------------------------===//
@@ -239,17 +247,11 @@
 }
 
 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
-  const PTMDataType PTMD = getPTMData();
-  if (PTMD.is<const NamedDecl *>())
-    return {};
-  return PTMD.get<const PointerToMemberData *>()->begin();
+  return getPTMData()->begin();
 }
 
 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
-  const PTMDataType PTMD = getPTMData();
-  if (PTMD.is<const NamedDecl *>())
-    return {};
-  return PTMD.get<const PointerToMemberData *>()->end();
+  return getPTMData()->end();
 }
 
 //===----------------------------------------------------------------------===//
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -236,7 +236,7 @@
   return nonloc::SymbolVal(sym);
 }
 
-DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) {
+DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND, QualType T) {
   assert(!ND || isa<CXXMethodDecl>(ND) || isa<FieldDecl>(ND) ||
          isa<IndirectFieldDecl>(ND));
 
@@ -250,7 +250,8 @@
       return getFunctionPointer(MD);
   }
 
-  return nonloc::PointerToMember(ND);
+  return nonloc::PointerToMember(
+      getBasicValueFactory().getPointerToMemberData(ND, T));
 }
 
 DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -516,7 +516,7 @@
         continue;
       }
       case CK_NullToMemberPointer: {
-        SVal V = svalBuilder.getMemberPointer(nullptr);
+        SVal V = svalBuilder.getMemberPointer(nullptr, CastE->getType());
         state = state->BindExpr(CastE, LCtx, V);
         Bldr.generateNode(CastE, Pred, state);
         continue;
@@ -1000,7 +1000,8 @@
             isa<IndirectFieldDecl>(VD)) {
           ProgramStateRef State = (*I)->getState();
           const LocationContext *LCtx = (*I)->getLocationContext();
-          SVal SV = svalBuilder.getMemberPointer(cast<NamedDecl>(VD));
+          SVal SV =
+              svalBuilder.getMemberPointer(cast<NamedDecl>(VD), U->getType());
           Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV));
           break;
         }
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -43,9 +43,10 @@
 }
 
 void PointerToMemberData::Profile(
-    llvm::FoldingSetNodeID &ID, const NamedDecl *D,
+    llvm::FoldingSetNodeID &ID, const NamedDecl *D, QualType T,
     llvm::ImmutableList<const CXXBaseSpecifier *> L) {
   ID.AddPointer(D);
+  ID.AddPointer(T.getAsOpaquePtr());
   ID.AddPointer(L.getInternalPointer());
 }
 
@@ -160,9 +161,10 @@
 }
 
 const PointerToMemberData *BasicValueFactory::getPointerToMemberData(
-    const NamedDecl *ND, llvm::ImmutableList<const CXXBaseSpecifier *> L) {
+    const NamedDecl *ND, QualType T,
+    llvm::ImmutableList<const CXXBaseSpecifier *> L) {
   llvm::FoldingSetNodeID ID;
-  PointerToMemberData::Profile(ID, ND, L);
+  PointerToMemberData::Profile(ID, ND, T, L);
   void *InsertPos;
 
   PointerToMemberData *D =
@@ -170,7 +172,7 @@
 
   if (!D) {
     D = (PointerToMemberData *)BPAlloc.Allocate<PointerToMemberData>();
-    new (D) PointerToMemberData(ND, L);
+    new (D) PointerToMemberData(ND, T, L);
     PointerToMemberDataSet.InsertNode(D, InsertPos);
   }
 
@@ -196,21 +198,9 @@
           kind == CK_BaseToDerivedMemberPointer ||
           kind == CK_ReinterpretMemberPointer) &&
          "accumCXXBase called with wrong CastKind");
-  nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
-  const NamedDecl *ND = nullptr;
-  llvm::ImmutableList<const CXXBaseSpecifier *> BaseSpecList;
-
-  if (PTMDT.isNull() || PTMDT.is<const NamedDecl *>()) {
-    if (PTMDT.is<const NamedDecl *>())
-      ND = PTMDT.get<const NamedDecl *>();
-
-    BaseSpecList = CXXBaseListFactory.getEmptyList();
-  } else {
-    const PointerToMemberData *PTMD = PTMDT.get<const PointerToMemberData *>();
-    ND = PTMD->getDeclaratorDecl();
-
-    BaseSpecList = PTMD->getCXXBaseList();
-  }
+  const PointerToMemberData *PTMD = PTM.getPTMData();
+  llvm::ImmutableList<const CXXBaseSpecifier *> BaseSpecList =
+      PTMD->getCXXBaseList();
 
   assert(hasNoRepeatedElements(BaseSpecList) &&
          "CXXBaseSpecifier list of PointerToMemberData must not have repeated "
@@ -237,13 +227,15 @@
             CXXBaseListFactory.add(BaseSpec, ReducedBaseSpecList);
     }
 
-    return getPointerToMemberData(ND, ReducedBaseSpecList);
+    return getPointerToMemberData(PTMD->getDeclaratorDecl(), PTMD->getType(),
+                                  ReducedBaseSpecList);
   }
   // FIXME: Reinterpret casts on member-pointers are not handled properly by
   // this code
   for (const CXXBaseSpecifier *I : llvm::reverse(PathRange))
     BaseSpecList = prependCXXBase(I, BaseSpecList);
-  return getPointerToMemberData(ND, BaseSpecList);
+  return getPointerToMemberData(PTMD->getDeclaratorDecl(), PTMD->getType(),
+                                BaseSpecList);
 }
 
 const llvm::APSInt*
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -523,17 +523,16 @@
   friend class ento::SValBuilder;
 
 public:
-  using PTMDataType =
-      llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>;
-
-  const PTMDataType getPTMData() const {
-    return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
+  const PointerToMemberData *getPTMData() const {
+    return static_cast<const PointerToMemberData *>(Data);
   }
 
   bool isNullMemberPointer() const;
 
   const NamedDecl *getDecl() const;
 
+  QualType getType() const;
+
   template<typename AdjustedDecl>
   const AdjustedDecl *getDeclAs() const {
     return dyn_cast_or_null<AdjustedDecl>(getDecl());
@@ -548,8 +547,8 @@
   friend class SVal;
 
   PointerToMember() = default;
-  explicit PointerToMember(const PTMDataType D)
-      : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
+  explicit PointerToMember(const PointerToMemberData *D)
+      : NonLoc(PointerToMemberKind, D) {}
 
   static bool isKind(const SVal& V) {
     return V.getBaseKind() == NonLocKind &&
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -247,7 +247,7 @@
                                    const LocationContext *LCtx,
                                    unsigned count);
 
-  DefinedSVal getMemberPointer(const NamedDecl *ND);
+  DefinedSVal getMemberPointer(const NamedDecl *ND, QualType T);
 
   DefinedSVal getFunctionPointer(const FunctionDecl *func);
 
@@ -271,10 +271,6 @@
         BasicVals.getLazyCompoundValData(store, region));
   }
 
-  NonLoc makePointerToMember(const DeclaratorDecl *DD) {
-    return nonloc::PointerToMember(DD);
-  }
-
   NonLoc makePointerToMember(const PointerToMemberData *PTMD) {
     return nonloc::PointerToMember(PTMD);
   }
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -82,12 +82,13 @@
 
 class PointerToMemberData : public llvm::FoldingSetNode {
   const NamedDecl *D;
+  QualType T;
   llvm::ImmutableList<const CXXBaseSpecifier *> L;
 
 public:
-  PointerToMemberData(const NamedDecl *D,
+  PointerToMemberData(const NamedDecl *D, QualType T,
                       llvm::ImmutableList<const CXXBaseSpecifier *> L)
-      : D(D), L(L) {}
+      : D(D), T(T), L(L) {}
 
   using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
 
@@ -95,11 +96,14 @@
   iterator end() const { return L.end(); }
 
   static void Profile(llvm::FoldingSetNodeID &ID, const NamedDecl *D,
+                      QualType T,
                       llvm::ImmutableList<const CXXBaseSpecifier *> L);
 
-  void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, L); }
+  void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, T, L); }
   const NamedDecl *getDeclaratorDecl() const { return D; }
 
+  QualType getType() const { return T; }
+
   llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
     return L;
   }
@@ -241,11 +245,16 @@
   const CompoundValData *getCompoundValData(QualType T,
                                             llvm::ImmutableList<SVal> Vals);
 
-  const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
-                                            const TypedValueRegion *region);
+  const LazyCompoundValData *
+  getLazyCompoundValData(const StoreRef &store, const TypedValueRegion *region);
+
+  const PointerToMemberData *getPointerToMemberData(const NamedDecl *ND,
+                                                    QualType T) {
+    return getPointerToMemberData(ND, T, CXXBaseListFactory.getEmptyList());
+  }
 
   const PointerToMemberData *
-  getPointerToMemberData(const NamedDecl *ND,
+  getPointerToMemberData(const NamedDecl *ND, QualType T,
                          llvm::ImmutableList<const CXXBaseSpecifier *> L);
 
   llvm::ImmutableList<SVal> getEmptySValList() {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to