-
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
570ce88
[clang-tidy] Portability Template Virtual Member Function Check
isuckatcs cf3cb22
address comments
isuckatcs 838ee48
address comments
isuckatcs 2ecd43d
using matchers
isuckatcs b575d5d
address comments
isuckatcs 9f78992
addressed comments
isuckatcs 7fd57a4
addressed comments
isuckatcs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
//===--- 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 { | ||
namespace { | ||
AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); } | ||
} // namespace | ||
|
||
void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher( | ||
cxxMethodDecl(ofClass(classTemplateSpecializationDecl( | ||
unless(isExplicitTemplateSpecialization())) | ||
.bind("specialization")), | ||
isVirtual(), unless(isUsed()), | ||
unless(cxxDestructorDecl(isDefaulted()))) | ||
.bind("method"), | ||
this); | ||
} | ||
|
||
void TemplateVirtualMemberFunctionCheck::check( | ||
const MatchFinder::MatchResult &Result) { | ||
const auto *ImplicitSpecialization = | ||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization"); | ||
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 |
38 changes: 38 additions & 0 deletions
38
clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
//===--- 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 { | ||
|
||
/// 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 | ||
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
...s-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
.. title:: clang-tidy - portability-template-virtual-member-function | ||
|
||
portability-template-virtual-member-function | ||
============================================ | ||
|
||
Finds cases when an uninstantiated virtual member function in a template class causes | ||
cross-compiler incompatibility. | ||
|
||
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. | ||
|
||
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. |
173 changes: 173 additions & 0 deletions
173
clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// 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 | ||
|
||
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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.