[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