diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-07-01 00:00:45 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-07-01 00:00:45 +0000 |
commit | bb3310a5fd9c08741b5272ed2665bdeab76a99a6 (patch) | |
tree | 567270e7c70485ee0c11fc30009c3c260c9399cf | |
parent | 424b6613a9e5631d61c4c8ed2f1601457b64bfd4 (diff) |
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>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107354 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Parse/Action.h | 150 | ||||
-rw-r--r-- | include/clang/Parse/Template.h | 2 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 80 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 22 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 172 |
5 files changed, 216 insertions, 210 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index fed4361f1a..678e62e10b 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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., /// diff --git a/include/clang/Parse/Template.h b/include/clang/Parse/Template.h index 1f8ccfbf05..84f4ed96b4 100644 --- a/include/clang/Parse/Template.h +++ b/include/clang/Parse/Template.h @@ -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; } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 9e95ca9f11..64306da2bf 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -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 diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3ed2a51e07..5588db79e3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7e5377ab9a..336a7bf9d0 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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,42 +492,31 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, IdResolver.AddDecl(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; + // 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); } - - Parm->setDefaultArgument(DefaultTInfo, false); + + return DeclPtrTy::make(Param); } /// \brief Check that the type of a non-type template parameter is @@ -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); } - 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; + + // 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); } - - TemplateParm->setDefaultArgument(DefaultE.takeAs<Expr>(), false); + + return DeclPtrTy::make(Param); } - /// 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 |