From dda7ced32ed79f4d60e89d2b64cd2ee041b66616 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 30 Jun 2009 17:20:14 +0000 Subject: [PATCH] When recursively instantiating function templates, keep track of the instantiation stack so that we provide a full instantiation backtrace. Previously, we performed all of the instantiations implied by the recursion, but each looked like a "top-level" instantiation. The included test case tests the previous fix for the instantiation of DeclRefExprs. Note that the "instantiated from" diagnostics still don't tell us which template arguments we're instantiating with. llvm-svn: 74540 --- clang/lib/Sema/Sema.h | 7 ++-- clang/lib/Sema/SemaExpr.cpp | 2 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 33 ++++++++++++++++--- .../CXX/basic/basic.def.odr/p2-typeid.cpp | 2 +- .../recursive-template-instantiation.cpp | 10 ++++++ 5 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 clang/test/SemaTemplate/recursive-template-instantiation.cpp diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 42c43291a961..308a78c80c1b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -29,9 +29,9 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" +#include #include #include -#include #include namespace llvm { @@ -2581,7 +2581,7 @@ public: /// \brief The queue of implicit template instantiations that are required /// but have not yet been performed. - std::queue PendingImplicitInstantiations; + std::deque PendingImplicitInstantiations; void PerformPendingImplicitInstantiations(); @@ -2636,7 +2636,8 @@ public: const TemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, - FunctionDecl *Function); + FunctionDecl *Function, + bool Recursive = false); void InstantiateVariableDefinition(VarDecl *Var); NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 1c5b76075e04..d66b002578b3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5641,7 +5641,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // instantiated, naturally). if (Function->getInstantiatedFromMemberFunction() || Function->getPrimaryTemplate()) - PendingImplicitInstantiations.push(std::make_pair(Function, Loc)); + PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7053bba8ede6..769e0d222ae9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -663,10 +663,19 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// \brief Instantiate the definition of the given function from its /// template. /// +/// \param PointOfInstantiation the point at which the instantiation was +/// required. Note that this is not precisely a "point of instantiation" +/// for the function, but it's close. +/// /// \param Function the already-instantiated declaration of a -/// function. +/// function template specialization or member function of a class template +/// specialization. +/// +/// \param Recursive if true, recursively instantiates any functions that +/// are required by this instantiation. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, - FunctionDecl *Function) { + FunctionDecl *Function, + bool Recursive) { if (Function->isInvalidDecl()) return; @@ -689,6 +698,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Inst) return; + // If we're performing recursive template instantiation, create our own + // queue of pending implicit instantiations that we will instantiate later, + // while we're still within our own instantiation context. + std::deque SavedPendingImplicitInstantiations; + if (Recursive) + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be @@ -717,6 +733,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); + + if (Recursive) { + // Instantiate any pending implicit instantiations found during the + // instantiation of this template. + PerformPendingImplicitInstantiations(); + + // Restore the set of pending implicit instantiations. + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + } } /// \brief Instantiate the definition of the given variable from its @@ -859,11 +884,11 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { void Sema::PerformPendingImplicitInstantiations() { while (!PendingImplicitInstantiations.empty()) { PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); - PendingImplicitInstantiations.pop(); + PendingImplicitInstantiations.pop_front(); if (FunctionDecl *Function = dyn_cast(Inst.first)) if (!Function->getBody()) - InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function); + InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); // FIXME: instantiate static member variables } diff --git a/clang/test/CXX/basic/basic.def.odr/p2-typeid.cpp b/clang/test/CXX/basic/basic.def.odr/p2-typeid.cpp index 7eb10ef52eb5..881212d74ba4 100644 --- a/clang/test/CXX/basic/basic.def.odr/p2-typeid.cpp +++ b/clang/test/CXX/basic/basic.def.odr/p2-typeid.cpp @@ -32,5 +32,5 @@ void test(X xp, X xpr, X xnp, X x xnpr.g(NonPoly()); // Triggers an error (as it should); - xpr.g(Poly()); + xpr.g(Poly()); // expected-note{{instantiation of member function}} } diff --git a/clang/test/SemaTemplate/recursive-template-instantiation.cpp b/clang/test/SemaTemplate/recursive-template-instantiation.cpp new file mode 100644 index 000000000000..7c88d5019fd5 --- /dev/null +++ b/clang/test/SemaTemplate/recursive-template-instantiation.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template void f(T* t) { + f(*t); // expected-error{{no matching function}}\ + // expected-note 3{{requested here}} +} + +void test_f(int ****p) { + f(p); // expected-note{{requested here}} +}