[flang-commits] [flang] [clang-tidy]add new check `bugprone-compare-pointer-to-member-virtual-function` (PR #66055)

Congcong Cai via flang-commits flang-commits at lists.llvm.org
Wed Sep 13 23:33:50 PDT 2023


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/66055:

>From ed5150a69925dc3b6557796026a2820ac5c2e2f5 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 12 Sep 2023 14:41:57 +0800
Subject: [PATCH 01/12] add

---
 .../bugprone/BugproneTidyModule.cpp           |  3 +
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 ...arePointerToMemberVirtualFunctionCheck.cpp | 90 +++++++++++++++++++
 ...mparePointerToMemberVirtualFunctionCheck.h | 30 +++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  6 ++
 ...are-pointer-to-member-virtual-function.rst | 44 +++++++++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 ...are-pointer-to-member-virtual-function.cpp | 73 +++++++++++++++
 8 files changed, 248 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index a67a91eedd10482..543c522899d7a52 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -16,6 +16,7 @@
 #include "BadSignalToKillThreadCheck.h"
 #include "BoolPointerImplicitConversionCheck.h"
 #include "BranchCloneCheck.h"
+#include "ComparePointerToMemberVirtualFunctionCheck.h"
 #include "CopyConstructorInitCheck.h"
 #include "DanglingHandleCheck.h"
 #include "DynamicStaticInitializersCheck.h"
@@ -103,6 +104,8 @@ class BugproneModule : public ClangTidyModule {
     CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
         "bugprone-bool-pointer-implicit-conversion");
     CheckFactories.registerCheck<BranchCloneCheck>("bugprone-branch-clone");
+    CheckFactories.registerCheck<ComparePointerToMemberVirtualFunctionCheck>(
+        "bugprone-compare-pointer-to-member-virtual-function");
     CheckFactories.registerCheck<CopyConstructorInitCheck>(
         "bugprone-copy-constructor-init");
     CheckFactories.registerCheck<DanglingHandleCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 3c768021feb1502..0df9e439b715e5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangTidyBugproneModule
   BoolPointerImplicitConversionCheck.cpp
   BranchCloneCheck.cpp
   BugproneTidyModule.cpp
+  ComparePointerToMemberVirtualFunctionCheck.cpp
   CopyConstructorInitCheck.cpp
   DanglingHandleCheck.cpp
   DynamicStaticInitializersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
new file mode 100644
index 000000000000000..fed5825dfdbde23
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -0,0 +1,90 @@
+//===--- ComparePointerToMemberVirtualFunctionCheck.cpp - clang-tidy ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ComparePointerToMemberVirtualFunctionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+// Matches a `UnaryOperator` whose operator is pre-increment:
+AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); }
+
+void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
+    MatchFinder *Finder) {
+
+  auto DirectMemberPointer = unaryOperator(
+      allOf(hasOperatorName("&"),
+            hasUnaryOperand(declRefExpr(to(cxxMethodDecl(isVirtual()))))));
+  auto IndirectMemberPointer = ignoringImpCasts(declRefExpr());
+
+  auto BinaryOperatorMatcher = [](auto &&Matcher) {
+    return binaryOperator(allOf(hasAnyOperatorName("==", "!="),
+                                hasEitherOperand(hasType(memberPointerType(
+                                    pointee(functionType())))),
+                                hasEitherOperand(Matcher)),
+                          unless(hasEitherOperand(
+                              castExpr(hasCastKind(CK_NullToMemberPointer)))));
+  };
+
+  Finder->addMatcher(
+      BinaryOperatorMatcher(DirectMemberPointer).bind("direct_member_pointer"),
+      this);
+
+  Finder->addMatcher(BinaryOperatorMatcher(IndirectMemberPointer)
+                         .bind("indirect_member_pointer"),
+                     this);
+}
+
+static const char *const ErrorMsg =
+    "A pointer to member virtual function shall only be tested for equality "
+    "with null-pointer-constant.";
+
+static const Expr *removeImplicitCast(const Expr *E) {
+  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+    E = ICE->getSubExpr();
+  return E;
+}
+
+void ComparePointerToMemberVirtualFunctionCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  if (const auto *DirectCompare =
+          Result.Nodes.getNodeAs<BinaryOperator>("direct_member_pointer")) {
+    diag(DirectCompare->getOperatorLoc(), ErrorMsg);
+  } else if (const auto *IndirectCompare =
+                 Result.Nodes.getNodeAs<BinaryOperator>(
+                     "indirect_member_pointer")) {
+    const Expr *E = removeImplicitCast(IndirectCompare->getLHS());
+    if (!isa<DeclRefExpr>(E))
+      E = removeImplicitCast(IndirectCompare->getRHS());
+    const auto *MPT = cast<MemberPointerType>(E->getType().getCanonicalType());
+    llvm::SmallVector<SourceLocation, 4U> SameSignatureVirtualMethods{};
+    for (const auto *D : MPT->getClass()->getAsCXXRecordDecl()->decls())
+      if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
+        if (MD->isVirtual() && MD->getType() == MPT->getPointeeType())
+          SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+    if (!SameSignatureVirtualMethods.empty()) {
+      diag(IndirectCompare->getOperatorLoc(), ErrorMsg);
+      for (const auto Loc : SameSignatureVirtualMethods)
+        diag(Loc, "potential member virtual function.", DiagnosticIDs::Note);
+    }
+  }
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
new file mode 100644
index 000000000000000..6e10c4c3f551880
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
@@ -0,0 +1,30 @@
+//===--- ComparePointerToMemberVirtualFunctionCheck.h - clang-tidy *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COMPAREPOINTERTOMEMBERVIRTUALFUNCTIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COMPAREPOINTERTOMEMBERVIRTUALFUNCTIONCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// [expr.eq] If either is a pointer to a virtual member function, the result is unspecified.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.html
+class ComparePointerToMemberVirtualFunctionCheck : public ClangTidyCheck {
+public:
+  ComparePointerToMemberVirtualFunctionCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COMPAREPOINTERTOMEMBERVIRTUALFUNCTIONCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 63c644ca1a52239..4d2cd82ce0ff790 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -120,6 +120,12 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-compare-pointer-to-member-virtual-function
+  <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check.
+
+  Detects equality comparison between pointer to member virtual function and
+  anything other than null-pointer-constant.
+
 - New :doc:`bugprone-inc-dec-in-conditions
   <clang-tidy/checks/bugprone/inc-dec-in-conditions>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
new file mode 100644
index 000000000000000..fc3d1d294537367
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -0,0 +1,44 @@
+.. title:: clang-tidy - bugprone-compare-pointer-to-member-virtual-function
+
+bugprone-compare-pointer-to-member-virtual-function
+===================================================
+
+Detects unspecified behavior about equality comparison between pointer to member virtual 
+function and anything other than null-pointer-constant.
+
+
+.. code-block:: c++
+    struct A {
+      void f1();
+      void f2();
+      virtual void f3();
+      virtual void f4();
+
+      void g1(int);
+    };
+
+    void fn() {
+      bool r1 = (&A::f1 == &A::f2);  // ok
+      bool r2 = (&A::f1 == &A::f3);  // bugprone
+      bool r3 = (&A::f1 != &A::f3);  // bugprone
+      bool r4 = (&A::f3 == nullptr); // ok
+      bool r5 = (&A::f3 == &A::f4);  // bugprone
+
+      void (A::*v1)() = &A::f3;
+      bool r6 = (v1 == &A::f1); // bugprone
+      bool r6 = (v1 == nullptr); // ok
+
+      void (A::*v2)() = &A::f2;
+      bool r7 = (v2 == &A::f1); // false positive
+
+      void (A::*v3)(int) = &A::g1;
+      bool r8 = (v3 == &A::g1); // ok, no virtual function match void(A::*)(int) signature
+    }
+
+
+Limitations
+-----------
+
+The check will not analyze values stored in a variable. For variable, the check will analyze all
+virtual methods in the same ``class`` or ``struct`` and diagnose when assigning a pointer to member
+virtual function to this variable is possible.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 75a86431d264412..1baabceea06ef48 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -82,6 +82,7 @@ Clang-Tidy Checks
    :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
    :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
    :doc:`bugprone-branch-clone <bugprone/branch-clone>`,
+   :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`, "Yes"
    :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
    :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
    :doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
new file mode 100644
index 000000000000000..fd9d1c4d766af41
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
@@ -0,0 +1,73 @@
+// RUN: %check_clang_tidy %s bugprone-compare-pointer-to-member-virtual-function %t
+
+struct A {
+  virtual ~A();
+  void f1();
+  void f2();
+  virtual void f3();
+  virtual void f4();
+
+  void g1(int);
+};
+
+bool Result;
+
+void base() {
+  Result = (&A::f1 == &A::f2);
+
+  Result = (&A::f1 == &A::f3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  Result = (&A::f1 != &A::f3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  Result = (&A::f3 == nullptr);
+
+  Result = (&A::f3 == &A::f4);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  void (A::*V1)() = &A::f3;
+  Result = (V1 == &A::f1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  Result = (&A::f1 == V1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+
+  auto& V2 = V1;
+  Result = (&A::f1 == V2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+
+  void (A::*V3)(int) = &A::g1;
+  Result = (V3 == &A::g1);
+  Result = (&A::g1 == V3);
+}
+
+using B = A;
+void usingRecordName() {
+  Result = (&B::f1 == &B::f3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  void (B::*V1)() = &B::f1;
+  Result = (V1 == &B::f1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+}
+
+
+typedef A C;
+void typedefRecordName() {
+  Result = (&C::f1 == &C::f3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  void (C::*V1)() = &C::f1;
+  Result = (V1 == &C::f1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+}

>From 2ba04c09c51bdb304e103511a683127665c6fb84 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 12 Sep 2023 16:42:32 +0800
Subject: [PATCH 02/12] remove useless comment

---
 .../bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp      | 1 -
 .../bugprone/ComparePointerToMemberVirtualFunctionCheck.h        | 1 -
 2 files changed, 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index fed5825dfdbde23..a42cf01885690a9 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -23,7 +23,6 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
-// Matches a `UnaryOperator` whose operator is pre-increment:
 AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); }
 
 void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
index 6e10c4c3f551880..736c0fda1fd5cc8 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
@@ -14,7 +14,6 @@
 namespace clang::tidy::bugprone {
 
 /// [expr.eq] If either is a pointer to a virtual member function, the result is unspecified.
-///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.html
 class ComparePointerToMemberVirtualFunctionCheck : public ClangTidyCheck {

>From 9507317e5d3329c3a63c7da36aa74669d712059f Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 09:41:10 +0800
Subject: [PATCH 03/12] fix ODR

---
 ...arePointerToMemberVirtualFunctionCheck.cpp | 24 +++++++++++--------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index a42cf01885690a9..36d0f3d41900092 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -23,8 +23,22 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
+namespace {
+
 AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); }
 
+static const char *const ErrorMsg =
+    "A pointer to member virtual function shall only be tested for equality "
+    "with null-pointer-constant.";
+
+static const Expr *removeImplicitCast(const Expr *E) {
+  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+    E = ICE->getSubExpr();
+  return E;
+}
+
+} // namespace
+
 void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
     MatchFinder *Finder) {
 
@@ -51,16 +65,6 @@ void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
                      this);
 }
 
-static const char *const ErrorMsg =
-    "A pointer to member virtual function shall only be tested for equality "
-    "with null-pointer-constant.";
-
-static const Expr *removeImplicitCast(const Expr *E) {
-  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
-    E = ICE->getSubExpr();
-  return E;
-}
-
 void ComparePointerToMemberVirtualFunctionCheck::check(
     const MatchFinder::MatchResult &Result) {
   if (const auto *DirectCompare =

>From c1f5c71d6af1f1b42c73fd83e7598f543172011c Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 09:52:00 +0800
Subject: [PATCH 04/12] rewriter matcher

---
 ...arePointerToMemberVirtualFunctionCheck.cpp | 75 ++++++++-----------
 1 file changed, 33 insertions(+), 42 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index 36d0f3d41900092..e73bd6711e7868b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -31,62 +31,53 @@ static const char *const ErrorMsg =
     "A pointer to member virtual function shall only be tested for equality "
     "with null-pointer-constant.";
 
-static const Expr *removeImplicitCast(const Expr *E) {
-  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
-    E = ICE->getSubExpr();
-  return E;
-}
-
 } // namespace
 
 void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
     MatchFinder *Finder) {
 
-  auto DirectMemberPointer = unaryOperator(
+  auto DirectMemberVirtualFunctionPointer = unaryOperator(
       allOf(hasOperatorName("&"),
             hasUnaryOperand(declRefExpr(to(cxxMethodDecl(isVirtual()))))));
-  auto IndirectMemberPointer = ignoringImpCasts(declRefExpr());
-
-  auto BinaryOperatorMatcher = [](auto &&Matcher) {
-    return binaryOperator(allOf(hasAnyOperatorName("==", "!="),
-                                hasEitherOperand(hasType(memberPointerType(
-                                    pointee(functionType())))),
-                                hasEitherOperand(Matcher)),
-                          unless(hasEitherOperand(
-                              castExpr(hasCastKind(CK_NullToMemberPointer)))));
-  };
+  auto IndirectMemberPointer =
+      ignoringImpCasts(declRefExpr().bind("indirect_member_pointer"));
 
   Finder->addMatcher(
-      BinaryOperatorMatcher(DirectMemberPointer).bind("direct_member_pointer"),
+      binaryOperator(
+          allOf(hasAnyOperatorName("==", "!="),
+                hasEitherOperand(
+                    hasType(memberPointerType(pointee(functionType())))),
+                anyOf(hasEitherOperand(DirectMemberVirtualFunctionPointer),
+                      hasEitherOperand(IndirectMemberPointer)),
+                unless(hasEitherOperand(
+                    castExpr(hasCastKind(CK_NullToMemberPointer))))))
+          .bind("binary_operator"),
       this);
-
-  Finder->addMatcher(BinaryOperatorMatcher(IndirectMemberPointer)
-                         .bind("indirect_member_pointer"),
-                     this);
 }
 
 void ComparePointerToMemberVirtualFunctionCheck::check(
     const MatchFinder::MatchResult &Result) {
-  if (const auto *DirectCompare =
-          Result.Nodes.getNodeAs<BinaryOperator>("direct_member_pointer")) {
-    diag(DirectCompare->getOperatorLoc(), ErrorMsg);
-  } else if (const auto *IndirectCompare =
-                 Result.Nodes.getNodeAs<BinaryOperator>(
-                     "indirect_member_pointer")) {
-    const Expr *E = removeImplicitCast(IndirectCompare->getLHS());
-    if (!isa<DeclRefExpr>(E))
-      E = removeImplicitCast(IndirectCompare->getRHS());
-    const auto *MPT = cast<MemberPointerType>(E->getType().getCanonicalType());
-    llvm::SmallVector<SourceLocation, 4U> SameSignatureVirtualMethods{};
-    for (const auto *D : MPT->getClass()->getAsCXXRecordDecl()->decls())
-      if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
-        if (MD->isVirtual() && MD->getType() == MPT->getPointeeType())
-          SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
-    if (!SameSignatureVirtualMethods.empty()) {
-      diag(IndirectCompare->getOperatorLoc(), ErrorMsg);
-      for (const auto Loc : SameSignatureVirtualMethods)
-        diag(Loc, "potential member virtual function.", DiagnosticIDs::Note);
-    }
+  const BinaryOperator *BO =
+      Result.Nodes.getNodeAs<BinaryOperator>("binary_operator");
+  const DeclRefExpr *DRE =
+      Result.Nodes.getNodeAs<DeclRefExpr>("indirect_member_pointer");
+
+  if (DRE == nullptr) {
+    // compare with pointer to member virtual function.
+    diag(BO->getOperatorLoc(), ErrorMsg);
+    return;
+  }
+  // compare with variable which type is pointer to member function.
+  const auto *MPT = cast<MemberPointerType>(DRE->getType().getCanonicalType());
+  llvm::SmallVector<SourceLocation, 12U> SameSignatureVirtualMethods{};
+  for (const auto *D : MPT->getClass()->getAsCXXRecordDecl()->decls())
+    if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
+      if (MD->isVirtual() && MD->getType() == MPT->getPointeeType())
+        SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+  if (!SameSignatureVirtualMethods.empty()) {
+    diag(BO->getOperatorLoc(), ErrorMsg);
+    for (const auto Loc : SameSignatureVirtualMethods)
+      diag(Loc, "potential member virtual function.", DiagnosticIDs::Note);
   }
 }
 

>From d21281322c811bd4afda25503e98a7750619dca3 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 10:05:19 +0800
Subject: [PATCH 05/12] check nullptr

---
 ...mparePointerToMemberVirtualFunctionCheck.cpp | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index e73bd6711e7868b..49f238d203c9651 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -68,12 +68,19 @@ void ComparePointerToMemberVirtualFunctionCheck::check(
     return;
   }
   // compare with variable which type is pointer to member function.
-  const auto *MPT = cast<MemberPointerType>(DRE->getType().getCanonicalType());
   llvm::SmallVector<SourceLocation, 12U> SameSignatureVirtualMethods{};
-  for (const auto *D : MPT->getClass()->getAsCXXRecordDecl()->decls())
-    if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
-      if (MD->isVirtual() && MD->getType() == MPT->getPointeeType())
-        SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+  const auto *MPT = cast<MemberPointerType>(DRE->getType().getCanonicalType());
+  const Type *T = MPT->getClass();
+  if (T == nullptr)
+    return;
+  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+  if (RD == nullptr)
+    return;
+  for (const auto *D : RD->decls()) {
+    const auto *MD = dyn_cast<CXXMethodDecl>(D);
+    if (MD && MD->isVirtual() && MD->getType() == MPT->getPointeeType())
+      SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+  }
   if (!SameSignatureVirtualMethods.empty()) {
     diag(BO->getOperatorLoc(), ErrorMsg);
     for (const auto Loc : SameSignatureVirtualMethods)

>From 366645f9d5b1f1bece713047698251f61d4fabb2 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 10:18:52 +0800
Subject: [PATCH 06/12] fix docs

---
 .../bugprone/ComparePointerToMemberVirtualFunctionCheck.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
index 736c0fda1fd5cc8..f04b0e9a86d93a5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
@@ -13,13 +13,19 @@
 
 namespace clang::tidy::bugprone {
 
-/// [expr.eq] If either is a pointer to a virtual member function, the result is unspecified.
+/// Detects unspecified behavior about equality comparison between pointer to
+/// member virtual function and anything other than null-pointer-constant.
+///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.html
 class ComparePointerToMemberVirtualFunctionCheck : public ClangTidyCheck {
 public:
   ComparePointerToMemberVirtualFunctionCheck(StringRef Name, ClangTidyContext *Context)
       : ClangTidyCheck(Name, Context) {}
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 };

>From 91c118c1b09a6484d3c5651f45f28ef8c5c167c4 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 11:14:49 +0800
Subject: [PATCH 07/12] consider inherit case

---
 ...arePointerToMemberVirtualFunctionCheck.cpp | 22 +++++++++++++++----
 ...are-pointer-to-member-virtual-function.cpp | 17 ++++++++++++++
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index 49f238d203c9651..2b908705f198a7a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -76,11 +76,25 @@ void ComparePointerToMemberVirtualFunctionCheck::check(
   const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
   if (RD == nullptr)
     return;
-  for (const auto *D : RD->decls()) {
-    const auto *MD = dyn_cast<CXXMethodDecl>(D);
-    if (MD && MD->isVirtual() && MD->getType() == MPT->getPointeeType())
-      SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+
+  const bool StopVisit = false;
+
+  auto VisitSameSignatureVirtualMethods =
+      [&](const CXXRecordDecl *CurrentRecordDecl) -> bool {
+    bool Ret = !StopVisit;
+    for (const auto *MD : CurrentRecordDecl->methods()) {
+      if (MD->isVirtual() && MD->getType() == MPT->getPointeeType()) {
+        SameSignatureVirtualMethods.push_back(MD->getBeginLoc());
+        Ret = StopVisit;
+      }
+    }
+    return Ret;
+  };
+
+  if (StopVisit != VisitSameSignatureVirtualMethods(RD)) {
+    RD->forallBases(VisitSameSignatureVirtualMethods);
   }
+
   if (!SameSignatureVirtualMethods.empty()) {
     diag(BO->getOperatorLoc(), ErrorMsg);
     for (const auto Loc : SameSignatureVirtualMethods)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
index fd9d1c4d766af41..6969b39a0e21383 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
@@ -71,3 +71,20 @@ void typedefRecordName() {
   // CHECK-MESSAGES: :7:3: note: potential member virtual function.
   // CHECK-MESSAGES: :8:3: note: potential member virtual function.
 }
+
+
+struct A1 : public A {
+};
+
+void inheritClass() {
+  Result = (&A1::f1 == &A1::f3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+
+  void (A1::*V1)() = &A1::f1;
+  Result = (V1 == &A1::f1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+}
+
+

>From 43133305daae46d83d96514c178fd6a0c797651e Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 20:40:27 +0800
Subject: [PATCH 08/12] improve document

---
 ...arePointerToMemberVirtualFunctionCheck.cpp | 12 +++--
 ...mparePointerToMemberVirtualFunctionCheck.h |  6 ++-
 ...are-pointer-to-member-virtual-function.rst | 36 +++++++++++---
 ...are-pointer-to-member-virtual-function.cpp | 48 +++++++++----------
 4 files changed, 64 insertions(+), 38 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index 2b908705f198a7a..62deeb06ea7d5a4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -28,9 +28,10 @@ namespace {
 AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); }
 
 static const char *const ErrorMsg =
-    "A pointer to member virtual function shall only be tested for equality "
-    "with null-pointer-constant.";
-
+    "comparing a pointer to member virtual function with other pointer is "
+    "unspecified behavior, only compare it with a null-pointer constant for "
+    "equality.";
+    
 } // namespace
 
 void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
@@ -77,7 +78,7 @@ void ComparePointerToMemberVirtualFunctionCheck::check(
   if (RD == nullptr)
     return;
 
-  const bool StopVisit = false;
+  constexpr bool StopVisit = false;
 
   auto VisitSameSignatureVirtualMethods =
       [&](const CXXRecordDecl *CurrentRecordDecl) -> bool {
@@ -98,7 +99,8 @@ void ComparePointerToMemberVirtualFunctionCheck::check(
   if (!SameSignatureVirtualMethods.empty()) {
     diag(BO->getOperatorLoc(), ErrorMsg);
     for (const auto Loc : SameSignatureVirtualMethods)
-      diag(Loc, "potential member virtual function.", DiagnosticIDs::Note);
+      diag(Loc, "potential member virtual function is declared here.",
+           DiagnosticIDs::Note);
   }
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
index f04b0e9a86d93a5..90c0c5330b5f3ed 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
@@ -1,4 +1,5 @@
-//===--- ComparePointerToMemberVirtualFunctionCheck.h - clang-tidy *- C++ -*-===//
+//===--- ComparePointerToMemberVirtualFunctionCheck.h - clang-tidy *- C++
+//-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -20,7 +21,8 @@ namespace clang::tidy::bugprone {
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.html
 class ComparePointerToMemberVirtualFunctionCheck : public ClangTidyCheck {
 public:
-  ComparePointerToMemberVirtualFunctionCheck(StringRef Name, ClangTidyContext *Context)
+  ComparePointerToMemberVirtualFunctionCheck(StringRef Name,
+                                             ClangTidyContext *Context)
       : ClangTidyCheck(Name, Context) {}
 
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
index fc3d1d294537367..a10bee389a35e82 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -3,8 +3,8 @@
 bugprone-compare-pointer-to-member-virtual-function
 ===================================================
 
-Detects unspecified behavior about equality comparison between pointer to member virtual 
-function and anything other than null-pointer-constant.
+Detects unspecified behavior about equality comparison between pointer to member
+virtual function and anything other than null-pointer-constant.
 
 
 .. code-block:: c++
@@ -29,16 +29,38 @@ function and anything other than null-pointer-constant.
       bool r6 = (v1 == nullptr); // ok
 
       void (A::*v2)() = &A::f2;
-      bool r7 = (v2 == &A::f1); // false positive
+      bool r7 = (v2 == &A::f1); // false positive, but potential risk if assigning other value to v2.
 
       void (A::*v3)(int) = &A::g1;
-      bool r8 = (v3 == &A::g1); // ok, no virtual function match void(A::*)(int) signature
+      bool r8 = (v3 == &A::g1); // ok, no virtual function match void(A::*)(int) signature.
     }
 
 
+This check warns on equality comparisons involve pointers to member virtual
+function or variables which is potential pointer to member virtual function and
+any entity other than a null-pointer constant.
+
+In certain compilers, virtual function addresses are not conventional pointers
+but instead consist of offsets and indexes within a virtual function table
+(vtable). Consequently, these pointers may vary between base and derived
+classes, leading to unpredictable behavior when compared directly. This issue
+becomes particularly challenging when dealing with pointers to pure virtual
+functions, as they may not even have a valid address, further complicating
+comparisons.
+
+Instead, it is recommended to utilize the ``typeid`` operator or other appropriate
+mechanisms for comparing objects to ensure robust and predictable behavior in
+your codebase. By heeding this detection and adopting a more reliable comparison
+method, you can mitigate potential issues related to unspecified behavior,
+especially when dealing with pointers to member virtual functions or pure
+virtual functions, thereby improving the overall stability and maintainability
+of your code. In scenarios involving pointers to member virtual functions, it's
+only advisable to employ nullptr for comparisons.
+
+
 Limitations
 -----------
 
-The check will not analyze values stored in a variable. For variable, the check will analyze all
-virtual methods in the same ``class`` or ``struct`` and diagnose when assigning a pointer to member
-virtual function to this variable is possible.
+The check will not analyze values stored in a variable. For variable, the check
+will analyze all virtual methods in the same ``class`` or ``struct`` and diagnose
+when assigning a pointer to member virtual function to this variable is possible.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
index 6969b39a0e21383..71bcdd862c9d26a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
@@ -16,31 +16,31 @@ void base() {
   Result = (&A::f1 == &A::f2);
 
   Result = (&A::f1 == &A::f3);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   Result = (&A::f1 != &A::f3);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   Result = (&A::f3 == nullptr);
 
   Result = (&A::f3 == &A::f4);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   void (A::*V1)() = &A::f3;
   Result = (V1 == &A::f1);
-  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
   Result = (&A::f1 == V1);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 
   auto& V2 = V1;
   Result = (&A::f1 == V2);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 
   void (A::*V3)(int) = &A::g1;
   Result = (V3 == &A::g1);
@@ -50,26 +50,26 @@ void base() {
 using B = A;
 void usingRecordName() {
   Result = (&B::f1 == &B::f3);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   void (B::*V1)() = &B::f1;
   Result = (V1 == &B::f1);
-  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
 
 
 typedef A C;
 void typedefRecordName() {
   Result = (&C::f1 == &C::f3);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   void (C::*V1)() = &C::f1;
   Result = (V1 == &C::f1);
-  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
 
 
@@ -78,13 +78,13 @@ struct A1 : public A {
 
 void inheritClass() {
   Result = (&A1::f1 == &A1::f3);
-  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
 
   void (A1::*V1)() = &A1::f1;
   Result = (V1 == &A1::f1);
-  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: A pointer to member virtual function shall only be tested for equality with null-pointer-constant.
-  // CHECK-MESSAGES: :7:3: note: potential member virtual function.
-  // CHECK-MESSAGES: :8:3: note: potential member virtual function.
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: comparing a pointer to member virtual function with other pointer is unspecified behavior, only compare it with a null-pointer constant for equality.
+  // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
+  // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
 
 

>From 23128316fb71d9d2ad05e17993df0a4cb25f1adb Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 21:38:49 +0800
Subject: [PATCH 09/12] quotes

---
 .../bugprone/compare-pointer-to-member-virtual-function.rst     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
index a10bee389a35e82..e94ecf637e4d95c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -55,7 +55,7 @@ method, you can mitigate potential issues related to unspecified behavior,
 especially when dealing with pointers to member virtual functions or pure
 virtual functions, thereby improving the overall stability and maintainability
 of your code. In scenarios involving pointers to member virtual functions, it's
-only advisable to employ nullptr for comparisons.
+only advisable to employ ``nullptr`` for comparisons.
 
 
 Limitations

>From 15b9ed44b447f7b48359a9ba55c63154103f6cca Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 21:41:08 +0800
Subject: [PATCH 10/12] remove this check

---
 .../compare-pointer-to-member-virtual-function.rst        | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
index e94ecf637e4d95c..f79bf1aa5f4fee0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -36,7 +36,7 @@ virtual function and anything other than null-pointer-constant.
     }
 
 
-This check warns on equality comparisons involve pointers to member virtual
+Provide warnings on equality comparisons involve pointers to member virtual
 function or variables which is potential pointer to member virtual function and
 any entity other than a null-pointer constant.
 
@@ -61,6 +61,6 @@ only advisable to employ ``nullptr`` for comparisons.
 Limitations
 -----------
 
-The check will not analyze values stored in a variable. For variable, the check
-will analyze all virtual methods in the same ``class`` or ``struct`` and diagnose
-when assigning a pointer to member virtual function to this variable is possible.
+Not analyze values stored in a variable. For variable, only analyze all virtual
+methods in the same ``class`` or ``struct`` and diagnose when assigning a pointer
+to member virtual function to this variable is possible.

>From 94e953a1e14b6978d82efab93d92234b53fa57eb Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 13 Sep 2023 23:57:53 +0800
Subject: [PATCH 11/12] doc

---
 .../bugprone/compare-pointer-to-member-virtual-function.rst     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
index f79bf1aa5f4fee0..08ea7165faf7565 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -61,6 +61,6 @@ only advisable to employ ``nullptr`` for comparisons.
 Limitations
 -----------
 
-Not analyze values stored in a variable. For variable, only analyze all virtual
+Does not analyze values stored in a variable. For variable, only analyze all virtual
 methods in the same ``class`` or ``struct`` and diagnose when assigning a pointer
 to member virtual function to this variable is possible.

>From 0fbdce0dc37ad637978f639a331a05371c5368a9 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Thu, 14 Sep 2023 14:31:39 +0800
Subject: [PATCH 12/12] clean new line and use auto

---
 .../ComparePointerToMemberVirtualFunctionCheck.cpp         | 7 +++----
 .../bugprone/ComparePointerToMemberVirtualFunctionCheck.h  | 3 +--
 .../compare-pointer-to-member-virtual-function.rst         | 3 ---
 .../compare-pointer-to-member-virtual-function.cpp         | 4 ----
 4 files changed, 4 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
index 62deeb06ea7d5a4..9d1d92b989bf1f0 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.cpp
@@ -31,7 +31,7 @@ static const char *const ErrorMsg =
     "comparing a pointer to member virtual function with other pointer is "
     "unspecified behavior, only compare it with a null-pointer constant for "
     "equality.";
-    
+
 } // namespace
 
 void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
@@ -58,9 +58,8 @@ void ComparePointerToMemberVirtualFunctionCheck::registerMatchers(
 
 void ComparePointerToMemberVirtualFunctionCheck::check(
     const MatchFinder::MatchResult &Result) {
-  const BinaryOperator *BO =
-      Result.Nodes.getNodeAs<BinaryOperator>("binary_operator");
-  const DeclRefExpr *DRE =
+  const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>("binary_operator");
+  const auto *DRE =
       Result.Nodes.getNodeAs<DeclRefExpr>("indirect_member_pointer");
 
   if (DRE == nullptr) {
diff --git a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
index 90c0c5330b5f3ed..15561e068a6709d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ComparePointerToMemberVirtualFunctionCheck.h
@@ -1,5 +1,4 @@
-//===--- ComparePointerToMemberVirtualFunctionCheck.h - clang-tidy *- C++
-//-*-===//
+//=--- ComparePointerToMemberVirtualFunctionCheck.h - clang-tidy --*- C++ -*-=//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
index a10bee389a35e82..6c4a8eb948b5b09 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function.rst
@@ -6,7 +6,6 @@ bugprone-compare-pointer-to-member-virtual-function
 Detects unspecified behavior about equality comparison between pointer to member
 virtual function and anything other than null-pointer-constant.
 
-
 .. code-block:: c++
     struct A {
       void f1();
@@ -35,7 +34,6 @@ virtual function and anything other than null-pointer-constant.
       bool r8 = (v3 == &A::g1); // ok, no virtual function match void(A::*)(int) signature.
     }
 
-
 This check warns on equality comparisons involve pointers to member virtual
 function or variables which is potential pointer to member virtual function and
 any entity other than a null-pointer constant.
@@ -57,7 +55,6 @@ virtual functions, thereby improving the overall stability and maintainability
 of your code. In scenarios involving pointers to member virtual functions, it's
 only advisable to employ nullptr for comparisons.
 
-
 Limitations
 -----------
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
index 71bcdd862c9d26a..af737f1db81072d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/compare-pointer-to-member-virtual-function.cpp
@@ -59,7 +59,6 @@ void usingRecordName() {
   // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
 
-
 typedef A C;
 void typedefRecordName() {
   Result = (&C::f1 == &C::f3);
@@ -72,7 +71,6 @@ void typedefRecordName() {
   // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
 
-
 struct A1 : public A {
 };
 
@@ -86,5 +84,3 @@ void inheritClass() {
   // CHECK-MESSAGES: :7:3: note: potential member virtual function is declared here.
   // CHECK-MESSAGES: :8:3: note: potential member virtual function is declared here.
 }
-
-



More information about the flang-commits mailing list