[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