aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseTemplate.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-25 19:37:18 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-25 19:37:18 +0000
commit39a8de10c18365bde7062d8959b7ed525449c561 (patch)
tree0de42dd5a33f1dce18647222a5802e6f14fce250 /lib/Parse/ParseTemplate.cpp
parent0096acf421c4609ce7f43e8b05f8c5ca866d4611 (diff)
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type When we parse a template-id that names a type, it will become either a template-id annotation (which is a parsed representation of a template-id that has not yet been through semantic analysis) or a typename annotation (where semantic analysis has resolved the template-id to an actual type), depending on the context. We only produce a type in contexts where we know that we only need type information, e.g., in a type specifier. Otherwise, we create a template-id annotation that can later be "upgraded" by transforming it into a typename annotation when the parser needs a type. This occurs, for example, when we've parsed "std::vector<int>" above and then see the '::' after it. However, it means that when writing something like this: template<> class Outer::Inner<int> { ... }; We have two tokens to represent Outer::Inner<int>: one token for the nested name specifier Outer::, and one template-id annotation token for Inner<int>, which will be passed to semantic analysis to define the class template specialization. Most of the churn in the template tests in this patch come from an improvement in our error recovery from ill-formed template-ids. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65467 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r--lib/Parse/ParseTemplate.cpp123
1 files changed, 109 insertions, 14 deletions
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 747a4de152..64fc8fdf47 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -444,16 +444,49 @@ Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template,
return false;
}
-/// 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.
+/// \brief Replace the tokens that form a simple-template-id with an
+/// annotation token containing the complete template-id.
+///
+/// The first token in the stream must be the name of a template that
+/// is followed by a '<'. This routine will parse the complete
+/// simple-template-id and replace the tokens with a single annotation
+/// token with one of two different kinds: if the template-id names a
+/// type (and \p AllowTypeAnnotation is true), the annotation token is
+/// a type annotation that includes the optional nested-name-specifier
+/// (\p SS). Otherwise, the annotation token is a template-id
+/// annotation that does not include the optional
+/// nested-name-specifier.
+///
+/// \param Template the declaration of the template named by the first
+/// token (an identifier), as returned from \c Action::isTemplateName().
+///
+/// \param TemplateNameKind the kind of template that \p Template
+/// refers to, as returned from \c Action::isTemplateName().
+///
+/// \param SS if non-NULL, the nested-name-specifier that precedes
+/// this template name.
+///
+/// \param TemplateKWLoc if valid, specifies that this template-id
+/// annotation was preceded by the 'template' keyword and gives the
+/// location of that keyword. If invalid (the default), then this
+/// template-id was not preceded by a 'template' keyword.
+///
+/// \param AllowTypeAnnotation if true (the default), then a
+/// simple-template-id that refers to a class template, template
+/// template parameter, or other template that produces a type will be
+/// replaced with a type annotation token. Otherwise, the
+/// simple-template-id is always replaced with a template-id
+/// annotation token.
void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
- const CXXScopeSpec *SS) {
+ const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc,
+ bool AllowTypeAnnotation) {
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");
// Consume the template-name.
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
SourceLocation TemplateNameLoc = ConsumeToken();
// Parse the enclosed template argument list.
@@ -476,7 +509,7 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
return;
// Build the annotation token.
- if (TNK == Action::TNK_Class_template) {
+ if (TNK == TNK_Class_template && AllowTypeAnnotation) {
Action::TypeResult Type
= Actions.ActOnClassTemplateId(Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr,
@@ -487,34 +520,96 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
Tok.setKind(tok::annot_typename);
Tok.setAnnotationValue(Type.get());
+ if (SS && SS->isNotEmpty())
+ Tok.setLocation(SS->getBeginLoc());
+ else if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
} else {
// This is a function template. We'll be building a template-id
// annotation token.
- Tok.setKind(tok::annot_template_id);
+ Tok.setKind(tok::annot_template_id);
TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
- sizeof(void*) * TemplateArgs.size());
+ = TemplateIdAnnotation::Allocate(TemplateArgs.size());
TemplateId->TemplateNameLoc = TemplateNameLoc;
+ TemplateId->Name = Name;
TemplateId->Template = Template;
+ TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->NumArgs = TemplateArgs.size();
- void **Args = (void**)(TemplateId + 1);
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
+ 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) {
Args[Arg] = TemplateArgs[Arg];
+ ArgIsType[Arg] = TemplateArgIsType[Arg];
+ ArgLocs[Arg] = TemplateArgLocations[Arg];
+ }
Tok.setAnnotationValue(TemplateId);
+ if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
+
+ TemplateArgsPtr.release();
}
// Common fields for the annotation token
Tok.setAnnotationEndLoc(RAngleLoc);
- Tok.setLocation(TemplateNameLoc);
- if (SS && SS->isNotEmpty())
- Tok.setLocation(SS->getBeginLoc());
// In case the tokens were cached, have Preprocessor replace them with the
// annotation token.
PP.AnnotateCachedTokens(Tok);
}
+/// \brief Replaces a template-id annotation token with a type
+/// annotation token.
+///
+/// \returns true if there was an error, false otherwise.
+bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
+ assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
+
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ assert(TemplateId->Kind == TNK_Class_template &&
+ "Only works for class templates");
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+
+ Action::TypeResult Type
+ = Actions.ActOnClassTemplateId(TemplateId->Template,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc, SS);
+ if (Type.isInvalid()) {
+ // FIXME: better recovery?
+ ConsumeToken();
+ TemplateId->Destroy();
+ return true;
+ }
+
+ // Create the new "type" annotation token.
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.get());
+ if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS->getBeginLoc());
+
+ // We might be backtracking, in which case we need to replace the
+ // template-id annotation token with the type annotation within the
+ // set of cached tokens. That way, we won't try to form the same
+ // class template specialization again.
+ PP.ReplaceLastTokenWithAnnotation(Tok);
+ TemplateId->Destroy();
+
+ return false;
+}
+
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
///
/// template-argument: [C++ 14.2]