[cfe-commits] r123348 - in /cfe/trunk: lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 12 16:08:50 PST 2011


Author: dgregor
Date: Wed Jan 12 18:08:50 2011
New Revision: 123348

URL: http://llvm.org/viewvc/llvm-project?rev=123348&view=rev
Log:
Implement C++0x [temp.arg.template]p3, which allows slightly fuzzy
matching of variadic template template parameters to template
arguments. This paragraph was the subject of ISO C++ committee
document N2555: Extending Variadic Template Template Parameters.

Added:
    cfe/trunk/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
Modified:
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=123348&r1=123347&r2=123348&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 12 18:08:50 2011
@@ -3651,7 +3651,12 @@
   }
 
   // Check that both are parameter packs are neither are parameter packs. 
-  if (Old->isTemplateParameterPack() != New->isTemplateParameterPack()) {
+  // However, if we are matching a template template argument to a 
+  // template template parameter, the template template parameter can have
+  // a parameter pack where the template template argument does not.
+  if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() &&
+      !(Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
+        Old->isTemplateParameterPack())) {
     if (Complain) {
       unsigned NextDiag = diag::err_template_parameter_pack_non_pack;
       if (TemplateArgLoc.isValid()) {
@@ -3726,6 +3731,28 @@
   return true;
 }
 
+/// \brief Diagnose a known arity mismatch when comparing template argument
+/// lists.
+static
+void DiagnoseTemplateParameterListArityMismatch(Sema &S, 
+                                                TemplateParameterList *New,
+                                                TemplateParameterList *Old,
+                                      Sema::TemplateParameterListEqualKind Kind,
+                                                SourceLocation TemplateArgLoc) {
+  unsigned NextDiag = diag::err_template_param_list_different_arity;
+  if (TemplateArgLoc.isValid()) {
+    S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch);
+    NextDiag = diag::note_template_param_list_different_arity;
+  }
+  S.Diag(New->getTemplateLoc(), NextDiag)
+    << (New->size() > Old->size())
+    << (Kind != Sema::TPL_TemplateMatch)
+    << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
+  S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+    << (Kind != Sema::TPL_TemplateMatch)
+    << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
+}
+
 /// \brief Determine whether the given template parameter lists are
 /// equivalent.
 ///
@@ -3755,21 +3782,10 @@
                                      bool Complain,
                                      TemplateParameterListEqualKind Kind,
                                      SourceLocation TemplateArgLoc) {
-  if (Old->size() != New->size()) {
-    if (Complain) {
-      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())
-          << (Kind != TPL_TemplateMatch)
-          << SourceRange(New->getTemplateLoc(), New->getRAngleLoc());
-      Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
-        << (Kind != TPL_TemplateMatch)
-        << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
-    }
+  if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
+    if (Complain)
+      DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
+                                                 TemplateArgLoc);
 
     return false;
   }
@@ -3779,15 +3795,52 @@
   //   when each of the template parameters in the template-parameter-list of 
   //   the template-argument’s corresponding class template or template alias
   //   (call it A) matches the corresponding template parameter in the 
-  //   template-parameter-list of P.
+  //   template-parameter-list of P. [...]
+  TemplateParameterList::iterator NewParm = New->begin();
+  TemplateParameterList::iterator NewParmEnd = New->end();
   for (TemplateParameterList::iterator OldParm = Old->begin(),
-         OldParmEnd = Old->end(), NewParm = New->begin();
-       OldParm != OldParmEnd; ++OldParm, ++NewParm) {
-    if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
-                                    Kind, TemplateArgLoc))
-      return false;    
+                                    OldParmEnd = Old->end();
+       OldParm != OldParmEnd; ++OldParm) {
+    if (!(*OldParm)->isTemplateParameterPack()) {
+      if (NewParm == NewParmEnd) {
+        if (Complain)
+          DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
+                                                     TemplateArgLoc);
+        
+        return false;
+      }
+      
+      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
+                                      Kind, TemplateArgLoc))
+        return false;    
+      
+      ++NewParm;
+      continue;
+    }
+    
+    // C++0x [temp.arg.template]p3:
+    //   [...] When P’s template- parameter-list contains a template parameter
+    //   pack (14.5.3), the template parameter pack will match zero or more 
+    //   template parameters or template parameter packs in the 
+    //   template-parameter-list of A with the same type and form as the
+    //   template parameter pack in P (ignoring whether those template
+    //   parameters are template parameter packs).
+    for (; NewParm != NewParmEnd; ++NewParm) {
+      if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
+                                      Kind, TemplateArgLoc))
+        return false;          
+    }
   }
-
+  
+  // Make sure we exhausted all of the arguments.
+  if (NewParm != NewParmEnd) {
+    if (Complain)
+      DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
+                                                 TemplateArgLoc);
+      
+    return false;
+  }
+  
   return true;
 }
 

Added: cfe/trunk/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp?rev=123348&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp Wed Jan 12 18:08:50 2011
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template <class T> struct eval; // expected-note 3{{template is declared here}}
+
+template <template <class, class...> class TT, class T1, class... Rest> 
+struct eval<TT<T1, Rest...>> { };
+
+template <class T1> struct A; 
+template <class T1, class T2> struct B; 
+template <int N> struct C; 
+template <class T1, int N> struct D; 
+template <class T1, class T2, int N = 17> struct E;
+
+eval<A<int>> eA;
+eval<B<int, float>> eB;
+eval<C<17>> eC; // expected-error{{implicit instantiation of undefined template 'eval<C<17> >'}}
+eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined template 'eval<D<int, 17> >'}}
+eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float, 17> >}}
+
+template<template <int ...N> class TT> struct X0 { }; // expected-note{{previous non-type template parameter with type 'int' is here}}
+template<int I, int J, int ...Rest> struct X0a;
+template<int ...Rest> struct X0b;
+template<int I, long J> struct X0c; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
+
+X0<X0a> inst_x0a;
+X0<X0b> inst_x0b;
+X0<X0c> inst_x0c; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+
+template<typename T, 
+         template <T ...N> class TT>  // expected-note{{previous non-type template parameter with type 'short' is here}}
+struct X1 { };
+template<int I, int J, int ...Rest> struct X1a;
+template<long I, long ...Rest> struct X1b;
+template<short I, short J> struct X1c;
+template<short I, long J> struct X1d; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
+
+X1<int, X1a> inst_x1a;
+X1<long, X1b> inst_x1b;
+X1<short, X1c> inst_x1c;
+X1<short, X1d> inst_x1d; // expected-error{{template template argument has different template parameters than its corresponding template template paramete}}

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp?rev=123348&r1=123347&r2=123348&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp Wed Jan 12 18:08:50 2011
@@ -14,6 +14,7 @@
 
 template<typename...> struct tuple { };
 template<int ...> struct int_tuple { };
+template<typename T, typename U> struct pair { };
 
 namespace Count {
   template<typename Head, typename ...Tail>
@@ -255,3 +256,19 @@
   int check3[Arity<int(float, double, long double...)>::value == 3? 1 : -1];
   Arity<int(float, double, long double, char)> check4; // expected-error{{implicit instantiation of undefined template 'FunctionTypes::Arity<int (float, double, long double, char)>'}}
 }
+
+namespace SuperReplace {
+  template<typename T>
+  struct replace_with_int {
+    typedef int type;
+  };
+  
+  template<template<typename ...> class TT, typename ...Types>
+  struct replace_with_int<TT<Types...>> {
+    typedef TT<typename replace_with_int<Types>::type...> type;
+  };
+  
+  int check0[is_same<replace_with_int<pair<tuple<float, double, short>,
+                                           pair<char, unsigned char>>>::type,
+                     pair<tuple<int, int, int>, pair<int, int>>>::value? 1 : -1];
+}





More information about the cfe-commits mailing list