/// 'class' keyword.
bool Typename : 1;
+ /// \brief Whether this template type parameter inherited its
+ /// default argument.
+ bool InheritedDefault : 1;
+
+ /// \brief The location of the default argument, if any.
+ SourceLocation DefaultArgumentLoc;
+
+ /// \brief The default template argument, if any.
+ QualType DefaultArgument;
+
TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
bool Typename, QualType Type)
- : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename) {
+ : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
+ InheritedDefault(false), DefaultArgument() {
TypeForDecl = Type.getTypePtr();
}
/// keyword.
bool wasDeclaredWithTypename() const { return Typename; }
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
+
+ /// \brief Retrieve the default argument, if any.
+ QualType getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
+
+ /// \brief Determines whether the default argument was inherited
+ /// from a previous declaration of this template.
+ bool defaultArgumentWasInherited() const { return InheritedDefault; }
+
+ /// \brief Set the default argument for this template parameter, and
+ /// whether that default argument was inherited from another
+ /// declaration.
+ void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
+ bool Inherited) {
+ DefaultArgument = DefArg;
+ DefaultArgumentLoc = DefArgLoc;
+ InheritedDefault = Inherited;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() == TemplateTypeParm;
/// @endcode
class NonTypeTemplateParmDecl
: public VarDecl, protected TemplateParmPosition {
+ /// \brief The default template argument, if any.
+ Expr *DefaultArgument;
+
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id, QualType T,
SourceLocation TSSL = SourceLocation())
: VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
- TemplateParmPosition(D, P) { }
+ TemplateParmPosition(D, P), DefaultArgument(0)
+ { }
+
public:
static NonTypeTemplateParmDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the default argument, if any.
+ Expr *getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const;
+
+ /// \brief Set the default argument for this template parameter.
+ void setDefaultArgument(Expr *DefArg) {
+ DefaultArgument = DefArg;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() == NonTypeTemplateParm;
/// name of a template and the template parameters allowable for substitution.
class TemplateTemplateParmDecl
: public TemplateDecl, protected TemplateParmPosition {
+
+ /// \brief The default template argument, if any.
+ Expr *DefaultArgument;
+
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
- TemplateParmPosition(D, P)
+ TemplateParmPosition(D, P), DefaultArgument(0)
{ }
+
public:
static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
+ /// \brief Determine whether this template parameter has a default
+ /// argument.
+ bool hasDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the default argument, if any.
+ Expr *getDefaultArgument() const { return DefaultArgument; }
+
+ /// \brief Retrieve the location of the default argument, if any.
+ SourceLocation getDefaultArgumentLoc() const;
+
+ /// \brief Set the default argument for this template parameter.
+ void setDefaultArgument(Expr *DefArg) {
+ DefaultArgument = DefArg;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() == TemplateTemplateParm;
"previous non-type template parameter with type %0 is here")
DIAG(err_template_nontype_parm_bad_type, ERROR,
"a non-type template parameter cannot have type %0")
+DIAG(err_template_param_default_arg_redefinition, ERROR,
+ "template parameter redefines default argument")
+DIAG(note_template_param_prev_default_arg, NOTE,
+ "previous default template argument defined here")
+DIAG(err_template_param_default_arg_missing, ERROR,
+ "template parameter missing a default argument")
// C++ Template Argument Lists
DIAG(err_template_arg_list_different_arity, ERROR,
/// ActOnTypeParameterDefault - Adds a default argument (the type
/// Default) to the given template type parameter (TypeParam).
- virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, TypeTy *Default) {
+ virtual void ActOnTypeParameterDefault(DeclTy *TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *Default) {
}
/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
return 0;
}
+ /// \brief Adds a default argument to the given non-type template
+ /// parameter.
+ virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default) {
+ }
+
/// ActOnTemplateTemplateParameter - Called when a C++ template template
/// parameter (e.g., "int T" in "template<template <typename> class T> class
/// Array") has been parsed. TmpLoc is the location of the "template" keyword,
return 0;
}
+ /// \brief Adds a default argument to the given template template
+ /// parameter.
+ virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default) {
+ }
+
/// ActOnTemplateParameterList - Called when a complete template
/// parameter list has been parsed, e.g.,
///
TypeSpecStartLoc);
}
+SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
+ return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+ : SourceLocation();
+}
+
//===----------------------------------------------------------------------===//
// TemplateTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
}
+SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
+ return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
+ : SourceLocation();
+}
// Grab a default type id (if given).
if(Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
+ SourceLocation DefaultLoc = Tok.getLocation();
if (TypeTy *DefaultType = ParseTypeName())
- Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
+ Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
+ DefaultType);
}
return TypeParam;
return 0;
}
- // Get the a default value, if given.
- // FIXME: I think that the results of this block need to be passed to the
- // act-on call, so we can assemble the parameter correctly.
- OwningExprResult DefaultExpr(Actions);
- if(Tok.is(tok::equal)) {
- ConsumeToken();
- DefaultExpr = ParseCXXIdExpression();
- if(DefaultExpr.isInvalid()) {
- return 0;
- }
- }
-
TemplateParamsTy *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
TemplateParams.size(),
RAngleLoc);
- return Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
- ParamList, ParamName,
- NameLoc, Depth, Position);
+ Parser::DeclTy * Param
+ = Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
+ ParamList, ParamName,
+ NameLoc, Depth, Position);
+
+ // Get the a default value, if given.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult DefaultExpr = ParseCXXIdExpression();
+ if (DefaultExpr.isInvalid())
+ return Param;
+ else if (Param)
+ Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultExpr));
+ }
+
+ return Param;
}
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
Depth, Position);
- // Is there a default value? Parsing this can be fairly annoying because
- // we have to stop on the first non-nested (paren'd) '>' as the closure
- // for the template parameter list. Or a ','.
+ // If there is a default value, parse it.
if (Tok.is(tok::equal)) {
- // TODO: Implement default non-type values.
- SkipUntil(tok::comma, tok::greater, true, true);
+ SourceLocation EqualLoc = ConsumeToken();
+
+ // C++ [temp.param]p15:
+ // When parsing a default template-argument for a non-type
+ // template-parameter, the first non-nested > is taken as the
+ // end of the template-parameter-list rather than a greater-than
+ // operator.
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+ OwningExprResult DefaultArg = ParseAssignmentExpression();
+ if (DefaultArg.isInvalid())
+ SkipUntil(tok::comma, tok::greater, true, true);
+ else if (Param)
+ Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultArg));
}
return Param;
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position);
+ virtual void ActOnTypeParameterDefault(DeclTy *TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *Default);
+
virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth,
unsigned Position);
+ virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default);
virtual DeclTy *ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc,
TemplateParamsTy *Params,
SourceLocation ParamNameLoc,
unsigned Depth,
unsigned Position);
+ virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam,
+ SourceLocation EqualLoc,
+ ExprArg Default);
+
virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation LAngleLoc,
DeclTy **Params, unsigned NumParams,
SourceLocation RAngleLoc);
-
+ bool CheckTemplateParameterList(TemplateParameterList *NewParams,
+ TemplateParameterList *OldParams);
+
virtual DeclTy *
ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
return Param;
}
+/// ActOnTypeParameterDefault - Adds a default argument (the type
+/// Default) to the given template type parameter (TypeParam).
+void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam,
+ SourceLocation EqualLoc,
+ SourceLocation DefaultLoc,
+ TypeTy *DefaultT) {
+ TemplateTypeParmDecl *Parm
+ = cast<TemplateTypeParmDecl>(static_cast<Decl *>(TypeParam));
+ QualType Default = QualType::getFromOpaquePtr(DefaultT);
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the template argument itself.
+ if (CheckTemplateArgument(Parm, Default, DefaultLoc)) {
+ Parm->setInvalidDecl();
+ return;
+ }
+
+ Parm->setDefaultArgument(Default, DefaultLoc, false);
+}
+
/// ActOnNonTypeTemplateParameter - Called when a C++ non-type
/// template parameter (e.g., "int Size" in "template<int Size>
/// class Array") has been parsed. S is the current scope and D is
return Param;
}
+/// \brief Adds a default argument to the given non-type template
+/// parameter.
+void Sema::ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParamD,
+ SourceLocation EqualLoc,
+ ExprArg DefaultE) {
+ NonTypeTemplateParmDecl *TemplateParm
+ = cast<NonTypeTemplateParmDecl>(static_cast<Decl *>(TemplateParamD));
+ Expr *Default = static_cast<Expr *>(DefaultE.get());
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the well-formedness of the default template argument.
+ if (CheckTemplateArgument(TemplateParm, Default)) {
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+
+ TemplateParm->setDefaultArgument(static_cast<Expr *>(DefaultE.release()));
+}
+
/// ActOnTemplateTemplateParameter - Called when a C++ template template
/// parameter (e.g. T in template <template <typename> class T> class array)
return Param;
}
+/// \brief Adds a default argument to the given template template
+/// parameter.
+void Sema::ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParamD,
+ SourceLocation EqualLoc,
+ ExprArg DefaultE) {
+ TemplateTemplateParmDecl *TemplateParm
+ = cast<TemplateTemplateParmDecl>(static_cast<Decl *>(TemplateParamD));
+
+ // Since a template-template parameter's default argument is an
+ // id-expression, it must be a DeclRefExpr.
+ DeclRefExpr *Default
+ = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get()));
+
+ // C++ [temp.param]p14:
+ // A template-parameter shall not be used in its own default argument.
+ // FIXME: Implement this check! Needs a recursive walk over the types.
+
+ // Check the well-formedness of the template argument.
+ if (!isa<TemplateDecl>(Default->getDecl())) {
+ Diag(Default->getSourceRange().getBegin(),
+ diag::err_template_arg_must_be_template)
+ << Default->getSourceRange();
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+ if (CheckTemplateArgument(TemplateParm, Default)) {
+ TemplateParm->setInvalidDecl();
+ return;
+ }
+
+ DefaultE.release();
+ TemplateParm->setDefaultArgument(Default);
+}
+
/// ActOnTemplateParameterList - Builds a TemplateParameterList that
/// contains the template parameters in Params/NumParams.
Sema::TemplateParamsTy *
MultiTemplateParamsArg TemplateParameterLists) {
assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
assert(TK != TK_Reference && "Can only declare or define class templates");
+ bool Invalid = false;
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParameterLists))
return 0;
}
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous class
+ // template declaration.
+ if (CheckTemplateParameterList(TemplateParams,
+ PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
+ Invalid = true;
+
// If we had a scope specifier, we better have a previous template
// declaration!
PushOnScopeChains(NewTemplate, S);
+ if (Invalid) {
+ NewTemplate->setInvalidDecl();
+ NewClass->setInvalidDecl();
+ }
return NewTemplate;
}
+/// \brief Checks the validity of a template parameter list, possibly
+/// considering the template parameter list from a previous
+/// declaration.
+///
+/// If an "old" template parameter list is provided, it must be
+/// equivalent (per TemplateParameterListsAreEqual) to the "new"
+/// template parameter list.
+///
+/// \param NewParams Template parameter list for a new template
+/// declaration. This template parameter list will be updated with any
+/// default arguments that are carried through from the previous
+/// template parameter list.
+///
+/// \param OldParams If provided, template parameter list from a
+/// previous declaration of the same template. Default template
+/// arguments will be merged from the old template parameter list to
+/// the new template parameter list.
+///
+/// \returns true if an error occurred, false otherwise.
+bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
+ TemplateParameterList *OldParams) {
+ bool Invalid = false;
+
+ // C++ [temp.param]p10:
+ // The set of default template-arguments available for use with a
+ // template declaration or definition is obtained by merging the
+ // default arguments from the definition (if in scope) and all
+ // declarations in scope in the same way default function
+ // arguments are (8.3.6).
+ bool SawDefaultArgument = false;
+ SourceLocation PreviousDefaultArgLoc;
+
+ TemplateParameterList::iterator OldParam;
+ if (OldParams)
+ OldParam = OldParams->begin();
+
+ for (TemplateParameterList::iterator NewParam = NewParams->begin(),
+ NewParamEnd = NewParams->end();
+ NewParam != NewParamEnd; ++NewParam) {
+ // Variables used to diagnose redundant default arguments
+ bool RedundantDefaultArg = false;
+ SourceLocation OldDefaultLoc;
+ SourceLocation NewDefaultLoc;
+
+ // Variables used to diagnose missing default arguments
+ bool MissingDefaultArg = false;
+
+ // Merge default arguments for template type parameters.
+ if (TemplateTypeParmDecl *NewTypeParm
+ = dyn_cast<TemplateTypeParmDecl>(*NewParam)) {
+ TemplateTypeParmDecl *OldTypeParm
+ = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
+
+ if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ NewTypeParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(),
+ OldTypeParm->getDefaultArgumentLoc(),
+ true);
+ PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc();
+ } else if (NewTypeParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+ // Merge default arguments for non-type template parameters
+ else if (NonTypeTemplateParmDecl *NewNonTypeParm
+ = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
+ NonTypeTemplateParmDecl *OldNonTypeParm
+ = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
+ if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ NewNonTypeParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ // FIXME: We need to create a new kind of "default argument"
+ // expression that points to a previous template template
+ // parameter.
+ NewNonTypeParm->setDefaultArgument(
+ OldNonTypeParm->getDefaultArgument());
+ PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc();
+ } else if (NewNonTypeParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+ // Merge default arguments for template template parameters
+ else {
+ TemplateTemplateParmDecl *NewTemplateParm
+ = cast<TemplateTemplateParmDecl>(*NewParam);
+ TemplateTemplateParmDecl *OldTemplateParm
+ = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
+ if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
+ NewTemplateParm->hasDefaultArgument()) {
+ OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc();
+ NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc();
+ SawDefaultArgument = true;
+ RedundantDefaultArg = true;
+ PreviousDefaultArgLoc = NewDefaultLoc;
+ } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
+ // Merge the default argument from the old declaration to the
+ // new declaration.
+ SawDefaultArgument = true;
+ // FIXME: We need to create a new kind of "default argument"
+ // expression that points to a previous template template
+ // parameter.
+ NewTemplateParm->setDefaultArgument(
+ OldTemplateParm->getDefaultArgument());
+ PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc();
+ } else if (NewTemplateParm->hasDefaultArgument()) {
+ SawDefaultArgument = true;
+ PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc();
+ } else if (SawDefaultArgument)
+ MissingDefaultArg = true;
+ }
+
+ if (RedundantDefaultArg) {
+ // C++ [temp.param]p12:
+ // A template-parameter shall not be given default arguments
+ // by two different declarations in the same scope.
+ Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition);
+ Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg);
+ Invalid = true;
+ } else if (MissingDefaultArg) {
+ // C++ [temp.param]p11:
+ // If a template-parameter has a default template-argument,
+ // all subsequent template-parameters shall have a default
+ // template-argument supplied.
+ Diag((*NewParam)->getLocation(),
+ diag::err_template_param_default_arg_missing);
+ Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg);
+ Invalid = true;
+ }
+ // If we have an old template parameter list that we're merging
+ // in, move on to the next parameter.
+ if (OldParams)
+ ++OldParam;
+ }
+
+ return Invalid;
+}
Action::TypeTy *
Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
// Forward declarations w/template template parameters
template <template <typename> class T> class TTP1;
template <template <typename> class> class TTP2;
-template <template <typename> class T = foo> class TTP3;
-template <template <typename> class = foo> class TTP3;
+template <template <typename> class T = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
+template <template <typename> class = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
template <template <typename X, typename Y> class T> class TTP5;
// Forward declararations with non-type params
template<int X[10]> struct A5;
template<int f(float, double)> struct A7;
+// C++ [temp.param]p11:
+template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}}
+template<typename, int> struct Y2;
+template<class T1 = int, // expected-note{{previous default template argument defined here}}
+ class T2> // expected-error{{template parameter missing a default argument}}
+ class B1;
+template<template<class> class = Y1, // expected-note{{previous default template argument defined here}}
+ template<class> class> // expected-error{{template parameter missing a default argument}}
+ class B1t;
+
+template<int N = 5, // expected-note{{previous default template argument defined here}}
+ int M> // expected-error{{template parameter missing a default argument}}
+ class B1n;
+
+// FIXME: spurious "shadow" warning!
+//template<template<class T> class = Y1,
+// template<class T> class>
+// class B1fixme;
+
+// C++ [temp.param]p10:
+template<class T1, class T2 = int> class B2;
+template<class T1 = int, class T2> class B2;
+
+template<template<class, int> class, template<class> class = Y1> class B2t;
+template<template<class, int> class = Y2, template<class> class> class B2t;
+
+template<int N, int M = 5> class B2n;
+template<int N = 5, int M> class B2n;
+
+// C++ [temp.param]p12:
+template<class T1,
+ class T2 = int> // expected-note{{previous default template argument defined here}}
+ class B3;
+template<class T1, typename T2> class B3;
+template<class T1,
+ typename T2 = float> // expected-error{{template parameter redefines default argument}}
+ class B3;
+
+template<template<class, int> class,
+ template<class> class = Y1> // expected-note{{previous default template argument defined here}}
+ class B3t;
+
+template<template<class, int> class, template<class> class> class B3t;
+
+template<template<class, int> class,
+ template<class> class = Y1> // expected-error{{template parameter redefines default argument}}
+ class B3t;
+
+template<int N,
+ int M = 5> // expected-note{{previous default template argument defined here}}
+ class B3n;
+
+template<int N, int M> class B3n;
+
+template<int N,
+ int M = 7> // expected-error{{template parameter redefines default argument}}
+ class B3n;
+
+// Check validity of default arguments
+template<template<class, int> 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;