From de650ae96b53eb6109f29fdb5ee51c514259e6e4 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 31 Mar 2009 18:38:02 +0000 Subject: [PATCH] Implement template instantiation for template names, including both template template parameters and dependent template names. For example, the oft-mentioned typename MetaFun::template apply::type can now be instantiated, with the appropriate name lookup for "apply". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68128 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/TemplateName.h | 4 + include/clang/Basic/DiagnosticSemaKinds.td | 2 + lib/AST/TemplateName.cpp | 10 +++ lib/Sema/Sema.h | 5 ++ lib/Sema/SemaTemplateInstantiate.cpp | 80 ++++++++++++++++++- .../instantiate-template-template-parm.cpp | 21 +++++ test/SemaTemplate/metafun-apply.cpp | 17 ++-- 7 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 test/SemaTemplate/instantiate-template-template-parm.cpp diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 3107a35841..09e81be091 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -99,6 +99,10 @@ public: /// \brief Print the template name. void Print(llvm::raw_ostream &OS) const; + /// \brief Debugging aid that dumps the template name to standard + /// error. + void Dump() const; + void Profile(llvm::FoldingSetNodeID &ID) { ID.AddPointer(Storage.getOpaqueValue()); } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b16e15ea0b..74a13478c1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -701,6 +701,8 @@ def note_typename_refers_here : Note< def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; +def err_template_kw_refers_to_function_template : Error< + "%0 following the 'template' keyword refers to a function template">; def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 4e54fe4955..3659e2350d 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "llvm/Support/raw_ostream.h" +#include using namespace clang; @@ -52,3 +53,12 @@ void TemplateName::Print(llvm::raw_ostream &OS) const { OS << DTN->getName()->getName(); } } + +void TemplateName::Dump() const { + std::string Result; + { + llvm::raw_string_ostream OS(Result); + Print(OS); + } + fprintf(stderr, "%s", Result.c_str()); +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 634c90a36e..3a18f9676b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1981,6 +1981,11 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); + TemplateName + InstantiateTemplateName(TemplateName Name, SourceLocation Loc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + // Simple function for cloning expressions. template OwningExprResult Clone(T *E) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 2eb874597e..c9f0d4fd79 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -472,10 +472,13 @@ InstantiateTemplateSpecializationType( // FIXME: We're missing the locations of the template name, '<', and // '>'. - // FIXME: Need to instantiate into the template name. - return SemaRef.CheckTemplateIdType(T->getTemplateName(), - Loc, - SourceLocation(), + + TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(), + Loc, + TemplateArgs, + NumTemplateArgs); + + return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(), &InstantiatedTemplateArgs[0], InstantiatedTemplateArgs.size(), SourceLocation()); @@ -839,3 +842,72 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, // Required to silence a GCC warning return 0; } + +TemplateName +Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null( + Name.getAsTemplateDecl())) { + assert(TTP->getDepth() == 0 && + "Cannot reduce depth of a template template parameter"); + assert(TTP->getPosition() < NumTemplateArgs && "Wrong # of template args"); + assert(dyn_cast_or_null( + TemplateArgs[TTP->getPosition()].getAsDecl()) && + "Wrong kind of template template argument"); + ClassTemplateDecl *ClassTemplate + = dyn_cast( + TemplateArgs[TTP->getPosition()].getAsDecl()); + + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + NestedNameSpecifier *NNS + = InstantiateNestedNameSpecifier(QTN->getQualifier(), + /*FIXME=*/SourceRange(Loc), + TemplateArgs, NumTemplateArgs); + if (NNS) + return Context.getQualifiedTemplateName(NNS, + QTN->hasTemplateKeyword(), + ClassTemplate); + } + + return TemplateName(ClassTemplate); + } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + NestedNameSpecifier *NNS + = InstantiateNestedNameSpecifier(DTN->getQualifier(), + /*FIXME=*/SourceRange(Loc), + TemplateArgs, NumTemplateArgs); + + if (!NNS) // FIXME: Not the best recovery strategy. + return Name; + + if (NNS->isDependent()) + return Context.getDependentTemplateName(NNS, DTN->getName()); + + // Somewhat redundant with ActOnDependentTemplateName. + CXXScopeSpec SS; + SS.setRange(SourceRange(Loc)); + SS.setScopeRep(NNS); + TemplateTy Template; + TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS); + if (TNK == TNK_Non_template) { + Diag(Loc, diag::err_template_kw_refers_to_non_template) + << DTN->getName(); + return Name; + } else if (TNK == TNK_Function_template) { + Diag(Loc, diag::err_template_kw_refers_to_non_template) + << DTN->getName(); + return Name; + } + + return Template.getAsVal(); + } + + + + // FIXME: Even if we're referring to a Decl that isn't a template + // template parameter, we may need to instantiate the outer contexts + // of that Decl. However, this won't be needed until we implement + // member templates. + return Name; +} diff --git a/test/SemaTemplate/instantiate-template-template-parm.cpp b/test/SemaTemplate/instantiate-template-template-parm.cpp new file mode 100644 index 0000000000..b158251915 --- /dev/null +++ b/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -0,0 +1,21 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template class MetaFun, typename Value> +struct apply { + typedef typename MetaFun::type type; +}; + +template +struct add_pointer { + typedef T* type; +}; + +template +struct add_reference { + typedef T& type; +}; + +int i; +apply::type ip = &i; +apply::type ir = i; +apply::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp index 22be5ab34f..e81d1421eb 100644 --- a/test/SemaTemplate/metafun-apply.cpp +++ b/test/SemaTemplate/metafun-apply.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang-cc -fsyntax-only -verify %s struct add_pointer { template @@ -10,20 +10,21 @@ struct add_pointer { struct add_reference { template struct apply { - typedef T& type; + typedef T& type; // expected-error{{cannot form a reference to 'void'}} }; }; template struct apply1 { - typedef typename MetaFun::template apply::type type; + typedef typename MetaFun::template apply::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply' requested here}} }; -#if 0 -// FIXME: The code below requires template instantiation for dependent -// template-names that occur within nested-name-specifiers. int i; - apply1::type ip = &i; apply1::type ir = i; -#endif +apply1::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} + +void test() { + apply1::type t; // expected-note{{in instantiation of template class 'struct apply1' requested here}} \ + // FIXME: expected-error{{unexpected type name 'type': expected expression}} +} -- 2.40.0