diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-09 18:46:07 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-09 18:46:07 +0000 |
commit | 55f6b14230c94272efbbcdd89a92224c8db9f225 (patch) | |
tree | 988ae940f14f93aac610fbc36d89766e539eab6c /lib/Parse | |
parent | 00e68e2cc5ce37cb95beb801cae73c0d1e9dda37 (diff) |
Start processing template-ids as types when the template-name refers
to a class template. For example, the template-id 'vector<int>' now
has a nice, sugary type in the type system. What we can do now:
- Parse template-ids like 'vector<int>' (where 'vector' names a
class template) and form proper types for them in the type system.
- Parse icky template-ids like 'A<5>' and 'A<(5 > 0)>' properly,
using (sadly) a bool in the parser to tell it whether '>' should
be treated as an operator or not.
This is a baby-step, with major problems and limitations:
- There are currently two ways that we handle template arguments
(whether they are types or expressions). These will be merged, and,
most likely, TemplateArg will disappear.
- We don't have any notion of the declaration of class template
specializations or of template instantiations, so all template-ids
are fancy names for 'int' :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64153 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 21 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 82 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 16 |
5 files changed, 109 insertions, 45 deletions
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 2d6c9a6ba5..ce15cf9dda 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -95,14 +95,11 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, return false; } - /// isTemplateName - Determines whether the identifier II is a - /// template name in the current scope, and returns the template - /// declaration if II names a template. An optional CXXScope can be - /// passed to indicate the C++ scope in which the identifier will be - /// found. -Action::DeclTy *MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S, - const CXXScopeSpec *SS ) { - return 0; +Action::TemplateNameKind +MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S, + DeclTy *&TemplateDecl, + const CXXScopeSpec *SS) { + return TNK_Non_template; } /// ActOnDeclarator - If this is a typedef declarator, we modify the diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 73a09ee39c..5d601bc4f1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -499,6 +499,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Token Next = NextToken(); TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), CurScope, &SS); + if (TypeRep == 0) goto DoneWithDeclSpec; @@ -553,9 +554,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // It has to be available as a typedef too! TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope); + + if (TypeRep == 0 && getLang().CPlusPlus && NextToken().is(tok::less)) { + // If we have a template name, annotate the token and try again. + DeclTy *Template = 0; + if (TemplateNameKind TNK = + Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, + Template)) { + AnnotateTemplateIdToken(Template, TNK, 0); + continue; + } + } + if (TypeRep == 0) goto DoneWithDeclSpec; + + // C++: If the identifier is actually the name of the class type // being defined and the next token is a '(', then this is a // constructor declaration. We're done with the decl-specifiers @@ -1752,11 +1767,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // If this identifier is followed by a '<', we may have a template-id. DeclTy *Template; + Action::TemplateNameKind TNK; if (getLang().CPlusPlus && NextToken().is(tok::less) && - (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope))) { + (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), + CurScope, Template))) { IdentifierInfo *II = Tok.getIdentifierInfo(); - AnnotateTemplateIdToken(Template, 0); + AnnotateTemplateIdToken(Template, TNK, 0); // FIXME: Set the declarator to a template-id. How? I don't // know... for now, just use the identifier. D.SetIdentifier(II, Tok.getLocation()); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 332ad7789e..0f04d13f6e 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -55,8 +55,17 @@ namespace prec { /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// -static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { +static prec::Level getBinOpPrecedence(tok::TokenKind Kind, + bool GreaterThanIsOperator) { switch (Kind) { + case tok::greater: + // The '>' token can act as either an operator or as the ending + // token for a template argument list. + // FIXME: '>>' is similar, for error recovery and C++0x. + if (GreaterThanIsOperator) + return prec::Relational; + return prec::Unknown; + default: return prec::Unknown; case tok::comma: return prec::Comma; case tok::equal: @@ -80,8 +89,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { case tok::equalequal: return prec::Equality; case tok::lessequal: case tok::less: - case tok::greaterequal: - case tok::greater: return prec::Relational; + case tok::greaterequal: return prec::Relational; case tok::lessless: case tok::greatergreater: return prec::Shift; case tok::plus: @@ -266,7 +274,7 @@ Parser::OwningExprResult Parser::ParseConstantExpression() { /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind()); + unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); SourceLocation ColonLoc; while (1) { @@ -316,7 +324,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. unsigned ThisPrec = NextTokPrec; - NextTokPrec = getBinOpPrecedence(Tok.getKind()); + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || @@ -335,7 +343,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { if (RHS.isInvalid()) return move(RHS); - NextTokPrec = getBinOpPrecedence(Tok.getKind()); + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); } assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); @@ -1104,6 +1112,7 @@ Parser::OwningExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, TypeTy *&CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); + MakeGreaterThanAnOperator G(GreaterThanIsOperator); SourceLocation OpenLoc = ConsumeParen(); OwningExprResult Result(Actions, true); CastTy = 0; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8836106e39..2e2cf5357f 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 "AstGuard.h" using namespace clang; @@ -354,7 +355,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { /// AnnotateTemplateIdToken - The current token is an identifier that /// refers to the template declaration Template, and is followed by a /// '<'. Turn this template-id into a template-id annotation token. -void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) { +void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, + const CXXScopeSpec *SS) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) && "Parser isn't at the beginning of a template-id"); @@ -366,13 +368,16 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) { SourceLocation LAngleLoc = ConsumeToken(); // Parse the optional template-argument-list. - TemplateArgList TemplateArgs; - if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) { - // Try to find the closing '>'. - SkipUntil(tok::greater, true, true); - - // FIXME: What's our recovery strategy for failed template-argument-lists? - return; + ASTVector<&ActionBase::DeleteTemplateArg, 8> TemplateArgs(Actions); + { + MakeGreaterThanTemplateArgumentListTerminator G(GreaterThanIsOperator); + if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) { + // Try to find the closing '>'. + SkipUntil(tok::greater, true, true); + + // FIXME: What's our recovery strategy for failed template-argument-lists? + return; + } } if (Tok.isNot(tok::greater)) @@ -382,24 +387,41 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) { // token, because we'll be replacing it with the template-id. SourceLocation RAngleLoc = Tok.getLocation(); - Tok.setKind(tok::annot_template_id); + // Build the annotation token. + if (TNK == Action::TNK_Function_template) { + // This is a function template. We'll be building a template-id + // annotation token. + TemplateArgs.take(); // Annotation token takes ownership + Tok.setKind(tok::annot_template_id); + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + + sizeof(TemplateArgTy*) * TemplateArgs.size()); + TemplateId->TemplateNameLoc = TemplateNameLoc; + TemplateId->Template = Template; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->NumArgs = TemplateArgs.size(); + TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) + Args[Arg] = TemplateArgs[Arg]; + Tok.setAnnotationValue(TemplateId); + } else { + // This is a type template, e.g., a class template, template + // template parameter, or template alias. We'll be building a + // "typename" annotation token. + TypeTy *Ty + = Actions.ActOnClassTemplateSpecialization(Template,LAngleLoc, + move_arg(TemplateArgs), + RAngleLoc, SS); + Tok.setKind(tok::annot_typename); + Tok.setAnnotationValue(Ty); + } + + // Common fields for the annotation token Tok.setAnnotationEndLoc(RAngleLoc); Tok.setLocation(TemplateNameLoc); if (SS && SS->isNotEmpty()) Tok.setLocation(SS->getBeginLoc()); - TemplateIdAnnotation *TemplateId - = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + - sizeof(TemplateArgTy*) * TemplateArgs.size()); - TemplateId->TemplateNameLoc = TemplateNameLoc; - TemplateId->Template = Template; - TemplateId->LAngleLoc = LAngleLoc; - TemplateId->NumArgs = TemplateArgs.size(); - TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) - Args[Arg] = TemplateArgs[Arg]; - Tok.setAnnotationValue(TemplateId); - // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); @@ -412,8 +434,22 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) { /// type-id /// id-expression Parser::OwningTemplateArgResult Parser::ParseTemplateArgument() { - // FIXME: Implement this! - return TemplateArgError(); + // 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 (isTypeIdInParens()) { + TypeTy *TypeArg = ParseTypeName(); + return Actions.ActOnTypeTemplateArgument(TypeArg); + } + + OwningExprResult ExprArg = ParseExpression(); + if (ExprArg.isInvalid()) + return TemplateArgError(); + + return Actions.ActOnExprTemplateArgument(move(ExprArg)); } /// ParseTemplateArgumentList - Parse a C++ template-argument-list diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f28767a0fd..7b09d2105c 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -20,7 +20,8 @@ using namespace clang; Parser::Parser(Preprocessor &pp, Action &actions) - : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) { + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true) { Tok.setKind(tok::eof); CurScope = 0; NumCachedScopes = 0; @@ -785,10 +786,15 @@ bool Parser::TryAnnotateTypeOrScopeToken() { } // If this is a template-id, annotate the template-id token. - if (NextToken().is(tok::less)) - if (DeclTy *Template = - Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, &SS)) - AnnotateTemplateIdToken(Template, &SS); + if (NextToken().is(tok::less)) { + DeclTy *Template; + if (TemplateNameKind TNK + = Actions.isTemplateName(*Tok.getIdentifierInfo(), + CurScope, Template, &SS)) { + AnnotateTemplateIdToken(Template, TNK, &SS); + return true; + } + } // We either have an identifier that is not a type name or we have // just created a template-id that might be a type name. Both |