Skip to content

Commit 823015d

Browse files
committed
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. llvm-svn: 100729
1 parent 81fd35f commit 823015d

File tree

6 files changed

+53
-6
lines changed

6 files changed

+53
-6
lines changed

clang/include/clang/AST/TemplateName.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace llvm {
2525
namespace clang {
2626

2727
class DependentTemplateName;
28+
class DiagnosticBuilder;
2829
class IdentifierInfo;
2930
class NestedNameSpecifier;
3031
struct PrintingPolicy;
@@ -173,6 +174,11 @@ class TemplateName {
173174
}
174175
};
175176

177+
/// Insertion operator for diagnostics. This allows sending TemplateName's
178+
/// into a diagnostic with <<.
179+
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
180+
TemplateName N);
181+
176182
/// \brief Represents a template name that was expressed as a
177183
/// qualified name.
178184
///

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,8 @@ def err_template_decl_ref : Error<
11841184
"cannot refer to class template %0 without a template argument list">;
11851185

11861186
// C++ Template Argument Lists
1187+
def err_template_missing_args : Error<
1188+
"use of class template %0 requires template arguments">;
11871189
def err_template_arg_list_different_arity : Error<
11881190
"%select{too few|too many}0 template arguments for "
11891191
"%select{class template|function template|template template parameter"

clang/lib/AST/TemplateName.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
#include "clang/AST/DeclTemplate.h"
1616
#include "clang/AST/NestedNameSpecifier.h"
1717
#include "clang/AST/PrettyPrinter.h"
18+
#include "clang/Basic/Diagnostic.h"
1819
#include "clang/Basic/LangOptions.h"
1920
#include "llvm/Support/raw_ostream.h"
2021
using namespace clang;
22+
using namespace llvm;
2123

2224
TemplateDecl *TemplateName::getAsTemplateDecl() const {
2325
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
@@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
6466
}
6567
}
6668

69+
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
70+
TemplateName N) {
71+
std::string NameStr;
72+
raw_string_ostream OS(NameStr);
73+
LangOptions LO;
74+
LO.CPlusPlus = true;
75+
LO.Bool = true;
76+
N.print(OS, PrintingPolicy(LO));
77+
OS.flush();
78+
return DB << NameStr;
79+
}
80+
6781
void TemplateName::dump() const {
6882
LangOptions LO; // FIXME!
6983
LO.CPlusPlus = true;

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,11 +1663,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
16631663
const TemplateArgument &Arg = AL.getArgument();
16641664

16651665
// Check template type parameter.
1666-
if (Arg.getKind() != TemplateArgument::Type) {
1666+
switch(Arg.getKind()) {
1667+
case TemplateArgument::Type:
16671668
// C++ [temp.arg.type]p1:
16681669
// A template-argument for a template-parameter which is a
16691670
// type shall be a type-id.
1671+
break;
1672+
case TemplateArgument::Template: {
1673+
// We have a template type parameter but the template argument
1674+
// is a template without any arguments.
1675+
SourceRange SR = AL.getSourceRange();
1676+
TemplateName Name = Arg.getAsTemplate();
1677+
Diag(SR.getBegin(), diag::err_template_missing_args)
1678+
<< Name << SR;
1679+
if (TemplateDecl *Decl = Name.getAsTemplateDecl())
1680+
Diag(Decl->getLocation(), diag::note_template_decl_here);
16701681

1682+
return true;
1683+
}
1684+
default: {
16711685
// We have a template type parameter but the template argument
16721686
// is not a type.
16731687
SourceRange SR = AL.getSourceRange();
@@ -1676,6 +1690,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
16761690

16771691
return true;
16781692
}
1693+
}
16791694

16801695
if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
16811696
return true;

clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ namespace test1 {
3232
// Test that we don't find the injected class name when parsing base
3333
// specifiers.
3434
namespace test2 {
35-
template <class T> struct bar {}; // expected-note {{template parameter is declared here}}
36-
template <class T> struct foo : bar<foo> {}; // expected-error {{template argument for template type parameter must be a type}}
35+
template <class T> struct bar {};
36+
template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template foo requires template arguments}} expected-note {{template is declared here}}
3737
}
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
2-
template<typename T> class A; // expected-note 2 {{template parameter is declared here}}
2+
template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
33

44
// [temp.arg.type]p1
55
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
66

7-
A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
7+
A<A> *a2; // expected-error{{use of class template A requires template arguments}}
88

99
A<int> *a3;
1010
A<int()> *a4;
1111
A<int(float)> *a5;
1212
A<A<int> > *a6;
1313

14+
// Pass an overloaded function template:
15+
template<typename T> void function_tpl(T);
16+
A<function_tpl> a7; // expected-error{{template argument for template type parameter must be a type}}
17+
18+
// Pass a qualified name:
19+
namespace ns {
20+
template<typename T> class B {}; // expected-note{{template is declared here}}
21+
}
22+
A<ns::B> a8; // expected-error{{use of class template ns::B requires template arguments}}
23+
1424
// [temp.arg.type]p2
1525
void f() {
1626
class X { };
1727
A<X> * a = 0; // expected-error{{template argument uses local type 'X'}}
1828
}
1929

2030
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
21-
A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}}
31+
A<__typeof__(Unnamed)> *a9; // expected-error{{template argument uses unnamed type}}
2232

2333
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
2434
// belongs somewhere in the template instantiation section).

0 commit comments

Comments
 (0)