aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--docs/InternalsManual.html10
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.def4
-rw-r--r--include/clang/Basic/TemplateKinds.h37
-rw-r--r--include/clang/Lex/Preprocessor.h16
-rw-r--r--include/clang/Lex/Token.h51
-rw-r--r--include/clang/Parse/Action.h31
-rw-r--r--include/clang/Parse/Ownership.h2
-rw-r--r--include/clang/Parse/Parser.h6
-rw-r--r--lib/AST/DeclTemplate.cpp2
-rw-r--r--lib/Parse/MinimalAction.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp63
-rw-r--r--lib/Parse/ParseDeclCXX.cpp105
-rw-r--r--lib/Parse/ParseExprCXX.cpp144
-rw-r--r--lib/Parse/ParseTemplate.cpp123
-rw-r--r--lib/Parse/Parser.cpp36
-rw-r--r--lib/Sema/Sema.h14
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp11
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--test/SemaTemplate/class-template-spec.cpp2
-rw-r--r--test/SemaTemplate/default-arguments.cpp3
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp50
-rw-r--r--test/SemaTemplate/temp_arg.cpp6
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp52
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp15
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp13
25 files changed, 571 insertions, 233 deletions
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 7b6d201053..9250fd1dd7 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -628,12 +628,10 @@ by the Action::ActOnCXXGlobalScopeSpecifier and
Action::ActOnCXXNestedNameSpecifier callbacks. In the case of Sema, this is a
<tt>DeclContext*</tt>.</li>
-<li><b>tok::annot_template_id</b>: This annotation token represents a C++
-template-id such as "foo&lt;int, 4&gt;", which may refer to a function or type
-depending on whether foo is a function template or class template. The
-AnnotationValue pointer is a pointer to a malloc'd TemplateIdAnnotation object.
-FIXME: I don't think the parsing logic is right for this. Shouldn't type
-templates be turned into annot_typename??</li>
+<li><b>tok::annot_template_id</b>: This annotation token represents a
+C++ template-id such as "foo&lt;int, 4&gt;", where "foo" is the name
+of a template. The AnnotationValue pointer is a pointer to a malloc'd
+TemplateIdAnnotation object. Depending on the context, a parsed template-id that names a type might become a typename annotation token (if all we care about is the named type, e.g., because it occurs in a type specifier) or might remain a template-id token (if we want to retain more source location information or produce a new type, e.g., in a declaration of a class template specialization). template-id annotation tokens that refer to a type can be "upgraded" to typename annotation tokens by the parser.</li>
</ol>
diff --git a/include/clang/Basic/DiagnosticParseKinds.def b/include/clang/Basic/DiagnosticParseKinds.def
index 6d87c70a17..e8485c69bf 100644
--- a/include/clang/Basic/DiagnosticParseKinds.def
+++ b/include/clang/Basic/DiagnosticParseKinds.def
@@ -274,6 +274,10 @@ DIAG(err_expected_class_before, ERROR,
"expected 'class' before '%0'")
DIAG(err_template_spec_syntax_non_template, ERROR,
"identifier followed by '<' indicates a class template specialization but %0 %select{does not refer to a template|refers to a function template|<unused>|refers to a template template parameter}1")
+DIAG(err_id_after_template_in_nested_name_spec, ERROR,
+ "expected template name after 'template' keyword in nested name specifier")
+DIAG(err_less_after_template_name_in_nested_name_spec, ERROR,
+ "expected '<' after 'template %0' in nested name specifier")
// Language specific pragmas
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
new file mode 100644
index 0000000000..dbaf5bdb60
--- /dev/null
+++ b/include/clang/Basic/TemplateKinds.h
@@ -0,0 +1,37 @@
+//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TemplateNameKind enum.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TEMPLATEKINDS_H
+#define LLVM_CLANG_TEMPLATEKINDS_H
+
+namespace clang {
+
+/// \brief Specifies the kind of template name that an identifier refers to.
+enum TemplateNameKind {
+ /// The name does not refer to a template.
+ TNK_Non_template = 0,
+ /// The name refers to a function template or a set of overloaded
+ /// functions that includes at least one function template.
+ TNK_Function_template,
+ /// The name refers to a class template.
+ TNK_Class_template,
+ /// The name referes to a template template parameter.
+ TNK_Template_template_parm,
+ /// The name is dependent and is known to be a template name based
+ /// on syntax, e.g., "Alloc::template rebind<Other>".
+ TNK_Dependent_template_name
+};
+
+}
+#endif
+
+
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index a0ed1767df..9d99142480 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -431,7 +431,21 @@ public:
if (CachedLexPos != 0 && isBacktrackEnabled())
AnnotatePreviousCachedTokens(Tok);
}
-
+
+ /// \brief Replace the last token with an annotation token.
+ ///
+ /// Like AnnotateCachedTokens(), this routine replaces an
+ /// already-parsed (and resolved) token with an annotation
+ /// token. However, this routine only replaces the last token with
+ /// the annotation token; it does not affect any other cached
+ /// tokens. This function has no effect if backtracking is not
+ /// enabled.
+ void ReplaceLastTokenWithAnnotation(const Token &Tok) {
+ assert(Tok.isAnnotation() && "Expected annotation token");
+ if (CachedLexPos != 0 && isBacktrackEnabled())
+ CachedTokens[CachedLexPos-1] = Tok;
+ }
+
/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
/// the specified Token's location, translating the token's start
/// position in the current buffer into a SourcePosition object for rendering.
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 73e087ecb6..5bbb63add9 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_TOKEN_H
#define LLVM_CLANG_TOKEN_H
+#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/SourceLocation.h"
@@ -247,24 +248,62 @@ struct PPConditionalInfo {
/// TemplateIdAnnotation - Information about a template-id annotation
/// token, which contains the template declaration, template
-/// arguments, and the source locations for important tokens.
+/// arguments, whether those template arguments were types or
+/// expressions, and the source locations for important tokens. All of
+/// the information about template arguments is allocated directly
+/// after this structure.
struct TemplateIdAnnotation {
/// TemplateNameLoc - The location of the template name within the
/// source.
SourceLocation TemplateNameLoc;
- /// Template - The declaration of the template corresponding to the
+ /// FIXME: Temporarily stores the name of a specialization
+ IdentifierInfo *Name;
+
+ /// The declaration of the template corresponding to the
/// template-name. This is an Action::DeclTy*.
void *Template;
- /// LAngleLoc - The location of the '<' before the template argument
+ /// The kind of template that Template refers to.
+ TemplateNameKind Kind;
+
+ /// The location of the '<' before the template argument
/// list.
SourceLocation LAngleLoc;
- /// NumArgs - The number of template arguments. The arguments
- /// themselves are Action::TemplateArgTy pointers allocated directly
- /// following the TemplateIdAnnotation structure.
+ /// The location of the '>' after the template argument
+ /// list.
+ SourceLocation RAngleLoc;
+
+ /// NumArgs - The number of template arguments.
unsigned NumArgs;
+
+ /// \brief Retrieves a pointer to the template arguments
+ void **getTemplateArgs() { return (void **)(this + 1); }
+
+ /// \brief Retrieves a pointer to the array of template argument
+ /// locations.
+ SourceLocation *getTemplateArgLocations() {
+ return (SourceLocation *)(getTemplateArgs() + NumArgs);
+ }
+
+ /// \brief Retrieves a pointer to the array of flags that states
+ /// whether the template arguments are types.
+ bool *getTemplateArgIsType() {
+ return (bool *)(getTemplateArgLocations() + NumArgs);
+ }
+
+ static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
+ TemplateIdAnnotation *TemplateId
+ = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
+ sizeof(void*) * NumArgs +
+ sizeof(SourceLocation) * NumArgs +
+ sizeof(bool) * NumArgs);
+ TemplateId->NumArgs = NumArgs;
+ return TemplateId;
+ }
+
+ void Destroy() { free(this); }
};
} // end namespace clang
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 5103c16ee3..ebcd79caae 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -16,6 +16,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Parse/AccessSpecifier.h"
#include "clang/Parse/Ownership.h"
@@ -134,20 +135,6 @@ public:
virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = 0) = 0;
- /// \brief Specifies the kind of template name. Returned from
- /// isTemplateName.
- enum TemplateNameKind {
- /// The name does not refer to a template.
- TNK_Non_template = 0,
- /// The name refers to a function template or a set of overloaded
- /// functions that includes at least one function template.
- TNK_Function_template,
- /// The name refers to a class template.
- TNK_Class_template,
- /// The name referes to a template template parameter.
- TNK_Template_template_parm
- };
-
/// \brief Determines whether the identifier II is a template name
/// in the current scope. If so, the kind of template name is
/// returned, and \p TemplateDecl receives the declaration. An
@@ -178,6 +165,22 @@ public:
return 0;
}
+ /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+ /// nested-name-specifier that involves a template-id, e.g.,
+ /// "foo::bar<int, float>::", and now we need to build a scope
+ /// specifier. \p SS is empty or the previously parsed nested-name
+ /// part ("foo::"), \p Type is the already-parsed class template
+ /// specialization (or other template-id that names a type), \p
+ /// TypeRange is the source range where the type is located, and \p
+ /// CCLoc is the location of the trailing '::'.
+ virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+ const CXXScopeSpec &SS,
+ TypeTy *Type,
+ SourceRange TypeRange,
+ SourceLocation CCLoc) {
+ return 0;
+ }
+
/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
/// scope or nested-name-specifier) is parsed, part of a declarator-id.
/// After this method is called, according to [C++ 3.4.3p3], names should be
diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h
index 684203d6d1..9665576a05 100644
--- a/include/clang/Parse/Ownership.h
+++ b/include/clang/Parse/Ownership.h
@@ -538,7 +538,7 @@ namespace clang
void **Args;
bool *ArgIsType;
mutable unsigned Count;
-
+
#if !defined(DISABLE_SMART_POINTERS)
void destroy() {
if (!Count)
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2432f445d9..9ef23d4865 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -993,7 +993,6 @@ private:
//===--------------------------------------------------------------------===//
// C++ 14: Templates [temp]
typedef llvm::SmallVector<DeclTy *, 4> TemplateParameterList;
- typedef Action::TemplateNameKind TemplateNameKind;
// C++ 14.1: Template Parameters [temp.param]
DeclTy *ParseTemplateDeclarationOrSpecialization(unsigned Context);
@@ -1023,7 +1022,10 @@ private:
SourceLocation &RAngleLoc);
void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
- const CXXScopeSpec *SS = 0);
+ const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc = SourceLocation(),
+ bool AllowTypeAnnotation = true);
+ bool AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
TemplateArgIsTypeList &TemplateArgIsType,
TemplateArgLocationList &TemplateArgLocations);
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index e10e270c7d..3ed4435bb3 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -162,7 +162,7 @@ ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
NumTemplateArgs(NumTemplateArgs), SpecializationKind(TSK_Undeclared) {
TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg)
- *Arg = TemplateArgs[ArgIdx];
+ new (Arg) TemplateArgument(TemplateArgs[ArgIdx]);
}
ClassTemplateSpecializationDecl *
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index ce15cf9dda..9cd5b979ca 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -95,7 +95,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
return false;
}
-Action::TemplateNameKind
+TemplateNameKind
MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
DeclTy *&TemplateDecl,
const CXXScopeSpec *SS) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 6e68b20fa5..bdd352f341 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -558,21 +558,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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
@@ -610,6 +597,25 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If a type specifier follows, it will be diagnosed elsewhere.
continue;
}
+
+ // type-name
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind != TNK_Class_template) {
+ // This template-id does not refer to a type name, so we're
+ // done with the type-specifiers.
+ goto DoneWithDeclSpec;
+ }
+
+ // Turn the template-id annotation token into a type annotation
+ // token, then try again to parse it as a type-specifier.
+ if (AnnotateTemplateIdTokenAsType())
+ DS.SetTypeSpecError();
+
+ continue;
+ }
+
// GNU attributes support.
case tok::kw___attribute:
DS.AddAttributes(ParseAttributes());
@@ -1749,7 +1755,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
/// operator-function-id
/// conversion-function-id [TODO]
/// '~' class-name
-/// template-id [TODO]
+/// template-id
///
void Parser::ParseDirectDeclarator(Declarator &D) {
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
@@ -1768,21 +1774,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (Tok.is(tok::identifier)) {
assert(Tok.getIdentifierInfo() && "Not an identifier?");
- // 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) &&
- (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
- CurScope, Template))) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- 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());
- }
// If this identifier is the name of the current class, it's a
// constructor name.
- else if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){
+ if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){
D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), CurScope),
Tok.getLocation());
@@ -1791,6 +1785,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+ // FIXME: Could this template-id name a constructor?
+
+ // FIXME: This is an egregious hack, where we silently ignore
+ // the specialization (which should be a function template
+ // specialization name) and use the name instead. This hack
+ // will go away when we have support for function
+ // specializations.
+ D.SetIdentifier(TemplateId->Name, Tok.getLocation());
+ TemplateId->Destroy();
+ ConsumeToken();
+ goto PastIdentifier;
} else if (Tok.is(tok::kw_operator)) {
SourceLocation OperatorLoc = Tok.getLocation();
SourceLocation EndLoc;
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,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index fb60bde4f1..50e6657ad8 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -42,6 +42,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
return true;
}
+ bool HasScopeSpecifier = false;
+
if (Tok.is(tok::coloncolon)) {
// ::new and ::delete aren't nested-name-specifiers.
tok::TokenKind NextKind = NextToken().getKind();
@@ -53,32 +55,132 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
SS.setBeginLoc(CCLoc);
SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
SS.setEndLoc(CCLoc);
- } else if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
- SS.setBeginLoc(Tok.getLocation());
- } else {
- // Not a CXXScopeSpecifier.
- return false;
+ HasScopeSpecifier = true;
}
- // nested-name-specifier:
- // type-name '::'
- // namespace-name '::'
- // nested-name-specifier identifier '::'
- // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
- while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- SourceLocation IdLoc = ConsumeToken();
- assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
- SourceLocation CCLoc = ConsumeToken();
- if (SS.isInvalid())
+ while (true) {
+ // nested-name-specifier:
+ // type-name '::'
+ // namespace-name '::'
+ // nested-name-specifier identifier '::'
+ if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
+ // We have an identifier followed by a '::'. Lookup this name
+ // as the name in a nested-name-specifier.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(IdLoc);
+ HasScopeSpecifier = true;
+ }
+
+ if (SS.isInvalid())
+ continue;
+
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
+ SS.setEndLoc(CCLoc);
continue;
+ }
- SS.setScopeRep(
- Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
- SS.setEndLoc(CCLoc);
- }
+ // nested-name-specifier:
+ // type-name '::'
+ // nested-name-specifier 'template'[opt] simple-template-id '::'
+ if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
+ Tok.is(tok::kw_template)) {
+ // Parse the optional 'template' keyword, then make sure we have
+ // 'identifier <' after it.
+ SourceLocation TemplateKWLoc;
+ if (Tok.is(tok::kw_template)) {
+ TemplateKWLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(),
+ diag::err_id_after_template_in_nested_name_spec)
+ << SourceRange(TemplateKWLoc);
+ break;
+ }
+
+ if (NextToken().isNot(tok::less)) {
+ Diag(NextToken().getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << Tok.getIdentifierInfo()->getName()
+ << SourceRange(TemplateKWLoc, Tok.getLocation());
+ break;
+ }
+ }
+ else {
+ // FIXME: If the nested-name-specifier thus far is dependent,
+ // we need to break out of here, because this '<' is taken as
+ // an operator and not as part of a simple-template-id.
+ }
+
+ DeclTy *Template = 0;
+ TemplateNameKind TNK = TNK_Non_template;
+ // FIXME: If the nested-name-specifier thus far is dependent,
+ // set TNK = TNK_Dependent_template_name and skip the
+ // "isTemplateName" check.
+ TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS);
+ if (TNK) {
+ // We have found a template name, so annotate this this token
+ // with a template-id annotation. We do not permit the
+ // template-id to be translated into a type annotation,
+ // because some clients (e.g., the parsing of class template
+ // specializations) still want to see the original template-id
+ // token.
+ AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false);
+ continue;
+ }
+ }
+
+ if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
+ // We have
+ //
+ // simple-template-id '::'
+ //
+ // So we need to check whether the simple-template-id is of the
+ // right kind (it should name a type), and then convert it into
+ // a type within the nes