summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ.Ru <juanruben.segovia@gmail.com>2018-10-25 08:48:20 +0200
committerJ.Ru <juanruben.segovia@gmail.com>2018-12-07 09:12:01 +0100
commita9f3656c0d99557bc7f3cc2e829f5823dbc0c706 (patch)
tree5f42130f5b77d35036904dd5a1686a49e1c30339
parent27da44e009660d8efc9726b1a4d80d8f9f063539 (diff)
Require explicit inst. decls to use main template
If the usage of a template has visible explicit instantiations decls, require them to be included along with the main template definition. ScanInstantiatedType has also been changed to make sure that the template being analyzed always corresponds to the definition to make it work as expected when there is an explicit instantiation definition visible. Fixes #558
-rw-r--r--iwyu.cc46
-rw-r--r--tests/cxx/explicit_instantiation2-template_helpers.h40
-rw-r--r--tests/cxx/explicit_instantiation2-template_short.h15
-rw-r--r--tests/cxx/explicit_instantiation2-template_short_direct.h14
-rw-r--r--tests/cxx/explicit_instantiation2.cc99
5 files changed, 213 insertions, 1 deletions
diff --git a/iwyu.cc b/iwyu.cc
index f5cfa5f..a111d56 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -217,6 +217,7 @@ using clang::ValueDecl;
using clang::VarDecl;
using llvm::cast;
using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
using llvm::errs;
using llvm::isa;
using std::make_pair;
@@ -2832,7 +2833,8 @@ class InstantiatedTemplateVisitor
// As in TraverseExpandedTemplateFunctionHelper, we ignore all AST nodes
// that will be reported when we traverse the uninstantiated type.
- if (const NamedDecl* type_decl_as_written = TypeToDeclAsWritten(type)) {
+ if (const NamedDecl* type_decl_as_written =
+ GetDefinitionAsWritten(TypeToDeclAsWritten(type))) {
AstFlattenerVisitor nodeset_getter(compiler());
nodes_to_ignore_ = nodeset_getter.GetNodesBelow(
const_cast<NamedDecl*>(type_decl_as_written));
@@ -3111,9 +3113,51 @@ class InstantiatedTemplateVisitor
// We attribute all uses in an instantiated template to the
// template's caller.
ReportTypeUse(caller_loc(), actual_type);
+
+ // Also report all previous explicit instantiations (declarations and
+ // definitions) as uses of the caller's location.
+ ReportExplicitInstantiations(actual_type);
+
return Base::VisitSubstTemplateTypeParmType(type);
}
+ bool VisitTemplateSpecializationType(TemplateSpecializationType* type) {
+ if (CanIgnoreCurrentASTNode())
+ return true;
+
+ CHECK_(current_ast_node()->GetAs<TemplateSpecializationType>() == type)
+ << "The current node must be equal to the template spec. type";
+
+ // Report previous explicit instantiations here, only if the type is needed
+ // fully.
+ if (!CanForwardDeclareType(current_ast_node()))
+ ReportExplicitInstantiations(type);
+
+ return Base::VisitTemplateSpecializationType(type);
+ }
+
+ void ReportExplicitInstantiations(const Type* type) {
+ const auto* decl = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ TypeToDeclAsWritten(type));
+
+ if (decl == nullptr)
+ return;
+
+ // Go through all previous redecls and filter out those that are not
+ // explicit template instantiations or already provided by the template.
+ for (const NamedDecl* redecl : decl->redecls()) {
+ if (!IsExplicitInstantiation(redecl) ||
+ !GlobalSourceManager()->isBeforeInTranslationUnit(
+ redecl->getLocation(), caller_loc()) ||
+ IsProvidedByTemplate(decl))
+ continue;
+
+ // Report the specific decl that points to the explicit instantiation
+ Base::ReportDeclUse(caller_loc(), redecl, "(for explicit instantiation)",
+ UF_ExplicitInstantiation);
+ }
+ }
+
// If constructing an object, check the type we're constructing.
// Normally we'd see that type later, when traversing the return
// type of the constructor-decl, but if we wait for that, we'll lose
diff --git a/tests/cxx/explicit_instantiation2-template_helpers.h b/tests/cxx/explicit_instantiation2-template_helpers.h
new file mode 100644
index 0000000..5068fe1
--- /dev/null
+++ b/tests/cxx/explicit_instantiation2-template_helpers.h
@@ -0,0 +1,40 @@
+//=== explicit_instantiation2-template_helpers.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_INSTANTIATION2_TEMPLATE_HELPERS_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2_TEMPLATE_HELPERS_H_
+
+template <class T>
+class Template;
+
+template <class T>
+class FullUseArg {
+ T t;
+};
+template <class T>
+class FwdDeclUseArg {
+ T* t;
+};
+template <class U = short, class T = Template<U>>
+class TemplateAsDefaultFull {
+ T t;
+};
+template <class U = short, class T = Template<U>>
+class TemplateAsDefaultFwd {
+ T* t;
+};
+template <template <class> class T>
+class TemplateTemplateArgShortFull {
+ T<short> t;
+};
+template <template <class> class T>
+class TemplateTemplateArgShortFwd {
+ T<short>* t;
+};
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2_TEMPLATE_HELPERS_H_
diff --git a/tests/cxx/explicit_instantiation2-template_short.h b/tests/cxx/explicit_instantiation2-template_short.h
new file mode 100644
index 0000000..0569349
--- /dev/null
+++ b/tests/cxx/explicit_instantiation2-template_short.h
@@ -0,0 +1,15 @@
+
+//===- explicit_instantiation2-template_short.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_INSTANTIATION2_TEMPLATE_SHORT_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2_TEMPLATE_SHORT_H_
+
+extern template class Template<short>;
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2_TEMPLATE_SHORT_H_
diff --git a/tests/cxx/explicit_instantiation2-template_short_direct.h b/tests/cxx/explicit_instantiation2-template_short_direct.h
new file mode 100644
index 0000000..17c9845
--- /dev/null
+++ b/tests/cxx/explicit_instantiation2-template_short_direct.h
@@ -0,0 +1,14 @@
+// explicit_instantiation2-template_short_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_INSTANTIATION2_TEMPLATE_SHORT_DIRECT_H_
+#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2_TEMPLATE_SHORT_DIRECT_H_
+
+#include "explicit_instantiation2-template_short.h"
+
+#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_EXPLICIT_INSTANTIATION2-TEMPLATE_SHORT_DIRECT_H_
diff --git a/tests/cxx/explicit_instantiation2.cc b/tests/cxx/explicit_instantiation2.cc
new file mode 100644
index 0000000..754ddc7
--- /dev/null
+++ b/tests/cxx/explicit_instantiation2.cc
@@ -0,0 +1,99 @@
+//===------- explicit_instantiation2.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"
+#include "explicit_instantiation2-template_helpers.h"
+#include "explicit_instantiation2-template_short_direct.h"
+
+// These tests verify that a dependent explicit instantiation declaration is
+// always required when the main template is also needed, but not otherwise.
+//
+// Positive scenarios:
+// 1a/1b: Implicit instantiation before and after an explicit instantiation
+// definition (2), as it affects the semantics.
+// 2: Explicit instantiation definition.
+// 3: Full use in a template, provided as an explicit parameter.
+// 4: Fwd-decl use in a template, provided as an explicit parameter.
+// 5: Full use in a template, provided as an default parameter.
+// 7: Full use in a template, provided as a template template parameter.
+// 8: Fwd-decl use in a template, provided as a template template parameter.
+//
+// Negative scenarios, where the dependent template specialization is not
+// required, or it does not provide an explicit instantiation:
+// 6: Fwd-decl use in a template, provided as a default parameter.
+// 9: Implicit instantiation of Template<int>
+// 10: Specialization of Template<T>
+
+
+// IWYU: Template is...*explicit_instantiation-template.h
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+Template<short> t1a; // 1a
+
+// IWYU: Template is...*explicit_instantiation-template.h
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+template class Template<short>; // 2
+
+// IWYU: Template is...*explicit_instantiation-template.h
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+Template<short> t1b; // 1b
+
+// IWYU: Template is...*explicit_instantiation-template.h
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+FullUseArg<
+ // IWYU: Template needs a declaration...*
+ Template<short>>
+ // IWYU: Template is...*explicit_instantiation-template.h
+ t3; // 3
+
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+FwdDeclUseArg<
+ // IWYU: Template needs a declaration...*
+ Template<short>>
+ t4; // 4
+
+// IWYU: Template is...*explicit_instantiation-template.h
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+TemplateAsDefaultFull<> t5; // 5
+TemplateAsDefaultFwd<> t6; // 6
+
+// IWYU: Template is...*template_short.h.*for explicit instantiation
+TemplateTemplateArgShortFull<
+ // IWYU: Template is...*explicit_instantiation-template.h
+ Template>
+ t7; // 7
+
+TemplateTemplateArgShortFwd<
+ // IWYU: Template is...*explicit_instantiation-template.h
+ Template>
+ t8; // 8
+
+// IWYU: Template is...*explicit_instantiation-template.h
+Template<int> t9; // 9
+
+// IWYU: Template needs a declaration...*
+template <> class Template<char> {};
+
+TemplateAsDefaultFull<char> t10; // 10
+
+/**** IWYU_SUMMARY
+
+tests/cxx/explicit_instantiation2.cc should add these lines:
+#include "explicit_instantiation-template.h"
+#include "explicit_instantiation2-template_short.h"
+
+tests/cxx/explicit_instantiation2.cc should remove these lines:
+- #include "explicit_instantiation-template_direct.h" // lines XX-XX
+- #include "explicit_instantiation2-template_short_direct.h" // lines XX-XX
+
+The full include-list for tests/cxx/explicit_instantiation2.cc:
+#include "explicit_instantiation-template.h" // for Template
+#include "explicit_instantiation2-template_helpers.h" // for FullUseArg, FwdDeclUseArg, TemplateAsDefaultFull, TemplateAsDefaultFwd, TemplateTemplateArgShortFull, TemplateTemplateArgShortFwd
+#include "explicit_instantiation2-template_short.h" // for Template
+
+***** IWYU_SUMMARY */