summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ.Ru <juanruben.segovia@gmail.com>2018-09-12 09:42:53 +0200
committerJ.Ru <juanruben.segovia@gmail.com>2018-12-07 09:12:01 +0100
commit0d0832fee7adffd7ead9e5c90683e403de5e9b2b (patch)
treecd56fb5f15f93ec804c96224fc6170c7d30d3446
parent2132e43fd15581238df170cf0d3b2ffb3027a67b (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.cc11
-rw-r--r--iwyu_ast_util.cc20
-rw-r--r--iwyu_ast_util.h4
-rw-r--r--tests/cxx/explicit_instantiation-template.h14
-rw-r--r--tests/cxx/explicit_instantiation-template_direct.h14
-rw-r--r--tests/cxx/explicit_instantiation.cc48
6 files changed, 108 insertions, 3 deletions
diff --git a/iwyu.cc b/iwyu.cc
index 989148f..a8cf92d 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -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 */