diff options
author | J.Ru <juanruben.segovia@gmail.com> | 2018-09-12 09:42:53 +0200 |
---|---|---|
committer | J.Ru <juanruben.segovia@gmail.com> | 2018-12-07 09:12:01 +0100 |
commit | 0d0832fee7adffd7ead9e5c90683e403de5e9b2b (patch) | |
tree | cd56fb5f15f93ec804c96224fc6170c7d30d3446 | |
parent | 2132e43fd15581238df170cf0d3b2ffb3027a67b (diff) |
Treat explicit template instantiations as full uses
Teach IsFowardDecl() to not confuse an explicit template instantiation
with a forward declaration.
Also make sure to report explicit instantiations (declaration or
definition) as full uses during visitation.
Fixes #558
-rw-r--r-- | iwyu.cc | 11 | ||||
-rw-r--r-- | iwyu_ast_util.cc | 20 | ||||
-rw-r--r-- | iwyu_ast_util.h | 4 | ||||
-rw-r--r-- | tests/cxx/explicit_instantiation-template.h | 14 | ||||
-rw-r--r-- | tests/cxx/explicit_instantiation-template_direct.h | 14 | ||||
-rw-r--r-- | tests/cxx/explicit_instantiation.cc | 48 |
6 files changed, 108 insertions, 3 deletions
@@ -3732,11 +3732,20 @@ class IwyuAstConsumer // template <class T> struct Foo; // template<> struct Foo<int> { ... }; // we don't want iwyu to recommend removing the 'forward declare' of Foo. + // + // Additionally, this type of decl is also used to represent explicit template + // instantiations, in which case we want the full type, not only a forward + // declaration. bool VisitClassTemplateSpecializationDecl( clang::ClassTemplateSpecializationDecl* decl) { if (CanIgnoreCurrentASTNode()) return true; ClassTemplateDecl* specialized_decl = decl->getSpecializedTemplate(); - ReportDeclForwardDeclareUse(CurrentLoc(), specialized_decl); + + if (IsExplicitInstantiation(decl)) + ReportDeclUse(CurrentLoc(), specialized_decl); + else + ReportDeclForwardDeclareUse(CurrentLoc(), specialized_decl); + return Base::VisitClassTemplateSpecializationDecl(decl); } diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc index e22b2c7..7bdd3df 100644 --- a/iwyu_ast_util.cc +++ b/iwyu_ast_util.cc @@ -105,6 +105,7 @@ using clang::TemplateArgumentLoc; using clang::TemplateDecl; using clang::TemplateName; using clang::TemplateParameterList; +using clang::TemplateSpecializationKind; using clang::TemplateSpecializationType; using clang::TranslationUnitDecl; using clang::Type; @@ -155,6 +156,13 @@ void DumpASTNode(llvm::raw_ostream& ostream, const ASTNode* node) { } } +TemplateSpecializationKind GetTemplateSpecializationKind(const Decl* decl) { + if (const auto* record = dyn_cast<CXXRecordDecl>(decl)) { + return record->getTemplateSpecializationKind(); + } + return clang::TSK_Undeclared; +} + } // anonymous namespace //------------------------------------------------------------ @@ -942,12 +950,20 @@ bool IsFriendDecl(const Decl* decl) { return decl->getFriendObjectKind() != Decl::FOK_None; } +bool IsExplicitInstantiation(const clang::Decl* decl) { + TemplateSpecializationKind kind = GetTemplateSpecializationKind(decl); + return kind == clang::TSK_ExplicitInstantiationDeclaration || + kind == clang::TSK_ExplicitInstantiationDefinition; +} + bool IsForwardDecl(const NamedDecl* decl) { - if (const auto* record_decl = dyn_cast<RecordDecl>(decl)) { + if (const auto* record_decl = dyn_cast<CXXRecordDecl>(decl)) { + return (!record_decl->getName().empty() && !record_decl->isCompleteDefinition() && !record_decl->isEmbeddedInDeclarator() && - !IsFriendDecl(record_decl)); + !IsFriendDecl(record_decl) && + !IsExplicitInstantiation(record_decl)); } return false; diff --git a/iwyu_ast_util.h b/iwyu_ast_util.h index 847c68e..67e038b 100644 --- a/iwyu_ast_util.h +++ b/iwyu_ast_util.h @@ -594,6 +594,10 @@ bool IsDefaultNewOrDelete(const clang::FunctionDecl* decl, // Returns true if this decl is part of a friend decl. bool IsFriendDecl(const clang::Decl* decl); +// Returns true if this decl is an explicit template instantiation declaration +// or definition. +bool IsExplicitInstantiation(const clang::Decl* decl); + // Returns true if a named decl looks like a forward-declaration of a // class (rather than a definition, a friend declaration, or an 'in // place' declaration like 'struct Foo' in 'void MyFunc(struct Foo*);' diff --git a/tests/cxx/explicit_instantiation-template.h b/tests/cxx/explicit_instantiation-template.h new file mode 100644 index 0000000..19d4a5a --- /dev/null +++ b/tests/cxx/explicit_instantiation-template.h @@ -0,0 +1,14 @@ +//===---- explicit_instantiation-template.h - test input file for iwyu ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_ +#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_ + +template<typename T> class Template {}; + +#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_H_ diff --git a/tests/cxx/explicit_instantiation-template_direct.h b/tests/cxx/explicit_instantiation-template_direct.h new file mode 100644 index 0000000..9df65f7 --- /dev/null +++ b/tests/cxx/explicit_instantiation-template_direct.h @@ -0,0 +1,14 @@ +//===- explicit_instantiation-template_direct.h - test input file for iwyu ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_ +#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_ + +#include "explicit_instantiation-template.h" + +#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION_TEMPLATE_DIRECT_H_ diff --git a/tests/cxx/explicit_instantiation.cc b/tests/cxx/explicit_instantiation.cc new file mode 100644 index 0000000..c3af267 --- /dev/null +++ b/tests/cxx/explicit_instantiation.cc @@ -0,0 +1,48 @@ +//===-------- explicit_instantiation.cc - test input file for iwyu --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "explicit_instantiation-template_direct.h" + +// Test that all explicit instantiations variants of the base template +// require the full type: + +// - Declaration and definition +// IWYU: Template is...*explicit_instantiation-template.h +extern template class Template<int>; +// IWYU: Template is...*explicit_instantiation-template.h +template class Template<int>; + +// - Only declaration +// IWYU: Template is...*explicit_instantiation-template.h +extern template class Template<short>; + +// - Only definition +// IWYU: Template is...*explicit_instantiation-template.h +template class Template<double>; + + +// The explicit instantiation of a specialization only needs a declaration +// of the base template +// IWYU: Template needs a declaration +template<> class Template<char> {}; +extern template class Template<char>; + + +/**** IWYU_SUMMARY + +tests/cxx/explicit_instantiation.cc should add these lines: +#include "explicit_instantiation-template.h" + +tests/cxx/explicit_instantiation.cc should remove these lines: +- #include "explicit_instantiation-template_direct.h" // lines XX-XX + +The full include-list for tests/cxx/explicit_instantiation.cc: +#include "explicit_instantiation-template.h" // for Template + +***** IWYU_SUMMARY */ |