From: Jeffrey Yasskin Date: Thu, 8 Apr 2010 00:03:06 +0000 (+0000) Subject: When a template (without arguments) is passed as a template type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db88d8ad74097e2601d81ee863ce46a8a48a7034;p=clang When a template (without arguments) is passed as a template type parameter, explicitly ask the user to give it arguments. We used to complain that it wasn't a type and expect the user to figure it out. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100729 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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()) @@ -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 struct bar {}; // expected-note {{template parameter is declared here}} - template struct foo : bar {}; // expected-error {{template argument for template type parameter must be a type}} + template struct bar {}; + template struct foo : bar {}; // 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 class A; // expected-note 2 {{template parameter is declared here}} +template 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 *a2; // expected-error{{template argument for template type parameter must be a type}} +A *a2; // expected-error{{use of class template A requires template arguments}} A *a3; A *a4; A *a5; A > *a6; +// Pass an overloaded function template: +template void function_tpl(T); +A a7; // expected-error{{template argument for template type parameter must be a type}} + +// Pass a qualified name: +namespace ns { +template class B {}; // expected-note{{template is declared here}} +} +A 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).