[cfe-commits] r64188 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp test/SemaTemplate/temp_arg_template.cpp
Douglas Gregor
dgregor at apple.com
Mon Feb 9 16:24:36 PST 2009
Author: dgregor
Date: Mon Feb 9 18:24:35 2009
New Revision: 64188
URL: http://llvm.org/viewvc/llvm-project?rev=64188&view=rev
Log:
Check template template arguments against their corresponding template
template parameters.
Added:
cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=64188&r1=64187&r2=64188&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Mon Feb 9 18:24:35 2009
@@ -479,12 +479,18 @@
"cannot declare a class template with no name")
DIAG(err_template_param_list_different_arity, ERROR,
"%select{too few|too many}0 template parameters in template %select{|template parameter }1redeclaration")
+DIAG(note_template_param_list_different_arity, NOTE,
+ "%select{too few|too many}0 template parameters in template template argument")
DIAG(note_template_prev_declaration, NOTE,
"previous template %select{declaration|template parameter}0 is here")
DIAG(err_template_param_different_kind, ERROR,
"template parameter has a different kind in template %select{|template parameter }0redeclaration")
+DIAG(note_template_param_different_kind, NOTE,
+ "template parameter has a different kind in template argument")
DIAG(err_template_nontype_parm_different_type, ERROR,
"template non-type parameter has a different type %0 in template %select{|template parameter }1redeclaration")
+DIAG(note_template_nontype_parm_different_type, NOTE,
+ "template non-type parameter has a different type %0 in template argument")
DIAG(note_template_nontype_parm_prev_declaration, NOTE,
"previous non-type template parameter with type %0 is here")
@@ -507,6 +513,12 @@
"template argument uses unnamed type")
DIAG(note_template_unnamed_type_here, NOTE,
"unnamed type used in template argument was declared here")
+DIAG(err_template_arg_not_class_template, ERROR,
+ "template argument does not refer to a class template")
+DIAG(note_template_arg_refers_here, NOTE,
+ "template argument refers to function template %0, here")
+DIAG(err_template_arg_template_params_mismatch, ERROR,
+ "template template argument has different template parameters than its corresponding template template parameter")
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name %0: expected expression")
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64188&r1=64187&r2=64188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb 9 18:24:35 2009
@@ -1538,7 +1538,9 @@
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
- bool IsTemplateTemplateParm = false);
+ bool IsTemplateTemplateParm = false,
+ SourceLocation TemplateArgLoc
+ = SourceLocation());
bool CheckTemplateDeclScope(Scope *S,
MultiTemplateParamsArg &TemplateParameterLists);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64188&r1=64187&r2=64188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb 9 18:24:35 2009
@@ -555,7 +555,27 @@
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
DeclRefExpr *Arg) {
- return false;
+ assert(isa<TemplateDecl>(Arg->getDecl()) && "Only template decls allowed");
+ TemplateDecl *Template = cast<TemplateDecl>(Arg->getDecl());
+
+ // C++ [temp.arg.template]p1:
+ // A template-argument for a template template-parameter shall be
+ // the name of a class template, expressed as id-expression. Only
+ // primary class templates are considered when matching the
+ // template template argument with the corresponding parameter;
+ // partial specializations are not considered even if their
+ // parameter lists match that of the template template parameter.
+ if (!isa<ClassTemplateDecl>(Template)) {
+ assert(isa<FunctionTemplateDecl>(Template) &&
+ "Only function templates are possible here");
+ Diag(Arg->getSourceRange().getBegin(), diag::note_template_arg_refers_here)
+ << Template;
+ }
+
+ return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
+ Param->getTemplateParameters(),
+ true, true,
+ Arg->getSourceRange().getBegin());
}
/// \brief Determine whether the given template parameter lists are
@@ -571,19 +591,35 @@
/// \param Complain If true, this routine will produce a diagnostic if
/// the template parameter lists are not equivalent.
///
+/// \param IsTemplateTemplateParm If true, this routine is being
+/// called to compare the template parameter lists of a template
+/// template parameter.
+///
+/// \param TemplateArgLoc If this source location is valid, then we
+/// are actually checking the template parameter list of a template
+/// argument (New) against the template parameter list of its
+/// corresponding template template parameter (Old). We produce
+/// slightly different diagnostics in this scenario.
+///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
bool
Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
- bool IsTemplateTemplateParm) {
+ bool IsTemplateTemplateParm,
+ SourceLocation TemplateArgLoc) {
if (Old->size() != New->size()) {
if (Complain) {
- Diag(New->getTemplateLoc(), diag::err_template_param_list_different_arity)
- << (New->size() > Old->size())
- << IsTemplateTemplateParm
- << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
+ unsigned NextDiag = diag::err_template_param_list_different_arity;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_param_list_different_arity;
+ }
+ Diag(New->getTemplateLoc(), NextDiag)
+ << (New->size() > Old->size())
+ << IsTemplateTemplateParm
+ << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
<< IsTemplateTemplateParm
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
@@ -596,7 +632,12 @@
OldParmEnd = Old->end(), NewParm = New->begin();
OldParm != OldParmEnd; ++OldParm, ++NewParm) {
if ((*OldParm)->getKind() != (*NewParm)->getKind()) {
- Diag((*NewParm)->getLocation(), diag::err_template_param_different_kind)
+ unsigned NextDiag = diag::err_template_param_different_kind;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_param_different_kind;
+ }
+ Diag((*NewParm)->getLocation(), NextDiag)
<< IsTemplateTemplateParm;
Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration)
<< IsTemplateTemplateParm;
@@ -605,8 +646,15 @@
if (isa<TemplateTypeParmDecl>(*OldParm)) {
// Okay; all template type parameters are equivalent (since we
- // know we're at the same depth/level).
-#ifndef NDEBUG
+ // know we're at the same index).
+#if 0
+ // FIXME: Enable this code in debug mode *after* we properly go
+ // through and "instantiate" the template parameter lists of
+ // template template parameters. It's only after this
+ // instantiation that (1) any dependent types within the
+ // template parameter list of the template template parameter
+ // can be checked, and (2) the template type parameter depths
+ // will match up.
QualType OldParmType
= Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm));
QualType NewParmType
@@ -623,8 +671,13 @@
if (Context.getCanonicalType(OldNTTP->getType()) !=
Context.getCanonicalType(NewNTTP->getType())) {
if (Complain) {
- Diag(NewNTTP->getLocation(),
- diag::err_template_nontype_parm_different_type)
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ Diag(NewNTTP->getLocation(), NextDiag)
<< NewNTTP->getType()
<< IsTemplateTemplateParm;
Diag(OldNTTP->getLocation(),
@@ -646,7 +699,8 @@
if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
OldTTP->getTemplateParameters(),
Complain,
- /*IsTemplateTemplateParm=*/true))
+ /*IsTemplateTemplateParm=*/true,
+ TemplateArgLoc))
return false;
}
}
Added: cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_template.cpp?rev=64188&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_template.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_arg_template.cpp Mon Feb 9 18:24:35 2009
@@ -0,0 +1,42 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<template<typename T> class X> struct A; // expected-note 2{{previous template template parameter is here}}
+
+template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}}
+
+template<template<int I> class X> struct C; // expected-note{{previous non-type template parameter with type 'int' is here}}
+
+template<class> struct X; // expected-note{{too few template parameters in template template argument}}
+template<int N> struct Y; // expected-note{{template parameter has a different kind in template argument}}
+template<long N> struct Ylong; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
+
+namespace N {
+ template<class> struct Z;
+}
+template<class, class> struct TooMany; // expected-note{{too many template parameters in template template argument}}
+
+
+A<X> *a1;
+A<N::Z> *a2;
+A< ::N::Z> *a3;
+
+A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
+ // FIXME::expected-error{{expected unqualified-id}}
+A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
+ // FIXME::expected-error{{expected unqualified-id}}
+B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
+ // FIXME::expected-error{{expected unqualified-id}}
+C<Y> *a7;
+C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
+ // FIXME::expected-error{{expected unqualified-id}}
+
+template<typename T> void f(int);
+
+// FIXME: we're right to provide an error message, but it should say
+// that we need a class template. We won't get this right until name
+// lookup of 'f' returns a TemplateDecl.
+A<f> *a9; // expected-error{{template argument for template template parameter must be a template}}
+
+// FIXME: The code below is ill-formed, because of the evil digraph '<:'.
+// We should provide a much better error message than we currently do.
+// A<::N::Z> *a10;
More information about the cfe-commits
mailing list