diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-11-10 19:49:08 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-11-10 19:49:08 +0000 |
commit | 314b97f8c564b465af605efaee23f91ec18a982b (patch) | |
tree | e0fddf8801f5e22bef57f935a3211ef8ceccbf97 /lib/Parse | |
parent | 4770a4a3d4e55fa8ad691bf4c046fae519120a09 (diff) |
Improve parsing of template arguments to lay the foundation for
handling template template parameters properly. This refactoring:
- Parses template template arguments as id-expressions, representing
the result of the parse as a template name (Action::TemplateTy)
rather than as an expression (lame!).
- Represents all parsed template arguments via a new parser-specific
type, ParsedTemplateArgument, which stores the kind of template
argument (type, non-type, template) along with all of the source
information about the template argument. This replaces an ad hoc
set of 3 vectors (one for a void*, which was either a type or an
expression; one for a bit telling whether the first was a type or
an expression; and one for a single source location pointing at
the template argument).
- Moves TemplateIdAnnotation into the new Parse/Template.h. It never
belonged in the Basic library anyway.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86708 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 135 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 1 |
6 files changed, 114 insertions, 59 deletions
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 0a4e036e43..f00f33fcb9 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Template.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" @@ -26,6 +27,15 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); } + +void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 99752b5950..2bfda30a95 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "ExtensionRAIIObject.h" #include "llvm/ADT/SmallSet.h" using namespace clang; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c006f8bc80..baf9e4ba59 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -16,6 +16,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "ExtensionRAIIObject.h" using namespace clang; @@ -586,13 +587,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Eat the template argument list and try to continue parsing this as // a class (or template thereof). TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; SourceLocation LAngleLoc, RAngleLoc; if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, true, LAngleLoc, - TemplateArgs, TemplateArgIsType, - TemplateArgLocations, RAngleLoc)) { + TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); @@ -704,7 +702,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Action::TUK_Declaration) { @@ -720,7 +717,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc, Attr); } else if (TUK == Action::TUK_Reference) { @@ -729,7 +725,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, @@ -777,7 +772,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc, Attr, Action::MultiTemplateParamsArg(Actions, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fa8e64dc12..a7e7648c1f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -814,13 +815,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, &SS, true, LAngleLoc, TemplateArgs, - TemplateArgIsType, - TemplateArgLocations, RAngleLoc)) return true; @@ -845,15 +842,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; - void **Args = TemplateId->getTemplateArgs(); - bool *ArgIsType = TemplateId->getTemplateArgIsType(); - SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); - Arg != ArgEnd; ++Arg) { + Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; - ArgIsType[Arg] = TemplateArgIsType[Arg]; - ArgLocs[Arg] = TemplateArgLocations[Arg]; - } Id.setTemplateId(TemplateId); return false; @@ -861,14 +853,12 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Bundle the template arguments together. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgIsType.data(), TemplateArgs.size()); // Constructor and destructor names. Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, NameLoc, LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], RAngleLoc); if (Type.isInvalid()) return true; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 99578837c2..4e7ceaa7c1 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "llvm/Support/Compiler.h" using namespace clang; @@ -582,8 +583,6 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, - TemplateArgIsTypeList &TemplateArgIsType, - TemplateArgLocationList &TemplateArgLocations, SourceLocation &RAngleLoc) { assert(Tok.is(tok::less) && "Must have already parsed the template-name"); @@ -595,8 +594,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, { GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); if (Tok.isNot(tok::greater)) - Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType, - TemplateArgLocations); + Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { // Try to find the closing '>'. @@ -688,14 +686,10 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, SS, false, LAngleLoc, TemplateArgs, - TemplateArgIsType, - TemplateArgLocations, RAngleLoc); if (Invalid) { @@ -707,7 +701,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, } ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgIsType.data(), TemplateArgs.size()); // Build the annotation token. @@ -715,7 +708,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], RAngleLoc); if (Type.isInvalid()) { // If we failed to parse the template ID but skipped ahead to a >, we're not @@ -751,14 +743,9 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; - void **Args = TemplateId->getTemplateArgs(); - bool *ArgIsType = TemplateId->getTemplateArgIsType(); - SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) { + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; - ArgIsType[Arg] = TemplateArgIsType[Arg]; - ArgLocs[Arg] = TemplateArgLocations[Arg]; - } Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); @@ -794,7 +781,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); Action::TypeResult Type @@ -802,7 +788,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); @@ -817,33 +802,112 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->Destroy(); } +/// \brief Determine whether the given token can end a template argument. +static const bool isEndOfTemplateArgument(Token Tok) { + return Tok.is(tok::comma) || Tok.is(tok::greater) || + Tok.is(tok::greatergreater); +} + /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). /// /// template-argument: [C++ 14.2] /// constant-expression /// type-id /// id-expression -void *Parser::ParseTemplateArgument(bool &ArgIsType) { +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. + // Therefore, we initially try to parse a type-id. if (isCXXTypeId(TypeIdAsTemplateArgument)) { - ArgIsType = true; + SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName(); if (TypeArg.isInvalid()) - return 0; - return TypeArg.get(); + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), + Loc); } + // 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: + // + // nested-name-specifier[opt] template[opt] identifier + // + // 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; + 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(); + } + + // Parse a non-type template argument. + SourceLocation Loc = Tok.getLocation(); OwningExprResult ExprArg = ParseConstantExpression(); if (ExprArg.isInvalid() || !ExprArg.get()) - return 0; + return ParsedTemplateArgument(); - ArgIsType = false; - return ExprArg.release(); + return ParsedTemplateArgument(ParsedTemplateArgument::NonType, + ExprArg.release(), Loc); } /// ParseTemplateArgumentList - Parse a C++ template-argument-list @@ -853,22 +917,17 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) { /// template-argument /// template-argument-list ',' template-argument bool -Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, - TemplateArgIsTypeList &TemplateArgIsType, - TemplateArgLocationList &TemplateArgLocations) { +Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { while (true) { - bool IsType = false; - SourceLocation Loc = Tok.getLocation(); - void *Arg = ParseTemplateArgument(IsType); - if (Arg) { - TemplateArgs.push_back(Arg); - TemplateArgIsType.push_back(IsType); - TemplateArgLocations.push_back(Loc); - } else { + ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Arg.isInvalid()) { SkipUntil(tok::comma, tok::greater, true, true); return true; } + // Save this template argument. + TemplateArgs.push_back(Arg); + // If the next token is a comma, consume it and keep reading // arguments. if (Tok.isNot(tok::comma)) break; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 335a6cf362..a9152745b3 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "llvm/Support/raw_ostream.h" #include "ExtensionRAIIObject.h" #include "ParsePragma.h" |