From: Douglas Gregor Date: Wed, 11 Nov 2009 01:00:40 +0000 (+0000) Subject: Introduce a new representation for template template X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=788cd06cf8e868a67158aafec5de3a1f408d14f3;p=clang Introduce a new representation for template template parameters. Rather than storing them as either declarations (for the non-dependent case) or expressions (for the dependent case), we now (always) store them as TemplateNames. The primary change here is to add a new kind of TemplateArgument, which stores a TemplateName. However, making that change ripples to every switch on a TemplateArgument's kind, also affecting TemplateArgumentLocInfo/TemplateArgumentLoc, default template arguments for template template parameters, type-checking of template template arguments, etc. This change is light on testing. It should fix several pre-existing problems with template template parameters, such as: - the inability to use dependent template names as template template arguments - template template parameter default arguments cannot be instantiation However, there are enough pieces missing that more implementation is required before we can adequately test template template parameters. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86777 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index f1a27933a1..14f666005c 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -699,13 +699,13 @@ class TemplateTemplateParmDecl : public TemplateDecl, protected TemplateParmPosition { /// \brief The default template argument, if any. - Expr *DefaultArgument; + TemplateArgumentLoc DefaultArgument; TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), DefaultArgument(0) + TemplateParmPosition(D, P), DefaultArgument() { } public: @@ -720,16 +720,17 @@ public: /// \brief Determine whether this template parameter has a default /// argument. - bool hasDefaultArgument() const { return DefaultArgument; } + bool hasDefaultArgument() const { + return !DefaultArgument.getArgument().isNull(); + } /// \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; + const TemplateArgumentLoc &getDefaultArgument() const { + return DefaultArgument; + } /// \brief Set the default argument for this template parameter. - void setDefaultArgument(Expr *DefArg) { + void setDefaultArgument(const TemplateArgumentLoc &DefArg) { DefaultArgument = DefArg; } diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index bb14c62d77..6db095872b 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -18,6 +18,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/Support/ErrorHandling.h" #include "clang/AST/Type.h" +#include "clang/AST/TemplateName.h" namespace llvm { class FoldingSetNodeID; @@ -48,21 +49,27 @@ class TemplateArgument { public: /// \brief The type of template argument we're storing. enum ArgKind { + /// \brief Represents an empty template argument, e.g., one that has not + /// been deduced. Null = 0, /// The template argument is a type. Its value is stored in the /// TypeOrValue field. - Type = 1, - /// The template argument is a declaration - Declaration = 2, - /// The template argument is an integral value stored in an llvm::APSInt. - Integral = 3, + Type, + /// The template argument is a declaration that was provided for a pointer + /// or reference non-type template parameter. + Declaration, + /// The template argument is an integral value stored in an llvm::APSInt + /// that was provided for an integral non-type template parameter. + Integral, + /// The template argument is a template name that was provided for a + /// template template parameter. + Template, /// The template argument is a value- or type-dependent expression /// stored in an Expr*. - Expression = 4, - + Expression, /// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. - Pack = 5 + Pack } Kind; /// \brief Construct an empty, invalid template argument. @@ -82,12 +89,21 @@ public: } /// \brief Construct an integral constant template argument. - TemplateArgument(const llvm::APSInt &Value, QualType Type) - : Kind(Integral) { + TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) { new (Integer.Value) llvm::APSInt(Value); Integer.Type = Type.getAsOpaquePtr(); } + /// \brief Construct a template argument that is a template. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + TemplateArgument(TemplateName Name) : Kind(Template) { + TypeOrValue = reinterpret_cast(Name.getAsVoidPointer()); + } + /// \brief Construct a template argument that is an expression. /// /// This form of template argument only occurs in template argument @@ -172,6 +188,15 @@ public: return reinterpret_cast(TypeOrValue); } + /// \brief Retrieve the template argument as a template name. + TemplateName getAsTemplate() const { + if (Kind != Template) + return TemplateName(); + + return TemplateName::getFromVoidPointer( + reinterpret_cast (TypeOrValue)); + } + /// \brief Retrieve the template argument as an integral value. llvm::APSInt *getAsIntegral() { if (Kind != Integral) @@ -242,13 +267,18 @@ private: union { Expr *Expression; DeclaratorInfo *Declarator; + struct { + unsigned QualifierRange[2]; + unsigned TemplateNameLoc; + } Template; }; #ifndef NDEBUG enum Kind { K_None, K_DeclaratorInfo, - K_Expression + K_Expression, + K_Template } Kind; #endif @@ -273,6 +303,17 @@ public: , Kind(K_Expression) #endif {} + + TemplateArgumentLocInfo(SourceRange QualifierRange, + SourceLocation TemplateNameLoc) +#ifndef NDEBUG + : Kind(K_Template) +#endif + { + Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding(); + Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding(); + Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); + } DeclaratorInfo *getAsDeclaratorInfo() const { assert(Kind == K_DeclaratorInfo); @@ -284,6 +325,18 @@ public: return Expression; } + SourceRange getTemplateQualifierRange() const { + assert(Kind == K_Template); + return SourceRange( + SourceLocation::getFromRawEncoding(Template.QualifierRange[0]), + SourceLocation::getFromRawEncoding(Template.QualifierRange[1])); + } + + SourceLocation getTemplateNameLoc() const { + assert(Kind == K_Template); + return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc); + } + #ifndef NDEBUG void validateForArgument(const TemplateArgument &Arg) { switch (Arg.getKind()) { @@ -294,6 +347,9 @@ public: case TemplateArgument::Declaration: assert(Kind == K_Expression); break; + case TemplateArgument::Template: + assert(Kind == K_Template); + break; case TemplateArgument::Integral: case TemplateArgument::Pack: assert(Kind == K_None); @@ -329,8 +385,18 @@ public: assert(Argument.getKind() == TemplateArgument::Expression); } - /// \brief - Fetches the start location of the argument. + TemplateArgumentLoc(const TemplateArgument &Argument, + SourceRange QualifierRange, + SourceLocation TemplateNameLoc) + : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) { + assert(Argument.getKind() == TemplateArgument::Template); + } + + /// \brief - Fetches the primary location of the argument. SourceLocation getLocation() const { + if (Argument.getKind() == TemplateArgument::Template) + return getTemplateNameLoc(); + return getSourceRange().getBegin(); } @@ -359,6 +425,16 @@ public: assert(Argument.getKind() == TemplateArgument::Declaration); return LocInfo.getAsExpr(); } + + SourceRange getTemplateQualifierRange() const { + assert(Argument.getKind() == TemplateArgument::Template); + return LocInfo.getTemplateQualifierRange(); + } + + SourceLocation getTemplateNameLoc() const { + assert(Argument.getKind() == TemplateArgument::Template); + return LocInfo.getTemplateNameLoc(); + } }; } diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index da7857822e..a06b9b82d0 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -919,6 +919,10 @@ public: Info = TemplateArgumentLocInfo((DeclaratorInfo*) 0); break; + case TemplateArgument::Template: + Info = TemplateArgumentLocInfo(SourceRange(), SourceLocation()); + break; + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 036d887865..28c46cd2d7 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -289,6 +289,10 @@ def err_explicit_spec_non_template : Error< def err_variadic_templates : Error< "variadic templates are only allowed in C++0x">; +def err_default_template_template_parameter_not_template : Error< + "default template argument for a template template parameter must be a class " + "template">; + // C++ declarations def err_friend_decl_defines_class : Error< "cannot define a type in a friend declaration">; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 4886970c74..ceeb9c40e5 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1577,7 +1577,7 @@ public: /// parameter. virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, SourceLocation EqualLoc, - ExprArg Default) { + const ParsedTemplateArgument &Default) { } /// ActOnTemplateParameterList - Called when a complete template diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index dd939a98bf..548d746859 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1371,6 +1371,7 @@ private: bool AllowTypeAnnotation = true); void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0); bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); + ParsedTemplateArgument ParseTemplateTemplateArgument(); ParsedTemplateArgument ParseTemplateArgument(); DeclPtrTy ParseExplicitInstantiation(SourceLocation ExternLoc, SourceLocation TemplateLoc, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index bb3559b50f..b5d9cac9fa 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2357,12 +2357,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { return Arg; case TemplateArgument::Expression: - // FIXME: Build canonical expression? return Arg; case TemplateArgument::Declaration: return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); + case TemplateArgument::Template: + return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); + case TemplateArgument::Integral: return TemplateArgument(*Arg.getAsIntegral(), getCanonicalType(Arg.getIntegralType())); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 9ebc91afe1..0c14714812 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -220,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast(*Param); - TemplateArgs.push_back(TemplateArgument(TTP)); + TemplateArgs.push_back(TemplateArgument(TemplateName(TTP))); } } @@ -285,11 +285,6 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); } -SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { - return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); -} - //===----------------------------------------------------------------------===// // TemplateArgumentListBuilder Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 02e0c74bb6..4458c2b9cd 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -695,6 +695,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { VisitType(Arg.getAsType()); break; + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplate()); + break; + case TemplateArgument::Declaration: VisitDecl(Arg.getAsDecl()); break; diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 94e1ca1e06..18a574c89c 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -58,6 +58,10 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); break; + case Template: + ID.AddPointer(getAsTemplate().getAsVoidPointer()); + break; + case Integral: getAsIntegral()->Profile(ID); getIntegralType().Profile(ID); @@ -82,10 +86,19 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: return getSourceExpression()->getSourceRange(); + case TemplateArgument::Declaration: return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::Type: return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + + case TemplateArgument::Template: + if (getTemplateQualifierRange().isValid()) + return SourceRange(getTemplateQualifierRange().getBegin(), + getTemplateNameLoc()); + return SourceRange(getTemplateNameLoc()); + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 844589fd3e..5ecc33cd8f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -807,6 +807,9 @@ static bool isDependent(const TemplateArgument &Arg) { case TemplateArgument::Type: return Arg.getAsType()->isDependentType(); + case TemplateArgument::Template: + return Arg.getAsTemplate().isDependent(); + case TemplateArgument::Declaration: case TemplateArgument::Integral: // Never dependent diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 807f7d86c5..ed12006211 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -576,6 +576,11 @@ static void PrintTemplateArgument(std::string &Buffer, Buffer = cast(Arg.getAsDecl())->getNameAsString(); break; + case TemplateArgument::Template: { + llvm::raw_string_ostream s(Buffer); + Arg.getAsTemplate().print(s, Policy); + } + case TemplateArgument::Integral: Buffer = Arg.getAsIntegral()->toString(10, true); break; diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 5cee9884ce..394d35891d 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2185,6 +2185,14 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, return ReadDeclExpr(); case TemplateArgument::Type: return GetDeclaratorInfo(Record, Index); + case TemplateArgument::Template: { + SourceLocation + QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), + QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]), + TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]); + return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd), + TemplateNameLoc); + } case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 82922a93b5..2dcb8b0cee 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -2122,6 +2122,12 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, case TemplateArgument::Type: AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); break; + case TemplateArgument::Template: + Record.push_back( + Arg.getTemplateQualifierRange().getBegin().getRawEncoding()); + Record.push_back(Arg.getTemplateQualifierRange().getEnd().getRawEncoding()); + Record.push_back(Arg.getTemplateNameLoc().getRawEncoding()); + break; case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index cf7d511697..b5063ee44b 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -485,12 +485,17 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Get the a default value, if given. if (Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult DefaultExpr = ParseCXXIdExpression(); - if (DefaultExpr.isInvalid()) + ParsedTemplateArgument Default = ParseTemplateTemplateArgument(); + if (Default.isInvalid()) { + Diag(Tok.getLocation(), + diag::err_default_template_template_parameter_not_template); + static tok::TokenKind EndToks[] = { + tok::comma, tok::greater, tok::greatergreater + }; + SkipUntil(EndToks, 3, true, true); return Param; - else if (Param) - Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, - move(DefaultExpr)); + } else if (Param) + Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, Default); } return Param; @@ -808,33 +813,16 @@ static bool isEndOfTemplateArgument(Token Tok) { Tok.is(tok::greatergreater); } -/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). -/// -/// template-argument: [C++ 14.2] -/// constant-expression -/// type-id -/// id-expression -ParsedTemplateArgument Parser::ParseTemplateArgument() { - // C++ [temp.arg]p2: - // In a template-argument, an ambiguity between a type-id and an - // expression is resolved to a type-id, regardless of the form of - // the corresponding template-parameter. - // - // Therefore, we initially try to parse a type-id. - if (isCXXTypeId(TypeIdAsTemplateArgument)) { - SourceLocation Loc = Tok.getLocation(); - TypeResult TypeArg = ParseTypeName(); - if (TypeArg.isInvalid()) - return ParsedTemplateArgument(); - - return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), - Loc); - } +/// \brief Parse a C++ template template argument. +ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { + if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && + !Tok.is(tok::annot_cxxscope)) + return ParsedTemplateArgument(); // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be the name // of a class template or a template alias, expressed as id-expression. - // + // // We perform some tentative parsing at this point, to determine whether // we have an id-expression that refers to a class template or template // alias. The grammar we tentatively parse is: @@ -843,63 +831,92 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // // followed by a token that terminates a template argument, such as ',', // '>', or (in some cases) '>>'. - if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - Tok.is(tok::annot_cxxscope)) { - TentativeParsingAction TPA(*this); - CXXScopeSpec SS; // nested-name-specifier, if present - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, - /*EnteringContext=*/false); - - if (SS.isSet() && Tok.is(tok::kw_template)) { - // Parse the optional 'template' keyword following the - // nested-name-specifier. - SourceLocation TemplateLoc = ConsumeToken(); - - if (Tok.is(tok::identifier)) { - // We appear to have a dependent template name. - UnqualifiedId Name; - Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); // the identifier - - // If the next token signals the end of a template argument, - // then we have a dependent template name that could be a template - // template argument. - if (isEndOfTemplateArgument(Tok)) { - TemplateTy Template - = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, - /*ObjectType=*/0); - if (Template.get()) { - TPA.Commit(); - return ParsedTemplateArgument(SS, Template, Name.StartLocation); - } - } - } - } else if (Tok.is(tok::identifier)) { - // We may have a (non-dependent) template name. - TemplateTy Template; + TentativeParsingAction TPA(*this); + CXXScopeSpec SS; // nested-name-specifier, if present + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + /*EnteringContext=*/false); + + if (SS.isSet() && Tok.is(tok::kw_template)) { + // Parse the optional 'template' keyword following the + // nested-name-specifier. + SourceLocation TemplateLoc = ConsumeToken(); + + if (Tok.is(tok::identifier)) { + // We appear to have a dependent template name. UnqualifiedId Name; Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); // the identifier - + + // If the next token signals the end of a template argument, + // then we have a dependent template name that could be a template + // template argument. if (isEndOfTemplateArgument(Tok)) { - TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, - /*ObjectType=*/0, - /*EnteringContext=*/false, - Template); - if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { - // We have an id-expression that refers to a class template or - // (C++0x) template alias. + TemplateTy Template + = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, + /*ObjectType=*/0); + if (Template.get()) { TPA.Commit(); return ParsedTemplateArgument(SS, Template, Name.StartLocation); } } + } + } else if (Tok.is(tok::identifier)) { + // We may have a (non-dependent) template name. + TemplateTy Template; + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + if (isEndOfTemplateArgument(Tok)) { + TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, + /*ObjectType=*/0, + /*EnteringContext=*/false, + Template); + if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { + // We have an id-expression that refers to a class template or + // (C++0x) template alias. + TPA.Commit(); + return ParsedTemplateArgument(SS, Template, Name.StartLocation); + } } + } + + // We don't have a template template argument; revert everything we have + // tentatively parsed. + TPA.Revert(); + + return ParsedTemplateArgument(); +} + +/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). +/// +/// template-argument: [C++ 14.2] +/// constant-expression +/// type-id +/// id-expression +ParsedTemplateArgument Parser::ParseTemplateArgument() { + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and an + // expression is resolved to a type-id, regardless of the form of + // the corresponding template-parameter. + // + // Therefore, we initially try to parse a type-id. + if (isCXXTypeId(TypeIdAsTemplateArgument)) { + SourceLocation Loc = Tok.getLocation(); + TypeResult TypeArg = ParseTypeName(); + if (TypeArg.isInvalid()) + return ParsedTemplateArgument(); - // We don't have a template template argument; revert everything we have - // tentatively parsed. - TPA.Revert(); + return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), + Loc); } + // Try to parse a template template argument. + ParsedTemplateArgument TemplateTemplateArgument + = ParseTemplateTemplateArgument(); + if (!TemplateTemplateArgument.isInvalid()) + return TemplateTemplateArgument; + // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); OwningExprResult ExprArg = ParseConstantExpression(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 90f580618a..6c88995a1b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2446,7 +2446,7 @@ public: unsigned Position); virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, SourceLocation EqualLoc, - ExprArg Default); + const ParsedTemplateArgument &Default); virtual TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, @@ -2606,13 +2606,14 @@ public: bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + const TemplateArgumentLoc &Arg); bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, bool IsTemplateTemplateParm = false, SourceLocation TemplateArgLoc - = SourceLocation()); + = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 13a66aaca0..4f261383ad 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1219,12 +1219,13 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, AssociatedClasses); break; - case TemplateArgument::Declaration: + case TemplateArgument::Template: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as // template template arguments are defined. + TemplateName Template = Arg.getAsTemplate(); if (ClassTemplateDecl *ClassTemplate - = dyn_cast(Arg.getAsDecl())) { + = dyn_cast(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) AssociatedClasses.insert(EnclosingClass); @@ -1234,7 +1235,9 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, CollectNamespace(AssociatedNamespaces, Ctx); } break; - + } + + case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: // [Note: non-type template arguments do not contribute to the set of diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 32a6d6c243..ce2ffc1ac1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -284,6 +284,46 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { return 0; } +static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, + const ParsedTemplateArgument &Arg) { + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: { + DeclaratorInfo *DI; + QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); + if (!DI) + DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation()); + return TemplateArgumentLoc(TemplateArgument(T), DI); + } + + case ParsedTemplateArgument::NonType: { + Expr *E = static_cast(Arg.getAsExpr()); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case ParsedTemplateArgument::Template: { + TemplateName Template + = TemplateName::getFromVoidPointer(Arg.getAsTemplate().get()); + return TemplateArgumentLoc(TemplateArgument(Template), + Arg.getScopeSpec().getRange(), + Arg.getLocation()); + } + } + + llvm::llvm_unreachable("Unhandled parsed template argument"); + return TemplateArgumentLoc(); +} + +/// \brief Translates template arguments as provided by the parser +/// into template arguments used by semantic analysis. +void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + llvm::SmallVectorImpl &TemplateArgs) { + TemplateArgs.reserve(TemplateArgsIn.size()); + + for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) + TemplateArgs.push_back(translateTemplateArgument(*this, TemplateArgsIn[I])); +} + /// 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 @@ -518,34 +558,22 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, /// parameter. void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, SourceLocation EqualLoc, - ExprArg DefaultE) { + const ParsedTemplateArgument &Default) { TemplateTemplateParmDecl *TemplateParm = cast(TemplateParamD.getAs()); - - // Since a template-template parameter's default argument is an - // id-expression, it must be a DeclRefExpr. - DeclRefExpr *Default - = cast(static_cast(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(Default->getDecl())) { - Diag(Default->getSourceRange().getBegin(), - diag::err_template_arg_must_be_template) - << Default->getSourceRange(); - TemplateParm->setInvalidDecl(); - return; - } - if (CheckTemplateArgument(TemplateParm, Default)) { + TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default); + if (CheckTemplateArgument(TemplateParm, DefaultArg)) { TemplateParm->setInvalidDecl(); return; } - DefaultE.release(); - TemplateParm->setDefaultArgument(Default); + TemplateParm->setDefaultArgument(DefaultArg); } /// ActOnTemplateParameterList - Builds a TemplateParameterList that @@ -924,8 +952,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, = OldParams? cast(*OldParam) : 0; if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { - OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc(); - NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc(); + OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); + NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; RedundantDefaultArg = true; PreviousDefaultArgLoc = NewDefaultLoc; @@ -937,10 +965,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // that points to a previous template template parameter. NewTemplateParm->setDefaultArgument( OldTemplateParm->getDefaultArgument()); - PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc(); + PreviousDefaultArgLoc + = OldTemplateParm->getDefaultArgument().getLocation(); } else if (NewTemplateParm->hasDefaultArgument()) { SawDefaultArgument = true; - PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc(); + PreviousDefaultArgLoc + = NewTemplateParm->getDefaultArgument().getLocation(); } else if (SawDefaultArgument) MissingDefaultArg = true; } @@ -1119,50 +1149,6 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, return ParamLists[NumParamLists - 1]; } -/// \brief Translates template arguments as provided by the parser -/// into template arguments used by semantic analysis. -void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - llvm::SmallVectorImpl &TemplateArgs) { - TemplateArgs.reserve(TemplateArgsIn.size()); - - for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) { - const ParsedTemplateArgument &Arg = TemplateArgsIn[I]; - switch (Arg.getKind()) { - case ParsedTemplateArgument::Type: { - DeclaratorInfo *DI; - QualType T = Sema::GetTypeFromParser(Arg.getAsType(), &DI); - if (!DI) DI = Context.getTrivialDeclaratorInfo(T, Arg.getLocation()); - TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(T), DI)); - break; - } - - case ParsedTemplateArgument::NonType: { - Expr *E = static_cast(Arg.getAsExpr()); - TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E)); - break; - } - - case ParsedTemplateArgument::Template: { - TemplateName Template - = TemplateName::getFromVoidPointer(Arg.getAsTemplate().get()); - - // FIXME: This is an egregious hack. We turn a nicely-parsed template name - // into a DeclRefExpr, because that's how we previously parsed template - // template parameters. This will disappear as part of the upcoming - // implementation of template template parameters. - const CXXScopeSpec &SS = Arg.getScopeSpec(); - Expr *E = DeclRefExpr::Create(Context, - (NestedNameSpecifier *)SS.getScopeRep(), - SS.getRange(), - Template.getAsTemplateDecl(), - Arg.getLocation(), - Context.DependentTy, false, false); - TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E)); - } - } - } -} - QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -1538,7 +1524,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// \param RAngleLoc the location of the right angle bracket ('>') that /// terminates the template-id. /// -/// \param Param the template template parameter whose default we are +/// \param Param the non-type template parameter whose default we are /// substituting into. /// /// \param Converted the list of template arguments provided for template @@ -1566,6 +1552,52 @@ SubstDefaultTemplateArgument(Sema &SemaRef, return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); } +/// \brief Substitute template arguments into the default template argument for +/// the given template template parameter. +/// +/// \param SemaRef the semantic analysis object for which we are performing +/// the substitution. +/// +/// \param Template the template that we are synthesizing template arguments +/// for. +/// +/// \param TemplateLoc the location of the template name that started the +/// template-id we are checking. +/// +/// \param RAngleLoc the location of the right angle bracket ('>') that +/// terminates the template-id. +/// +/// \param Param the template template parameter whose default we are +/// substituting into. +/// +/// \param Converted the list of template arguments provided for template +/// parameters that precede \p Param in the template parameter list. +/// +/// \returns the substituted template argument, or NULL if an error occurred. +static TemplateName +SubstDefaultTemplateArgument(Sema &SemaRef, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + TemplateTemplateParmDecl *Param, + TemplateArgumentListBuilder &Converted) { + TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, + /*TakeArgs=*/false); + + MultiLevelTemplateArgumentList AllTemplateArgs + = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); + + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, + Template, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + return SemaRef.SubstTemplateName( + Param->getDefaultArgument().getArgument().getAsTemplate(), + Param->getDefaultArgument().getTemplateNameLoc(), + AllTemplateArgs); +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -1666,9 +1698,17 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TempParm->hasDefaultArgument()) break; - // FIXME: Subst default argument - Arg = TemplateArgumentLoc(TemplateArgument(TempParm->getDefaultArgument()), - TempParm->getDefaultArgument()); + TemplateName Name = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TempParm, + Converted); + if (Name.isNull()) + return true; + + Arg = TemplateArgumentLoc(TemplateArgument(Name), + TempParm->getDefaultArgument().getTemplateQualifierRange(), + TempParm->getDefaultArgument().getTemplateNameLoc()); } } else { // Retrieve the template argument produced by the user. @@ -1743,6 +1783,41 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Converted.Append(Arg.getArgument()); break; + case TemplateArgument::Template: + // We were given a template template argument. It may not be ill-formed; + // see below. + if (DependentTemplateName *DTN + = Arg.getArgument().getAsTemplate().getAsDependentTemplateName()) { + // We have a template argument such as \c T::template X, which we + // parsed as a template template argument. However, since we now + // know that we need a non-type template argument, convert this + // template name into an expression. + Expr *E = new (Context) UnresolvedDeclRefExpr(DTN->getIdentifier(), + Context.DependentTy, + Arg.getTemplateNameLoc(), + Arg.getTemplateQualifierRange(), + DTN->getQualifier(), + /*isAddressOfOperand=*/false); + + TemplateArgument Result; + if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + Invalid = true; + else + Converted.Append(Result); + + break; + } + + // We have a template argument that actually does refer to a class + // template, template alias, or template template parameter, and + // therefore cannot be a non-type template argument. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) + << Arg.getSourceRange(); + + Diag((*Param)->getLocation(), diag::note_template_param_here); + Invalid = true; + break; + case TemplateArgument::Type: { // We have a non-type template parameter but the template // argument is a type. @@ -1780,38 +1855,28 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, assert(false && "Should never see a NULL template argument here"); break; - case TemplateArgument::Expression: { - Expr *ArgExpr = Arg.getArgument().getAsExpr(); - if (ArgExpr && isa(ArgExpr) && - isa(cast(ArgExpr)->getDecl())) { - if (CheckTemplateArgument(TempParm, cast(ArgExpr))) - Invalid = true; - - // Add the converted template argument. - Decl *D - = cast(ArgExpr)->getDecl()->getCanonicalDecl(); - Converted.Append(TemplateArgument(D)); - continue; - } - } - // fall through - - case TemplateArgument::Type: { + case TemplateArgument::Template: + if (CheckTemplateArgument(TempParm, Arg)) + Invalid = true; + else + Converted.Append(Arg.getArgument()); + break; + + case TemplateArgument::Expression: + case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); Invalid = true; break; - } case TemplateArgument::Declaration: - // We've already checked this template argument, so just copy - // it to the list of converted arguments. - Converted.Append(Arg.getArgument()); + llvm::llvm_unreachable( + "Declaration argument with template template parameter"); break; - case TemplateArgument::Integral: - assert(false && "Integral argument with template template parameter"); + llvm::llvm_unreachable( + "Integral argument with template template parameter"); break; case TemplateArgument::Pack: @@ -2357,9 +2422,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - DeclRefExpr *Arg) { - assert(isa(Arg->getDecl()) && "Only template decls allowed"); - TemplateDecl *Template = cast(Arg->getDecl()); + const TemplateArgumentLoc &Arg) { + TemplateName Name = Arg.getArgument().getAsTemplate(); + TemplateDecl *Template = Name.getAsTemplateDecl(); + if (!Template) { + // Any dependent template name is fine. + assert(Name.isDependent() && "Non-dependent template isn't a declaration?"); + return false; + } // C++ [temp.arg.template]p1: // A template-argument for a template template-parameter shall be @@ -2376,7 +2446,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, !isa(Template)) { assert(isa(Template) && "Only function templates are possible here"); - Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template); + Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); Diag(Template->getLocation(), diag::note_template_arg_refers_here_func) << Template; } @@ -2384,7 +2454,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Param->getTemplateParameters(), true, true, - Arg->getSourceRange().getBegin()); + Arg.getLocation()); } /// \brief Determine whether the given template parameter lists are @@ -2735,16 +2805,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( } else if (TemplateTemplateParmDecl *TTP = dyn_cast( TemplateParams->getParam(I))) { - // FIXME: We should settle on either Declaration storage or - // Expression storage for template template parameters. + TemplateName Name = ArgList[I].getAsTemplate(); TemplateTemplateParmDecl *ArgDecl - = dyn_cast_or_null( - ArgList[I].getAsDecl()); - if (!ArgDecl) - if (DeclRefExpr *DRE - = dyn_cast_or_null(ArgList[I].getAsExpr())) - ArgDecl = dyn_cast(DRE->getDecl()); - + = dyn_cast_or_null(Name.getAsTemplateDecl()); if (!ArgDecl || ArgDecl->getIndex() != TTP->getIndex() || ArgDecl->getDepth() != TTP->getDepth()) @@ -2871,12 +2934,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } } else { TemplateTemplateParmDecl *TTP = cast(Param); - if (Expr *DefArg = TTP->getDefaultArgument()) { - Diag(TTP->getDefaultArgumentLoc(), + if (TTP->hasDefaultArgument()) { + Diag(TTP->getDefaultArgument().getLocation(), diag::err_default_arg_in_partial_spec) - << DefArg->getSourceRange(); - TTP->setDefaultArgument(0); - DefArg->Destroy(Context); + << TTP->getDefaultArgument().getSourceRange(); + TTP->setDefaultArgument(TemplateArgumentLoc()); } } } @@ -4580,6 +4642,14 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, break; } + case TemplateArgument::Template: { + std::string Str; + llvm::raw_string_ostream OS(Str); + Args[I].getAsTemplate().print(OS, Context.PrintingPolicy); + Result += OS.str(); + break; + } + case TemplateArgument::Integral: { Result += Args[I].getAsIntegral()->toString(10); break; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7b5ad7fc64..2eb3af2b60 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -785,13 +785,32 @@ DeduceTemplateArguments(ASTContext &Context, break; case TemplateArgument::Type: - assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch"); - return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), - Arg.getAsType(), Info, Deduced, 0); - + if (Arg.getKind() == TemplateArgument::Type) + return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), + Arg.getAsType(), Info, Deduced, 0); + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + + case TemplateArgument::Template: +#if 0 + // FIXME: We need template argument deduction for template template + // parameters. + if (Arg.getKind() == TemplateArgument::Template) + return DeduceTemplateArguments(Context, TemplateParams, + Param.getAsTemplate(), + Arg.getAsTemplate(), Info, Deduced, 0); +#endif + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + case TemplateArgument::Declaration: - // FIXME: Implement this check - assert(false && "Unimplemented template argument deduction case"); + if (Arg.getKind() == TemplateArgument::Declaration && + Param.getAsDecl()->getCanonicalDecl() == + Arg.getAsDecl()->getCanonicalDecl()) + return Sema::TDK_Success; + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -885,13 +904,21 @@ static bool isSameTemplateArg(ASTContext &Context, return X.getAsDecl()->getCanonicalDecl() == Y.getAsDecl()->getCanonicalDecl(); + case TemplateArgument::Template: + return Context.getCanonicalTemplateName(X.getAsTemplate()) + .getAsVoidPointer() == + Context.getCanonicalTemplateName(Y.getAsTemplate()) + .getAsVoidPointer(); + case TemplateArgument::Integral: return *X.getAsIntegral() == *Y.getAsIntegral(); - case TemplateArgument::Expression: - // FIXME: We assume that all expressions are distinct, but we should - // really check their canonical forms. - return false; + case TemplateArgument::Expression: { + llvm::FoldingSetNodeID XID, YID; + X.getAsExpr()->Profile(XID, Context, true); + Y.getAsExpr()->Profile(YID, Context, true); + return XID == YID; + } case TemplateArgument::Pack: if (X.pack_size() != Y.pack_size()) @@ -1030,15 +1057,6 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } - } else if (TemplateTemplateParmDecl *TTP - = dyn_cast(Param)) { - // FIXME: template template arguments should really resolve to decls - DeclRefExpr *DRE = dyn_cast(InstExpr); - if (!DRE || CheckTemplateArgument(TTP, DRE)) { - Info.Param = makeTemplateParameter(Param); - Info.FirstArg = Partial->getTemplateArgs()[I]; - return TDK_SubstitutionFailure; - } } } @@ -2153,6 +2171,9 @@ MarkUsedTemplateParameters(Sema &SemaRef, return; } + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) + MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, + Depth, Used); if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Depth, Used); @@ -2309,6 +2330,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: + case TemplateArgument::Declaration: break; case TemplateArgument::Type: @@ -2316,12 +2338,9 @@ MarkUsedTemplateParameters(Sema &SemaRef, Depth, Used); break; - case TemplateArgument::Declaration: - if (TemplateTemplateParmDecl *TTP - = dyn_cast(TemplateArg.getAsDecl())) { - if (TTP->getDepth() == Depth) - Used[TTP->getIndex()] = true; - } + case TemplateArgument::Template: + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsTemplate(), + OnlyDeduced, Depth, Used); break; case TemplateArgument::Expression: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 9e8dc2ea2c..74f521e3cf 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -452,10 +452,11 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { if (TemplateTemplateParmDecl *TTP = dyn_cast(D)) { if (TTP->getDepth() < TemplateArgs.getNumLevels()) { - assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() && + TemplateName Template + = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); + assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); - return cast(TemplateArgs(TTP->getDepth(), - TTP->getPosition()).getAsDecl()); + return Template.getAsTemplateDecl(); } // If the corresponding template argument is NULL or non-existent, it's @@ -466,9 +467,8 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { TTP->getPosition())) return D; - // FIXME: Implement depth reduction of template template parameters - assert(false && - "Reducing depth of template template parameters is not yet implemented"); + // Fall through to find the instantiated declaration for this template + // template parameter. } return SemaRef.FindInstantiatedDecl(cast(D), TemplateArgs); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 799d01b0ed..2095fba616 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1957,6 +1957,10 @@ void TreeTransform::InventTemplateArgumentLoc( break; + case TemplateArgument::Template: + Output = TemplateArgumentLoc(Arg, SourceRange(), Loc); + break; + case TemplateArgument::Expression: Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); break; @@ -1997,7 +2001,7 @@ bool TreeTransform::TransformTemplateArgument( DeclarationName Name; if (NamedDecl *ND = dyn_cast(Arg.getAsDecl())) Name = ND->getDeclName(); - TemporaryBase Rebase(*this, SourceLocation(), Name); + TemporaryBase Rebase(*this, Input.getLocation(), Name); Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); if (!D) return true; @@ -2018,6 +2022,19 @@ bool TreeTransform::TransformTemplateArgument( return false; } + case TemplateArgument::Template: { + TemporaryBase Rebase(*this, Input.getLocation(), DeclarationName()); + TemplateName Template + = getDerived().TransformTemplateName(Arg.getAsTemplate()); + if (Template.isNull()) + return true; + + Output = TemplateArgumentLoc(TemplateArgument(Template), + Input.getTemplateQualifierRange(), + Input.getTemplateNameLoc()); + return false; + } + case TemplateArgument::Expression: { // Template argument expressions are not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(getSema(), diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index a6611582f1..bde92be93d 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -10,8 +10,7 @@ A *a2; // expected-error{{template argument for non-type template parameter A<1 >> 2> *a3; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++0x}} // C++ [temp.arg.nontype]p5: -A *a4; // expected-error{{must have an integral or enumeration type}} \ - // FIXME: the error message above is a bit lame +A *a4; // expected-error{{must be an expression}} enum E { Enumerator = 17 }; A *a5; // expected-error{{template argument for non-type template parameter must be an expression}} diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp index f2ee66b3f7..ada244bb5d 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -26,12 +26,9 @@ B *a6; // expected-error{{template template argument has different template p C *a7; C *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} -template void f(int); // expected-note{{function template}} +template void f(int); -// FIXME: we're right to provide an error message, but it should say -// that we need a class template. We won't get this right until name -// lookup of 'f' returns a TemplateDecl. -A *a9; // expected-error{{template argument does not refer to}} +A *a9; // expected-error{{must be a class template}} // FIXME: The code below is ill-formed, because of the evil digraph '<:'. // We should provide a much better error message than we currently do.