aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-09 18:46:07 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-09 18:46:07 +0000
commit55f6b14230c94272efbbcdd89a92224c8db9f225 (patch)
tree988ae940f14f93aac610fbc36d89766e539eab6c /lib/Parse
parent00e68e2cc5ce37cb95beb801cae73c0d1e9dda37 (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.cpp13
-rw-r--r--lib/Parse/ParseDecl.cpp22
-rw-r--r--lib/Parse/ParseExpr.cpp21
-rw-r--r--lib/Parse/ParseTemplate.cpp82
-rw-r--r--lib/Parse/Parser.cpp16
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