/// \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. /// /// If an unrecoverable parse error occurs and no annotation token can be /// formed, this function returns true. /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); assert(Template && Tok.is(tok::less) && "Parser isn't at the beginning of a template-id"); // Consume the template-name. SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, SS, false, LAngleLoc, TemplateArgs, RAngleLoc); if (Invalid) { // If we failed to parse the template ID but skipped ahead to a >, we're not // going to be able to form a token annotation. Eat the '>' if present. if (Tok.is(tok::greater)) ConsumeToken(); return true; } ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), TemplateArgs.size()); // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type = Actions.ActOnTemplateIdType(SS, Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) { // If we failed to parse the template ID but skipped ahead to a >, we're not // going to be able to form a token annotation. Eat the '>' if present. if (Tok.is(tok::greater)) ConsumeToken(); return true; } Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.get()); if (SS.isNotEmpty()) Tok.setLocation(SS.getBeginLoc()); else if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); else Tok.setLocation(TemplateNameLoc); } else { // Build a template-id annotation token that can be processed // later. Tok.setKind(tok::annot_template_id); TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = TemplateName.Identifier; TemplateId->Operator = OO_None; } else { TemplateId->Name = 0; TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; } TemplateId->SS = SS; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = ParsedTemplateArgument(TemplateArgs[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); // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); return false; }
/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration /// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could /// be either a decl-specifier or a function-style cast, and TPResult::Error() /// if a parsing error was found and reported. /// /// decl-specifier: /// storage-class-specifier /// type-specifier /// function-specifier /// 'friend' /// 'typedef' /// [C++0x] 'constexpr' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: /// 'register' /// 'static' /// 'extern' /// 'mutable' /// 'auto' /// [GNU] '__thread' /// /// function-specifier: /// 'inline' /// 'virtual' /// 'explicit' /// /// typedef-name: /// identifier /// /// type-specifier: /// simple-type-specifier /// class-specifier /// enum-specifier /// elaborated-type-specifier /// typename-specifier /// cv-qualifier /// /// simple-type-specifier: /// '::'[opt] nested-name-specifier[opt] type-name /// '::'[opt] nested-name-specifier 'template' /// simple-template-id [TODO] /// 'char' /// 'wchar_t' /// 'bool' /// 'short' /// 'int' /// 'long' /// 'signed' /// 'unsigned' /// 'float' /// 'double' /// 'void' /// [GNU] typeof-specifier /// [GNU] '_Complex' /// [C++0x] 'auto' [TODO] /// [C++0x] 'decltype' ( expression ) /// /// type-name: /// class-name /// enum-name /// typedef-name /// /// elaborated-type-specifier: /// class-key '::'[opt] nested-name-specifier[opt] identifier /// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt] /// simple-template-id /// 'enum' '::'[opt] nested-name-specifier[opt] identifier /// /// enum-name: /// identifier /// /// enum-specifier: /// 'enum' identifier[opt] '{' enumerator-list[opt] '}' /// 'enum' identifier[opt] '{' enumerator-list ',' '}' /// /// class-specifier: /// class-head '{' member-specification[opt] '}' /// /// class-head: /// class-key identifier[opt] base-clause[opt] /// class-key nested-name-specifier identifier base-clause[opt] /// class-key nested-name-specifier[opt] simple-template-id /// base-clause[opt] /// /// class-key: /// 'class' /// 'struct' /// 'union' /// /// cv-qualifier: /// 'const' /// 'volatile' /// [GNU] restrict /// Parser::TPResult Parser::isCXXDeclarationSpecifier() { switch (Tok.getKind()) { case tok::identifier: // foo::bar // Check for need to substitute AltiVec __vector keyword // for "vector" identifier. if (TryAltiVecVectorToken()) return TPResult::True(); // Fall through. case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); if (Tok.is(tok::identifier)) return TPResult::False(); return isCXXDeclarationSpecifier(); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); if (Next.is(tok::kw_new) || // ::new Next.is(tok::kw_delete)) // ::delete return TPResult::False(); } // Fall through. case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); return isCXXDeclarationSpecifier(); // decl-specifier: // storage-class-specifier // type-specifier // function-specifier // 'friend' // 'typedef' // 'constexpr' case tok::kw_friend: case tok::kw_typedef: case tok::kw_constexpr: // storage-class-specifier case tok::kw_register: case tok::kw_static: case tok::kw_extern: case tok::kw_mutable: case tok::kw_auto: case tok::kw___thread: // function-specifier case tok::kw_inline: case tok::kw_virtual: case tok::kw_explicit: // Modules case tok::kw___module_private__: // type-specifier: // simple-type-specifier // class-specifier // enum-specifier // elaborated-type-specifier // typename-specifier // cv-qualifier // class-specifier // elaborated-type-specifier case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: // cv-qualifier case tok::kw_const: case tok::kw_volatile: // GNU case tok::kw_restrict: case tok::kw__Complex: case tok::kw___attribute: return TPResult::True(); // Microsoft case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: case tok::kw___unaligned: return TPResult::True(); // Borland case tok::kw___pascal: return TPResult::True(); // AltiVec case tok::kw___vector: return TPResult::True(); case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind != TNK_Type_template) return TPResult::False(); CXXScopeSpec SS; AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename)); goto case_typename; } case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); if (!Tok.is(tok::annot_typename)) { // If the next token is an identifier or a type qualifier, then this // can't possibly be a valid expression either. if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) { CXXScopeSpec SS; Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { TentativeParsingAction PA(*this); ConsumeToken(); ConsumeToken(); bool isIdentifier = Tok.is(tok::identifier); TPResult TPR = TPResult::False(); if (!isIdentifier) TPR = isCXXDeclarationSpecifier(); PA.Revert(); if (isIdentifier || TPR == TPResult::True() || TPR == TPResult::Error()) return TPResult::Error(); } } return TPResult::False(); } // If that succeeded, fallthrough into the generic simple-type-id case. // The ambiguity resides in a simple-type-specifier/typename-specifier // followed by a '('. The '(' could either be the start of: // // direct-declarator: // '(' declarator ')' // // direct-abstract-declarator: // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] // exception-specification[opt] // '(' abstract-declarator ')' // // or part of a function-style cast expression: // // simple-type-specifier '(' expression-list[opt] ')' // // simple-type-specifier: case tok::annot_typename: case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLang().ObjC1 && NextToken().is(tok::less)) { // Tentatively parse the TentativeParsingAction PA(*this); ConsumeToken(); // The type token TPResult TPR = TryParseProtocolQualifiers(); bool isFollowedByParen = Tok.is(tok::l_paren); PA.Revert(); if (TPR == TPResult::Error()) return TPResult::Error(); if (isFollowedByParen) return TPResult::Ambiguous(); return TPResult::True(); } case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: case tok::kw_short: case tok::kw_int: case tok::kw_long: case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: case tok::annot_decltype: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); if (isStartOfObjCClassMessageMissingOpenBracket()) return TPResult::False(); return TPResult::True(); // GNU typeof support. case tok::kw_typeof: { if (NextToken().isNot(tok::l_paren)) return TPResult::True(); TentativeParsingAction PA(*this); TPResult TPR = TryParseTypeofSpecifier(); bool isFollowedByParen = Tok.is(tok::l_paren); PA.Revert(); if (TPR == TPResult::Error()) return TPResult::Error(); if (isFollowedByParen) return TPResult::Ambiguous(); return TPResult::True(); } // C++0x type traits support case tok::kw___underlying_type: return TPResult::True(); // C11 _Atomic case tok::kw__Atomic: return TPResult::True(); default: return TPResult::False(); } }