aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDeclCXX.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/ParseDeclCXX.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/ParseDeclCXX.cpp')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp105
1 files changed, 40 insertions, 65 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index e36bc40bac..3ef3f93fdf 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -309,75 +309,42 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
// Parse the (optional) nested-name-specifier.
CXXScopeSpec SS;
- if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
- // FIXME: can we get a class template specialization or
- // template-id token here?
- if (Tok.isNot(tok::identifier))
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
Diag(Tok, diag::err_expected_ident);
- }
-
-
- // These variables encode the simple-template-id that we might end
- // up parsing below. We don't translate this into a type
- // automatically because (1) we want to create a separate
- // declaration for each specialization, and (2) we want to retain
- // more information about source locations that types provide.
- DeclTy *Template = 0;
- SourceLocation LAngleLoc, RAngleLoc;
- TemplateArgList TemplateArgs;
- TemplateArgIsTypeList TemplateArgIsType;
- TemplateArgLocationList TemplateArgLocations;
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0);
-
// Parse the (optional) class name or simple-template-id.
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
+ TemplateIdAnnotation *TemplateId = 0;
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ NameLoc = ConsumeToken();
- if (Tok.is(tok::less)) {
- // This is a simple-template-id.
- Action::TemplateNameKind TNK
- = Actions.isTemplateName(*Name, CurScope, Template, &SS);
-
- bool Invalid = false;
-
- // Parse the enclosed template argument list.
- if (TNK != Action::TNK_Non_template)
- Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc,
- &SS, true, LAngleLoc,
- TemplateArgs,
- TemplateArgIsType,
- TemplateArgLocations,
- RAngleLoc);
+ if (TemplateId->Kind != TNK_Class_template) {
+ // The template-name in the simple-template-id refers to
+ // something other than a class template. Give an appropriate
+ // error message and skip to the ';'.
+ SourceRange Range(NameLoc);
+ if (SS.isNotEmpty())
+ Range.setBegin(SS.getBeginLoc());
+
+ Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
+ << Name << static_cast<int>(TemplateId->Kind) << Range;
- TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0],
- TemplateArgs.size());
-
- if (TNK != Action::TNK_Class_template) {
- // The template-name in the simple-template-id refers to
- // something other than a class template. Give an appropriate
- // error message and skip to the ';'.
- SourceRange Range(NameLoc);
- if (SS.isNotEmpty())
- Range.setBegin(SS.getBeginLoc());
- else if (!Invalid)
-
- Diag(LAngleLoc, diag::err_template_spec_syntax_non_template)
- << Name << static_cast<int>(TNK) << Range;
-
- DS.SetTypeSpecError();
- SkipUntil(tok::semi, false, true);
- return;
- }
+ DS.SetTypeSpecError();
+ SkipUntil(tok::semi, false, true);
+ TemplateId->Destroy();
+ return;
}
}
// There are three options here. If we have 'struct foo;', then
// this is a forward declaration. If we have 'struct foo {...' or
- // 'struct fo :...' then this is a definition. Otherwise we have
+ // 'struct foo :...' then this is a definition. Otherwise we have
// something like 'struct foo xyz', a reference.
Action::TagKind TK;
if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
@@ -387,35 +354,43 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
else
TK = Action::TK_Reference;
- if (!Name && TK != Action::TK_Definition) {
+ if (!Name && !TemplateId && TK != Action::TK_Definition) {
// We have a declaration or reference to an anonymous class.
Diag(StartLoc, diag::err_anon_type_definition)
<< DeclSpec::getSpecifierName(TagType);
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, true);
+
+ if (TemplateId)
+ TemplateId->Destroy();
return;
}
// Create the tag portion of the class or class template.
DeclTy *TagOrTempDecl;
- if (Template && TK != Action::TK_Reference)
+ if (TemplateId && TK != Action::TK_Reference) {
// Explicit specialization or class template partial
// specialization. Let semantic analysis decide.
-
- // FIXME: we want a source range covering the simple-template-id.
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
TagOrTempDecl
= Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
- StartLoc, SS, /*Range*/
- Template, NameLoc,
- LAngleLoc, TemplateArgsPtr,
- &TemplateArgLocations[0],
- RAngleLoc, Attr,
+ StartLoc, SS,
+ TemplateId->Template,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc,
+ Attr,
Action::MultiTemplateParamsArg(Actions,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
-
- else if (TemplateParams && TK != Action::TK_Reference)
+ TemplateId->Destroy();
+ } else if (TemplateParams && TK != Action::TK_Reference)
TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc,
SS, Name, NameLoc, Attr,
Action::MultiTemplateParamsArg(Actions,