Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5848,9 +5848,10 @@ QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateArgumentLoc &Arg, - unsigned ArgumentPackIndex); + bool CheckTemplateArgument( + TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex, + bool IsCheckingDefaultArgumentAtTemplateDefinitionTime = false); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, @@ -5891,7 +5892,28 @@ /// template struct integer_c; /// X xic; /// \endcode - TPL_TemplateTemplateArgumentMatch + /// NOTE: Any enumerator that follows this one, implies it (i.e OK to use + /// '<' or '>' to check for implication) + TPL_TemplateTemplateArgumentMatch, + + /// \brief We are matching the template parameter lists of a dependent + /// default template template argument (i.e. 'TT' below) against the + /// template parameter lists of a template template parameter. + /// + /// \code + /// template class TT> struct X { + /// template class UU = TT> struct Y; + /// } + /// template struct Q; + /// X::Y<> y; // OK + /// \endcode + /// + /// This enum MUST follow TPL_TemplateTemplateArgumentMatch since it implies + /// that. + TPL_DependentTemplateTemplateArgumentMatchAtTemplateDefinition + + /// NOTE: Any enumerator added here, implies + /// TPL_TemplateTemplateArgumentMatch }; bool TemplateParameterListsAreEqual(TemplateParameterList *New, Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -790,14 +790,6 @@ } if (!Default.isInvalid()) { - // Check only that we have a template template argument. We don't want to - // try to check well-formedness now, because our template template parameter - // might have dependent types in its template parameters, which we wouldn't - // be able to match now. - // - // If none of the template template parameter's template arguments mention - // other template parameters, we could actually perform more checking here. - // However, it isn't worth doing. TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default); if (DefaultArg.getArgument().getAsTemplate().isNull()) { Diag(DefaultArg.getLocation(), diag::err_template_arg_not_valid_template) @@ -810,7 +802,12 @@ DefaultArg.getArgument().getAsTemplate(), UPPC_DefaultArgument)) return Param; - + // Check that the default template template argument is compatible with + // the template template parameter, in as much as we can check at this + // time. + if (CheckTemplateArgument(Param, DefaultArg, /*ArgumentPackIndex*/ 0, + /*IsCheckingDefaultArgumentAtTemplateDefinitionTime*/ true)) + return Param; Param->setDefaultArgument(Context, DefaultArg); } @@ -5324,9 +5321,10 @@ /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateArgumentLoc &Arg, - unsigned ArgumentPackIndex) { +bool Sema::CheckTemplateArgument( + TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, + const unsigned ArgumentPackIndex, + const bool IsCheckingDefaultArgumentAtTemplateDefinitionTime) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { @@ -5346,7 +5344,8 @@ // // Note that we also allow template template parameters here, which // will happen when we are dealing with, e.g., class template - // partial specializations. + // partial specializations or default template template arguments that + // are template template parameters from enclosing class templates. if (!isa(Template) && !isa(Template) && !isa(Template)) { @@ -5360,11 +5359,16 @@ TemplateParameterList *Params = Param->getTemplateParameters(); if (Param->isExpandedParameterPack()) Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); - + TemplateParameterListEqualKind Kind = + IsCheckingDefaultArgumentAtTemplateDefinitionTime + ? (isa(Template) + ? TPL_DependentTemplateTemplateArgumentMatchAtTemplateDefinition + : TPL_TemplateTemplateArgumentMatch) + : TPL_TemplateTemplateArgumentMatch; return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Params, true, - TPL_TemplateTemplateArgumentMatch, + Kind, Arg.getLocation()); } @@ -5572,11 +5576,19 @@ return false; } - // Check that both are parameter packs are neither are parameter packs. - // 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. + // Check that both are parameter packs or neither are parameter packs. + // However, if we are matching a template template argument (A) to a + // template template parameter (P): + // - if 'A' is a default template template argument that is itself an + // enclosing template template parameter then if either one has a pack, + // do not check it at template definition time + // (i.e. TPL_DependentTemplateTemplateArgumentMatchAtTemplateDefinition) + // - otherwise, 'P' can have a parameter pack where 'A' does not. + if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() && + Kind != + Sema:: + TPL_DependentTemplateTemplateArgumentMatchAtTemplateDefinition && !(Kind == Sema::TPL_TemplateTemplateArgumentMatch && Old->isTemplateParameterPack())) { if (Complain) { @@ -5608,7 +5620,7 @@ // template parameter and one of the non-type template parameter types // is dependent, then we must wait until template instantiation time // to actually compare the arguments. - if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && + if (Kind >= Sema::TPL_TemplateTemplateArgumentMatch && (OldNTTP->getType()->isDependentType() || NewNTTP->getType()->isDependentType())) return true; @@ -5704,7 +5716,7 @@ bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { - if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) { + if (Old->size() != New->size() && Kind < TPL_TemplateTemplateArgumentMatch) { if (Complain) DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, TemplateArgLoc); @@ -5723,7 +5735,7 @@ for (TemplateParameterList::iterator OldParm = Old->begin(), OldParmEnd = Old->end(); OldParm != OldParmEnd; ++OldParm) { - if (Kind != TPL_TemplateTemplateArgumentMatch || + if (Kind < TPL_TemplateTemplateArgumentMatch || !(*OldParm)->isTemplateParameterPack()) { if (NewParm == NewParmEnd) { if (Complain) Index: test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp =================================================================== --- test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp +++ test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -38,3 +38,116 @@ X1 inst_x1b; X1 inst_x1c; X1 inst_x1d; // expected-error{{template template argument has different template parameters than its corresponding template template paramete}} + + +namespace ns0 { +template using TA = int*; +template class TT = TA> struct X; + +} + + +namespace ns1 { +template class TT> //expected-note{{too many template parameters}} +struct X { + template //expected-note{{previous template template parameter is here}} + class UU = TT> //expected-error{{different template parameters}} + struct Y; +}; +} // end ns1 +namespace ns2 { +template class TT> +struct A { + template class UU = TT> + struct B; +}; +} // end ns2 +namespace ns3 { +template class TT> struct A { + template class UU = T::template X> struct B { }; +}; +} // end ns3 +namespace ns4 { +template class TT> +struct A { + template + class UU = TT> // OK + struct B; +}; +template struct Q; +A::B *b; // OK + +namespace ns4_0 { +template class TT> +struct A { + template + class UU = TT> // OK + struct B; +}; +template struct Q; +A::B *b; +} // end ns4_0 + +namespace ns4_1 { +template class> class TT> +struct A { + template class> + class UU = TT> // OK + struct B; +}; + +} // end ns4_0 + +} // end ns4 + +namespace ns5 { +template class TT> +struct A { + template + class UU = TT> + struct B; +}; + + +} // end ns5 + +namespace ns6 { + +template class A> +struct X { + template class = A> struct Y {}; +}; + +} // end ns6 + + +namespace ns7 { + +template class A> +struct X; + +template class A> struct X { + using type = char*; +}; +template struct Q; +X::type *pc; + +} // end ns6 + +namespace ns8 { +// NOTE: This test for partial specializations is added here to remind us +// that these cases are somewhat similar, yet not without differences. +// Even though for default arguments at template defintion we allow +// the contravariant case (a pack on argument is compatible with a non-pack +// on the parameter) in the partial specialization setting, we do not allow it. +template class A> //expected-note{{declared here}} +struct X {}; + +template class A> //expected-note{{pack does not match}} +struct X { //expected-error{{different template parameters than its corresponding template template parameter}} + using type = char*; +}; + +} // end ns6 + + Index: test/CXX/temp/temp.param/p10-0x.cpp =================================================================== --- test/CXX/temp/temp.param/p10-0x.cpp +++ test/CXX/temp/temp.param/p10-0x.cpp @@ -8,7 +8,7 @@ template using B2 = T1; template class F, template class G = Y1> using B2t = F>; -template class F = Y2, template class G> using B2t = F>; +template class F = Y1, template class G> using B2t = F>; template using B2n = Y2; template using B2n = Y2; Index: test/CXX/temp/temp.param/p12.cpp =================================================================== --- test/CXX/temp/temp.param/p12.cpp +++ test/CXX/temp/temp.param/p12.cpp @@ -34,6 +34,6 @@ // Check validity of default arguments template class // expected-note{{previous template template parameter is here}} = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} - class C1 {}; + class C1 {}; //expected-note{{template is declared here}} -C1<> c1; // expected-note{{while checking a default template argument}} +C1<> c1; // expected-error{{too few template arguments}}