[clang-tools-extra] [clang-tidy] Portability Template Virtual Member Function Check (PR #110099)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 26 17:56:28 PDT 2024


https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/110099

>From 9cdba3e947705053b14f8eeca39c281fd18e21ce Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 26 Sep 2024 11:43:10 +0200
Subject: [PATCH 1/6] [clang-tidy] Portability Template Virtual Member Function
 Check

---
 .../clang-tidy/portability/CMakeLists.txt     |   1 +
 .../portability/PortabilityTidyModule.cpp     |   3 +
 .../TemplateVirtualMemberFunctionCheck.cpp    |  49 +++++++
 .../TemplateVirtualMemberFunctionCheck.h      |  36 +++++
 clang-tools-extra/docs/ReleaseNotes.rst       |   7 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../template-virtual-member-function.rst      |  33 +++++
 .../template-virtual-member-function.cpp      | 134 ++++++++++++++++++
 8 files changed, 264 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp

diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
index 01a86d686daa76..df08cf2c8e292c 100644
--- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangTidyPortabilityModule
   RestrictSystemIncludesCheck.cpp
   SIMDIntrinsicsCheck.cpp
   StdAllocatorConstCheck.cpp
+  TemplateVirtualMemberFunctionCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
index b3759a754587d7..316b98b46cf3f2 100644
--- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
@@ -12,6 +12,7 @@
 #include "RestrictSystemIncludesCheck.h"
 #include "SIMDIntrinsicsCheck.h"
 #include "StdAllocatorConstCheck.h"
+#include "TemplateVirtualMemberFunctionCheck.h"
 
 namespace clang::tidy {
 namespace portability {
@@ -25,6 +26,8 @@ class PortabilityModule : public ClangTidyModule {
         "portability-simd-intrinsics");
     CheckFactories.registerCheck<StdAllocatorConstCheck>(
         "portability-std-allocator-const");
+    CheckFactories.registerCheck<TemplateVirtualMemberFunctionCheck>(
+        "portability-template-virtual-member-function");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
new file mode 100644
index 00000000000000..6b7b50798798fa
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -0,0 +1,49 @@
+//===--- TemplateVirtualMemberFunctionCheck.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 "TemplateVirtualMemberFunctionCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::portability {
+
+void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(classTemplateSpecializationDecl().bind("specialization"),
+                     this);
+}
+
+void TemplateVirtualMemberFunctionCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *MatchedDecl =
+      Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
+
+  if (MatchedDecl->isExplicitSpecialization())
+    return;
+
+  for (auto &&Method : MatchedDecl->methods()) {
+    if (!Method->isVirtual())
+      continue;
+
+    if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method);
+        Dtor && Dtor->isDefaulted())
+      continue;
+
+    if (!Method->isUsed()) {
+      diag(Method->getLocation(),
+           "unspecified virtual member function instantiation; the virtual "
+           "member function is not instantiated but it might be with a "
+           "different compiler");
+      diag(MatchedDecl->getPointOfInstantiation(), "template instantiated here",
+           DiagnosticIDs::Note);
+    }
+  }
+}
+
+} // namespace clang::tidy::portability
diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
new file mode 100644
index 00000000000000..9d7918dbdba612
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
@@ -0,0 +1,36 @@
+//===--- TemplateVirtualMemberFunctionCheck.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_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::portability {
+
+/// Detects C++ [temp.inst#11]: "It is unspecified whether or not an
+/// implementation implicitly instantiates a virtual member function of a class
+/// template if the virtual member function would not otherwise be
+/// instantiated."
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/portability/template-virtual-member-function.html
+class TemplateVirtualMemberFunctionCheck : public ClangTidyCheck {
+public:
+  TemplateVirtualMemberFunctionCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+};
+
+} // namespace clang::tidy::portability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8f7b0b5333f3a1..81e83c66273ed0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -103,6 +103,13 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`portability-template-virtual-member-function
+  <clang-tidy/checks/portability/template-virtual-member-function>` check.
+
+  Detects C++ [temp.inst#11]: "It is unspecified whether or not an implementation 
+  implicitly instantiates a virtual member function of a class template if the 
+  virtual member function would not otherwise be instantiated."
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 1909d7b8d8e246..b7fc78de79eadd 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -346,6 +346,7 @@ Clang-Tidy Checks
    :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
    :doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
    :doc:`portability-std-allocator-const <portability/std-allocator-const>`,
+   :doc:`portability-template-virtual-member-function <portability/template-virtual-member-function>`,
    :doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
    :doc:`readability-avoid-nested-conditional-operator <readability/avoid-nested-conditional-operator>`,
    :doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
new file mode 100644
index 00000000000000..3e22d967734fa1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
@@ -0,0 +1,33 @@
+.. title:: clang-tidy - portability-template-virtual-member-function
+
+portability-template-virtual-member-function
+============================================
+Per C++ ``[temp.inst#11]``: "It is unspecified whether or not an implementation 
+implicitly instantiates a virtual member function of a class template if the virtual 
+member function would not otherwise be instantiated."
+
+In the following snippets the virtual member function is not instantiated by gcc and clang,
+but it is instantiated by MSVC, so while the snippet is accepted by the former compilers,
+it is rejected by the latter.
+
+.. code:: c++
+
+    template<typename T>
+    struct CrossPlatformError {
+        virtual ~CrossPlatformError() = default;
+        
+        static void used() {}
+
+        virtual void unused() {
+            T MSVCError = this;
+        };
+    };
+
+    int main() {
+        CrossPlatformError<int>::used();
+        return 0;
+    }
+
+Cross-platform projects that need to support MSVC on Windows might see compiler errors
+because certain virtual member functions are instantiated, which are not instantiated 
+by other compilers on other platforms. This check highlights such virtual member functions.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
new file mode 100644
index 00000000000000..59503e46b9bf3f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
@@ -0,0 +1,134 @@
+// RUN: %check_clang_tidy %s portability-template-virtual-member-function %t
+namespace UninstantiatedVirtualMember {
+template<typename T>
+struct CrossPlatformError {
+    virtual ~CrossPlatformError() = default;
+
+    static void used() {}
+
+    // CHECK-MESSAGES: [[#@LINE+1]]:18: warning: unspecified virtual member function instantiation
+    virtual void unused() {
+        T MSVCError = this;
+    };
+};
+
+int main() {
+    // CHECK-MESSAGES: [[#@LINE+1]]:5: note: template instantiated here
+    CrossPlatformError<int>::used();
+    return 0;
+}
+} // namespace UninstantiatedVirtualMember
+
+namespace UninstantiatedVirtualMembers {
+template<typename T>
+struct CrossPlatformError {
+    virtual ~CrossPlatformError() = default;
+
+    static void used() {}
+
+    // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+13]]:5: note: template instantiated here
+    virtual void unused() {
+        T MSVCError = this;
+    };
+
+    // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here
+    virtual void unused2() {
+        T MSVCError = this;
+    };
+};
+
+int main() {
+    CrossPlatformError<int>::used();
+    return 0;
+}
+} // namespace UninstantiatedVirtualMembers
+
+namespace UninstantiatedVirtualDestructor {
+template<typename T>
+struct CrossPlatformError {
+    // CHECK-MESSAGES: [[#@LINE+2]]:13: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+9]]:5: note: template instantiated here
+    virtual ~CrossPlatformError() {
+        T MSVCError = this;
+    };
+
+    static void used() {}
+};
+
+int main() {
+    CrossPlatformError<int>::used();
+    return 0;
+}
+} // namespace UninstantiatedVirtualDestructor
+
+namespace MultipleImplicitInstantiations {
+template<typename T>
+struct CrossPlatformError {
+    virtual ~CrossPlatformError() = default;
+
+    static void used() {}
+
+    // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here
+    virtual void unused() {
+        T MSVCError = this;
+    };
+};
+
+int main() {
+    CrossPlatformError<int>::used();
+    CrossPlatformError<float>::used();
+    CrossPlatformError<long>::used();
+    return 0;
+}
+} // namespace MultipleImplicitInstantiations
+
+namespace SomeImplicitInstantiationError {
+template <typename T> struct CrossPlatformError {
+    virtual ~CrossPlatformError() = default;
+
+    static void used() {}
+
+    // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+5]]:5: note: template instantiated here
+    virtual void unused(){};
+};
+
+int main() {
+    CrossPlatformError<int>::used();
+    CrossPlatformError<float> NoError;
+    return 0;
+}
+} // namespace SomeImplicitInstantiationError
+
+namespace InstantiatedVirtualMemberFunctions {
+template<typename T>
+struct NoError {
+    virtual ~NoError() {};
+    virtual void unused() {};
+    virtual void unused2() {};
+    virtual void unused3() {};
+};
+
+int main() {
+    NoError<int> Ne;
+    return 0;
+}
+} // namespace InstantiatedVirtualMemberFunctions
+
+namespace UninstantiatedNonVirtualMemberFunctions {
+template<typename T>
+struct NoError {
+    static void used() {};
+    void unused() {};
+    void unused2() {};
+    void unused3() {};
+};
+
+int main() {
+    NoError<int>::used();
+    return 0;
+}
+} // namespace UninstantiatedNonVirtualMemberFunctions

>From 19fee22058d3e73618e11f41073d889db1700a36 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 26 Sep 2024 20:09:16 +0200
Subject: [PATCH 2/6] address comments

---
 .../TemplateVirtualMemberFunctionCheck.cpp            |  3 +--
 clang-tools-extra/docs/ReleaseNotes.rst               |  8 +++++---
 .../portability/template-virtual-member-function.rst  | 11 +++++++----
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
index 6b7b50798798fa..e97c32ba46ed27 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -1,5 +1,4 @@
-//===--- TemplateVirtualMemberFunctionCheck.cpp - clang-tidy
-//-------------------===//
+//===--- TemplateVirtualMemberFunctionCheck.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.
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 81e83c66273ed0..11947cd1631bf1 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -106,9 +106,11 @@ New checks
 - New :doc:`portability-template-virtual-member-function
   <clang-tidy/checks/portability/template-virtual-member-function>` check.
 
-  Detects C++ [temp.inst#11]: "It is unspecified whether or not an implementation 
-  implicitly instantiates a virtual member function of a class template if the 
-  virtual member function would not otherwise be instantiated."
+  Upon instantiating a template class, non-virtual member functions don't have 
+  to be instantiated unless they are used. Virtual member function instantiation 
+  on the other hand is unspecified and depends on the implementation of the compiler.
+  This check intends to find cases when a virtual member function is not instantiated 
+  but it might be with a different compiler.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
index 3e22d967734fa1..084488a68ea82e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
@@ -2,11 +2,14 @@
 
 portability-template-virtual-member-function
 ============================================
-Per C++ ``[temp.inst#11]``: "It is unspecified whether or not an implementation 
-implicitly instantiates a virtual member function of a class template if the virtual 
-member function would not otherwise be instantiated."
 
-In the following snippets the virtual member function is not instantiated by gcc and clang,
+Upon instantiating a template class, non-virtual member functions don't have to be 
+instantiated unless they are used. Virtual member function instantiation on the other hand 
+is unspecified and depends on the implementation of the compiler. This check intends to find 
+cases when a virtual member function is not instantiated but it might be with a different 
+compiler.
+
+In the following snippets the virtual member function is not instantiated by GCC and Clang,
 but it is instantiated by MSVC, so while the snippet is accepted by the former compilers,
 it is rejected by the latter.
 

>From 2e0f9ab80032938fbdac8aaa3ab87a1be0a89ad7 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Fri, 27 Sep 2024 01:57:00 +0200
Subject: [PATCH 3/6] address comments

---
 .../TemplateVirtualMemberFunctionCheck.cpp    |  9 ++---
 .../TemplateVirtualMemberFunctionCheck.h      | 10 +++--
 .../template-virtual-member-function.cpp      | 39 +++++++++++++++++++
 3 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
index e97c32ba46ed27..80e59a2f0e596a 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -14,7 +14,9 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::portability {
 
 void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(classTemplateSpecializationDecl().bind("specialization"),
+  Finder->addMatcher(classTemplateSpecializationDecl(
+                         unless(isExplicitTemplateSpecialization()))
+                         .bind("specialization"),
                      this);
 }
 
@@ -23,10 +25,7 @@ void TemplateVirtualMemberFunctionCheck::check(
   const auto *MatchedDecl =
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
 
-  if (MatchedDecl->isExplicitSpecialization())
-    return;
-
-  for (auto &&Method : MatchedDecl->methods()) {
+  for (const CXXMethodDecl *Method : MatchedDecl->methods()) {
     if (!Method->isVirtual())
       continue;
 
diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
index 9d7918dbdba612..41f92adadd6e8a 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
@@ -13,10 +13,12 @@
 
 namespace clang::tidy::portability {
 
-/// Detects C++ [temp.inst#11]: "It is unspecified whether or not an
-/// implementation implicitly instantiates a virtual member function of a class
-/// template if the virtual member function would not otherwise be
-/// instantiated."
+/// Upon instantiating a template class, non-virtual member functions don't have
+/// to be instantiated unless they are used. Virtual member function
+/// instantiation on the other hand is unspecified and depends on the
+/// implementation of the compiler. This check intends to find cases when a
+/// virtual member function is not instantiated but it might be with a different
+/// compiler.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/portability/template-virtual-member-function.html
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
index 59503e46b9bf3f..94786ae93dd3f3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
@@ -132,3 +132,42 @@ int main() {
     return 0;
 }
 } // namespace UninstantiatedNonVirtualMemberFunctions
+
+namespace PartialSpecializationError {
+template<typename T, typename U>
+struct CrossPlatformError {};
+
+template<typename U>
+struct CrossPlatformError<int, U>{
+    virtual ~CrossPlatformError() = default;
+
+    static void used() {}
+
+    // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation
+    // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here
+    virtual void unused() {
+        U MSVCError = this;
+    };
+};
+
+int main() {
+    CrossPlatformError<int, float>::used();
+    return 0;
+}
+} // namespace PartialSpecializationError
+
+namespace PartialSpecializationNoInstantiation {
+template<typename T, typename U>
+struct NoInstantiation {};
+
+template<typename U>
+struct NoInstantiation<int, U>{
+    virtual ~NoInstantiation() = default;
+
+    static void used() {}
+
+    virtual void unused() {
+        U MSVCError = this;
+    };
+};
+} // namespace PartialSpecializationNoInstantiation

>From 88811df21a83b80f1f74345736d323fc695077dc Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Fri, 27 Sep 2024 02:42:49 +0200
Subject: [PATCH 4/6] using matchers

---
 .../TemplateVirtualMemberFunctionCheck.cpp    | 44 +++++++++----------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
index 80e59a2f0e596a..79e002d8b945c5 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -12,36 +12,34 @@
 using namespace clang::ast_matchers;
 
 namespace clang::tidy::portability {
+namespace {
+AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); }
+} // namespace
 
 void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(classTemplateSpecializationDecl(
-                         unless(isExplicitTemplateSpecialization()))
-                         .bind("specialization"),
-                     this);
+  Finder->addMatcher(
+      cxxMethodDecl(
+          allOf(ofClass(classTemplateSpecializationDecl(
+                            unless(isExplicitTemplateSpecialization()))
+                            .bind("specialization")),
+                isVirtual(), unless(isUsed()),
+                unless(cxxDestructorDecl(isDefaulted()))))
+          .bind("method"),
+      this);
 }
 
 void TemplateVirtualMemberFunctionCheck::check(
     const MatchFinder::MatchResult &Result) {
-  const auto *MatchedDecl =
+  const auto *ImplicitSpecialization =
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
-
-  for (const CXXMethodDecl *Method : MatchedDecl->methods()) {
-    if (!Method->isVirtual())
-      continue;
-
-    if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method);
-        Dtor && Dtor->isDefaulted())
-      continue;
-
-    if (!Method->isUsed()) {
-      diag(Method->getLocation(),
-           "unspecified virtual member function instantiation; the virtual "
-           "member function is not instantiated but it might be with a "
-           "different compiler");
-      diag(MatchedDecl->getPointOfInstantiation(), "template instantiated here",
-           DiagnosticIDs::Note);
-    }
-  }
+  const auto *MethodDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
+
+  diag(MethodDecl->getLocation(),
+       "unspecified virtual member function instantiation; the virtual "
+       "member function is not instantiated but it might be with a "
+       "different compiler");
+  diag(ImplicitSpecialization->getPointOfInstantiation(),
+       "template instantiated here", DiagnosticIDs::Note);
 }
 
 } // namespace clang::tidy::portability

>From 25a75f366fb061f36af0759c5c945a90e9891e90 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Fri, 27 Sep 2024 02:48:07 +0200
Subject: [PATCH 5/6] address comments

---
 .../TemplateVirtualMemberFunctionCheck.cpp            | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
index 79e002d8b945c5..9c2f27f01f1849 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -18,12 +18,11 @@ AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); }
 
 void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      cxxMethodDecl(
-          allOf(ofClass(classTemplateSpecializationDecl(
-                            unless(isExplicitTemplateSpecialization()))
-                            .bind("specialization")),
-                isVirtual(), unless(isUsed()),
-                unless(cxxDestructorDecl(isDefaulted()))))
+      cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
+                                unless(isExplicitTemplateSpecialization()))
+                                .bind("specialization")),
+                    isVirtual(), unless(isUsed()),
+                    unless(cxxDestructorDecl(isDefaulted())))
           .bind("method"),
       this);
 }

>From 553609475bda4fc6314e0866bb4cd3c694c5a843 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Fri, 27 Sep 2024 02:55:18 +0200
Subject: [PATCH 6/6] addressed comments

---
 clang-tools-extra/docs/ReleaseNotes.rst | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 11947cd1631bf1..5f41e4ac2af307 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -106,11 +106,8 @@ New checks
 - New :doc:`portability-template-virtual-member-function
   <clang-tidy/checks/portability/template-virtual-member-function>` check.
 
-  Upon instantiating a template class, non-virtual member functions don't have 
-  to be instantiated unless they are used. Virtual member function instantiation 
-  on the other hand is unspecified and depends on the implementation of the compiler.
-  This check intends to find cases when a virtual member function is not instantiated 
-  but it might be with a different compiler.
+  Finds cases when an uninstantiated virtual member function in a template class 
+  causes cross-compiler incompatibility.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^



More information about the cfe-commits mailing list