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

View File

@ -58,7 +58,7 @@ namespace clang {
Loc(TemplateLoc), SS(SS) { }
/// \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.
KindType getKind() const { return Kind; }

View File

@ -471,22 +471,19 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
return DeclPtrTy();
}
DeclPtrTy TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
Ellipsis, EllipsisLoc,
KeyLoc, ParamName, NameLoc,
Depth, Position);
// Grab a default type id (if given).
// Grab a default argument (if available).
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
// we introduce the type parameter into the local scope.
SourceLocation EqualLoc;
TypeTy *DefaultArg = 0;
if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
SourceLocation DefaultLoc = Tok.getLocation();
TypeResult DefaultType = ParseTypeName();
if (!DefaultType.isInvalid())
Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
DefaultType.get());
EqualLoc = ConsumeToken();
DefaultArg = ParseTypeName().get();
}
return TypeParam;
return Actions.ActOnTypeParameter(CurScope, TypenameKeyword, Ellipsis,
EllipsisLoc, KeyLoc, ParamName, NameLoc,
Depth, Position, EqualLoc, DefaultArg);
}
/// ParseTemplateTemplateParameter - Handle the parsing of template
@ -541,28 +538,28 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
TemplateParams.size(),
RAngleLoc);
Parser::DeclPtrTy Param
= Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
ParamList, ParamName,
NameLoc, Depth, Position);
// Get the a default value, if given.
// Grab a default argument (if available).
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
// we introduce the template parameter into the local scope.
SourceLocation EqualLoc;
ParsedTemplateArgument DefaultArg;
if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
ParsedTemplateArgument Default = ParseTemplateTemplateArgument();
if (Default.isInvalid()) {
EqualLoc = ConsumeToken();
DefaultArg = ParseTemplateTemplateArgument();
if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(),
diag::err_default_template_template_parameter_not_template);
static const tok::TokenKind EndToks[] = {
tok::comma, tok::greater, tok::greatergreater
};
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
@ -571,13 +568,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
/// template-parameter:
/// ...
/// 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::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
SourceLocation StartLoc = Tok.getLocation();
@ -601,13 +591,13 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
return DeclPtrTy();
}
// Create the parameter.
DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
Depth, Position);
// 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)) {
SourceLocation EqualLoc = ConsumeToken();
EqualLoc = ConsumeToken();
// C++ [temp.param]p15:
// When parsing a default template-argument for a non-type
@ -616,15 +606,15 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// operator.
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
OwningExprResult DefaultArg = ParseAssignmentExpression();
DefaultArg = ParseAssignmentExpression();
if (DefaultArg.isInvalid())
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

View File

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

View File

@ -459,7 +459,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth, unsigned Position) {
unsigned Depth, unsigned Position,
SourceLocation EqualLoc,
TypeTy *DefaultArg) {
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
bool Invalid = false;
@ -490,44 +492,33 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
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);
}
/// 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
/// well-formed.
///
@ -580,13 +571,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
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,
unsigned Depth,
unsigned Position) {
unsigned Position,
SourceLocation EqualLoc,
ExprArg DefaultArg) {
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType();
@ -622,34 +611,21 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
S->AddDecl(DeclPtrTy::make(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);
}
/// \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
/// parameter (e.g. T in template <template <typename> class T> class array)
/// has been parsed. S is the current scope.
@ -659,7 +635,9 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
IdentifierInfo *Name,
SourceLocation NameLoc,
unsigned Depth,
unsigned Position) {
unsigned Position,
SourceLocation EqualLoc,
const ParsedTemplateArgument &Default) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
@ -669,53 +647,33 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
TmpLoc, Depth, Position, Name,
(TemplateParameterList*)Params);
// Make sure the parameter is valid.
// FIXME: Decl object is not currently invalidated anywhere so this doesn't
// 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 the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
S->AddDecl(DeclPtrTy::make(Param));
IdResolver.AddDecl(Param);
}
return DeclPtrTy::make(Param);
}
/// \brief Adds a default argument to the given template template
/// parameter.
void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD,
SourceLocation EqualLoc,
const ParsedTemplateArgument &Default) {
TemplateTemplateParmDecl *TemplateParm
= cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>());
// 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 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_class_template)
<< DefaultArg.getSourceRange();
return;
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_class_template)
<< DefaultArg.getSourceRange();
return DeclPtrTy::make(Param);
}
Param->setDefaultArgument(DefaultArg, false);
}
TemplateParm->setDefaultArgument(DefaultArg, false);
return DeclPtrTy::make(Param);
}
/// ActOnTemplateParameterList - Builds a TemplateParameterList that