/// \brief Replaces a template-id annotation token with a type /// annotation token. /// /// If there was a failure when forming the type from the template-id, /// a type annotation token will still be created, but will have a /// NULL type pointer to signify an error. void Parser::AnnotateTemplateIdTokenAsType() { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); assert((TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) && "Only works for type and dependent templates"); ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult Type = Actions.ActOnTemplateIdType(TemplateId->SS, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(TemplateId->SS.getBeginLoc()); // End location stays the same // Replace the template-id annotation token, and possible the scope-specifier // that precedes it, with the typename annotation token. PP.AnnotateCachedTokens(Tok); TemplateId->Destroy(); }
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). /// /// template-argument: [C++ 14.2] /// constant-expression /// type-id /// id-expression ParsedTemplateArgument Parser::ParseTemplateArgument() { // C++ [temp.arg]p2: // In a template-argument, an ambiguity between a type-id and an // expression is resolved to a type-id, regardless of the form of // the corresponding template-parameter. // // Therefore, we initially try to parse a type-id. if (isCXXTypeId(TypeIdAsTemplateArgument)) { SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName(/*Range=*/0, Declarator::TemplateTypeArgContext); if (TypeArg.isInvalid()) return ParsedTemplateArgument(); return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get().getAsOpaquePtr(), Loc); } // Try to parse a template template argument. { TentativeParsingAction TPA(*this); ParsedTemplateArgument TemplateTemplateArgument = ParseTemplateTemplateArgument(); if (!TemplateTemplateArgument.isInvalid()) { TPA.Commit(); return TemplateTemplateArgument; } // Revert this tentative parse to parse a non-type template argument. TPA.Revert(); } // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); ExprResult ExprArg = ParseConstantExpression(); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); return ParsedTemplateArgument(ParsedTemplateArgument::NonType, ExprArg.release(), Loc); }
ParsedTemplateArgument Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc) { if (Arg.isInvalid()) return Arg; switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc); if (Result.isInvalid()) return ParsedTemplateArgument(); return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(), Arg.getLocation()); } case ParsedTemplateArgument::NonType: { ExprResult Result = ActOnPackExpansion(Arg.getAsExpr(), EllipsisLoc); if (Result.isInvalid()) return ParsedTemplateArgument(); return ParsedTemplateArgument(Arg.getKind(), Result.get(), Arg.getLocation()); } case ParsedTemplateArgument::Template: if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) { SourceRange R(Arg.getLocation()); if (Arg.getScopeSpec().isValid()) R.setBegin(Arg.getScopeSpec().getBeginLoc()); Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << R; return ParsedTemplateArgument(); } return Arg.getTemplatePackExpansion(EllipsisLoc); } llvm_unreachable("Unhandled template argument kind?"); return ParsedTemplateArgument(); }
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isAmbiguous, SourceLocation LParenLoc, ParamInfo *Params, unsigned NumParams, SourceLocation EllipsisLoc, SourceLocation RParenLoc, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, SourceLocation ConstQualifierLoc, SourceLocation VolatileQualifierLoc, SourceLocation RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType) { assert(!(TypeQuals & DeclSpec::TQ_atomic) && "function cannot have _Atomic qualifier"); DeclaratorChunk I; I.Kind = Function; I.Loc = LocalRangeBegin; I.EndLoc = LocalRangeEnd; I.Fun.AttrList = nullptr; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = EllipsisLoc.isValid(); I.Fun.isAmbiguous = isAmbiguous; I.Fun.LParenLoc = LParenLoc.getRawEncoding(); I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); I.Fun.RParenLoc = RParenLoc.getRawEncoding(); I.Fun.DeleteParams = false; I.Fun.TypeQuals = TypeQuals; I.Fun.NumParams = NumParams; I.Fun.Params = nullptr; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding(); I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding(); I.Fun.RestrictQualifierLoc = RestrictQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); I.Fun.NumExceptions = 0; I.Fun.Exceptions = nullptr; I.Fun.NoexceptExpr = nullptr; I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow"); assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow"); // new[] a parameter array if needed. if (NumParams) { // If the 'InlineParams' in Declarator is unused and big enough, put our // parameter list there (in an effort to avoid new/delete traffic). If it // is already used (consider a function returning a function pointer) or too // small (function with too many parameters), go to the heap. if (!TheDeclarator.InlineParamsUsed && NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.Params = TheDeclarator.InlineParams; I.Fun.DeleteParams = false; TheDeclarator.InlineParamsUsed = true; } else { I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams]; I.Fun.DeleteParams = true; } memcpy(I.Fun.Params, Params, sizeof(Params[0]) * NumParams); } // Check what exception specification information we should actually store. switch (ESpecType) { default: break; // By default, save nothing. case EST_Dynamic: // new[] an exception array if needed if (NumExceptions) { I.Fun.NumExceptions = NumExceptions; I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; for (unsigned i = 0; i != NumExceptions; ++i) { I.Fun.Exceptions[i].Ty = Exceptions[i]; I.Fun.Exceptions[i].Range = ExceptionRanges[i]; } } break; case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; case EST_Unparsed: I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; break; } return I; }
/// \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; }
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, SourceLocation ConstQualifierLoc, SourceLocation VolatileQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, TypeResult TrailingReturnType) { DeclaratorChunk I; I.Kind = Function; I.Loc = LocalRangeBegin; I.EndLoc = LocalRangeEnd; I.Fun.AttrList = 0; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = isVariadic; I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); I.Fun.DeleteArgInfo = false; I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; I.Fun.ArgInfo = 0; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding(); I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); I.Fun.NumExceptions = 0; I.Fun.Exceptions = 0; I.Fun.NoexceptExpr = 0; I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); // new[] an argument array if needed. if (NumArgs) { // If the 'InlineParams' in Declarator is unused and big enough, put our // parameter list there (in an effort to avoid new/delete traffic). If it // is already used (consider a function returning a function pointer) or too // small (function taking too many arguments), go to the heap. if (!TheDeclarator.InlineParamsUsed && NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.ArgInfo = TheDeclarator.InlineParams; I.Fun.DeleteArgInfo = false; TheDeclarator.InlineParamsUsed = true; } else { I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs]; I.Fun.DeleteArgInfo = true; } memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs); } // Check what exception specification information we should actually store. switch (ESpecType) { default: break; // By default, save nothing. case EST_Dynamic: // new[] an exception array if needed if (NumExceptions) { I.Fun.NumExceptions = NumExceptions; I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; for (unsigned i = 0; i != NumExceptions; ++i) { I.Fun.Exceptions[i].Ty = Exceptions[i]; I.Fun.Exceptions[i].Range = ExceptionRanges[i]; } } break; case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; } return I; }
/// TryAnnotateTypeOrScopeToken - If the current token position is on a /// typename (possibly qualified in C++) or a C++ scope specifier not followed /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens /// with a single annotation token representing the typename or C++ scope /// respectively. /// This simplifies handling of C++ scope specifiers and allows efficient /// backtracking without the need to re-parse and resolve nested-names and /// typenames. /// It will mainly be called when we expect to treat identifiers as typenames /// (if they are typenames). For example, in C we do not expect identifiers /// inside expressions to be treated as typenames so it will not be called /// for expressions in C. /// The benefit for C/ObjC is that a typename will be annotated and /// Actions.getTypeName will not be needed to be called again (e.g. getTypeName /// will not be called twice, once to check whether we have a declaration /// specifier, and another one to get the actual type inside /// ParseDeclarationSpecifiers). /// /// This returns true if the token was annotated or an unrecoverable error /// occurs. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateTypeOrScopeToken() { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename)) && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { // Parse a C++ typename-specifier, e.g., "typename T::type". // // typename-specifier: // 'typename' '::' [opt] nested-name-specifier identifier // 'typename' '::' [opt] nested-name-specifier template [opt] // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS); if (!HadNestedNameSpecifier) { Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return false; } TypeResult Ty; if (Tok.is(tok::identifier)) { // FIXME: check whether the next token is '<', first! Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), Tok.getLocation()); } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Function_template) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); return false; } AnnotateTemplateIdTokenAsType(0); assert(Tok.is(tok::annot_typename) && "AnnotateTemplateIdTokenAsType isn't working properly"); if (Tok.getAnnotationValue()) Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(), Tok.getAnnotationValue()); else Ty = true; } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); return false; } Tok.setKind(tok::annot_typename); Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get()); Tok.setAnnotationEndLoc(Tok.getLocation()); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); return true; } CXXScopeSpec SS; if (getLang().CPlusPlus) ParseOptionalCXXScopeSpecifier(SS); if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope, &SS)) { // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); Tok.setAnnotationValue(Ty); Tok.setAnnotationEndLoc(Tok.getLocation()); if (SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS.getBeginLoc()); // In case the tokens were cached, have Preprocessor replace // them with the annotation token. PP.AnnotateCachedTokens(Tok); return true; } if (!getLang().CPlusPlus) { // If we're in C, we can't have :: tokens at all (the lexer won't return // them). If the identifier is not a type, then it can't be scope either, // just early exit. return false; } // If this is a template-id, annotate with a template-id or type token. if (NextToken().is(tok::less)) { TemplateTy Template; if (TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, Template, &SS)) if (AnnotateTemplateIdToken(Template, TNK, &SS)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. return Tok.isNot(tok::identifier); } } // The current token, which is either an identifier or a // template-id, is not part of the annotation. Fall through to // push that token back into the stream and complete the C++ scope // specifier annotation. } if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template) { // A template-id that refers to a type was parsed into a // template-id annotation in a context where we weren't allowed // to produce a type annotation token. Update the template-id // annotation token to a type annotation token now. AnnotateTemplateIdTokenAsType(&SS); return true; } } if (SS.isEmpty()) return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon); // A C++ scope specifier that isn't followed by a typename. // Push the current token back into the token stream (or revert it if it is // cached) and use an annotation scope token for current token. if (PP.isBacktrackEnabled()) PP.RevertCachedTokens(1); else PP.EnterToken(Tok); Tok.setKind(tok::annot_cxxscope); Tok.setAnnotationValue(SS.getScopeRep()); Tok.setAnnotationRange(SS.getRange()); // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); return true; }