diff options
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 99 | ||||
-rw-r--r-- | test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp | 40 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp | 17 |
3 files changed, 133 insertions, 23 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8d0462daad..08384ccef5 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3651,7 +3651,12 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, } // 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 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, 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 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, 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 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // 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; } diff --git a/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp new file mode 100644 index 0000000000..794a050258 --- /dev/null +++ b/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -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}} diff --git a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp index f5453e0844..d80182c1b6 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp @@ -14,6 +14,7 @@ struct is_same<T, T> { 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 @@ namespace FunctionTypes { 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]; +} |