diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 52eb89e2a05cbb16312ddd253012131524696828..d710544bf867fdf293ed1b54158dd1ee00dfc472 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -18,6 +18,7 @@ #include "IdentifierResolver.h" #include "CXXFieldCollector.h" #include "SemaOverload.h" +#include "SemaTemplate.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclBase.h" #include "clang/AST/Decl.h" @@ -2626,7 +2627,7 @@ public: // C++ Template Instantiation // - const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D); + MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { diff --git a/clang/lib/Sema/SemaTemplate.h b/clang/lib/Sema/SemaTemplate.h new file mode 100644 index 0000000000000000000000000000000000000000..3f814e413db3deb99cebb5d5e14f228c82135386 --- /dev/null +++ b/clang/lib/Sema/SemaTemplate.h @@ -0,0 +1,80 @@ +//===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file provides types used in the semantic analysis of C++ templates. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATE_H +#define LLVM_CLANG_SEMA_TEMPLATE_H + +#include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace clang { + /// \brief Data structure that captures multiple levels of template argument + /// lists for use in template instantiation. + /// + /// Multiple levels of template arguments occur when instantiating the + /// definitions of member templates. For example: + /// + /// \code + /// template + /// struct X { + /// template + /// struct Y { + /// void f(); + /// }; + /// }; + /// \endcode + /// + /// When instantiating X::Y<17>::f, the multi-level template argument + /// list will contain a template argument list (int) at depth 0 and a + /// template argument list (17) at depth 1. + struct MultiLevelTemplateArgumentList { + /// \brief The template argument lists, stored from the innermost template + /// argument list (first) to the outermost template argument list (last) + llvm::SmallVector TemplateArgumentLists; + + public: + /// \brief Construct an empty set of template argument lists. + MultiLevelTemplateArgumentList() { } + + /// \brief Construct a single-level template argument list. + MultiLevelTemplateArgumentList(const TemplateArgumentList *TemplateArgs) { + TemplateArgumentLists.push_back(TemplateArgs); + } + + /// \brief Determine the number of levels in this template argument + /// list. + unsigned getNumLevels() const { return TemplateArgumentLists.size(); } + + /// \brief Retrieve the template argument at a given depth and index. + const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth]->size()); + return TemplateArgumentLists[getNumLevels() - Depth]->get(Index); + } + + /// \brief Add a new outermost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { + TemplateArgumentLists.push_back(TemplateArgs); + } + + // Implicit conversion to a single template argument list, to facilitate a + // gradual transition to MultiLevelTemplateArgumentLists. + operator const TemplateArgumentList &() const { + assert(getNumLevels() == 1 && + "Conversion only works with a single level of template arguments"); + return *TemplateArgumentLists.front(); + } + }; +} + +#endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 4642251d95ad57e7f74173f4546043bb27060029..b330ae960be79324ff27b39221e242b0a64e78e1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -28,30 +28,39 @@ using namespace clang; /// \brief Retrieve the template argument list that should be used to /// instantiate the given declaration. -const TemplateArgumentList & +MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D) { - // Template arguments for a class template specialization. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(D)) - return Spec->getTemplateInstantiationArgs(); - - // Template arguments for a function template specialization. - if (FunctionDecl *Function = dyn_cast(D)) - if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) - return *TemplateArgs; + // Accumulate the set of template argument lists in this structure. + MultiLevelTemplateArgumentList Result; + + DeclContext *Ctx = dyn_cast(D); + if (!Ctx) + Ctx = D->getDeclContext(); + + for (; !Ctx->isFileContext(); Ctx = Ctx->getParent()) { + // Add template arguments from a class template instantiation. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Ctx)) { + // We're done when we hit an explicit specialization. + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization) + break; + + Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + continue; + } + + // Add template arguments from a function template specialization. + if (FunctionDecl *Function = dyn_cast(Ctx)) { + // FIXME: Check whether this is an explicit specialization. + if (const TemplateArgumentList *TemplateArgs + = Function->getTemplateSpecializationArgs()) + Result.addOuterTemplateArguments(TemplateArgs); - // Template arguments for a member of a class template specialization. - DeclContext *EnclosingTemplateCtx = D->getDeclContext(); - while (!isa(EnclosingTemplateCtx)) { - assert(!EnclosingTemplateCtx->isFileContext() && - "Tried to get the instantiation arguments of a non-template"); - EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); + continue; + } } - - ClassTemplateSpecializationDecl *EnclosingTemplate - = cast(EnclosingTemplateCtx); - return EnclosingTemplate->getTemplateInstantiationArgs(); + + return Result; } Sema::InstantiatingTemplate:: diff --git a/clang/test/SemaTemplate/instantiate-member-template.cpp b/clang/test/SemaTemplate/instantiate-member-template.cpp index 959e5c157af05bce0746959c36728f51ce13e156..dc79012801156251b7697f875f8dd9613057f734 100644 --- a/clang/test/SemaTemplate/instantiate-member-template.cpp +++ b/clang/test/SemaTemplate/instantiate-member-template.cpp @@ -20,3 +20,4 @@ void test_X0(int *ip, double *dp) { X0 xv; double *&dpr2 = xv.f1(ip, dp); } +