-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-tidy] Portability Template Virtual Member Function Check #110099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang-tidy Author: None (isuckatcs) ChangesPer C++ 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. (See godbolt) 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. Full diff: https://github.com/llvm/llvm-project/pull/110099.diff 8 Files Affected:
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
|
@llvm/pr-subscribers-clang-tools-extra Author: None (isuckatcs) ChangesPer C++ 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. (See godbolt) 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. Full diff: https://github.com/llvm/llvm-project/pull/110099.diff 8 Files Affected:
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
|
|
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
Outdated
Show resolved
Hide resolved
clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but let's keep this open for others to review as well
clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
Show resolved
Hide resolved
@EugeneZelenko can you please take a look at the changes once again and let us know if you're happy with them? |
@isuckatcs: I mostly check documentation, so will be good idea if somebody from active developers will take a look in addition to @5chmidti. |
I see. Hopefully someone will take a look then and we can merge the patch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me as well.
Thank you for the review! |
…#110099) Introduced a new check that finds cases when an uninstantiated virtual member function in a template class causes cross-compiler incompatibility.
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. (See godbolt)
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.