diff options
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<int, 4>", 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<int, 4>", 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 nested-name-specifier. + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + + if (TemplateId->Kind == TNK_Class_template) { + if (AnnotateTemplateIdTokenAsType(&SS)) + SS.setScopeRep(0); + + assert(Tok.is(tok::annot_typename) && + "AnnotateTemplateIdTokenAsType isn't working"); + + Token TypeToken = Tok; + ConsumeToken(); + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + if (!HasScopeSpecifier) { + SS.setBeginLoc(TypeToken.getLocation()); + HasScopeSpecifier = true; + } - return true; + SS.setScopeRep( + Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, + TypeToken.getAnnotationValue(), + TypeToken.getAnnotationRange(), + CCLoc)); + SS.setEndLoc(CCLoc); + continue; + } else + assert(false && "FIXME: Only class template names supported here"); + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + return HasScopeSpecifier; } /// ParseCXXIdExpression - Handle id-expression. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 747a4de152..64fc8fdf47 100644 --- a/l |