]> granicus.if.org Git - clang/commitdiff
When a template (without arguments) is passed as a template type
authorJeffrey Yasskin <jyasskin@google.com>
Thu, 8 Apr 2010 00:03:06 +0000 (00:03 +0000)
committerJeffrey Yasskin <jyasskin@google.com>
Thu, 8 Apr 2010 00:03:06 +0000 (00:03 +0000)
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

include/clang/AST/TemplateName.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/TemplateName.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
test/SemaTemplate/temp_arg_type.cpp

index aafe963811920b03cc2c8fc90c52088471a6e482..f3de9fa011bc2616c5780d05f0db4925705d4ab6 100644 (file)
@@ -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.
 ///
index 2c5a7d4e2cb744f854b056ebc731c6371c4a5b9c..ed2db770d885257bcc4ea61053ac4a96d6c6509f 100644 (file)
@@ -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"
index b56c0cebfa5833bcf78e9b5fbabbe9998cc8a5c3..a1ee5522640e9a32bb2f99a1b011224652028b78 100644 (file)
 #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;
index 40ec4bcb58e4661067fb18b720f18d83902596e4..44afbd7d1b54912458e60acdd858bf3ff64fcb44 100644 (file)
@@ -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;
index e57954609907e548c9d6ed3fdd411003cc6ba43d..d2afd5d83fdc85ae7328b4fb1a4838031053413c 100644 (file)
@@ -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}}
 }
index a1db3f8057acaac5007a73b3a8ec22d08b891461..eea7297b533f0c250fcab0034aa4142aad5f74de 100644 (file)
@@ -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).