Implement C++ DR481, which clarifies that the scope of template

parameters starts at the end of the template-parameter rather than at
the point where the template parameter name is encounted. For example,
given:

  typedef unsigned char T;
  template<typename T = T> struct X0 { };

The "T" in the default argument refers to the typedef of "unsigned
char", rather than referring to the newly-introduced template type
parameter 'T'. 

Addresses <rdar://problem/8122812>.

llvm-svn: 107354
This commit is contained in:
Douglas Gregor 2010-07-01 00:00:45 +00:00
parent 9dcde4bdec
commit dc13ded606
5 changed files with 216 additions and 210 deletions

View File

@ -1833,46 +1833,87 @@ public:
//===---------------------------C++ Templates----------------------------===// //===---------------------------C++ Templates----------------------------===//
/// ActOnTypeParameter - Called when a C++ template type parameter /// \brief Called when a C++ template type parameter(e.g., "typename T") has
/// (e.g., "typename T") has been parsed. Typename specifies whether /// been parsed.
/// the keyword "typename" was used to declare the type parameter ///
/// (otherwise, "class" was used), ellipsis specifies whether this is a /// Given
/// C++0x parameter pack, EllipsisLoc specifies the start of the ellipsis, ///
/// and KeyLoc is the location of the "class" or "typename" keyword. /// \code
// ParamName is the name of the parameter (NULL indicates an unnamed template /// template<typename T, typename U = T> struct pair;
// parameter) and ParamNameLoc is the location of the parameter name (if any) /// \endcode
/// If the type parameter has a default argument, it will be added ///
/// later via ActOnTypeParameterDefault. Depth and Position provide /// this callback will be invoked twice: once for the type parameter \c T
/// the number of enclosing templates (see /// with \p Depth=0 and \p Position=0, and once for the type parameter \c U
/// ActOnTemplateParameterList) and the number of previous /// with \p Depth=0 and \p Position=1.
/// parameters within this template parameter list. ///
/// \param Typename Specifies whether the keyword "typename" was used to
/// declare the type parameter (otherwise, "class" was used).
///
/// \param Ellipsis Specifies whether this is a C++0x parameter pack.
///
/// \param EllipsisLoc Specifies the start of the ellipsis.
///
/// \param KeyLoc The location of the "class" or "typename" keyword.
///
/// \param ParamName The name of the parameter, where NULL indicates an
/// unnamed template parameter.
///
/// \param ParamNameLoc The location of the parameter name (if any).
///
/// \param Depth The depth of this template parameter, e.g., the number of
/// template parameter lists that occurred outside the template parameter
/// list in which this template type parameter occurs.
///
/// \param Position The zero-based position of this template parameter within
/// its template parameter list, which is also the number of template
/// parameters that precede this parameter in the template parameter list.
///
/// \param EqualLoc The location of the '=' sign for the default template
/// argument, if any.
///
/// \param DefaultArg The default argument, if provided.
virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation EllipsisLoc, SourceLocation EllipsisLoc,
SourceLocation KeyLoc, SourceLocation KeyLoc,
IdentifierInfo *ParamName, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position) { unsigned Depth, unsigned Position,
SourceLocation EqualLoc,
TypeTy *DefaultArg) {
return DeclPtrTy(); return DeclPtrTy();
} }
/// ActOnTypeParameterDefault - Adds a default argument (the type /// \brief Called when a C++ non-type template parameter has been parsed.
/// Default) to the given template type parameter (TypeParam). ///
virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, /// Given
SourceLocation EqualLoc, ///
SourceLocation DefaultLoc, /// \code
TypeTy *Default) { /// template<int Size> class Array;
} /// \endcode
///
/// ActOnNonTypeTemplateParameter - Called when a C++ non-type /// This callback will be invoked for the 'Size' non-type template parameter.
/// template parameter (e.g., "int Size" in "template<int Size> ///
/// class Array") has been parsed. S is the current scope and D is /// \param S The current scope.
/// the parsed declarator. Depth and Position provide the number of ///
/// enclosing templates (see /// \param D The parsed declarator.
/// ActOnTemplateParameterList) and the number of previous ///
/// parameters within this template parameter list. /// \param Depth The depth of this template parameter, e.g., the number of
/// template parameter lists that occurred outside the template parameter
/// list in which this template type parameter occurs.
///
/// \param Position The zero-based position of this template parameter within
/// its template parameter list, which is also the number of template
/// parameters that precede this parameter in the template parameter list.
///
/// \param EqualLoc The location of the '=' sign for the default template
/// argument, if any.
///
/// \param DefaultArg The default argument, if provided.
virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth, unsigned Depth,
unsigned Position) { unsigned Position,
SourceLocation EqualLoc,
ExprArg DefaultArg) {
return DeclPtrTy(); return DeclPtrTy();
} }
@ -1883,29 +1924,50 @@ public:
ExprArg Default) { ExprArg Default) {
} }
/// ActOnTemplateTemplateParameter - Called when a C++ template template /// \brief Called when a C++ template template parameter has been parsed.
/// parameter (e.g., "int T" in "template<template <typename> class T> class ///
/// Array") has been parsed. TmpLoc is the location of the "template" keyword, /// Given
/// TemplateParams is the sequence of parameters required by the template, ///
/// ParamName is the name of the parameter (null if unnamed), and ParamNameLoc /// \code
/// is the source location of the identifier (if given). /// template<template <typename> class T> class X;
/// \endcode
///
/// this callback will be invoked for the template template parameter \c T.
///
/// \param S The scope in which this template template parameter occurs.
///
/// \param TmpLoc The location of the "template" keyword.
///
/// \param TemplateParams The template parameters required by the template.
///
/// \param ParamName The name of the parameter, or NULL if unnamed.
///
/// \param ParamNameLoc The source location of the parameter name (if given).
///
/// \param Depth The depth of this template parameter, e.g., the number of
/// template parameter lists that occurred outside the template parameter
/// list in which this template parameter occurs.
///
/// \param Position The zero-based position of this template parameter within
/// its template parameter list, which is also the number of template
/// parameters that precede this parameter in the template parameter list.
///
/// \param EqualLoc The location of the '=' sign for the default template
/// argument, if any.
///
/// \param DefaultArg The default argument, if provided.
virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S, virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc, SourceLocation TmpLoc,
TemplateParamsTy *Params, TemplateParamsTy *Params,
IdentifierInfo *ParamName, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, SourceLocation ParamNameLoc,
unsigned Depth, unsigned Depth,
unsigned Position) { unsigned Position,
SourceLocation EqualLoc,
const ParsedTemplateArgument &DefaultArg) {
return DeclPtrTy(); return DeclPtrTy();
} }
/// \brief Adds a default argument to the given template template
/// parameter.
virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam,
SourceLocation EqualLoc,
const ParsedTemplateArgument &Default) {
}
/// ActOnTemplateParameterList - Called when a complete template /// ActOnTemplateParameterList - Called when a complete template
/// parameter list has been parsed, e.g., /// parameter list has been parsed, e.g.,
/// ///

View File

@ -58,7 +58,7 @@ namespace clang {
Loc(TemplateLoc), SS(SS) { } Loc(TemplateLoc), SS(SS) { }
/// \brief Determine whether the given template argument is invalid. /// \brief Determine whether the given template argument is invalid.
bool isInvalid() { return Arg == 0; } bool isInvalid() const { return Arg == 0; }
/// \brief Determine what kind of template argument we have. /// \brief Determine what kind of template argument we have.
KindType getKind() const { return Kind; } KindType getKind() const { return Kind; }

View File

@ -471,22 +471,19 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
return DeclPtrTy(); return DeclPtrTy();
} }
DeclPtrTy TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword, // Grab a default argument (if available).
Ellipsis, EllipsisLoc, // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
KeyLoc, ParamName, NameLoc, // we introduce the type parameter into the local scope.
Depth, Position); SourceLocation EqualLoc;
TypeTy *DefaultArg = 0;
// Grab a default type id (if given).
if (Tok.is(tok::equal)) { if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken(); EqualLoc = ConsumeToken();
SourceLocation DefaultLoc = Tok.getLocation(); DefaultArg = ParseTypeName().get();
TypeResult DefaultType = ParseTypeName();
if (!DefaultType.isInvalid())
Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
DefaultType.get());
} }
return TypeParam; return Actions.ActOnTypeParameter(CurScope, TypenameKeyword, Ellipsis,
EllipsisLoc, KeyLoc, ParamName, NameLoc,
Depth, Position, EqualLoc, DefaultArg);
} }
/// ParseTemplateTemplateParameter - Handle the parsing of template /// ParseTemplateTemplateParameter - Handle the parsing of template
@ -541,28 +538,28 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
TemplateParams.size(), TemplateParams.size(),
RAngleLoc); RAngleLoc);
Parser::DeclPtrTy Param // Grab a default argument (if available).
= Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc, // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
ParamList, ParamName, // we introduce the template parameter into the local scope.
NameLoc, Depth, Position); SourceLocation EqualLoc;
ParsedTemplateArgument DefaultArg;
// Get the a default value, if given.
if (Tok.is(tok::equal)) { if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken(); EqualLoc = ConsumeToken();
ParsedTemplateArgument Default = ParseTemplateTemplateArgument(); DefaultArg = ParseTemplateTemplateArgument();
if (Default.isInvalid()) { if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(), Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template); diag::err_default_template_template_parameter_not_template);
static const tok::TokenKind EndToks[] = { static const tok::TokenKind EndToks[] = {
tok::comma, tok::greater, tok::greatergreater tok::comma, tok::greater, tok::greatergreater
}; };
SkipUntil(EndToks, 3, true, true); SkipUntil(EndToks, 3, true, true);
return Param; }
} else if (Param)
Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, Default);
} }
return Param; return Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
ParamList, ParamName,
NameLoc, Depth, Position,
EqualLoc, DefaultArg);
} }
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type /// ParseNonTypeTemplateParameter - Handle the parsing of non-type
@ -571,13 +568,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
/// template-parameter: /// template-parameter:
/// ... /// ...
/// parameter-declaration /// parameter-declaration
///
/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
/// but that didn't work out to well. Instead, this tries to recrate the basic
/// parsing of parameter declarations, but tries to constrain it for template
/// parameters.
/// FIXME: We need to make a ParseParameterDeclaration that works for
/// non-type template parameters and normal function parameters.
Parser::DeclPtrTy Parser::DeclPtrTy
Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
SourceLocation StartLoc = Tok.getLocation(); SourceLocation StartLoc = Tok.getLocation();
@ -601,13 +591,13 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
return DeclPtrTy(); return DeclPtrTy();
} }
// Create the parameter.
DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
Depth, Position);
// If there is a default value, parse it. // If there is a default value, parse it.
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
// we introduce the template parameter into the local scope.
SourceLocation EqualLoc;
OwningExprResult DefaultArg(Actions);
if (Tok.is(tok::equal)) { if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken(); EqualLoc = ConsumeToken();
// C++ [temp.param]p15: // C++ [temp.param]p15:
// When parsing a default template-argument for a non-type // When parsing a default template-argument for a non-type
@ -616,15 +606,15 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// operator. // operator.
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
OwningExprResult DefaultArg = ParseAssignmentExpression(); DefaultArg = ParseAssignmentExpression();
if (DefaultArg.isInvalid()) if (DefaultArg.isInvalid())
SkipUntil(tok::comma, tok::greater, true, true); SkipUntil(tok::comma, tok::greater, true, true);
else if (Param)
Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
move(DefaultArg));
} }
return Param; // Create the parameter.
return Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
Depth, Position, EqualLoc,
move(DefaultArg));
} }
/// \brief Parses a template-id that after the template name has /// \brief Parses a template-id that after the template name has

View File

@ -2861,29 +2861,25 @@ public:
SourceLocation KeyLoc, SourceLocation KeyLoc,
IdentifierInfo *ParamName, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position); unsigned Depth, unsigned Position,
virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, SourceLocation EqualLoc,
SourceLocation EqualLoc, TypeTy *DefaultArg);
SourceLocation DefaultLoc,
TypeTy *Default);
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth, unsigned Depth,
unsigned Position); unsigned Position,
virtual void ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParam, SourceLocation EqualLoc,
SourceLocation EqualLoc, ExprArg DefaultArg);
ExprArg Default);
virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S, virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc, SourceLocation TmpLoc,
TemplateParamsTy *Params, TemplateParamsTy *Params,
IdentifierInfo *ParamName, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, SourceLocation ParamNameLoc,
unsigned Depth, unsigned Depth,
unsigned Position); unsigned Position,
virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, SourceLocation EqualLoc,
SourceLocation EqualLoc, const ParsedTemplateArgument &DefaultArg);
const ParsedTemplateArgument &Default);
virtual TemplateParamsTy * virtual TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth, ActOnTemplateParameterList(unsigned Depth,

View File

@ -459,7 +459,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation KeyLoc, SourceLocation KeyLoc,
IdentifierInfo *ParamName, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position) { unsigned Depth, unsigned Position,
SourceLocation EqualLoc,
TypeTy *DefaultArg) {
assert(S->isTemplateParamScope() && assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!"); "Template type parameter not in template parameter scope!");
bool Invalid = false; bool Invalid = false;
@ -490,44 +492,33 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
IdResolver.AddDecl(Param); IdResolver.AddDecl(Param);
} }
// Handle the default argument, if provided.
if (DefaultArg) {
TypeSourceInfo *DefaultTInfo;
GetTypeFromParser(DefaultArg, &DefaultTInfo);
assert(DefaultTInfo && "expected source information for type");
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
// template-parameter that is not a template parameter pack.
if (Ellipsis) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
return DeclPtrTy::make(Param);
}
// Check the template argument itself.
if (CheckTemplateArgument(Param, DefaultTInfo)) {
Param->setInvalidDecl();
return DeclPtrTy::make(Param);;
}
Param->setDefaultArgument(DefaultTInfo, false);
}
return DeclPtrTy::make(Param); return DeclPtrTy::make(Param);
} }
/// ActOnTypeParameterDefault - Adds a default argument (the type
/// Default) to the given template type parameter (TypeParam).
void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam,
SourceLocation EqualLoc,
SourceLocation DefaultLoc,
TypeTy *DefaultT) {
TemplateTypeParmDecl *Parm
= cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>());
TypeSourceInfo *DefaultTInfo;
GetTypeFromParser(DefaultT, &DefaultTInfo);
assert(DefaultTInfo && "expected source information for type");
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
// template-parameter that is not a template parameter pack.
if (Parm->isParameterPack()) {
Diag(DefaultLoc, diag::err_template_param_pack_default_arg);
return;
}
// 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, DefaultTInfo)) {
Parm->setInvalidDecl();
return;
}
Parm->setDefaultArgument(DefaultTInfo, false);
}
/// \brief Check that the type of a non-type template parameter is /// \brief Check that the type of a non-type template parameter is
/// well-formed. /// well-formed.
/// ///
@ -580,13 +571,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
return QualType(); return QualType();
} }
/// 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
/// the parsed declarator.
Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
unsigned Depth, unsigned Depth,
unsigned Position) { unsigned Position,
SourceLocation EqualLoc,
ExprArg DefaultArg) {
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType(); QualType T = TInfo->getType();
@ -622,34 +611,21 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
S->AddDecl(DeclPtrTy::make(Param)); S->AddDecl(DeclPtrTy::make(Param));
IdResolver.AddDecl(Param); IdResolver.AddDecl(Param);
} }
// Check the well-formedness of the default template argument, if provided.
if (Expr *Default = static_cast<Expr *>(DefaultArg.get())) {
TemplateArgument Converted;
if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) {
Param->setInvalidDecl();
return DeclPtrTy::make(Param);;
}
Param->setDefaultArgument(DefaultArg.takeAs<Expr>(), false);
}
return DeclPtrTy::make(Param); return DeclPtrTy::make(Param);
} }
/// \brief Adds a default argument to the given non-type template
/// parameter.
void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
ExprArg DefaultE) {
NonTypeTemplateParmDecl *TemplateParm
= cast<NonTypeTemplateParmDecl>(TemplateParamD.getAs<Decl>());
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.
TemplateArgument Converted;
if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default,
Converted)) {
TemplateParm->setInvalidDecl();
return;
}
TemplateParm->setDefaultArgument(DefaultE.takeAs<Expr>(), false);
}
/// ActOnTemplateTemplateParameter - Called when a C++ template template /// ActOnTemplateTemplateParameter - Called when a C++ template template
/// parameter (e.g. T in template <template <typename> class T> class array) /// parameter (e.g. T in template <template <typename> class T> class array)
/// has been parsed. S is the current scope. /// has been parsed. S is the current scope.
@ -659,7 +635,9 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
IdentifierInfo *Name, IdentifierInfo *Name,
SourceLocation NameLoc, SourceLocation NameLoc,
unsigned Depth, unsigned Depth,
unsigned Position) { unsigned Position,
SourceLocation EqualLoc,
const ParsedTemplateArgument &Default) {
assert(S->isTemplateParamScope() && assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!"); "Template template parameter not in template parameter scope!");
@ -669,53 +647,33 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
TmpLoc, Depth, Position, Name, TmpLoc, Depth, Position, Name,
(TemplateParameterList*)Params); (TemplateParameterList*)Params);
// Make sure the parameter is valid. // If the template template parameter has a name, then link the identifier
// FIXME: Decl object is not currently invalidated anywhere so this doesn't // into the scope and lookup mechanisms.
// do anything yet. However, if the template parameter list or (eventual)
// default value is ever invalidated, that will propagate here.
bool Invalid = false;
if (Invalid) {
Param->setInvalidDecl();
}
// If the tt-param has a name, then link the identifier into the scope
// and lookup mechanisms.
if (Name) { if (Name) {
S->AddDecl(DeclPtrTy::make(Param)); S->AddDecl(DeclPtrTy::make(Param));
IdResolver.AddDecl(Param); IdResolver.AddDecl(Param);
} }
return DeclPtrTy::make(Param); 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
/// \brief Adds a default argument to the given template template // might have dependent types in its template parameters, which we wouldn't
/// parameter. // be able to match now.
void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, //
SourceLocation EqualLoc, // If none of the template template parameter's template arguments mention
const ParsedTemplateArgument &Default) { // other template parameters, we could actually perform more checking here.
TemplateTemplateParmDecl *TemplateParm // However, it isn't worth doing.
= cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>()); TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default);
if (DefaultArg.getArgument().getAsTemplate().isNull()) {
// C++ [temp.param]p14: Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template)
// A template-parameter shall not be used in its own default argument. << DefaultArg.getSourceRange();
// FIXME: Implement this check! Needs a recursive walk over the types. return DeclPtrTy::make(Param);
}
// 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 Param->setDefaultArgument(DefaultArg, false);
// 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_class_template)
<< DefaultArg.getSourceRange();
return;
} }
TemplateParm->setDefaultArgument(DefaultArg, false); return DeclPtrTy::make(Param);
} }
/// ActOnTemplateParameterList - Builds a TemplateParameterList that /// ActOnTemplateParameterList - Builds a TemplateParameterList that