Skip to content

Commit

Permalink
When a template (without arguments) is passed as a template type
Browse files Browse the repository at this point in the history
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.

llvm-svn: 100729
  • Loading branch information
jyasskin committed Apr 8, 2010
1 parent 81fd35f commit 823015d
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 6 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace llvm {
namespace clang {

class DependentTemplateName;
class DiagnosticBuilder;
class IdentifierInfo;
class NestedNameSpecifier;
struct PrintingPolicy;
Expand Down Expand Up @@ -173,6 +174,11 @@ class TemplateName {
}
};

/// 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.
///
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/TemplateName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *>())
Expand Down Expand Up @@ -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;
Expand Down
17 changes: 16 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -1676,6 +1690,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,

return true;
}
}

if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
return true;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}
16 changes: 13 additions & 3 deletions clang/test/SemaTemplate/temp_arg_type.cpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
// 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 { };
A<X> * a = 0; // expected-error{{template argument uses local type 'X'}}
}

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).

0 comments on commit 823015d

Please sign in to comment.