diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/TemplateName.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/AST/TemplateName.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 80 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiate-template-template-parm.cpp | 21 | ||||
-rw-r--r-- | clang/test/SemaTemplate/metafun-apply.cpp | 17 |
7 files changed, 127 insertions, 12 deletions
diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 3107a358419..09e81be091d 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/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/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b16e15ea0b4..74a13478c16 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 4e54fe49559..3659e2350de 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/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 <stdio.h> 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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 634c90a36e2..3a18f9676b0 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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<typename T> OwningExprResult Clone(T *E) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 2eb874597e4..c9f0d4fd799 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/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<TemplateTemplateParmDecl>( + 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<ClassTemplateDecl>( + TemplateArgs[TTP->getPosition()].getAsDecl()) && + "Wrong kind of template template argument"); + ClassTemplateDecl *ClassTemplate + = dyn_cast<ClassTemplateDecl>( + 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<TemplateName>(); + } + + + + // 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/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp new file mode 100644 index 00000000000..b158251915a --- /dev/null +++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -0,0 +1,21 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<template<typename T> class MetaFun, typename Value> +struct apply { + typedef typename MetaFun<Value>::type type; +}; + +template<class T> +struct add_pointer { + typedef T* type; +}; + +template<class T> +struct add_reference { + typedef T& type; +}; + +int i; +apply<add_pointer, int>::type ip = &i; +apply<add_reference, int>::type ir = i; +apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} diff --git a/clang/test/SemaTemplate/metafun-apply.cpp b/clang/test/SemaTemplate/metafun-apply.cpp index 22be5ab34f7..e81d1421ebe 100644 --- a/clang/test/SemaTemplate/metafun-apply.cpp +++ b/clang/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<typename T> @@ -10,20 +10,21 @@ struct add_pointer { struct add_reference { template<typename T> struct apply { - typedef T& type; + typedef T& type; // expected-error{{cannot form a reference to 'void'}} }; }; template<typename MetaFun, typename T> struct apply1 { - typedef typename MetaFun::template apply<T>::type type; + typedef typename MetaFun::template apply<T>::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply<void>' requested here}} }; -#if 0 -// FIXME: The code below requires template instantiation for dependent -// template-names that occur within nested-name-specifiers. int i; - apply1<add_pointer, int>::type ip = &i; apply1<add_reference, int>::type ir = i; -#endif +apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} + +void test() { + apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \ + // FIXME: expected-error{{unexpected type name 'type': expected expression}} +} |