diff options
-rw-r--r-- | include/clang/AST/TemplateName.h | 6 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/AST/TemplateName.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 17 | ||||
-rw-r--r-- | test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/temp_arg_type.cpp | 16 |
6 files changed, 53 insertions, 6 deletions
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index aafe963811..f3de9fa011 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -25,6 +25,7 @@ namespace llvm { namespace clang { class DependentTemplateName; +class DiagnosticBuilder; class IdentifierInfo; class NestedNameSpecifier; struct PrintingPolicy; @@ -173,6 +174,11 @@ public: } }; +/// Insertion operator for diagnostics. This allows sending TemplateName's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + TemplateName N); + /// \brief Represents a template name that was expressed as a /// qualified name. /// diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2c5a7d4e2c..ed2db770d8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1184,6 +1184,8 @@ def err_template_decl_ref : Error< "cannot refer to class template %0 without a template argument list">; // C++ Template Argument Lists +def err_template_missing_args : Error< + "use of class template %0 requires template arguments">; def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " "%select{class template|function template|template template parameter" diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index b56c0cebfa..a1ee552264 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -15,9 +15,11 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace llvm; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) @@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, } } +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + TemplateName N) { + std::string NameStr; + raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + N.print(OS, PrintingPolicy(LO)); + OS.flush(); + return DB << NameStr; +} + void TemplateName::dump() const { LangOptions LO; // FIXME! LO.CPlusPlus = true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 40ec4bcb58..44afbd7d1b 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1663,11 +1663,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. - if (Arg.getKind() != TemplateArgument::Type) { + switch(Arg.getKind()) { + case TemplateArgument::Type: // C++ [temp.arg.type]p1: // A template-argument for a template-parameter which is a // type shall be a type-id. + break; + case TemplateArgument::Template: { + // We have a template type parameter but the template argument + // is a template without any arguments. + SourceRange SR = AL.getSourceRange(); + TemplateName Name = Arg.getAsTemplate(); + Diag(SR.getBegin(), diag::err_template_missing_args) + << Name << SR; + if (TemplateDecl *Decl = Name.getAsTemplateDecl()) + Diag(Decl->getLocation(), diag::note_template_decl_here); + return true; + } + default: { // We have a template type parameter but the template argument // is not a type. SourceRange SR = AL.getSourceRange(); @@ -1676,6 +1690,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } + } if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp index e579546099..d2afd5d83f 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp @@ -32,6 +32,6 @@ namespace test1 { // Test that we don't find the injected class name when parsing base // specifiers. namespace test2 { - template <class T> struct bar {}; // expected-note {{template parameter is declared here}} - template <class T> struct foo : bar<foo> {}; // expected-error {{template argument for template type parameter must be a type}} + template <class T> struct bar {}; + template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template foo requires template arguments}} expected-note {{template is declared here}} } diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp index a1db3f8057..eea7297b53 100644 --- a/test/SemaTemplate/temp_arg_type.cpp +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -1,16 +1,26 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template<typename T> class A; // expected-note 2 {{template parameter is declared here}} +template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}} // [temp.arg.type]p1 A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} -A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} +A<A> *a2; // expected-error{{use of class template A requires template arguments}} A<int> *a3; A<int()> *a4; A<int(float)> *a5; A<A<int> > *a6; +// Pass an overloaded function template: +template<typename T> void function_tpl(T); +A<function_tpl> a7; // expected-error{{template argument for template type parameter must be a type}} + +// Pass a qualified name: +namespace ns { +template<typename T> class B {}; // expected-note{{template is declared here}} +} +A<ns::B> a8; // expected-error{{use of class template ns::B requires template arguments}} + // [temp.arg.type]p2 void f() { class X { }; @@ -18,7 +28,7 @@ void f() { } struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}} -A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} +A<__typeof__(Unnamed)> *a9; // expected-error{{template argument uses unnamed type}} // FIXME: [temp.arg.type]p3. The check doesn't really belong here (it // belongs somewhere in the template instantiation section). |