//===--- Parser.h - C Language Parser ---------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the Parser interface. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_PARSE_PARSER_H #define LLVM_CLANG_PARSE_PARSER_H #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaOpenMP.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/OpenMP/OMPContext.h" #include "llvm/Support/SaveAndRestore.h" #include #include namespace clang { class PragmaHandler; class Scope; class BalancedDelimiterTracker; class CorrectionCandidateCallback; class DeclGroupRef; class DiagnosticBuilder; struct LoopHint; class Parser; class ParsingDeclRAIIObject; class ParsingDeclSpec; class ParsingDeclarator; class ParsingFieldDeclarator; class ColonProtectionRAIIObject; class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class OMPClause; class OpenACCClause; class ObjCTypeParamList; struct OMPTraitProperty; struct OMPTraitSelector; struct OMPTraitSet; class OMPTraitInfo; enum class AnnotatedNameKind { /// Annotation has failed and emitted an error. Error, /// The identifier is a tentatively-declared name. TentativeDecl, /// The identifier is a template name. FIXME: Add an annotation for that. TemplateName, /// The identifier can't be resolved. Unresolved, /// Annotation was successful. Success }; /// The kind of extra semi diagnostic to emit. enum class ExtraSemiKind { OutsideFunction = 0, InsideStruct = 1, InstanceVariableList = 2, AfterMemberFunctionDefinition = 3 }; /// The kind of template we are parsing. enum class ParsedTemplateKind { /// We are not parsing a template at all. NonTemplate = 0, /// We are parsing a template declaration. Template, /// We are parsing an explicit specialization. ExplicitSpecialization, /// We are parsing an explicit instantiation. ExplicitInstantiation }; enum class CachedInitKind { DefaultArgument, DefaultInitializer }; // Definitions for Objective-c context sensitive keywords recognition. enum class ObjCTypeQual { in = 0, out, inout, oneway, bycopy, byref, nonnull, nullable, null_unspecified, NumQuals }; /// If a typo should be encountered, should typo correction suggest type names, /// non type names, or both? enum class TypoCorrectionTypeBehavior { AllowNonTypes, AllowTypes, AllowBoth, }; /// Control what ParseCastExpression will parse. enum class CastParseKind { AnyCastExpr = 0, UnaryExprOnly, PrimaryExprOnly }; /// ParenParseOption - Control what ParseParenExpression will parse. enum class ParenParseOption { SimpleExpr, // Only parse '(' expression ')' FoldExpr, // Also allow fold-expression CompoundStmt, // Also allow '(' compound-statement ')' CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}' CastExpr // Also allow '(' type-name ')' }; /// In a call to ParseParenExpression, are the initial parentheses part of an /// operator that requires the parens be there (like typeof(int)) or could they /// be something else, such as part of a compound literal or a sizeof /// expression, etc. enum class ParenExprKind { PartOfOperator, // typeof(int) Unknown, // sizeof(int) or sizeof (int)1.0f, or compound literal, etc }; /// Describes the behavior that should be taken for an __if_exists /// block. enum class IfExistsBehavior { /// Parse the block; this code is always used. Parse, /// Skip the block entirely; this code is never used. Skip, /// Parse the block as a dependent block, which may be used in /// some template instantiations but not others. Dependent }; /// Specifies the context in which type-id/expression /// disambiguation will occur. enum class TentativeCXXTypeIdContext { InParens, Unambiguous, AsTemplateArgument, InTrailingReturnType, AsGenericSelectionArgument, }; /// The kind of attribute specifier we have found. enum class CXX11AttributeKind { /// This is not an attribute specifier. NotAttributeSpecifier, /// This should be treated as an attribute-specifier. AttributeSpecifier, /// The next tokens are '[[', but this is not an attribute-specifier. This /// is ill-formed by C++11 [dcl.attr.grammar]p6. InvalidAttributeSpecifier }; /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has /// been read. /// /// \nosubgrouping class Parser : public CodeCompletionHandler { // Table of Contents // ----------------- // 1. Parsing (Parser.cpp) // 2. C++ Class Inline Methods (ParseCXXInlineMethods.cpp) // 3. Declarations (ParseDecl.cpp) // 4. C++ Declarations (ParseDeclCXX.cpp) // 5. Expressions (ParseExpr.cpp) // 6. C++ Expressions (ParseExprCXX.cpp) // 7. HLSL Constructs (ParseHLSL.cpp) // 8. Initializers (ParseInit.cpp) // 9. Objective-C Constructs (ParseObjc.cpp) // 10. OpenACC Constructs (ParseOpenACC.cpp) // 11. OpenMP Constructs (ParseOpenMP.cpp) // 12. Pragmas (ParsePragma.cpp) // 13. Statements (ParseStmt.cpp) // 14. `inline asm` Statement (ParseStmtAsm.cpp) // 15. C++ Templates (ParseTemplate.cpp) // 16. Tentative Parsing (ParseTentative.cpp) /// \name Parsing /// Implementations are in Parser.cpp ///@{ public: friend class ColonProtectionRAIIObject; friend class PoisonSEHIdentifiersRAIIObject; friend class ParenBraceBracketBalancer; friend class BalancedDelimiterTracker; Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); ~Parser() override; const LangOptions &getLangOpts() const { return PP.getLangOpts(); } const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } Preprocessor &getPreprocessor() const { return PP; } Sema &getActions() const { return Actions; } AttributeFactory &getAttrFactory() { return AttrFactory; } const Token &getCurToken() const { return Tok; } Scope *getCurScope() const { return Actions.getCurScope(); } void incrementMSManglingNumber() const { return Actions.incrementMSManglingNumber(); } // Type forwarding. All of these are statically 'void*', but they may all be // different actual classes based on the actions in place. typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; /// Initialize - Warm up the parser. /// void Initialize(); /// Parse the first top-level declaration in a translation unit. /// /// \verbatim /// translation-unit: /// [C] external-declaration /// [C] translation-unit external-declaration /// [C++] top-level-declaration-seq[opt] /// [C++20] global-module-fragment[opt] module-declaration /// top-level-declaration-seq[opt] private-module-fragment[opt] /// \endverbatim /// /// Note that in C, it is an error if there is no first declaration. bool ParseFirstTopLevelDecl(DeclGroupPtrTy &Result, Sema::ModuleImportState &ImportState); /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. /// /// \verbatim /// top-level-declaration: /// declaration /// [C++20] module-import-declaration /// \endverbatim bool ParseTopLevelDecl(DeclGroupPtrTy &Result, Sema::ModuleImportState &ImportState); bool ParseTopLevelDecl() { DeclGroupPtrTy Result; Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module; return ParseTopLevelDecl(Result, IS); } /// ConsumeToken - Consume the current 'peek token' and lex the next one. /// This does not work with special tokens: string literals, code completion, /// annotation tokens and balanced tokens must be handled using the specific /// consume methods. /// Returns the location of the consumed token. SourceLocation ConsumeToken() { assert(!isTokenSpecial() && "Should consume special tokens with Consume*Token"); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } bool TryConsumeToken(tok::TokenKind Expected) { if (Tok.isNot(Expected)) return false; assert(!isTokenSpecial() && "Should consume special tokens with Consume*Token"); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return true; } bool TryConsumeToken(tok::TokenKind Expected, SourceLocation &Loc) { if (!TryConsumeToken(Expected)) return false; Loc = PrevTokLocation; return true; } /// ConsumeAnyToken - Dispatch to the right Consume* method based on the /// current token type. This should only be used in cases where the type of /// the token really isn't known, e.g. in error recovery. SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { if (isTokenParen()) return ConsumeParen(); if (isTokenBracket()) return ConsumeBracket(); if (isTokenBrace()) return ConsumeBrace(); if (isTokenStringLiteral()) return ConsumeStringToken(); if (Tok.is(tok::code_completion)) return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken() : handleUnexpectedCodeCompletionToken(); if (Tok.isAnnotation()) return ConsumeAnnotationToken(); return ConsumeToken(); } SourceLocation getEndOfPreviousToken() const; /// GetLookAheadToken - This peeks ahead N tokens and returns that token /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) /// returns the token after Tok, etc. /// /// Note that this differs from the Preprocessor's LookAhead method, because /// the Parser always has one token lexed that the preprocessor doesn't. /// const Token &GetLookAheadToken(unsigned N) { if (N == 0 || Tok.is(tok::eof)) return Tok; return PP.LookAhead(N - 1); } /// NextToken - This peeks ahead one token and returns it without /// consuming it. const Token &NextToken() { return PP.LookAhead(0); } /// getTypeAnnotation - Read a parsed type out of an annotation token. static TypeResult getTypeAnnotation(const Token &Tok) { if (!Tok.getAnnotationValue()) return TypeError(); return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); } /// 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 an error occurred. /// /// 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 TryAnnotateTypeOrScopeToken(ImplicitTypenameContext AllowImplicitTypename = ImplicitTypenameContext::No); /// Try to annotate a type or scope token, having already parsed an /// optional scope specifier. \p IsNewScope should be \c true unless the scope /// specifier was extracted from an existing tok::annot_cxxscope annotation. bool TryAnnotateTypeOrScopeTokenAfterScopeSpec( CXXScopeSpec &SS, bool IsNewScope, ImplicitTypenameContext AllowImplicitTypename); /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only /// annotates C++ scope specifiers and template-ids. This returns /// true if there was an error that could not be recovered from. /// /// 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 TryAnnotateCXXScopeToken(bool EnteringContext = false); bool MightBeCXXScopeToken() { return getLangOpts().CPlusPlus && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)); } bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) { return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext); } //===--------------------------------------------------------------------===// // Scope manipulation /// ParseScope - Introduces a new scope for parsing. The kind of /// scope is determined by ScopeFlags. Objects of this type should /// be created on the stack to coincide with the position where the /// parser enters the new scope, and this object's constructor will /// create that new scope. Similarly, once the object is destroyed /// the parser will exit the scope. class ParseScope { Parser *Self; ParseScope(const ParseScope &) = delete; void operator=(const ParseScope &) = delete; public: // ParseScope - Construct a new object to manage a scope in the // parser Self where the new Scope is created with the flags // ScopeFlags, but only when we aren't about to enter a compound statement. ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true, bool BeforeCompoundStmt = false) : Self(Self) { if (EnteredScope && !BeforeCompoundStmt) Self->EnterScope(ScopeFlags); else { if (BeforeCompoundStmt) Self->incrementMSManglingNumber(); this->Self = nullptr; } } // Exit - Exit the scope associated with this object now, rather // than waiting until the object is destroyed. void Exit() { if (Self) { Self->ExitScope(); Self = nullptr; } } ~ParseScope() { Exit(); } }; /// Introduces zero or more scopes for parsing. The scopes will all be exited /// when the object is destroyed. class MultiParseScope { Parser &Self; unsigned NumScopes = 0; MultiParseScope(const MultiParseScope &) = delete; public: MultiParseScope(Parser &Self) : Self(Self) {} void Enter(unsigned ScopeFlags) { Self.EnterScope(ScopeFlags); ++NumScopes; } void Exit() { while (NumScopes) { Self.ExitScope(); --NumScopes; } } ~MultiParseScope() { Exit(); } }; /// EnterScope - Start a new scope. void EnterScope(unsigned ScopeFlags); /// ExitScope - Pop a scope off the scope stack. void ExitScope(); //===--------------------------------------------------------------------===// // Diagnostic Emission and Error recovery. DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); DiagnosticBuilder Diag(unsigned DiagID) { return Diag(Tok, DiagID); } DiagnosticBuilder DiagCompat(SourceLocation Loc, unsigned CompatDiagId); DiagnosticBuilder DiagCompat(const Token &Tok, unsigned CompatDiagId); DiagnosticBuilder DiagCompat(unsigned CompatDiagId) { return DiagCompat(Tok, CompatDiagId); } /// Control flags for SkipUntil functions. enum SkipUntilFlags { StopAtSemi = 1 << 0, ///< Stop skipping at semicolon /// Stop skipping at specified token, but don't skip the token itself StopBeforeMatch = 1 << 1, StopAtCodeCompletion = 1 << 2 ///< Stop at code completion }; friend constexpr SkipUntilFlags operator|(SkipUntilFlags L, SkipUntilFlags R) { return static_cast(static_cast(L) | static_cast(R)); } /// SkipUntil - Read tokens until we get to the specified token, then consume /// it (unless StopBeforeMatch is specified). Because we cannot guarantee /// that the token will ever occur, this skips to the next token, or to some /// likely good stopping point. If Flags has StopAtSemi flag, skipping will /// stop at a ';' character. Balances (), [], and {} delimiter tokens while /// skipping. /// /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool SkipUntil(tok::TokenKind T, SkipUntilFlags Flags = static_cast(0)) { return SkipUntil(llvm::ArrayRef(T), Flags); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, SkipUntilFlags Flags = static_cast(0)) { tok::TokenKind TokArray[] = {T1, T2}; return SkipUntil(TokArray, Flags); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3, SkipUntilFlags Flags = static_cast(0)) { tok::TokenKind TokArray[] = {T1, T2, T3}; return SkipUntil(TokArray, Flags); } /// SkipUntil - Read tokens until we get to the specified token, then consume /// it (unless no flag StopBeforeMatch). Because we cannot guarantee that the /// token will ever occur, this skips to the next token, or to some likely /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' /// character. /// /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool SkipUntil(ArrayRef Toks, SkipUntilFlags Flags = static_cast(0)); private: Preprocessor &PP; /// Tok - The current token we are peeking ahead. All parsing methods assume /// that this is valid. Token Tok; // PrevTokLocation - The location of the token we previously // consumed. This token is used for diagnostics where we expected to // see a token following another token (e.g., the ';' at the end of // a statement). SourceLocation PrevTokLocation; /// Tracks an expected type for the current token when parsing an expression. /// Used by code completion for ranking. PreferredTypeBuilder PreferredType; unsigned short ParenCount = 0, BracketCount = 0, BraceCount = 0; unsigned short MisplacedModuleBeginCount = 0; /// Actions - These are the callbacks we invoke as we parse various constructs /// in the file. Sema &Actions; DiagnosticsEngine &Diags; StackExhaustionHandler StackHandler; /// ScopeCache - Cache scopes to reduce malloc traffic. static constexpr int ScopeCacheSize = 16; unsigned NumCachedScopes; Scope *ScopeCache[ScopeCacheSize]; /// Identifiers used for SEH handling in Borland. These are only /// allowed in particular circumstances // __except block IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except filter expression IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __finally IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; /// Contextual keywords for Microsoft extensions. IdentifierInfo *Ident__except; // C++2a contextual keywords. mutable IdentifierInfo *Ident_import; mutable IdentifierInfo *Ident_module; std::unique_ptr CommentSemaHandler; /// Gets set to true after calling ProduceSignatureHelp, it is for a /// workaround to make sure ProduceSignatureHelp is only called at the deepest /// function call. bool CalledSignatureHelp = false; IdentifierInfo *getSEHExceptKeyword(); /// Whether to skip parsing of function bodies. /// /// This option can be used, for example, to speed up searches for /// declarations/definitions when indexing. bool SkipFunctionBodies; //===--------------------------------------------------------------------===// // Low-Level token peeking and consumption methods. // /// isTokenParen - Return true if the cur token is '(' or ')'. bool isTokenParen() const { return Tok.isOneOf(tok::l_paren, tok::r_paren); } /// isTokenBracket - Return true if the cur token is '[' or ']'. bool isTokenBracket() const { return Tok.isOneOf(tok::l_square, tok::r_square); } /// isTokenBrace - Return true if the cur token is '{' or '}'. bool isTokenBrace() const { return Tok.isOneOf(tok::l_brace, tok::r_brace); } /// isTokenStringLiteral - True if this token is a string-literal. bool isTokenStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); } /// isTokenSpecial - True if this token requires special consumption methods. bool isTokenSpecial() const { return isTokenStringLiteral() || isTokenParen() || isTokenBracket() || isTokenBrace() || Tok.is(tok::code_completion) || Tok.isAnnotation(); } /// Returns true if the current token is '=' or is a type of '='. /// For typos, give a fixit to '=' bool isTokenEqualOrEqualTypo(); /// Return the current token to the token stream and make the given /// token the current token. void UnconsumeToken(Token &Consumed) { Token Next = Tok; PP.EnterToken(Consumed, /*IsReinject*/ true); PP.Lex(Tok); PP.EnterToken(Next, /*IsReinject*/ true); } SourceLocation ConsumeAnnotationToken() { assert(Tok.isAnnotation() && "wrong consume method"); SourceLocation Loc = Tok.getLocation(); PrevTokLocation = Tok.getAnnotationEndLoc(); PP.Lex(Tok); return Loc; } /// ConsumeParen - This consume method keeps the paren count up-to-date. /// SourceLocation ConsumeParen() { assert(isTokenParen() && "wrong consume method"); if (Tok.getKind() == tok::l_paren) ++ParenCount; else if (ParenCount) { AngleBrackets.clear(*this); --ParenCount; // Don't let unbalanced )'s drive the count negative. } PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeBracket - This consume method keeps the bracket count up-to-date. /// SourceLocation ConsumeBracket() { assert(isTokenBracket() && "wrong consume method"); if (Tok.getKind() == tok::l_square) ++BracketCount; else if (BracketCount) { AngleBrackets.clear(*this); --BracketCount; // Don't let unbalanced ]'s drive the count negative. } PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeBrace - This consume method keeps the brace count up-to-date. /// SourceLocation ConsumeBrace() { assert(isTokenBrace() && "wrong consume method"); if (Tok.getKind() == tok::l_brace) ++BraceCount; else if (BraceCount) { AngleBrackets.clear(*this); --BraceCount; // Don't let unbalanced }'s drive the count negative. } PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// ConsumeStringToken - Consume the current 'peek token', lexing a new one /// and returning the token kind. This method is specific to strings, as it /// handles string literal concatenation, as per C99 5.1.1.2, translation /// phase #6. SourceLocation ConsumeStringToken() { assert(isTokenStringLiteral() && "Should only consume string literals with this method"); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// Consume the current code-completion token. /// /// This routine can be called to consume the code-completion token and /// continue processing in special cases where \c cutOffParsing() isn't /// desired, such as token caching or completion with lookahead. SourceLocation ConsumeCodeCompletionToken() { assert(Tok.is(tok::code_completion)); PrevTokLocation = Tok.getLocation(); PP.Lex(Tok); return PrevTokLocation; } /// When we are consuming a code-completion token without having matched /// specific position in the grammar, provide code-completion results based /// on context. /// /// \returns the source location of the code-completion token. SourceLocation handleUnexpectedCodeCompletionToken(); /// Abruptly cut off parsing; mainly used when we have reached the /// code-completion point. void cutOffParsing() { if (PP.isCodeCompletionEnabled()) PP.setCodeCompletionReached(); // Cut off parsing by acting as if we reached the end-of-file. Tok.setKind(tok::eof); } /// Determine if we're at the end of the file or at a transition /// between modules. bool isEofOrEom() { tok::TokenKind Kind = Tok.getKind(); return Kind == tok::eof || Kind == tok::annot_module_begin || Kind == tok::annot_module_end || Kind == tok::annot_module_include || Kind == tok::annot_repl_input_end; } static void setTypeAnnotation(Token &Tok, TypeResult T) { assert((T.isInvalid() || T.get()) && "produced a valid-but-null type annotation?"); Tok.setAnnotationValue(T.isInvalid() ? nullptr : T.get().getAsOpaquePtr()); } static NamedDecl *getNonTypeAnnotation(const Token &Tok) { return static_cast(Tok.getAnnotationValue()); } static void setNonTypeAnnotation(Token &Tok, NamedDecl *ND) { Tok.setAnnotationValue(ND); } static IdentifierInfo *getIdentifierAnnotation(const Token &Tok) { return static_cast(Tok.getAnnotationValue()); } static void setIdentifierAnnotation(Token &Tok, IdentifierInfo *ND) { Tok.setAnnotationValue(ND); } /// Read an already-translated primary expression out of an annotation /// token. static ExprResult getExprAnnotation(const Token &Tok) { return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue()); } /// Set the primary expression corresponding to the given annotation /// token. static void setExprAnnotation(Token &Tok, ExprResult ER) { Tok.setAnnotationValue(ER.getAsOpaquePointer()); } /// Attempt to classify the name at the current token position. This may /// form a type, scope or primary expression annotation, or replace the token /// with a typo-corrected keyword. This is only appropriate when the current /// name must refer to an entity which has already been declared. /// /// \param CCC Indicates how to perform typo-correction for this name. If /// NULL, no typo correction will be performed. /// \param AllowImplicitTypename Whether we are in a context where a dependent /// nested-name-specifier without typename is treated as a type (e.g. /// T::type). AnnotatedNameKind TryAnnotateName(CorrectionCandidateCallback *CCC = nullptr, ImplicitTypenameContext AllowImplicitTypename = ImplicitTypenameContext::No); /// Push a tok::annot_cxxscope token onto the token stream. void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation); /// TryKeywordIdentFallback - For compatibility with system headers using /// keywords as identifiers, attempt to convert the current token to an /// identifier and optionally disable the keyword for the remainder of the /// translation unit. This returns false if the token was not replaced, /// otherwise emits a diagnostic and returns true. bool TryKeywordIdentFallback(bool DisableKeyword); /// Get the TemplateIdAnnotation from the token and put it in the /// cleanup pool so that it gets destroyed when parsing the current top level /// declaration is finished. TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the /// input. If so, it is consumed and false is returned. /// /// If a trivial punctuator misspelling is encountered, a FixIt error /// diagnostic is issued and false is returned after recovery. /// /// If the input is malformed, this emits the specified diagnostic and true is /// returned. bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag = diag::err_expected, StringRef DiagMsg = ""); /// The parser expects a semicolon and, if present, will consume it. /// /// If the next token is not a semicolon, this emits the specified diagnostic, /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior /// to the semicolon, consumes that extra token. bool ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed = ""); /// Consume any extra semi-colons until the end of the line. void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified); /// Return false if the next token is an identifier. An 'expected identifier' /// error is emitted otherwise. /// /// The parser tries to recover from the error by checking if the next token /// is a C++ keyword when parsing Objective-C++. Return false if the recovery /// was successful. bool expectIdentifier(); /// Kinds of compound pseudo-tokens formed by a sequence of two real tokens. enum class CompoundToken { /// A '(' '{' beginning a statement-expression. StmtExprBegin, /// A '}' ')' ending a statement-expression. StmtExprEnd, /// A '[' '[' beginning a C++11 or C23 attribute. AttrBegin, /// A ']' ']' ending a C++11 or C23 attribute. AttrEnd, /// A '::' '*' forming a C++ pointer-to-member declaration. MemberPtr, }; /// Check that a compound operator was written in a "sensible" way, and warn /// if not. void checkCompoundToken(SourceLocation FirstTokLoc, tok::TokenKind FirstTokKind, CompoundToken Op); void diagnoseUseOfC11Keyword(const Token &Tok); /// RAII object used to modify the scope flags for the current scope. class ParseScopeFlags { Scope *CurScope; unsigned OldFlags = 0; ParseScopeFlags(const ParseScopeFlags &) = delete; void operator=(const ParseScopeFlags &) = delete; public: /// Set the flags for the current scope to ScopeFlags. If ManageFlags is /// false, this object does nothing. ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true); /// Restore the flags for the current scope to what they were before this /// object overrode them. ~ParseScopeFlags(); }; /// Emits a diagnostic suggesting parentheses surrounding a /// given range. /// /// \param Loc The location where we'll emit the diagnostic. /// \param DK The kind of diagnostic to emit. /// \param ParenRange Source range enclosing code that should be /// parenthesized. void SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange); //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. /// ParseExternalDeclaration: /// /// The `Attrs` that are passed in are C++11 attributes and appertain to the /// declaration. /// /// \verbatim /// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] /// function-definition /// declaration /// [GNU] asm-definition /// [GNU] __extension__ external-declaration /// [OBJC] objc-class-definition /// [OBJC] objc-class-declaration /// [OBJC] objc-alias-declaration /// [OBJC] objc-protocol-definition /// [OBJC] objc-method-definition /// [OBJC] @end /// [C++] linkage-specification /// [GNU] asm-definition: /// simple-asm-expr ';' /// [C++11] empty-declaration /// [C++11] attribute-declaration /// /// [C++11] empty-declaration: /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration /// /// [C++20] module-import-declaration /// \endverbatim /// DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS = nullptr); /// Determine whether the current token, if it occurs after a /// declarator, continues a declaration or declaration list. bool isDeclarationAfterDeclarator(); /// Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS = nullptr, AccessSpecifier AS = AS_none); /// Parse either a function-definition or a declaration. We can't tell which /// we have until we read up to the compound-statement in function-definition. /// TemplateParams, if non-NULL, provides the template parameters when we're /// parsing a C++ template-declaration. /// /// \verbatim /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement /// [C90] function-definition: [C99 6.7.1] - implicit int result /// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement /// /// declaration: [C99 6.7] /// declaration-specifiers init-declarator-list[opt] ';' /// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] /// [OMP] threadprivate-directive /// [OMP] allocate-directive [TODO] /// \endverbatim /// DeclGroupPtrTy ParseDeclOrFunctionDefInternal(ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec &DS, AccessSpecifier AS); void SkipFunctionBody(); struct ParsedTemplateInfo; class LateParsedAttrList; /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. /// /// \verbatim /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement /// [C90] function-definition: [C99 6.7.1] - implicit int result /// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator ctor-initializer[opt] /// function-body /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// \endverbatim /// Decl *ParseFunctionDefinition( ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), LateParsedAttrList *LateParsedAttrs = nullptr); /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void ParseKNRParamDeclarations(Declarator &D); /// ParseSimpleAsm /// /// \verbatim /// [GNU] simple-asm-expr: /// 'asm' '(' asm-string-literal ')' /// \endverbatim /// /// EndLoc is filled with the location of the last token of the simple-asm. ExprResult ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc); /// ParseAsmStringLiteral - This is just a normal string-literal, but is not /// allowed to be a wide string, and is not subject to character translation. /// Unlike GCC, we also diagnose an empty string literal when parsing for an /// asm label as opposed to an asm statement, because such a construct does /// not behave well. /// /// \verbatim /// [GNU] asm-string-literal: /// string-literal /// \endverbatim /// ExprResult ParseAsmStringLiteral(bool ForAsmLabel); /// Describes the condition of a Microsoft __if_exists or /// __if_not_exists block. struct IfExistsCondition { /// The location of the initial keyword. SourceLocation KeywordLoc; /// Whether this is an __if_exists block (rather than an /// __if_not_exists block). bool IsIfExists; /// Nested-name-specifier preceding the name. CXXScopeSpec SS; /// The name we're looking for. UnqualifiedId Name; /// The behavior of this __if_exists or __if_not_exists block /// should. IfExistsBehavior Behavior; }; bool ParseMicrosoftIfExistsCondition(IfExistsCondition &Result); void ParseMicrosoftIfExistsExternalDeclaration(); //===--------------------------------------------------------------------===// // Modules /// Parse a declaration beginning with the 'module' keyword or C++20 /// context-sensitive keyword (optionally preceded by 'export'). /// /// \verbatim /// module-declaration: [C++20] /// 'export'[opt] 'module' module-name attribute-specifier-seq[opt] ';' /// /// global-module-fragment: [C++2a] /// 'module' ';' top-level-declaration-seq[opt] /// module-declaration: [C++2a] /// 'export'[opt] 'module' module-name module-partition[opt] /// attribute-specifier-seq[opt] ';' /// private-module-fragment: [C++2a] /// 'module' ':' 'private' ';' top-level-declaration-seq[opt] /// \endverbatim DeclGroupPtrTy ParseModuleDecl(Sema::ModuleImportState &ImportState); /// Parse a module import declaration. This is essentially the same for /// Objective-C and C++20 except for the leading '@' (in ObjC) and the /// trailing optional attributes (in C++). /// /// \verbatim /// [ObjC] @import declaration: /// '@' 'import' module-name ';' /// [ModTS] module-import-declaration: /// 'import' module-name attribute-specifier-seq[opt] ';' /// [C++20] module-import-declaration: /// 'export'[opt] 'import' module-name /// attribute-specifier-seq[opt] ';' /// 'export'[opt] 'import' module-partition /// attribute-specifier-seq[opt] ';' /// 'export'[opt] 'import' header-name /// attribute-specifier-seq[opt] ';' /// \endverbatim Decl *ParseModuleImport(SourceLocation AtLoc, Sema::ModuleImportState &ImportState); /// Try recover parser when module annotation appears where it must not /// be found. /// \returns false if the recover was successful and parsing may be continued, /// or true if parser must bail out to top level and handle the token there. bool parseMisplacedModuleImport(); bool tryParseMisplacedModuleImport() { tok::TokenKind Kind = Tok.getKind(); if (Kind == tok::annot_module_begin || Kind == tok::annot_module_end || Kind == tok::annot_module_include) return parseMisplacedModuleImport(); return false; } /// Parse a C++ / Objective-C module name (both forms use the same /// grammar). /// /// \verbatim /// module-name: /// module-name-qualifier[opt] identifier /// module-name-qualifier: /// module-name-qualifier[opt] identifier '.' /// \endverbatim bool ParseModuleName(SourceLocation UseLoc, SmallVectorImpl &Path, bool IsImport); //===--------------------------------------------------------------------===// // Preprocessor code-completion pass-through void CodeCompleteDirective(bool InConditional) override; void CodeCompleteInConditionalExclusion() override; void CodeCompleteMacroName(bool IsDefinition) override; void CodeCompletePreprocessorExpression() override; void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex) override; void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled) override; void CodeCompleteNaturalLanguage() override; ///@} // // // ------------------------------------------------------------------------- // // /// \name C++ Class Inline Methods /// Implementations are in ParseCXXInlineMethods.cpp ///@{ private: struct ParsingClass; /// [class.mem]p1: "... the class is regarded as complete within /// - function bodies /// - default arguments /// - exception-specifications (TODO: C++0x) /// - and brace-or-equal-initializers for non-static data members /// (including such things in nested classes)." /// LateParsedDeclarations build the tree of those elements so they can /// be parsed after parsing the top-level class. class LateParsedDeclaration { public: virtual ~LateParsedDeclaration(); virtual void ParseLexedMethodDeclarations(); virtual void ParseLexedMemberInitializers(); virtual void ParseLexedMethodDefs(); virtual void ParseLexedAttributes(); virtual void ParseLexedPragmas(); }; /// Inner node of the LateParsedDeclaration tree that parses /// all its members recursively. class LateParsedClass : public LateParsedDeclaration { public: LateParsedClass(Parser *P, ParsingClass *C); ~LateParsedClass() override; void ParseLexedMethodDeclarations() override; void ParseLexedMemberInitializers() override; void ParseLexedMethodDefs() override; void ParseLexedAttributes() override; void ParseLexedPragmas() override; // Delete copy constructor and copy assignment operator. LateParsedClass(const LateParsedClass &) = delete; LateParsedClass &operator=(const LateParsedClass &) = delete; private: Parser *Self; ParsingClass *Class; }; /// Contains the lexed tokens of an attribute with arguments that /// may reference member variables and so need to be parsed at the /// end of the class declaration after parsing all other member /// member declarations. /// FIXME: Perhaps we should change the name of LateParsedDeclaration to /// LateParsedTokens. struct LateParsedAttribute : public LateParsedDeclaration { Parser *Self; CachedTokens Toks; IdentifierInfo &AttrName; IdentifierInfo *MacroII = nullptr; SourceLocation AttrNameLoc; SmallVector Decls; explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name, SourceLocation Loc) : Self(P), AttrName(Name), AttrNameLoc(Loc) {} void ParseLexedAttributes() override; void addDecl(Decl *D) { Decls.push_back(D); } }; /// Contains the lexed tokens of a pragma with arguments that /// may reference member variables and so need to be parsed at the /// end of the class declaration after parsing all other member /// member declarations. class LateParsedPragma : public LateParsedDeclaration { Parser *Self = nullptr; AccessSpecifier AS = AS_none; CachedTokens Toks; public: explicit LateParsedPragma(Parser *P, AccessSpecifier AS) : Self(P), AS(AS) {} void takeToks(CachedTokens &Cached) { Toks.swap(Cached); } const CachedTokens &toks() const { return Toks; } AccessSpecifier getAccessSpecifier() const { return AS; } void ParseLexedPragmas() override; }; // A list of late-parsed attributes. Used by ParseGNUAttributes. class LateParsedAttrList : public SmallVector { public: LateParsedAttrList(bool PSoon = false, bool LateAttrParseExperimentalExtOnly = false) : ParseSoon(PSoon), LateAttrParseExperimentalExtOnly(LateAttrParseExperimentalExtOnly) {} bool parseSoon() { return ParseSoon; } /// returns true iff the attribute to be parsed should only be late parsed /// if it is annotated with `LateAttrParseExperimentalExt` bool lateAttrParseExperimentalExtOnly() { return LateAttrParseExperimentalExtOnly; } private: bool ParseSoon; // Are we planning to parse these shortly after creation? bool LateAttrParseExperimentalExtOnly; }; /// Contains the lexed tokens of a member function definition /// which needs to be parsed at the end of the class declaration /// after parsing all other member declarations. struct LexedMethod : public LateParsedDeclaration { Parser *Self; Decl *D; CachedTokens Toks; explicit LexedMethod(Parser *P, Decl *MD) : Self(P), D(MD) {} void ParseLexedMethodDefs() override; }; /// LateParsedDefaultArgument - Keeps track of a parameter that may /// have a default argument that cannot be parsed yet because it /// occurs within a member function declaration inside the class /// (C++ [class.mem]p2). struct LateParsedDefaultArgument { explicit LateParsedDefaultArgument( Decl *P, std::unique_ptr Toks = nullptr) : Param(P), Toks(std::move(Toks)) {} /// Param - The parameter declaration for this parameter. Decl *Param; /// Toks - The sequence of tokens that comprises the default /// argument expression, not including the '=' or the terminating /// ')' or ','. This will be NULL for parameters that have no /// default argument. std::unique_ptr Toks; }; /// LateParsedMethodDeclaration - A method declaration inside a class that /// contains at least one entity whose parsing needs to be delayed /// until the class itself is completely-defined, such as a default /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration : public LateParsedDeclaration { explicit LateParsedMethodDeclaration(Parser *P, Decl *M) : Self(P), Method(M), ExceptionSpecTokens(nullptr) {} void ParseLexedMethodDeclarations() override; Parser *Self; /// Method - The method declaration. Decl *Method; /// DefaultArgs - Contains the parameters of the function and /// their default arguments. At least one of the parameters will /// have a default argument, but all of the parameters of the /// method will be stored so that they can be reintroduced into /// scope at the appropriate times. SmallVector DefaultArgs; /// The set of tokens that make up an exception-specification that /// has not yet been parsed. CachedTokens *ExceptionSpecTokens; }; /// LateParsedMemberInitializer - An initializer for a non-static class data /// member whose parsing must to be delayed until the class is completely /// defined (C++11 [class.mem]p2). struct LateParsedMemberInitializer : public LateParsedDeclaration { LateParsedMemberInitializer(Parser *P, Decl *FD) : Self(P), Field(FD) {} void ParseLexedMemberInitializers() override; Parser *Self; /// Field - The field declaration. Decl *Field; /// CachedTokens - The sequence of tokens that comprises the initializer, /// including any leading '='. CachedTokens Toks; }; /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) /// C++ class, its method declarations that contain parts that won't be /// parsed until after the definition is completed (C++ [class.mem]p2), /// the method declarations and possibly attached inline definitions /// will be stored here with the tokens that will be parsed to create those /// entities. typedef SmallVector LateParsedDeclarationsContainer; /// Utility to re-enter a possibly-templated scope while parsing its /// late-parsed components. struct ReenterTemplateScopeRAII; /// Utility to re-enter a class scope while parsing its late-parsed /// components. struct ReenterClassScopeRAII; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. NamedDecl *ParseCXXInlineMethodDef(AccessSpecifier AS, const ParsedAttributesView &AccessAttrs, ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers &VS, SourceLocation PureSpecLoc); /// Parse the optional ("message") part of a deleted-function-body. StringLiteral *ParseCXXDeletedFunctionMessage(); /// If we've encountered '= delete' in a context where it is ill-formed, such /// as in the declaration of a non-function, also skip the ("message") part if /// it is present to avoid issuing further diagnostics. void SkipDeletedFunctionBody(); /// ParseCXXNonStaticMemberInitializer - We parsed and verified that the /// specified Declarator is a well formed C++ non-static data member /// declaration. Now lex its initializer and store its tokens for parsing /// after the class is complete. void ParseCXXNonStaticMemberInitializer(Decl *VarD); /// Wrapper class which calls ParseLexedAttribute, after setting up the /// scope appropriately. void ParseLexedAttributes(ParsingClass &Class); /// Parse all attributes in LAs, and attach them to Decl D. void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition); /// Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and /// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. void ParseLexedAttribute(LateParsedAttribute &LA, bool EnterScope, bool OnDefinition); /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was /// delayed (such as default arguments) and parse them. void ParseLexedMethodDeclarations(ParsingClass &Class); void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); /// ParseLexedMethodDefs - We finished parsing the member specification of a /// top (non-nested) C++ class. Now go over the stack of lexed methods that /// were collected during its parsing and parse them all. void ParseLexedMethodDefs(ParsingClass &Class); void ParseLexedMethodDef(LexedMethod &LM); /// ParseLexedMemberInitializers - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the stack of /// lexed data member initializers that were collected during its parsing and /// parse them all. void ParseLexedMemberInitializers(ParsingClass &Class); void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI); ///@} // // // ------------------------------------------------------------------------- // // /// \name Declarations /// Implementations are in ParseDecl.cpp ///@{ public: /// SkipMalformedDecl - Read tokens until we get to some likely good stopping /// point for skipping past a simple-declaration. /// /// Skip until we reach something which seems like a sensible place to pick /// up parsing after a malformed declaration. This will sometimes stop sooner /// than SkipUntil(tok::r_brace) would, but will never stop later. void SkipMalformedDecl(); /// ParseTypeName /// \verbatim /// type-name: [C99 6.7.6] /// specifier-qualifier-list abstract-declarator[opt] /// \endverbatim /// /// Called type-id in C++. TypeResult ParseTypeName(SourceRange *Range = nullptr, DeclaratorContext Context = DeclaratorContext::TypeName, AccessSpecifier AS = AS_none, Decl **OwnedType = nullptr, ParsedAttributes *Attrs = nullptr); private: /// Ident_vector, Ident_bool, Ident_Bool - cached IdentifierInfos for "vector" /// and "bool" fast comparison. Only present if AltiVec or ZVector are /// enabled. IdentifierInfo *Ident_vector; IdentifierInfo *Ident_bool; IdentifierInfo *Ident_Bool; /// Ident_pixel - cached IdentifierInfos for "pixel" fast comparison. /// Only present if AltiVec enabled. IdentifierInfo *Ident_pixel; /// Identifier for "introduced". IdentifierInfo *Ident_introduced; /// Identifier for "deprecated". IdentifierInfo *Ident_deprecated; /// Identifier for "obsoleted". IdentifierInfo *Ident_obsoleted; /// Identifier for "unavailable". IdentifierInfo *Ident_unavailable; /// Identifier for "message". IdentifierInfo *Ident_message; /// Identifier for "strict". IdentifierInfo *Ident_strict; /// Identifier for "replacement". IdentifierInfo *Ident_replacement; /// Identifier for "environment". IdentifierInfo *Ident_environment; /// Identifiers used by the 'external_source_symbol' attribute. IdentifierInfo *Ident_language, *Ident_defined_in, *Ident_generated_declaration, *Ident_USR; /// Factory object for creating ParsedAttr objects. AttributeFactory AttrFactory; /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, /// replacing them with the non-context-sensitive keywords. This returns /// true if the token was replaced. bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) { if (!getLangOpts().AltiVec && !getLangOpts().ZVector) return false; if (Tok.getIdentifierInfo() != Ident_vector && Tok.getIdentifierInfo() != Ident_bool && Tok.getIdentifierInfo() != Ident_Bool && (!getLangOpts().AltiVec || Tok.getIdentifierInfo() != Ident_pixel)) return false; return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid); } /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector /// identifier token, replacing it with the non-context-sensitive __vector. /// This returns true if the token was replaced. bool TryAltiVecVectorToken() { if ((!getLangOpts().AltiVec && !getLangOpts().ZVector) || Tok.getIdentifierInfo() != Ident_vector) return false; return TryAltiVecVectorTokenOutOfLine(); } /// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be /// called from TryAltiVecVectorToken. bool TryAltiVecVectorTokenOutOfLine(); bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid); void ParseLexedCAttributeList(LateParsedAttrList &LA, bool EnterScope, ParsedAttributes *OutAttrs = nullptr); /// Finish parsing an attribute for which parsing was delayed. /// This will be called at the end of parsing a class declaration /// for each LateParsedAttribute. We consume the saved tokens and /// create an attribute with the arguments filled in. We add this /// to the Attribute list for the decl. void ParseLexedCAttribute(LateParsedAttribute &LA, bool EnterScope, ParsedAttributes *OutAttrs = nullptr); void ParseLexedPragmas(ParsingClass &Class); void ParseLexedPragma(LateParsedPragma &LP); /// Consume tokens and store them in the passed token container until /// we've passed the try keyword and constructor initializers and have /// consumed the opening brace of the function body. The opening brace will be /// consumed if and only if there was no error. /// /// \return True on error. bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks); /// ConsumeAndStoreInitializer - Consume and store the token at the passed /// token container until the end of the current initializer expression /// (either a default argument or an in-class initializer for a non-static /// data member). /// /// Returns \c true if we reached the end of something initializer-shaped, /// \c false if we bailed out. bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK); /// Consume and store tokens from the '?' to the ':' in a conditional /// expression. bool ConsumeAndStoreConditional(CachedTokens &Toks); bool ConsumeAndStoreUntil(tok::TokenKind T1, CachedTokens &Toks, bool StopAtSemi = true, bool ConsumeFinalToken = true) { return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken); } /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). /// If StopAtSemi is true, then we will stop early at a ';' character. /// Returns true if token 'T1' or 'T2' was found. /// NOTE: This is a specialized version of Parser::SkipUntil. bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, bool StopAtSemi = true, bool ConsumeFinalToken = true); //===--------------------------------------------------------------------===// // C99 6.7: Declarations. /// A context for parsing declaration specifiers. TODO: flesh this /// out, there are other significant restrictions on specifiers than /// would be best implemented in the parser. enum class DeclSpecContext { DSC_normal, // normal context DSC_class, // class context, enables 'friend' DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list DSC_trailing, // C++11 trailing-type-specifier in a trailing return type DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration DSC_conv_operator, // C++ type-specifier-seq in an conversion operator DSC_top_level, // top-level/namespace declaration context DSC_template_param, // template parameter context DSC_template_arg, // template argument context DSC_template_type_arg, // template type argument context DSC_objc_method_result, // ObjC method result context, enables // 'instancetype' DSC_condition, // condition declaration context DSC_association, // A _Generic selection expression's type association DSC_new, // C++ new expression }; /// Is this a context in which we are parsing just a type-specifier (or /// trailing-type-specifier)? static bool isTypeSpecifier(DeclSpecContext DSC) { switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_template_param: case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_objc_method_result: case DeclSpecContext::DSC_condition: return false; case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_conv_operator: case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_alias_declaration: case DeclSpecContext::DSC_association: case DeclSpecContext::DSC_new: return true; } llvm_unreachable("Missing DeclSpecContext case"); } /// Whether a defining-type-specifier is permitted in a given context. enum class AllowDefiningTypeSpec { /// The grammar doesn't allow a defining-type-specifier here, and we must /// not parse one (eg, because a '{' could mean something else). No, /// The grammar doesn't allow a defining-type-specifier here, but we permit /// one for error recovery purposes. Sema will reject. NoButErrorRecovery, /// The grammar allows a defining-type-specifier here, even though it's /// always invalid. Sema will reject. YesButInvalid, /// The grammar allows a defining-type-specifier here, and one can be valid. Yes }; /// Is this a context in which we are parsing defining-type-specifiers (and /// so permit class and enum definitions in addition to non-defining class and /// enum elaborated-type-specifiers)? static AllowDefiningTypeSpec isDefiningTypeSpecifierContext(DeclSpecContext DSC, bool IsCPlusPlus) { switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_alias_declaration: case DeclSpecContext::DSC_objc_method_result: return AllowDefiningTypeSpec::Yes; case DeclSpecContext::DSC_condition: case DeclSpecContext::DSC_template_param: return AllowDefiningTypeSpec::YesButInvalid; case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_type_specifier: return AllowDefiningTypeSpec::NoButErrorRecovery; case DeclSpecContext::DSC_association: return IsCPlusPlus ? AllowDefiningTypeSpec::NoButErrorRecovery : AllowDefiningTypeSpec::Yes; case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_conv_operator: case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_new: return AllowDefiningTypeSpec::No; } llvm_unreachable("Missing DeclSpecContext case"); } /// Is this a context in which an opaque-enum-declaration can appear? static bool isOpaqueEnumDeclarationContext(DeclSpecContext DSC) { switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: return true; case DeclSpecContext::DSC_alias_declaration: case DeclSpecContext::DSC_objc_method_result: case DeclSpecContext::DSC_condition: case DeclSpecContext::DSC_template_param: case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_association: case DeclSpecContext::DSC_conv_operator: case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_new: return false; } llvm_unreachable("Missing DeclSpecContext case"); } /// Is this a context in which we can perform class template argument /// deduction? static bool isClassTemplateDeductionContext(DeclSpecContext DSC) { switch (DSC) { case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_template_param: case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_condition: case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_association: case DeclSpecContext::DSC_conv_operator: case DeclSpecContext::DSC_new: return true; case DeclSpecContext::DSC_objc_method_result: case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_alias_declaration: return false; } llvm_unreachable("Missing DeclSpecContext case"); } // Is this a context in which an implicit 'typename' is allowed? static ImplicitTypenameContext getImplicitTypenameContext(DeclSpecContext DSC) { switch (DSC) { case DeclSpecContext::DSC_class: case DeclSpecContext::DSC_top_level: case DeclSpecContext::DSC_type_specifier: case DeclSpecContext::DSC_template_type_arg: case DeclSpecContext::DSC_trailing: case DeclSpecContext::DSC_alias_declaration: case DeclSpecContext::DSC_template_param: case DeclSpecContext::DSC_new: return ImplicitTypenameContext::Yes; case DeclSpecContext::DSC_normal: case DeclSpecContext::DSC_objc_method_result: case DeclSpecContext::DSC_condition: case DeclSpecContext::DSC_template_arg: case DeclSpecContext::DSC_conv_operator: case DeclSpecContext::DSC_association: return ImplicitTypenameContext::No; } llvm_unreachable("Missing DeclSpecContext case"); } /// Information on a C++0x for-range-initializer found while parsing a /// declaration which turns out to be a for-range-declaration. struct ForRangeInit { SourceLocation ColonLoc; ExprResult RangeExpr; SmallVector LifetimeExtendTemps; bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); } }; struct ForRangeInfo : ForRangeInit { StmtResult LoopVar; }; /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a DeclaratorContext value. This returns the /// location of the semicolon in DeclEnd. /// /// \verbatim /// declaration: [C99 6.7] /// block-declaration -> /// simple-declaration /// others [FIXME] /// [C++] template-declaration /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration /// [C++11/C11] static_assert-declaration /// others... [FIXME] /// \endverbatim /// DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, SourceLocation *DeclSpecStart = nullptr); /// \verbatim /// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] /// declaration-specifiers init-declarator-list[opt] ';' /// [C++11] attribute-specifier-seq decl-specifier-seq[opt] /// init-declarator-list ';' ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive /// [OMP] allocate-directive [TODO] /// /// for-range-declaration: [C++11 6.5p1: stmt.ranged] /// attribute-specifier-seq[opt] type-specifier-seq declarator /// \endverbatim /// /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. If it is true, it checks for and eats it. /// /// If FRI is non-null, we might be parsing a for-range-declaration instead /// of a simple-declaration. If we find that we are, we also parse the /// for-range-initializer, and place it here. /// /// DeclSpecStart is used when decl-specifiers are parsed before parsing /// the Declaration. The SourceLocation for this Decl is set to /// DeclSpecStart if DeclSpecStart is non-null. DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, bool RequireSemi, ForRangeInit *FRI = nullptr, SourceLocation *DeclSpecStart = nullptr); /// ParseDeclGroup - Having concluded that this is either a function /// definition or a group of object declarations, actually parse the /// result. /// /// Returns true if this might be the start of a declarator, or a common typo /// for a declarator. bool MightBeDeclarator(DeclaratorContext Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, ParsedAttributes &Attrs, ParsedTemplateInfo &TemplateInfo, SourceLocation *DeclEnd = nullptr, ForRangeInit *FRI = nullptr); /// Parse 'declaration' after parsing 'declaration-specifiers /// declarator'. This method parses the remainder of the declaration /// (including any attributes or initializer, among other things) and /// finalizes the declaration. /// /// \verbatim /// init-declarator: [C99 6.7] /// declarator /// declarator '=' initializer /// [GNU] declarator simple-asm-expr[opt] attributes[opt] /// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer /// [C++] declarator initializer[opt] /// /// [C++] initializer: /// [C++] '=' initializer-clause /// [C++] '(' expression-list ')' /// [C++0x] '=' 'default' [TODO] /// [C++0x] '=' 'delete' /// [C++0x] braced-init-list /// \endverbatim /// /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// Decl *ParseDeclarationAfterDeclarator( Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); /// Parse an optional simple-asm-expr and attributes, and attach them to a /// declarator. Returns true on an error. bool ParseAsmAttributesAfterDeclarator(Declarator &D); Decl *ParseDeclarationAfterDeclaratorAndAttributes( Declarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), ForRangeInit *FRI = nullptr); /// ParseImplicitInt - This method is called when we have an non-typename /// identifier in a declspec (which normally terminates the decl spec) when /// the declspec has no type specifier. In this case, the declspec is either /// malformed or is "implicit int" (in K&R and C89). /// /// This method handles diagnosing this prettily and returns false if the /// declspec is done being processed. If it recovers and thinks there may be /// other pieces of declspec after it, it returns true. /// bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC, ParsedAttributes &Attrs); /// Determine the declaration specifier context from the declarator /// context. /// /// \param Context the declarator context, which is one of the /// DeclaratorContext enumerator values. DeclSpecContext getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context); void ParseDeclarationSpecifiers(DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS = AS_none, DeclSpecContext DSC = DeclSpecContext::DSC_normal, LateParsedAttrList *LateAttrs = nullptr) { return ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC, LateAttrs, getImplicitTypenameContext(DSC)); } /// ParseDeclarationSpecifiers /// \verbatim /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] /// type-specifier declaration-specifiers[opt] /// [C99] function-specifier declaration-specifiers[opt] /// [C11] alignment-specifier declaration-specifiers[opt] /// [GNU] attributes declaration-specifiers[opt] /// [Clang] '__module_private__' declaration-specifiers[opt] /// [ObjC1] '__kindof' declaration-specifiers[opt] /// /// storage-class-specifier: [C99 6.7.1] /// 'typedef' /// 'extern' /// 'static' /// 'auto' /// 'register' /// [C++] 'mutable' /// [C++11] 'thread_local' /// [C11] '_Thread_local' /// [GNU] '__thread' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' /// [C++] 'virtual' /// [C++] 'explicit' /// [OpenCL] '__kernel' /// 'friend': [C++ dcl.friend] /// 'constexpr': [C++0x dcl.constexpr] /// \endverbatim void ParseDeclarationSpecifiers(DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC, LateParsedAttrList *LateAttrs, ImplicitTypenameContext AllowImplicitTypename); /// Determine whether we're looking at something that might be a declarator /// in a simple-declaration. If it can't possibly be a declarator, maybe /// diagnose a missing semicolon after a prior tag definition in the decl /// specifier. /// /// \return \c true if an error occurred and this can't be any kind of /// declaration. bool DiagnoseMissingSemiAfterTagDefinition( DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext, LateParsedAttrList *LateAttrs = nullptr); void ParseSpecifierQualifierList( DeclSpec &DS, AccessSpecifier AS = AS_none, DeclSpecContext DSC = DeclSpecContext::DSC_normal) { ParseSpecifierQualifierList(DS, getImplicitTypenameContext(DSC), AS, DSC); } /// ParseSpecifierQualifierList /// \verbatim /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] /// type-qualifier specifier-qualifier-list[opt] /// [GNU] attributes specifier-qualifier-list[opt] /// \endverbatim /// void ParseSpecifierQualifierList( DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename, AccessSpecifier AS = AS_none, DeclSpecContext DSC = DeclSpecContext::DSC_normal); /// ParseEnumSpecifier /// \verbatim /// enum-specifier: [C99 6.7.2.2] /// 'enum' identifier[opt] '{' enumerator-list '}' ///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' /// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' attributes[opt] /// [MS] 'enum' __declspec[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// /// [C++11] enum-head '{' enumerator-list[opt] '}' /// [C++11] enum-head '{' enumerator-list ',' '}' /// /// enum-head: [C++11] /// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] /// enum-key attribute-specifier-seq[opt] nested-name-specifier /// identifier enum-base[opt] /// /// enum-key: [C++11] /// 'enum' /// 'enum' 'class' /// 'enum' 'struct' /// /// enum-base: [C++11] /// ':' type-specifier-seq /// /// [C++] elaborated-type-specifier: /// [C++] 'enum' nested-name-specifier[opt] identifier /// \endverbatim /// void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC); /// ParseEnumBody - Parse a {} enclosed enumerator-list. /// \verbatim /// enumerator-list: /// enumerator /// enumerator-list ',' enumerator /// enumerator: /// enumeration-constant attributes[opt] /// enumeration-constant attributes[opt] '=' constant-expression /// enumeration-constant: /// identifier /// \endverbatim /// void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl, SkipBodyInfo *SkipBody = nullptr); /// ParseStructUnionBody /// \verbatim /// struct-contents: /// struct-declaration-list /// [EXT] empty /// [GNU] "struct-declaration-list" without terminating ';' /// struct-declaration-list: /// struct-declaration /// struct-declaration-list struct-declaration /// [OBC] '@' 'defs' '(' class-name ')' /// \endverbatim /// void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType, RecordDecl *TagDecl); /// ParseStructDeclaration - Parse a struct declaration without the /// terminating semicolon. /// /// Note that a struct declaration refers to a declaration in a struct, /// not to the declaration of a struct. /// /// \verbatim /// struct-declaration: /// [C23] attributes-specifier-seq[opt] /// specifier-qualifier-list struct-declarator-list /// [GNU] __extension__ struct-declaration /// [GNU] specifier-qualifier-list /// struct-declarator-list: /// struct-declarator /// struct-declarator-list ',' struct-declarator /// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator /// struct-declarator: /// declarator /// [GNU] declarator attributes[opt] /// declarator[opt] ':' constant-expression /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// \endverbatim /// void ParseStructDeclaration( ParsingDeclSpec &DS, llvm::function_ref FieldsCallback, LateParsedAttrList *LateFieldAttrs = nullptr); DeclGroupPtrTy ParseTopLevelStmtDecl(); /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. /// /// \param AllowImplicitTypename whether this is a context where T::type [T /// dependent] can appear. /// \param DisambiguatingWithExpression True to indicate that the purpose of /// this check is to disambiguate between an expression and a declaration. bool isDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, bool DisambiguatingWithExpression = false); /// isTypeSpecifierQualifier - Return true if the current token could be the /// start of a specifier-qualifier-list. bool isTypeSpecifierQualifier(); /// isKnownToBeTypeSpecifier - Return true if we know that the specified token /// is definitely a type-specifier. Return false if it isn't part of a type /// specifier or if we're not sure. bool isKnownToBeTypeSpecifier(const Token &Tok) const; /// Starting with a scope specifier, identifier, or /// template-id that refers to the current class, determine whether /// this is a constructor declarator. bool isConstructorDeclarator( bool Unqualified, bool DeductionGuide = false, DeclSpec::FriendSpecified IsFriend = DeclSpec::FriendSpecified::No, const ParsedTemplateInfo *TemplateInfo = nullptr); /// Diagnoses use of _ExtInt as being deprecated, and diagnoses use of /// _BitInt as an extension when appropriate. void DiagnoseBitIntUse(const Token &Tok); // Check for the start of an attribute-specifier-seq in a context where an // attribute is not allowed. bool CheckProhibitedCXX11Attribute() { assert(Tok.is(tok::l_square)); if (NextToken().isNot(tok::l_square)) return false; return DiagnoseProhibitedCXX11Attribute(); } /// DiagnoseProhibitedCXX11Attribute - We have found the opening square /// brackets of a C++11 attribute-specifier in a location where an attribute /// is not permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. /// Diagnose this situation. /// /// \return \c true if we skipped an attribute-like chunk of tokens, \c false /// if this doesn't appear to actually be an attribute-specifier, and the /// caller should try to parse it. bool DiagnoseProhibitedCXX11Attribute(); void CheckMisplacedCXX11Attribute(ParsedAttributes &Attrs, SourceLocation CorrectLocation) { if (!Tok.isRegularKeywordAttribute() && (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && Tok.isNot(tok::kw_alignas)) return; DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation); } /// We have found the opening square brackets of a C++11 /// attribute-specifier in a location where an attribute is not permitted, but /// we know where the attributes ought to be written. Parse them anyway, and /// provide a fixit moving them to the right place. void DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs, SourceLocation CorrectLocation); // Usually, `__attribute__((attrib)) class Foo {} var` means that attribute // applies to var, not the type Foo. // As an exception to the rule, __declspec(align(...)) before the // class-key affects the type instead of the variable. // Also, Microsoft-style [attributes] seem to affect the type instead of the // variable. // This function moves attributes that should apply to the type off DS to // Attrs. void stripTypeAttributesOffDeclSpec(ParsedAttributes &Attrs, DeclSpec &DS, TagUseKind TUK); // FixItLoc = possible correct location for the attributes void ProhibitAttributes(ParsedAttributes &Attrs, SourceLocation FixItLoc = SourceLocation()) { if (Attrs.Range.isInvalid()) return; DiagnoseProhibitedAttributes(Attrs, FixItLoc); Attrs.clear(); } void ProhibitAttributes(ParsedAttributesView &Attrs, SourceLocation FixItLoc = SourceLocation()) { if (Attrs.Range.isInvalid()) return; DiagnoseProhibitedAttributes(Attrs, FixItLoc); Attrs.clearListOnly(); } void DiagnoseProhibitedAttributes(const ParsedAttributesView &Attrs, SourceLocation FixItLoc); // Forbid C++11 and C23 attributes that appear on certain syntactic locations // which standard permits but we don't supported yet, for example, attributes // appertain to decl specifiers. // For the most cases we don't want to warn on unknown type attributes, but // left them to later diagnoses. However, for a few cases like module // declarations and module import declarations, we should do it. void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID, unsigned KeywordDiagId, bool DiagnoseEmptyAttrs = false, bool WarnOnUnknownAttrs = false); /// Emit warnings for C++11 and C23 attributes that are in a position that /// clang accepts as an extension. void DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs); ExprResult ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName); /// Parses a comma-delimited list of arguments of an attribute \p AttrName, /// filling \p Exprs. \p ArgsProperties specifies which of the arguments /// should be parsed as unevaluated string literals. \p Arg is the number /// of arguments parsed before calling / this function (the index of the /// argument to be parsed next). bool ParseAttributeArgumentList( const IdentifierInfo &AttrName, SmallVectorImpl &Exprs, ParsedAttributeArgumentsProperties ArgsProperties, unsigned Arg); /// Parses syntax-generic attribute arguments for attributes which are /// known to the implementation, and adds them to the given ParsedAttributes /// list with the given attribute syntax. Returns the number of arguments /// parsed for the attribute. unsigned ParseAttributeArgsCommon(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); enum ParseAttrKindMask { PAKM_GNU = 1 << 0, PAKM_Declspec = 1 << 1, PAKM_CXX11 = 1 << 2, }; /// \brief Parse attributes based on what syntaxes are desired, allowing for /// the order to vary. e.g. with PAKM_GNU | PAKM_Declspec: /// __attribute__((...)) __declspec(...) __attribute__((...))) /// Note that Microsoft attributes (spelled with single square brackets) are /// not supported by this because of parsing ambiguities with other /// constructs. /// /// There are some attribute parse orderings that should not be allowed in /// arbitrary order. e.g., /// /// \verbatim /// [[]] __attribute__(()) int i; // OK /// __attribute__(()) [[]] int i; // Not OK /// \endverbatim /// /// Such situations should use the specific attribute parsing functionality. void ParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr); /// \brief Possibly parse attributes based on what syntaxes are desired, /// allowing for the order to vary. bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) || isAllowedCXX11AttributeSpecifier()) { ParseAttributes(WhichAttrKinds, Attrs, LateAttrs); return true; } return false; } void MaybeParseGNUAttributes(Declarator &D, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) { ParsedAttributes Attrs(AttrFactory); ParseGNUAttributes(Attrs, LateAttrs, &D); D.takeAttributesAppending(Attrs); } } bool MaybeParseGNUAttributes(ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(Attrs, LateAttrs); return true; } return false; } /// ParseSingleGNUAttribute - Parse a single GNU attribute. /// /// \verbatim /// [GNU] attrib: /// empty /// attrib-name /// attrib-name '(' identifier ')' /// attrib-name '(' identifier ',' nonempty-expr-list ')' /// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// /// [GNU] attrib-name: /// identifier /// typespec /// typequal /// storageclass /// \endverbatim bool ParseSingleGNUAttribute(ParsedAttributes &Attrs, SourceLocation &EndLoc, LateParsedAttrList *LateAttrs = nullptr, Declarator *D = nullptr); /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// \verbatim /// [GNU] attributes: /// attribute /// attributes attribute /// /// [GNU] attribute: /// '__attribute__' '(' '(' attribute-list ')' ')' /// /// [GNU] attribute-list: /// attrib /// attribute_list ',' attrib /// /// [GNU] attrib: /// empty /// attrib-name /// attrib-name '(' identifier ')' /// attrib-name '(' identifier ',' nonempty-expr-list ')' /// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// /// [GNU] attrib-name: /// identifier /// typespec /// typequal /// storageclass /// \endverbatim /// /// Whether an attribute takes an 'identifier' is determined by the /// attrib-name. GCC's behavior here is not worth imitating: /// /// * In C mode, if the attribute argument list starts with an identifier /// followed by a ',' or an ')', and the identifier doesn't resolve to /// a type, it is parsed as an identifier. If the attribute actually /// wanted an expression, it's out of luck (but it turns out that no /// attributes work that way, because C constant expressions are very /// limited). /// * In C++ mode, if the attribute argument list starts with an identifier, /// and the attribute *wants* an identifier, it is parsed as an identifier. /// At block scope, any additional tokens between the identifier and the /// ',' or ')' are ignored, otherwise they produce a parse error. /// /// We follow the C++ model, but don't allow junk after the identifier. void ParseGNUAttributes(ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr, Declarator *D = nullptr); /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. void ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form, Declarator *D); IdentifierLoc *ParseIdentifierLoc(); unsigned ParseClangAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); void MaybeParseCXX11Attributes(Declarator &D) { if (isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); ParseCXX11Attributes(Attrs); D.takeAttributesAppending(Attrs); } } bool MaybeParseCXX11Attributes(ParsedAttributes &Attrs, bool OuterMightBeMessageSend = false) { if (isAllowedCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) { ParseCXX11Attributes(Attrs); return true; } return false; } bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) { bool AttrsParsed = false; if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) && Tok.is(tok::l_square)) { ParsedAttributes AttrsWithRange(AttrFactory); ParseMicrosoftAttributes(AttrsWithRange); AttrsParsed = !AttrsWithRange.empty(); Attrs.takeAllAppendingFrom(AttrsWithRange); } return AttrsParsed; } bool MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs) { if (getLangOpts().DeclSpecKeyword && Tok.is(tok::kw___declspec)) { ParseMicrosoftDeclSpecs(Attrs); return true; } return false; } /// \verbatim /// [MS] decl-specifier: /// __declspec ( extended-decl-modifier-seq ) /// /// [MS] extended-decl-modifier-seq: /// extended-decl-modifier[opt] /// extended-decl-modifier extended-decl-modifier-seq /// \endverbatim void ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs); bool ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs); void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); void ParseWebAssemblyFuncrefTypeAttribute(ParsedAttributes &Attrs); void DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); SourceLocation SkipExtendedMicrosoftTypeAttributes(); void ParseBorlandTypeAttributes(ParsedAttributes &attrs); void ParseOpenCLKernelAttributes(ParsedAttributes &attrs); void ParseOpenCLQualifiers(ParsedAttributes &Attrs); void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs); void ParseCUDAFunctionAttributes(ParsedAttributes &attrs); bool isHLSLQualifier(const Token &Tok) const; void ParseHLSLQualifiers(ParsedAttributes &Attrs); /// Parse a version number. /// /// \verbatim /// version: /// simple-integer /// simple-integer '.' simple-integer /// simple-integer '_' simple-integer /// simple-integer '.' simple-integer '.' simple-integer /// simple-integer '_' simple-integer '_' simple-integer /// \endverbatim VersionTuple ParseVersionTuple(SourceRange &Range); /// Parse the contents of the "availability" attribute. /// /// \verbatim /// availability-attribute: /// 'availability' '(' platform ',' opt-strict version-arg-list, /// opt-replacement, opt-message')' /// /// platform: /// identifier /// /// opt-strict: /// 'strict' ',' /// /// version-arg-list: /// version-arg /// version-arg ',' version-arg-list /// /// version-arg: /// 'introduced' '=' version /// 'deprecated' '=' version /// 'obsoleted' = version /// 'unavailable' /// opt-replacement: /// 'replacement' '=' /// opt-message: /// 'message' '=' /// \endverbatim void ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); /// Parse the contents of the "external_source_symbol" attribute. /// /// \verbatim /// external-source-symbol-attribute: /// 'external_source_symbol' '(' keyword-arg-list ')' /// /// keyword-arg-list: /// keyword-arg /// keyword-arg ',' keyword-arg-list /// /// keyword-arg: /// 'language' '=' /// 'defined_in' '=' /// 'USR' '=' /// 'generated_declaration' /// \endverbatim void ParseExternalSourceSymbolAttribute(IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); /// Parse the contents of the "objc_bridge_related" attribute. /// \verbatim /// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' /// related_class: /// Identifier /// /// opt-class_method: /// Identifier: | /// /// opt-instance_method: /// Identifier | /// \endverbatim /// void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated, SourceLocation ObjCBridgeRelatedLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); void ParseSwiftNewTypeAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); void ParseAttributeWithTypeArg(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); void DistributeCLateParsedAttrs(Decl *Dcl, LateParsedAttrList *LateAttrs); /// Bounds attributes (e.g., counted_by): /// \verbatim /// AttrName '(' expression ')' /// \endverbatim void ParseBoundsAttribute(IdentifierInfo &AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); /// \verbatim /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// [C23] typeof-specifier: /// typeof '(' typeof-specifier-argument ')' /// typeof_unqual '(' typeof-specifier-argument ')' /// /// typeof-specifier-argument: /// expression /// type-name /// \endverbatim /// void ParseTypeofSpecifier(DeclSpec &DS); /// \verbatim /// [C11] atomic-specifier: /// _Atomic ( type-name ) /// \endverbatim /// void ParseAtomicSpecifier(DeclSpec &DS); /// ParseAlignArgument - Parse the argument to an alignment-specifier. /// /// \verbatim /// [C11] type-id /// [C11] constant-expression /// [C++0x] type-id ...[opt] /// [C++0x] assignment-expression ...[opt] /// \endverbatim ExprResult ParseAlignArgument(StringRef KWName, SourceLocation Start, SourceLocation &EllipsisLoc, bool &IsType, ParsedType &Ty); /// ParseAlignmentSpecifier - Parse an alignment-specifier, and add the /// attribute to Attrs. /// /// \verbatim /// alignment-specifier: /// [C11] '_Alignas' '(' type-id ')' /// [C11] '_Alignas' '(' constant-expression ')' /// [C++11] 'alignas' '(' type-id ...[opt] ')' /// [C++11] 'alignas' '(' assignment-expression ...[opt] ')' /// \endverbatim void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = nullptr); ExprResult ParseExtIntegerArgument(); /// \verbatim /// type-qualifier: /// ('__ptrauth') '(' constant-expression /// (',' constant-expression)[opt] /// (',' constant-expression)[opt] ')' /// \endverbatim void ParsePtrauthQualifier(ParsedAttributes &Attrs); /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is /// finished. class DeclaratorScopeObj { Parser &P; CXXScopeSpec &SS; bool EnteredScope; bool CreatedScope; public: DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss), EnteredScope(false), CreatedScope(false) {} void EnterDeclaratorScope() { assert(!EnteredScope && "Already entered the scope!"); assert(SS.isSet() && "C++ scope was not set!"); CreatedScope = true; P.EnterScope(0); // Not a decl scope. if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS)) EnteredScope = true; } ~DeclaratorScopeObj() { if (EnteredScope) { assert(SS.isSet() && "C++ scope was cleared ?"); P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS); } if (CreatedScope) P.ExitScope(); } }; /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); /// A function that parses a variant of direct-declarator. typedef void (Parser::*DirectDeclParseFunction)(Declarator &); /// ParseDeclaratorInternal - Parse a C or C++ declarator. The /// direct-declarator is parsed by the function passed to it. Pass null, and /// the direct-declarator isn't parsed at all, making this function /// effectively parse the C++ ptr-operator production. /// /// If the grammar of this construct is extended, matching changes must also /// be made to TryParseDeclarator and MightBeDeclarator, and possibly to /// isConstructorDeclarator. /// /// \verbatim /// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl] /// [C] pointer[opt] direct-declarator /// [C++] direct-declarator /// [C++] ptr-operator declarator /// /// pointer: [C99 6.7.5] /// '*' type-qualifier-list[opt] /// '*' type-qualifier-list[opt] pointer /// /// ptr-operator: /// '*' cv-qualifier-seq[opt] /// '&' /// [C++0x] '&&' /// [GNU] '&' restrict[opt] attributes[opt] /// [GNU?] '&&' restrict[opt] attributes[opt] /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] /// \endverbatim void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); enum AttrRequirements { AR_NoAttributesParsed = 0, ///< No attributes are diagnosed. AR_GNUAttributesParsedAndRejected = 1 << 0, ///< Diagnose GNU attributes. AR_GNUAttributesParsed = 1 << 1, AR_CXX11AttributesParsed = 1 << 2, AR_DeclspecAttributesParsed = 1 << 3, AR_AllAttributesParsed = AR_GNUAttributesParsed | AR_CXX11AttributesParsed | AR_DeclspecAttributesParsed, AR_VendorAttributesParsed = AR_GNUAttributesParsed | AR_DeclspecAttributesParsed }; /// ParseTypeQualifierListOpt /// \verbatim /// type-qualifier-list: [C99 6.7.5] /// type-qualifier /// [vendor] attributes /// [ only if AttrReqs & AR_VendorAttributesParsed ] /// type-qualifier-list type-qualifier /// [vendor] type-qualifier-list attributes /// [ only if AttrReqs & AR_VendorAttributesParsed ] /// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq /// [ only if AttReqs & AR_CXX11AttributesParsed ] /// \endverbatim /// Note: vendor can be GNU, MS, etc and can be explicitly controlled via /// AttrRequirements bitmask values. void ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs = AR_AllAttributesParsed, bool AtomicOrPtrauthAllowed = true, bool IdentifierRequired = false, llvm::function_ref CodeCompletionHandler = {}); /// ParseDirectDeclarator /// \verbatim /// direct-declarator: [C99 6.7.5] /// [C99] identifier /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// [C++] direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] /// [C++11] direct-declarator '(' parameter-declaration-clause ')' /// attribute-specifier-seq[opt] cv-qualifier-seq[opt] /// ref-qualifier[opt] exception-specification[opt] /// [C++] declarator-id /// [C++11] declarator-id attribute-specifier-seq[opt] /// /// declarator-id: [C++ 8] /// '...'[opt] id-expression /// '::'[opt] nested-name-specifier[opt] type-name /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// C++17 adds the following, which we also handle here: /// /// simple-declaration: /// '[' identifier-list ']' brace-or-equal-initializer ';' /// \endverbatim /// /// Note, any additional constructs added here may need corresponding changes /// in isConstructorDeclarator. void ParseDirectDeclarator(Declarator &D); void ParseDecompositionDeclarator(Declarator &D); /// ParseParenDeclarator - We parsed the declarator D up to a paren. This is /// only called before the identifier, so these are most likely just grouping /// parens for precedence. If we find that these are actually function /// parameter parens in an abstract-declarator, we call /// ParseFunctionDeclarator. /// /// \verbatim /// direct-declarator: /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// direct-declarator '(' parameter-type-list ')' /// direct-declarator '(' identifier-list[opt] ')' /// [GNU] direct-declarator '(' parameter-forward-declarations /// parameter-type-list[opt] ')' /// \endverbatim /// void ParseParenDeclarator(Declarator &D); /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. /// /// If FirstArgAttrs is non-null, then the caller parsed those attributes /// immediately after the open paren - they will be applied to the DeclSpec /// of the first parameter. /// /// If RequiresArg is true, then the first argument of the function is /// required to be present and required to not be an identifier list. /// /// For C++, after the parameter-list, it also parses the /// cv-qualifier-seq[opt], (C++11) ref-qualifier[opt], /// exception-specification[opt], (C++11) attribute-specifier-seq[opt], /// (C++11) trailing-return-type[opt] and (C++2a) the trailing /// requires-clause. /// /// \verbatim /// [C++11] exception-specification: /// dynamic-exception-specification /// noexcept-specification /// \endverbatim /// void ParseFunctionDeclarator(Declarator &D, ParsedAttributes &FirstArgAttrs, BalancedDelimiterTracker &Tracker, bool IsAmbiguous, bool RequiresArg = false); void InitCXXThisScopeForDeclaratorIfRelevant( const Declarator &D, const DeclSpec &DS, std::optional &ThisScope); /// ParseRefQualifier - Parses a member function ref-qualifier. Returns /// true if a ref-qualifier is found. bool ParseRefQualifier(bool &RefQualifierIsLValueRef, SourceLocation &RefQualifierLoc); /// isFunctionDeclaratorIdentifierList - This parameter list may have an /// identifier list form for a K&R-style function: void foo(a,b,c) /// /// Note that identifier-lists are only allowed for normal declarators, not /// for abstract-declarators. bool isFunctionDeclaratorIdentifierList(); /// ParseFunctionDeclaratorIdentifierList - While parsing a function /// declarator we found a K&R-style identifier list instead of a typed /// parameter list. /// /// After returning, ParamInfo will hold the parsed parameters. /// /// \verbatim /// identifier-list: [C99 6.7.5] /// identifier /// identifier-list ',' identifier /// \endverbatim /// void ParseFunctionDeclaratorIdentifierList( Declarator &D, SmallVectorImpl &ParamInfo); void ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &attrs, SmallVectorImpl &ParamInfo, SourceLocation &EllipsisLoc) { return ParseParameterDeclarationClause( D.getContext(), attrs, ParamInfo, EllipsisLoc, D.getCXXScopeSpec().isSet() && D.isFunctionDeclaratorAFunctionDeclaration()); } /// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// /// DeclContext is the context of the declarator being parsed. If /// FirstArgAttrs is non-null, then the caller parsed those attributes /// immediately after the open paren - they will be applied to the DeclSpec of /// the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc /// will be the location of the ellipsis, if any was parsed. /// /// \verbatim /// parameter-type-list: [C99 6.7.5] /// parameter-list /// parameter-list ',' '...' /// [C++] parameter-list '...' /// /// parameter-list: [C99 6.7.5] /// parameter-declaration /// parameter-list ',' parameter-declaration /// /// parameter-declaration: [C99 6.7.5] /// declaration-specifiers declarator /// [C++] declaration-specifiers declarator '=' assignment-expression /// [C++11] initializer-clause /// [GNU] declaration-specifiers declarator attributes /// declaration-specifiers abstract-declarator[opt] /// [C++] declaration-specifiers abstract-declarator[opt] /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// [C++11] attribute-specifier-seq parameter-declaration /// [C++2b] attribute-specifier-seq 'this' parameter-declaration /// \endverbatim /// void ParseParameterDeclarationClause( DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, SmallVectorImpl &ParamInfo, SourceLocation &EllipsisLoc, bool IsACXXFunctionDeclaration = false); /// \verbatim /// [C90] direct-declarator '[' constant-expression[opt] ']' /// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' /// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' /// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' /// [C++11] direct-declarator '[' constant-expression[opt] ']' /// attribute-specifier-seq[opt] /// \endverbatim void ParseBracketDeclarator(Declarator &D); /// Diagnose brackets before an identifier. void ParseMisplacedBracketDeclarator(Declarator &D); /// Parse the given string as a type. /// /// This is a dangerous utility function currently employed only by API notes. /// It is not a general entry-point for safely parsing types from strings. /// /// \param TypeStr The string to be parsed as a type. /// \param Context The name of the context in which this string is being /// parsed, which will be used in diagnostics. /// \param IncludeLoc The location at which this parse was triggered. TypeResult ParseTypeFromString(StringRef TypeStr, StringRef Context, SourceLocation IncludeLoc); ///@} // // // ------------------------------------------------------------------------- // // /// \name C++ Declarations /// Implementations are in ParseDeclCXX.cpp ///@{ private: /// Contextual keywords for Microsoft extensions. mutable IdentifierInfo *Ident_sealed; mutable IdentifierInfo *Ident_abstract; /// C++11 contextual keywords. mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_GNU_final; mutable IdentifierInfo *Ident_override; /// Representation of a class that has been parsed, including /// any member function declarations or definitions that need to be /// parsed after the corresponding top-level class is complete. struct ParsingClass { ParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface) : TopLevelClass(TopLevelClass), IsInterface(IsInterface), TagOrTemplate(TagOrTemplate) {} /// Whether this is a "top-level" class, meaning that it is /// not nested within another class. bool TopLevelClass : 1; /// Whether this class is an __interface. bool IsInterface : 1; /// The class or class template whose definition we are parsing. Decl *TagOrTemplate; /// LateParsedDeclarations - Method declarations, inline definitions and /// nested classes that contain pieces whose parsing will be delayed until /// the top-level class is fully defined. LateParsedDeclarationsContainer LateParsedDeclarations; }; /// The stack of classes that is currently being /// parsed. Nested and local classes will be pushed onto this stack /// when they are parsed, and removed afterward. std::stack ClassStack; ParsingClass &getCurrentClass() { assert(!ClassStack.empty() && "No lexed method stacks!"); return *ClassStack.top(); } /// RAII object used to manage the parsing of a class definition. class ParsingClassDefinition { Parser &P; bool Popped; Sema::ParsingClassState State; public: ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface) : P(P), Popped(false), State(P.PushParsingClass(TagOrTemplate, TopLevelClass, IsInterface)) { } /// Pop this class of the stack. void Pop() { assert(!Popped && "Nested class has already been popped"); Popped = true; P.PopParsingClass(State); } ~ParsingClassDefinition() { if (!Popped) P.PopParsingClass(State); } }; /// Parse a C++ exception-specification if present (C++0x [except.spec]). /// /// \verbatim /// exception-specification: /// dynamic-exception-specification /// noexcept-specification /// /// noexcept-specification: /// 'noexcept' /// 'noexcept' '(' constant-expression ')' /// \endverbatim ExceptionSpecificationType tryParseExceptionSpecification( bool Delayed, SourceRange &SpecificationRange, SmallVectorImpl &DynamicExceptions, SmallVectorImpl &DynamicExceptionRanges, ExprResult &NoexceptExpr, CachedTokens *&ExceptionSpecTokens); /// ParseDynamicExceptionSpecification - Parse a C++ /// dynamic-exception-specification (C++ [except.spec]). /// EndLoc is filled with the location of the last token of the specification. /// /// \verbatim /// dynamic-exception-specification: /// 'throw' '(' type-id-list [opt] ')' /// [MS] 'throw' '(' '...' ')' /// /// type-id-list: /// type-id ... [opt] /// type-id-list ',' type-id ... [opt] /// \endverbatim /// ExceptionSpecificationType ParseDynamicExceptionSpecification(SourceRange &SpecificationRange, SmallVectorImpl &Exceptions, SmallVectorImpl &Ranges); //===--------------------------------------------------------------------===// // C++0x 8: Function declaration trailing-return-type /// ParseTrailingReturnType - Parse a trailing return type on a new-style /// function declaration. TypeResult ParseTrailingReturnType(SourceRange &Range, bool MayBeFollowedByDirectInit); /// Parse a requires-clause as part of a function declaration. void ParseTrailingRequiresClause(Declarator &D); void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, ParsedAttributes &AccessAttrs, AccessSpecifier &CurAS); SourceLocation ParsePackIndexingType(DeclSpec &DS); void AnnotateExistingIndexedTypeNamePack(ParsedType T, SourceLocation StartLoc, SourceLocation EndLoc); /// Return true if the next token should be treated as a [[]] attribute, /// or as a keyword that behaves like one. The former is only true if /// [[]] attributes are enabled, whereas the latter is true whenever /// such a keyword appears. The arguments are as for /// isCXX11AttributeSpecifier. bool isAllowedCXX11AttributeSpecifier(bool Disambiguate = false, bool OuterMightBeMessageSend = false) { return (Tok.isRegularKeywordAttribute() || isCXX11AttributeSpecifier(Disambiguate, OuterMightBeMessageSend) != CXX11AttributeKind::NotAttributeSpecifier); } /// Skip C++11 and C23 attributes and return the end location of the /// last one. /// \returns SourceLocation() if there are no attributes. SourceLocation SkipCXX11Attributes(); /// Diagnose and skip C++11 and C23 attributes that appear in syntactic /// locations where attributes are not allowed. void DiagnoseAndSkipCXX11Attributes(); void ParseOpenMPAttributeArgs(const IdentifierInfo *AttrName, CachedTokens &OpenMPTokens); /// Parse a C++11 or C23 attribute-specifier. /// /// \verbatim /// [C++11] attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// /// [C++11] attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] /// attribute '...' /// attribute-list ',' attribute '...' /// /// [C++11] attribute: /// attribute-token attribute-argument-clause[opt] /// /// [C++11] attribute-token: /// identifier /// attribute-scoped-token /// /// [C++11] attribute-scoped-token: /// attribute-namespace '::' identifier /// /// [C++11] attribute-namespace: /// identifier /// \endverbatim void ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, CachedTokens &OpenMPTokens, SourceLocation *EndLoc = nullptr); void ParseCXX11AttributeSpecifier(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr) { CachedTokens OpenMPTokens; ParseCXX11AttributeSpecifierInternal(Attrs, OpenMPTokens, EndLoc); ReplayOpenMPAttributeTokens(OpenMPTokens); } /// ParseCXX11Attributes - Parse a C++11 or C23 attribute-specifier-seq. /// /// \verbatim /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier /// \endverbatim void ParseCXX11Attributes(ParsedAttributes &attrs); /// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause. /// Parses a C++11 (or C23)-style attribute argument list. Returns true /// if this results in adding an attribute to the ParsedAttributes list. /// /// \verbatim /// [C++11] attribute-argument-clause: /// '(' balanced-token-seq ')' /// /// [C++11] balanced-token-seq: /// balanced-token /// balanced-token-seq balanced-token /// /// [C++11] balanced-token: /// '(' balanced-token-seq ')' /// '[' balanced-token-seq ']' /// '{' balanced-token-seq '}' /// any token but '(', ')', '[', ']', '{', or '}' /// \endverbatim bool ParseCXX11AttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, CachedTokens &OpenMPTokens); /// Parse the argument to C++23's [[assume()]] attribute. Returns true on /// error. bool ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs, IdentifierInfo *AttrName, SourceLocation AttrNameLoc, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, SourceLocation *EndLoc, ParsedAttr::Form Form); /// Try to parse an 'identifier' which appears within an attribute-token. /// /// \return the parsed identifier on success, and 0 if the next token is not /// an attribute-token. /// /// C++11 [dcl.attr.grammar]p3: /// If a keyword or an alternative token that satisfies the syntactic /// requirements of an identifier is contained in an attribute-token, /// it is considered an identifier. IdentifierInfo *TryParseCXX11AttributeIdentifier( SourceLocation &Loc, SemaCodeCompletion::AttributeCompletion Completion = SemaCodeCompletion::AttributeCompletion::None, const IdentifierInfo *EnclosingScope = nullptr); /// Parse uuid() attribute when it appears in a [] Microsoft attribute. void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs); /// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr] /// /// \verbatim /// [MS] ms-attribute: /// '[' token-seq ']' /// /// [MS] ms-attribute-seq: /// ms-attribute[opt] /// ms-attribute ms-attribute-seq /// \endverbatim void ParseMicrosoftAttributes(ParsedAttributes &Attrs); void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs); void ParseNullabilityClassAttributes(ParsedAttributes &attrs); /// ParseDecltypeSpecifier - Parse a C++11 decltype specifier. /// /// \verbatim /// 'decltype' ( expression ) /// 'decltype' ( 'auto' ) [C++1y] /// \endverbatim /// SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, SourceLocation StartLoc, SourceLocation EndLoc); /// isCXX11VirtSpecifier - Determine whether the given token is a C++11 /// virt-specifier. /// /// \verbatim /// virt-specifier: /// override /// final /// __final /// \endverbatim VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const; VirtSpecifiers::Specifier isCXX11VirtSpecifier() const { return isCXX11VirtSpecifier(Tok); } /// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq. /// /// \verbatim /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier /// \endverbatim void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface, SourceLocation FriendLoc); /// isCXX11FinalKeyword - Determine whether the next token is a C++11 /// 'final' or Microsoft 'sealed' contextual keyword. bool isCXX11FinalKeyword() const; /// isClassCompatibleKeyword - Determine whether the next token is a C++11 /// 'final', a C++26 'trivially_relocatable_if_eligible', /// or Microsoft 'sealed' or 'abstract' contextual /// keyword. bool isClassCompatibleKeyword() const; bool MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS); DeclSpec::TST TypeTransformTokToDeclSpec(); void DiagnoseUnexpectedNamespace(NamedDecl *Context); /// ParseNamespace - We know that the current token is a namespace keyword. /// This may either be a top level namespace or a block-level namespace alias. /// If there was an inline keyword, it has already been parsed. /// /// \verbatim /// namespace-definition: [C++: namespace.def] /// named-namespace-definition /// unnamed-namespace-definition /// nested-namespace-definition /// /// named-namespace-definition: /// 'inline'[opt] 'namespace' attributes[opt] identifier '{' /// namespace-body '}' /// /// unnamed-namespace-definition: /// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}' /// /// nested-namespace-definition: /// 'namespace' enclosing-namespace-specifier '::' 'inline'[opt] /// identifier '{' namespace-body '}' /// /// enclosing-namespace-specifier: /// identifier /// enclosing-namespace-specifier '::' 'inline'[opt] identifier /// /// namespace-alias-definition: [C++ 7.3.2: namespace.alias] /// 'namespace' identifier '=' qualified-namespace-specifier ';' /// \endverbatim /// DeclGroupPtrTy ParseNamespace(DeclaratorContext Context, SourceLocation &DeclEnd, SourceLocation InlineLoc = SourceLocation()); struct InnerNamespaceInfo { SourceLocation NamespaceLoc; SourceLocation InlineLoc; SourceLocation IdentLoc; IdentifierInfo *Ident; }; using InnerNamespaceInfoList = llvm::SmallVector; /// ParseInnerNamespace - Parse the contents of a namespace. void ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs, unsigned int index, SourceLocation &InlineLoc, ParsedAttributes &attrs, BalancedDelimiterTracker &Tracker); /// ParseLinkage - We know that the current token is a string_literal /// and just before that, that extern was seen. /// /// \verbatim /// linkage-specification: [C++ 7.5p2: dcl.link] /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// \endverbatim /// Decl *ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context); /// Parse a standard C++ Modules export-declaration. /// /// \verbatim /// export-declaration: /// 'export' declaration /// 'export' '{' declaration-seq[opt] '}' /// \endverbatim /// /// HLSL: Parse export function declaration. /// /// \verbatim /// export-function-declaration: /// 'export' function-declaration /// /// export-declaration-group: /// 'export' '{' function-declaration-seq[opt] '}' /// \endverbatim /// Decl *ParseExportDeclaration(); /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. DeclGroupPtrTy ParseUsingDirectiveOrDeclaration( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd, ParsedAttributes &Attrs); /// ParseUsingDirective - Parse C++ using-directive, assumes /// that current token is 'namespace' and 'using' was already parsed. /// /// \verbatim /// using-directive: [C++ 7.3.p4: namespace.udir] /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name ; /// [GNU] using-directive: /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name attributes[opt] ; /// \endverbatim /// Decl *ParseUsingDirective(DeclaratorContext Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &attrs); struct UsingDeclarator { SourceLocation TypenameLoc; CXXScopeSpec SS; UnqualifiedId Name; SourceLocation EllipsisLoc; void clear() { TypenameLoc = EllipsisLoc = SourceLocation(); SS.clear(); Name.clear(); } }; /// Parse a using-declarator (or the identifier in a C++11 alias-declaration). /// /// \verbatim /// using-declarator: /// 'typename'[opt] nested-name-specifier unqualified-id /// \endverbatim /// bool ParseUsingDeclarator(DeclaratorContext Context, UsingDeclarator &D); /// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. /// Assumes that 'using' was already seen. /// /// \verbatim /// using-declaration: [C++ 7.3.p3: namespace.udecl] /// 'using' using-declarator-list[opt] ; /// /// using-declarator-list: [C++1z] /// using-declarator '...'[opt] /// using-declarator-list ',' using-declarator '...'[opt] /// /// using-declarator-list: [C++98-14] /// using-declarator /// /// alias-declaration: C++11 [dcl.dcl]p1 /// 'using' identifier attribute-specifier-seq[opt] = type-id ; /// /// using-enum-declaration: [C++20, dcl.enum] /// 'using' elaborated-enum-specifier ; /// The terminal name of the elaborated-enum-specifier undergoes /// type-only lookup /// /// elaborated-enum-specifier: /// 'enum' nested-name-specifier[opt] identifier /// \endverbatim DeclGroupPtrTy ParseUsingDeclaration(DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributes &Attrs, AccessSpecifier AS = AS_none); Decl *ParseAliasDeclarationAfterDeclarator( const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS, ParsedAttributes &Attrs, Decl **OwnedType = nullptr); /// ParseStaticAssertDeclaration - Parse C++0x or C11 /// static_assert-declaration. /// /// \verbatim /// [C++0x] static_assert-declaration: /// static_assert ( constant-expression , string-literal ) ; /// /// [C11] static_assert-declaration: /// _Static_assert ( constant-expression , string-literal ) ; /// \endverbatim /// Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd); //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. /// Determine whether the following tokens are valid after a type-specifier /// which could be a standalone declaration. This will conservatively return /// true if there's any doubt, and is appropriate for insert-';' fixits. bool isValidAfterTypeSpecifier(bool CouldBeBitfield); /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which /// until we reach the start of a definition or see a token that /// cannot start a definition. /// /// \verbatim /// class-specifier: [C++ class] /// class-head '{' member-specification[opt] '}' /// class-head '{' member-specification[opt] '}' attributes[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] /// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier /// identifier base-clause[opt] /// [GNU] class-key attributes[opt] nested-name-specifier[opt] /// simple-template-id base-clause[opt] /// class-key: /// 'class' /// 'struct' /// 'union' /// /// elaborated-type-specifier: [C++ dcl.type.elab] /// class-key ::[opt] nested-name-specifier[opt] identifier /// class-key ::[opt] nested-name-specifier[opt] 'template'[opt] /// simple-template-id /// /// Note that the C++ class-specifier and elaborated-type-specifier, /// together, subsume the C99 struct-or-union-specifier: /// /// struct-or-union-specifier: [C99 6.7.2.1] /// struct-or-union identifier[opt] '{' struct-contents '}' /// struct-or-union identifier /// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents /// '}' attributes[opt] /// [GNU] struct-or-union attributes[opt] identifier /// struct-or-union: /// 'struct' /// 'union' /// \endverbatim void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, DeclSpecContext DSC, ParsedAttributes &Attributes); void SkipCXXMemberSpecification(SourceLocation StartLoc, SourceLocation AttrFixitLoc, unsigned TagType, Decl *TagDecl); /// ParseCXXMemberSpecification - Parse the class definition. /// /// \verbatim /// member-specification: /// member-declaration member-specification[opt] /// access-specifier ':' member-specification[opt] /// \endverbatim /// void ParseCXXMemberSpecification(SourceLocation StartLoc, SourceLocation AttrFixitLoc, ParsedAttributes &Attrs, unsigned TagType, Decl *TagDecl); /// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer. /// Also detect and reject any attempted defaulted/deleted function /// definition. The location of the '=', if any, will be placed in EqualLoc. /// /// This does not check for a pure-specifier; that's handled elsewhere. /// /// \verbatim /// brace-or-equal-initializer: /// '=' initializer-expression /// braced-init-list /// /// initializer-clause: /// assignment-expression /// braced-init-list /// /// defaulted/deleted function-definition: /// '=' 'default' /// '=' 'delete' /// \endverbatim /// /// Prior to C++0x, the assignment-expression in an initializer-clause must /// be a constant-expression. ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc); /// Parse a C++ member-declarator up to, but not including, the optional /// brace-or-equal-initializer or pure-specifier. bool ParseCXXMemberDeclaratorBeforeInitializer(Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize, LateParsedAttrList &LateAttrs); /// Look for declaration specifiers possibly occurring after C++11 /// virt-specifier-seq and diagnose them. void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator &D, VirtSpecifiers &VS); /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// \verbatim /// member-declaration: /// decl-specifier-seq[opt] member-declarator-list[opt] ';' /// function-definition ';'[opt] /// [C++26] friend-type-declaration /// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO] /// using-declaration [TODO] /// [C++0x] static_assert-declaration /// template-declaration /// [GNU] '__extension__' member-declaration /// /// member-declarator-list: /// member-declarator /// member-declarator-list ',' member-declarator /// /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] /// [C++2a] declarator requires-clause /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression /// /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier /// /// virt-specifier: /// override /// final /// [MS] sealed /// /// pure-specifier: /// '= 0' /// /// constant-initializer: /// '=' constant-expression /// /// friend-type-declaration: /// 'friend' friend-type-specifier-list ; /// /// friend-type-specifier-list: /// friend-type-specifier ...[opt] /// friend-type-specifier-list , friend-type-specifier ...[opt] /// /// friend-type-specifier: /// simple-type-specifier /// elaborated-type-specifier /// typename-specifier /// \endverbatim /// DeclGroupPtrTy ParseCXXClassMemberDeclaration( AccessSpecifier AS, ParsedAttributes &Attr, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *DiagsFromTParams = nullptr); DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas(AccessSpecifier &AS, ParsedAttributes &AccessAttrs, DeclSpec::TST TagType, Decl *Tag); /// ParseConstructorInitializer - Parse a C++ constructor initializer, /// which explicitly initializes the members or base classes of a /// class (C++ [class.base.init]). For example, the three initializers /// after the ':' in the Derived constructor below: /// /// @code /// class Base { }; /// class Derived : Base { /// int x; /// float f; /// public: /// Derived(float f) : Base(), x(17), f(f) { } /// }; /// @endcode /// /// \verbatim /// [C++] ctor-initializer: /// ':' mem-initializer-list /// /// [C++] mem-initializer-list: /// mem-initializer ...[opt] /// mem-initializer ...[opt] , mem-initializer-list /// \endverbatim void ParseConstructorInitializer(Decl *ConstructorDecl); /// ParseMemInitializer - Parse a C++ member initializer, which is /// part of a constructor initializer that explicitly initializes one /// member or base class (C++ [class.base.init]). See /// ParseConstructorInitializer for an example. /// /// \verbatim /// [C++] mem-initializer: /// mem-initializer-id '(' expression-list[opt] ')' /// [C++0x] mem-initializer-id braced-init-list /// /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name /// identifier /// \endverbatim MemInitResult ParseMemInitializer(Decl *ConstructorDecl); /// If the given declarator has any parts for which parsing has to be /// delayed, e.g., default arguments or an exception-specification, create a /// late-parsed method declaration record to handle the parsing at the end of /// the class definition. void HandleMemberFunctionDeclDelays(Declarator &DeclaratorInfo, Decl *ThisDecl); //===--------------------------------------------------------------------===// // C++ 10: Derived classes [class.derived] /// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a /// class name or decltype-specifier. Note that we only check that the result /// names a type; semantic analysis will need to verify that the type names a /// class. The result is either a type or null, depending on whether a type /// name was found. /// /// \verbatim /// base-type-specifier: [C++11 class.derived] /// class-or-decltype /// class-or-decltype: [C++11 class.derived] /// nested-name-specifier[opt] class-name /// decltype-specifier /// class-name: [C++ class.name] /// identifier /// simple-template-id /// \endverbatim /// /// In C++98, instead of base-type-specifier, we have: /// /// \verbatim /// ::[opt] nested-name-specifier[opt] class-name /// \endverbatim TypeResult ParseBaseTypeSpecifier(SourceLocation &BaseLoc, SourceLocation &EndLocation); /// ParseBaseClause - Parse the base-clause of a C++ class [C++ /// class.derived]. /// /// \verbatim /// base-clause : [C++ class.derived] /// ':' base-specifier-list /// base-specifier-list: /// base-specifier '...'[opt] /// base-specifier-list ',' base-specifier '...'[opt] /// \endverbatim void ParseBaseClause(Decl *ClassDecl); /// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is /// one entry in the base class list of a class specifier, for example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. /// /// \verbatim /// base-specifier: [C++ class.derived] /// attribute-specifier-seq[opt] base-type-specifier /// attribute-specifier-seq[opt] 'virtual' access-specifier[opt] /// base-type-specifier /// attribute-specifier-seq[opt] access-specifier 'virtual'[opt] /// base-type-specifier /// \endverbatim BaseResult ParseBaseSpecifier(Decl *ClassDecl); /// getAccessSpecifierIfPresent - Determine whether the next token is /// a C++ access-specifier. /// /// \verbatim /// access-specifier: [C++ class.derived] /// 'private' /// 'protected' /// 'public' /// \endverbatim AccessSpecifier getAccessSpecifierIfPresent() const; /// 'final', a C++26 'trivially_relocatable_if_eligible', /// or Microsoft 'sealed' or 'abstract' contextual /// keyword. bool isClassCompatibleKeyword(Token Tok) const; void ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs); ///@} // // // ------------------------------------------------------------------------- // // /// \name Expressions /// Implementations are in ParseExpr.cpp ///@{ public: friend class OffsetOfStateRAIIObject; typedef Sema::FullExprArg FullExprArg; //===--------------------------------------------------------------------===// // C99 6.5: Expressions. /// Simple precedence-based parser for binary/ternary operators. /// /// Note: we diverge from the C99 grammar when parsing the /// assignment-expression production. C99 specifies that the LHS of an /// assignment operator should be parsed as a unary-expression, but /// consistency dictates that it be a conditional-expession. In practice, the /// important thing here is that the LHS of an assignment has to be an /// l-value, which productions between unary-expression and /// conditional-expression don't produce. Because we want consistency, we /// parse the LHS as a conditional-expression, then check for l-value-ness in /// semantic analysis stages. /// /// \verbatim /// pm-expression: [C++ 5.5] /// cast-expression /// pm-expression '.*' cast-expression /// pm-expression '->*' cast-expression /// /// multiplicative-expression: [C99 6.5.5] /// Note: in C++, apply pm-expression instead of cast-expression /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression /// multiplicative-expression '%' cast-expression /// /// additive-expression: [C99 6.5.6] /// multiplicative-expression /// additive-expression '+' multiplicative-expression /// additive-expression '-' multiplicative-expression /// /// shift-expression: [C99 6.5.7] /// additive-expression /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// /// compare-expression: [C++20 expr.spaceship] /// shift-expression /// compare-expression '<=>' shift-expression /// /// relational-expression: [C99 6.5.8] /// compare-expression /// relational-expression '<' compare-expression /// relational-expression '>' compare-expression /// relational-expression '<=' compare-expression /// relational-expression '>=' compare-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression /// equality-expression '==' relational-expression /// equality-expression '!=' relational-expression /// /// AND-expression: [C99 6.5.10] /// equality-expression /// AND-expression '&' equality-expression /// /// exclusive-OR-expression: [C99 6.5.11] /// AND-expression /// exclusive-OR-expression '^' AND-expression /// /// inclusive-OR-expression: [C99 6.5.12] /// exclusive-OR-expression /// inclusive-OR-expression '|' exclusive-OR-expression /// /// logical-AND-expression: [C99 6.5.13] /// inclusive-OR-expression /// logical-AND-expression '&&' inclusive-OR-expression /// /// logical-OR-expression: [C99 6.5.14] /// logical-AND-expression /// logical-OR-expression '||' logical-AND-expression /// /// conditional-expression: [C99 6.5.15] /// logical-OR-expression /// logical-OR-expression '?' expression ':' conditional-expression /// [GNU] logical-OR-expression '?' ':' conditional-expression /// [C++] the third operand is an assignment-expression /// /// assignment-expression: [C99 6.5.16] /// conditional-expression /// unary-expression assignment-operator assignment-expression /// [C++] throw-expression [C++ 15] /// /// assignment-operator: one of /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] /// \endverbatim ExprResult ParseExpression(TypoCorrectionTypeBehavior CorrectionBehavior = TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConstantExpressionInExprEvalContext( TypoCorrectionTypeBehavior CorrectionBehavior = TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConstantExpression(); ExprResult ParseArrayBoundExpression(); ExprResult ParseCaseExpression(SourceLocation CaseLoc); /// Parse a constraint-expression. /// /// \verbatim /// constraint-expression: C++2a[temp.constr.decl]p1 /// logical-or-expression /// \endverbatim ExprResult ParseConstraintExpression(); /// \brief Parse a constraint-logical-and-expression. /// /// \verbatim /// C++2a[temp.constr.decl]p1 /// constraint-logical-and-expression: /// primary-expression /// constraint-logical-and-expression '&&' primary-expression /// /// \endverbatim ExprResult ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause); /// \brief Parse a constraint-logical-or-expression. /// /// \verbatim /// C++2a[temp.constr.decl]p1 /// constraint-logical-or-expression: /// constraint-logical-and-expression /// constraint-logical-or-expression '||' /// constraint-logical-and-expression /// /// \endverbatim ExprResult ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause); /// Parse an expr that doesn't include (top-level) commas. ExprResult ParseAssignmentExpression(TypoCorrectionTypeBehavior CorrectionBehavior = TypoCorrectionTypeBehavior::AllowNonTypes); ExprResult ParseConditionalExpression(); /// ParseStringLiteralExpression - This handles the various token types that /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// /// \verbatim /// primary-expression: [C99 6.5.1] /// string-literal /// \endverbatim ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); ExprResult ParseUnevaluatedStringLiteralExpression(); private: /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ /// template argument list, where the '>' closes the template /// argument list. bool GreaterThanIsOperator; // C++ type trait keywords that can be reverted to identifiers and still be // used as type traits. llvm::SmallDenseMap RevertibleTypeTraits; OffsetOfKind OffsetOfState = OffsetOfKind::Outside; /// The location of the expression statement that is being parsed right now. /// Used to determine if an expression that is being parsed is a statement or /// just a regular sub-expression. SourceLocation ExprStatementTokLoc; /// Checks if the \p Level is valid for use in a fold expression. bool isFoldOperator(prec::Level Level) const; /// Checks if the \p Kind is a valid operator for fold expressions. bool isFoldOperator(tok::TokenKind Kind) const; /// We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. Sema::ParsingClassState PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface); /// Deallocate the given parsed class and all of its nested /// classes. void DeallocateParsedClasses(ParsingClass *Class); /// Pop the top class of the stack of classes that are /// currently being parsed. /// /// This routine should be called when we have finished parsing the /// definition of a class, but have not yet popped the Scope /// associated with the class's definition. void PopParsingClass(Sema::ParsingClassState); ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral, bool Unevaluated); /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This /// routine is necessary to disambiguate \@try-statement from, /// for example, \@encode-expression. /// ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); /// This routine is called when a leading '__extension__' is seen and /// consumed. This is necessary because the token gets consumed in the /// process of disambiguating between an expression and a declaration. ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); /// Parse a binary expression that starts with \p LHS and has a /// precedence of at least \p MinPrec. ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec); bool isRevertibleTypeTrait(const IdentifierInfo *Id, clang::tok::TokenKind *Kind = nullptr); /// Parse a cast-expression, or, if \pisUnaryExpression is true, parse /// a unary-expression. /// /// \p isAddressOfOperand exists because an id-expression that is the operand /// of address-of gets special treatment due to member pointers. NotCastExpr /// is set to true if the token is not the start of a cast-expression, and no /// diagnostic is emitted in this case and no tokens are consumed. /// /// \verbatim /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression /// /// unary-expression: [C99 6.5.3] /// postfix-expression /// '++' unary-expression /// '--' unary-expression /// [Coro] 'co_await' cast-expression /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [C2y] '_Countof' unary-expression /// [C2y] '_Countof' '(' type-name ')' /// [GNU] '&&' identifier /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] /// [C++] new-expression /// [C++] delete-expression /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' /// [GNU] '__extension__' '__real' '__imag' /// /// primary-expression: [C99 6.5.1] /// [C99] identifier /// [C++] id-expression /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] /// [C++11] 'nullptr' [C++11 2.14.7] /// [C++11] user-defined-literal /// '(' expression ')' /// [C11] generic-selection /// [C++2a] requires-expression /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [MS] '__FUNCDNAME__' /// [MS] 'L__FUNCTION__' /// [MS] '__FUNCSIG__' /// [MS] 'L__FUNCSIG__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_FILE' '(' ')' /// [CLANG] '__builtin_FILE_NAME' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' /// [MS] '__builtin_FUNCSIG' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_source_location' '(' ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '\@selector' '(' objc-selector-arg ')' /// [OBJC] '\@protocol' '(' identifier ')' /// [OBJC] '\@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] typename-specifier braced-init-list [C++11 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1] /// [C++] 'this' [C++ 9.3.2] /// [G++] unary-type-trait '(' type-id ')' /// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] /// [EMBT] array-type-trait '(' type-id ',' integer ')' /// [clang] '^' block-literal /// /// constant: [C99 6.4.4] /// integer-constant /// floating-constant /// enumeration-constant -> identifier /// character-constant /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// delete-expression: [C++ 5.3.5] /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU/Embarcadero] unary-type-trait: /// '__is_arithmetic' /// '__is_floating_point' /// '__is_integral' /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// '__is_complete_type' /// '__is_void' /// '__is_array' /// '__is_function' /// '__is_reference' /// '__is_lvalue_reference' /// '__is_rvalue_reference' /// '__is_fundamental' /// '__is_object' /// '__is_scalar' /// '__is_compound' /// '__is_pointer' /// '__is_member_object_pointer' /// '__is_member_function_pointer' /// '__is_member_pointer' /// '__is_const' /// '__is_volatile' /// '__is_trivial' /// '__is_standard_layout' /// '__is_signed' /// '__is_unsigned' /// /// [GNU] unary-type-trait: /// '__has_nothrow_assign' /// '__has_nothrow_copy' /// '__has_nothrow_constructor' /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' /// '__has_trivial_destructor' /// '__has_virtual_destructor' /// '__is_abstract' [TODO] /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' /// '__is_final' /// '__is_pod' /// '__is_polymorphic' /// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' /// '__has_unique_object_representations' /// /// [Clang] unary-type-trait: /// '__is_aggregate' /// '__trivially_copyable' /// /// binary-type-trait: /// [GNU] '__is_base_of' /// [MS] '__is_convertible_to' /// '__is_convertible' /// '__is_same' /// /// [Embarcadero] array-type-trait: /// '__array_rank' /// '__array_extent' /// /// [Embarcadero] expression-trait: /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// \endverbatim /// ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, TypoCorrectionTypeBehavior CorrectionBehavior, bool isVectorLiteral = false, bool *NotPrimaryExpression = nullptr); ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand = false, TypoCorrectionTypeBehavior CorrectionBehavior = TypoCorrectionTypeBehavior::AllowNonTypes, bool isVectorLiteral = false, bool *NotPrimaryExpression = nullptr); /// Returns true if the next token cannot start an expression. bool isNotExpressionStart(); /// Returns true if the next token would start a postfix-expression /// suffix. bool isPostfixExpressionSuffixStart() { tok::TokenKind K = Tok.getKind(); return (K == tok::l_square || K == tok::l_paren || K == tok::period || K == tok::arrow || K == tok::plusplus || K == tok::minusminus); } /// Once the leading part of a postfix-expression is parsed, this /// method parses any suffixes that apply. /// /// \verbatim /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' /// postfix-expression '[' braced-init-list ']' /// postfix-expression '[' expression-list [opt] ']' [C++23 12.4.5] /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier /// postfix-expression '++' /// postfix-expression '--' /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] /// argument-expression ...[opt] /// argument-expression-list ',' assignment-expression ...[opt] /// \endverbatim ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); /// Parse a sizeof or alignof expression. /// /// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' /// [Clang] '__datasizeof' unary-expression /// [Clang] '__datasizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [C2y] '_Countof' unary-expression /// [C2y] '_Countof' '(' type-name ')' /// \endverbatim ExprResult ParseUnaryExprOrTypeTraitExpression(); /// ParseBuiltinPrimaryExpression /// /// \verbatim /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__builtin_FILE' '(' ')' /// [CLANG] '__builtin_FILE_NAME' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' /// [MS] '__builtin_FUNCSIG' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_source_location' '(' ')' /// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// \endverbatim ExprResult ParseBuiltinPrimaryExpression(); /// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id /// as a parameter. ExprResult ParseSYCLUniqueStableNameExpression(); /// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ /// vec_step and we are at the start of an expression or a parenthesized /// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the /// expression (isCastExpr == false) or the type (isCastExpr == true). /// /// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [Clang] '__datasizeof' unary-expression /// [Clang] '__datasizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// [C23] typeof-specifier: /// typeof '(' typeof-specifier-argument ')' /// typeof_unqual '(' typeof-specifier-argument ')' /// /// typeof-specifier-argument: /// expression /// type-name /// /// [OpenCL 1.1 6.11.12] vec_step built-in function: /// vec_step ( expressions ) /// vec_step ( type-name ) /// \endverbatim ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, ParsedType &CastTy, SourceRange &CastRange); /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// \verbatim /// argument-expression-list: /// assignment-expression /// argument-expression-list , assignment-expression /// /// [C++] expression-list: /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// /// [C++0x] expression-list: /// [C++0x] initializer-list /// /// [C++0x] initializer-list /// [C++0x] initializer-clause ...[opt] /// [C++0x] initializer-list , initializer-clause ...[opt] /// /// [C++0x] initializer-clause: /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// \endverbatim bool ParseExpressionList(SmallVectorImpl &Exprs, llvm::function_ref ExpressionStarts = llvm::function_ref(), bool FailImmediatelyOnInvalidExpr = false); /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. /// /// \verbatim /// simple-expression-list: /// assignment-expression /// simple-expression-list , assignment-expression /// \endverbatim bool ParseSimpleExpressionList(SmallVectorImpl &Exprs); /// This parses the unit that starts with a '(' token, based on what is /// allowed by ExprType. The actual thing parsed is returned in ExprType. If /// StopIfCastExpr is true, it will only return the parsed type, not the /// parsed cast-expression. If ParenBehavior is ParenExprKind::PartOfOperator, /// the initial open paren and its matching close paren are known to be part /// of another grammar production and not part of the operand. e.g., the /// typeof and typeof_unqual operators in C. Otherwise, the function has to /// parse the parens to determine whether they're part of a cast or compound /// literal expression rather than a parenthesized type. /// /// \verbatim /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// [ARC] bridged-cast-expression /// [ARC] bridged-cast-expression: /// (__bridge type-name) cast-expression /// (__bridge_transfer type-name) cast-expression /// (__bridge_retained type-name) cast-expression /// fold-expression: [C++1z] /// '(' cast-expression fold-operator '...' ')' /// '(' '...' fold-operator cast-expression ')' /// '(' cast-expression fold-operator '...' /// fold-operator cast-expression ')' /// [OPENMP] Array shaping operation /// '(' '[' expression ']' { '[' expression ']' } cast-expression /// \endverbatim ExprResult ParseParenExpression(ParenParseOption &ExprType, bool StopIfCastExpr, ParenExprKind ParenBehavior, TypoCorrectionTypeBehavior CorrectionBehavior, ParsedType &CastTy, SourceLocation &RParenLoc); /// ParseCompoundLiteralExpression - We have parsed the parenthesized /// type-name and we are at the left brace. /// /// \verbatim /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// \endverbatim ExprResult ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc); /// ParseGenericSelectionExpression - Parse a C11 generic-selection /// [C11 6.5.1.1]. /// /// \verbatim /// generic-selection: /// _Generic ( assignment-expression , generic-assoc-list ) /// generic-assoc-list: /// generic-association /// generic-assoc-list , generic-association /// generic-association: /// type-name : assignment-expression /// default : assignment-expression /// \endverbatim /// /// As an extension, Clang also accepts: /// \verbatim /// generic-selection: /// _Generic ( type-name, generic-assoc-list ) /// \endverbatim ExprResult ParseGenericSelectionExpression(); /// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. /// /// '__objc_yes' /// '__objc_no' ExprResult ParseObjCBoolLiteral(); /// Parse A C++1z fold-expression after the opening paren and optional /// left-hand-side expression. /// /// \verbatim /// fold-expression: /// ( cast-expression fold-operator ... ) /// ( ... fold-operator cast-expression ) /// ( cast-expression fold-operator ... fold-operator cast-expression ) /// \endverbatim ExprResult ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T); void injectEmbedTokens(); //===--------------------------------------------------------------------===// // clang Expressions /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// /// \verbatim /// block-literal: /// [clang] '^' block-args[opt] compound-statement /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' /// \endverbatim ExprResult ParseBlockLiteralExpression(); // ^{...} /// Parse an assignment expression where part of an Objective-C message /// send has already been parsed. /// /// In this case \p LBracLoc indicates the location of the '[' of the message /// send, and either \p ReceiverName or \p ReceiverExpr is non-null indicating /// the receiver of the message. /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. ExprResult ParseAssignmentExprWithObjCMessageExprStart( SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, Expr *ReceiverExpr); /// Return true if we know that we are definitely looking at a /// decl-specifier, and isn't part of an expression such as a function-style /// cast. Return false if it's no a decl-specifier, or we're not sure. bool isKnownToBeDeclarationSpecifier() { if (getLangOpts().CPlusPlus) return isCXXDeclarationSpecifier(ImplicitTypenameContext::No) == TPResult::True; return isDeclarationSpecifier(ImplicitTypenameContext::No, true); } /// Checks whether the current tokens form a type-id or an expression for the /// purposes of use as the initial operand to a generic selection expression. /// This requires special handling in C++ because it accepts either a type or /// an expression, and we need to disambiguate which is which. However, we /// cannot use the same logic as we've used for sizeof expressions, because /// that logic relies on the operator only accepting a single argument, /// whereas _Generic accepts a list of arguments. bool isTypeIdForGenericSelection() { if (getLangOpts().CPlusPlus) { bool isAmbiguous; return isCXXTypeId(TentativeCXXTypeIdContext::AsGenericSelectionArgument, isAmbiguous); } return isTypeSpecifierQualifier(); } /// Checks if the current tokens form type-id or expression. /// It is similar to isTypeIdInParens but does not suppose that type-id /// is in parenthesis. bool isTypeIdUnambiguously() { if (getLangOpts().CPlusPlus) { bool isAmbiguous; return isCXXTypeId(TentativeCXXTypeIdContext::Unambiguous, isAmbiguous); } return isTypeSpecifierQualifier(); } /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// /// \verbatim /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator /// \endverbatim void ParseBlockId(SourceLocation CaretLoc); /// Parse availability query specification. /// /// \verbatim /// availability-spec: /// '*' /// identifier version-tuple /// \endverbatim std::optional ParseAvailabilitySpec(); ExprResult ParseAvailabilityCheckExpr(SourceLocation StartLoc); /// Tries to parse cast part of OpenMP array shaping operation: /// \verbatim /// '[' expression ']' { '[' expression ']' } ')' /// \endverbatim bool tryParseOpenMPArrayShapingCastPart(); ExprResult ParseBuiltinPtrauthTypeDiscriminator(); ///@} // // // ------------------------------------------------------------------------- // // /// \name C++ Expressions /// Implementations are in ParseExprCXX.cpp ///@{ public: /// Parse a C++ unqualified-id (or a C identifier), which describes the /// name of an entity. /// /// \verbatim /// unqualified-id: [C++ expr.prim.general] /// identifier /// operator-function-id /// conversion-function-id /// [C++0x] literal-operator-id [TODO] /// ~ class-name /// template-id /// \endverbatim /// /// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param ObjectHadErrors if this unqualified-id occurs within a member /// access expression, indicates whether the original subexpressions had any /// errors. When true, diagnostics for missing 'template' keyword will be /// supressed. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param AllowDestructorName whether we allow parsing of a destructor name. /// /// \param AllowConstructorName whether we allow parsing a constructor name. /// /// \param AllowDeductionGuide whether we allow parsing a deduction guide /// name. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, bool AllowDeductionGuide, SourceLocation *TemplateKWLoc, UnqualifiedId &Result); private: /// ColonIsSacred - When this is false, we aggressively try to recover from /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not /// safe in case statements and a few other things. This is managed by the /// ColonProtectionRAIIObject RAII object. bool ColonIsSacred; /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a /// parenthesized ambiguous type-id. This uses tentative parsing to /// disambiguate based on the context past the parens. ExprResult ParseCXXAmbiguousParenExpression( ParenParseOption &ExprType, ParsedType &CastTy, BalancedDelimiterTracker &Tracker, ColonProtectionRAIIObject &ColonProt); //===--------------------------------------------------------------------===// // C++ Expressions ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement); ExprResult tryParseCXXPackIndexingExpression(ExprResult PackIdExpression); ExprResult ParseCXXPackIndexingExpression(ExprResult PackIdExpression); /// ParseCXXIdExpression - Handle id-expression. /// /// \verbatim /// id-expression: /// unqualified-id /// qualified-id /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id /// '::' template-id /// /// NOTE: The standard specifies that, for qualified-id, the parser does not /// expect: /// /// '::' conversion-function-id /// '::' '~' class-name /// \endverbatim /// /// This may cause a slight inconsistency on diagnostics: /// /// class C {}; /// namespace A {} /// void f() { /// :: A :: ~ C(); // Some Sema error about using destructor with a /// // namespace. /// :: ~ C(); // Some Parser error like 'unexpected ~'. /// } /// /// We simplify the parser a bit and make it work like: /// /// \verbatim /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' unqualified-id /// \endverbatim /// /// That way Sema can handle and report similar errors for namespaces and the /// global scope. /// /// The isAddressOfOperand parameter indicates that this id-expression is a /// direct operand of the address-of operator. This is, besides member /// contexts, the only place where a qualified-id naming a non-static class /// member may appear. /// ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); // Are the two tokens adjacent in the same source file? bool areTokensAdjacent(const Token &A, const Token &B); // Check for '<::' which should be '< ::' instead of '[:' when following // a template name. void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr, bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS); /// Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which /// may be preceded by '::'). Note that this routine will not parse ::new or /// ::delete; it will just leave them in the token stream. /// /// \verbatim /// '::'[opt] nested-name-specifier /// '::' /// /// nested-name-specifier: /// type-name '::' /// namespace-name '::' /// nested-name-specifier identifier '::' /// nested-name-specifier 'template'[opt] simple-template-id '::' /// \endverbatim /// /// /// \param SS the scope specifier that will be set to the parsed /// nested-name-specifier (or empty) /// /// \param ObjectType if this nested-name-specifier is being parsed following /// the "." or "->" of a member access expression, this parameter provides the /// type of the object whose members are being accessed. /// /// \param ObjectHadErrors if this unqualified-id occurs within a member /// access expression, indicates whether the original subexpressions had any /// errors. When true, diagnostics for missing 'template' keyword will be /// supressed. /// /// \param EnteringContext whether we will be entering into the context of /// the nested-name-specifier after parsing it. /// /// \param MayBePseudoDestructor When non-NULL, points to a flag that /// indicates whether this nested-name-specifier may be part of a /// pseudo-destructor name. In this case, the flag will be set false /// if we don't actually end up parsing a destructor name. Moreover, /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. /// /// \param IsTypename If \c true, this nested-name-specifier is known to be /// part of a type name. This is used to improve error recovery. /// /// \param LastII When non-NULL, points to an IdentifierInfo* that will be /// filled in with the leading identifier in the last component of the /// nested-name-specifier, if any. /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// /// /// \returns true if there was an error parsing a scope specifier bool ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, bool EnteringContext, bool *MayBePseudoDestructor = nullptr, bool IsTypename = false, const IdentifierInfo **LastII = nullptr, bool OnlyNamespace = false, bool InUsingDeclaration = false, bool Disambiguation = false); //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions /// Result of tentatively parsing a lambda-introducer. enum class LambdaIntroducerTentativeParse { /// This appears to be a lambda-introducer, which has been fully parsed. Success, /// This is a lambda-introducer, but has not been fully parsed, and this /// function needs to be called again to parse it. Incomplete, /// This is definitely an Objective-C message send expression, rather than /// a lambda-introducer, attribute-specifier, or array designator. MessageSend, /// This is not a lambda-introducer. Invalid, }; /// ParseLambdaExpression - Parse a C++11 lambda expression. /// /// \verbatim /// lambda-expression: /// lambda-introducer lambda-declarator compound-statement /// lambda-introducer '<' template-parameter-list '>' /// requires-clause[opt] lambda-declarator compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' /// /// lambda-capture: /// capture-default /// capture-list /// capture-default ',' capture-list /// /// capture-default: /// '&' /// '=' /// /// capture-list: /// capture /// capture-list ',' capture /// /// capture: /// simple-capture /// init-capture [C++1y] /// /// simple-capture: /// identifier /// '&' identifier /// 'this' /// /// init-capture: [C++1y] /// identifier initializer /// '&' identifier initializer /// /// lambda-declarator: /// lambda-specifiers [C++23] /// '(' parameter-declaration-clause ')' lambda-specifiers /// requires-clause[opt] /// /// lambda-specifiers: /// decl-specifier-seq[opt] noexcept-specifier[opt] /// attribute-specifier-seq[opt] trailing-return-type[opt] /// \endverbatim /// ExprResult ParseLambdaExpression(); /// Use lookahead and potentially tentative parsing to determine if we are /// looking at a C++11 lambda expression, and parse it if we are. /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult TryParseLambdaExpression(); /// Parse a lambda introducer. /// \param Intro A LambdaIntroducer filled in with information about the /// contents of the lambda-introducer. /// \param Tentative If non-null, we are disambiguating between a /// lambda-introducer and some other construct. In this mode, we do not /// produce any diagnostics or take any other irreversible action /// unless we're sure that this is a lambda-expression. /// \return \c true if parsing (or disambiguation) failed with a diagnostic /// and the caller should bail out / recover. bool ParseLambdaIntroducer(LambdaIntroducer &Intro, LambdaIntroducerTentativeParse *Tentative = nullptr); /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult ParseLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts /// ParseCXXCasts - This handles the various ways to cast expressions to /// another type. /// /// \verbatim /// postfix-expression: [C++ 5.2p1] /// 'dynamic_cast' '<' type-name '>' '(' expression ')' /// 'static_cast' '<' type-name '>' '(' expression ')' /// 'reinterpret_cast' '<' type-name '>' '(' expression ')' /// 'const_cast' '<' type-name '>' '(' expression ')' /// \endverbatim /// /// C++ for OpenCL s2.3.1 adds: /// 'addrspace_cast' '<' type-name '>' '(' expression ')' ExprResult ParseCXXCasts(); /// Parse a __builtin_bit_cast(T, E), used to implement C++2a std::bit_cast. ExprResult ParseBuiltinBitCast(); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Type Identification /// ParseCXXTypeid - This handles the C++ typeid expression. /// /// \verbatim /// postfix-expression: [C++ 5.2p1] /// 'typeid' '(' expression ')' /// 'typeid' '(' type-id ')' /// \endverbatim /// ExprResult ParseCXXTypeid(); //===--------------------------------------------------------------------===// // C++ : Microsoft __uuidof Expression /// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. /// /// \verbatim /// '__uuidof' '(' expression ')' /// '__uuidof' '(' type-id ')' /// \endverbatim /// ExprResult ParseCXXUuidof(); //===--------------------------------------------------------------------===// // C++ 5.2.4: C++ Pseudo-Destructor Expressions /// Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. We're handling this fragment of the grammar: /// /// \verbatim /// postfix-expression: [C++2a expr.post] /// postfix-expression . template[opt] id-expression /// postfix-expression -> template[opt] id-expression /// /// id-expression: /// qualified-id /// unqualified-id /// /// qualified-id: /// nested-name-specifier template[opt] unqualified-id /// /// nested-name-specifier: /// type-name :: /// decltype-specifier :: FIXME: not implemented, but probably only /// allowed in C++ grammar by accident /// nested-name-specifier identifier :: /// nested-name-specifier template[opt] simple-template-id :: /// [...] /// /// unqualified-id: /// ~ type-name /// ~ decltype-specifier /// [...] /// \endverbatim /// /// ... where the all but the last component of the nested-name-specifier /// has already been parsed, and the base expression is not of a non-dependent /// class type. ExprResult ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, ParsedType ObjectType); //===--------------------------------------------------------------------===// // C++ 9.3.2: C++ 'this' pointer /// ParseCXXThis - This handles the C++ 'this' pointer. /// /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. ExprResult ParseCXXThis(); //===--------------------------------------------------------------------===// // C++ 15: C++ Throw Expression /// ParseThrowExpression - This handles the C++ throw expression. /// /// \verbatim /// throw-expression: [C++ 15] /// 'throw' assignment-expression[opt] /// \endverbatim ExprResult ParseThrowExpression(); //===--------------------------------------------------------------------===// // C++ 2.13.5: C++ Boolean Literals /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. /// /// \verbatim /// boolean-literal: [C++ 2.13.5] /// 'true' /// 'false' /// \endverbatim ExprResult ParseCXXBoolLiteral(); //===--------------------------------------------------------------------===// // C++ 5.2.3: Explicit type conversion (functional notation) /// ParseCXXTypeConstructExpression - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). /// See [C++ 5.2.3]. /// /// \verbatim /// postfix-expression: [C++ 5.2p1] /// simple-type-specifier '(' expression-list[opt] ')' /// [C++0x] simple-type-specifier braced-init-list /// typename-specifier '(' expression-list[opt] ')' /// [C++0x] typename-specifier braced-init-list /// \endverbatim /// /// In C++1z onwards, the type specifier can also be a template-name. ExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. /// /// \verbatim /// 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 /// [C++0x] auto [TODO] /// /// type-name: /// class-name /// enum-name /// typedef-name /// \endverbatim /// void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); /// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ /// [dcl.name]), which is a non-empty sequence of type-specifiers, /// e.g., "const short int". Note that the DeclSpec is *not* finished /// by parsing the type-specifier-seq, because these sequences are /// typically followed by some form of declarator. Returns true and /// emits diagnostics if this is not a type-specifier-seq, false /// otherwise. /// /// \verbatim /// type-specifier-seq: [C++ 8.1] /// type-specifier type-specifier-seq[opt] /// \endverbatim /// bool ParseCXXTypeSpecifierSeq( DeclSpec &DS, DeclaratorContext Context = DeclaratorContext::TypeName); //===--------------------------------------------------------------------===// // C++ 5.3.4 and 5.3.5: C++ new and delete /// ParseExpressionListOrTypeId - Parse either an expression-list or a /// type-id. This ambiguity appears in the syntax of the C++ new operator. /// /// \verbatim /// new-expression: /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// \endverbatim /// bool ParseExpressionListOrTypeId(SmallVectorImpl &Exprs, Declarator &D); /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be /// passed to ParseDeclaratorInternal. /// /// \verbatim /// direct-new-declarator: /// '[' expression[opt] ']' /// direct-new-declarator '[' constant-expression ']' /// \endverbatim /// void ParseDirectNewDeclarator(Declarator &D); /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to /// allocate memory in a typesafe manner and call constructors. /// /// This method is called to parse the new expression after the optional :: /// has been already parsed. If the :: was present, "UseGlobal" is true and /// "Start" is its location. Otherwise, "Start" is the location of the 'new' /// token. /// /// \verbatim /// new-expression: /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// /// new-type-id: /// type-specifier-seq new-declarator[opt] /// [GNU] attributes type-specifier-seq new-declarator[opt] /// /// new-declarator: /// ptr-operator new-declarator[opt] /// direct-new-declarator /// /// new-initializer: /// '(' expression-list[opt] ')' /// [C++0x] braced-init-list /// \endverbatim /// ExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start); /// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used /// to free memory allocated by new. /// /// This method is called to parse the 'delete' expression after the optional /// '::' has been already parsed. If the '::' was present, "UseGlobal" is /// true and "Start" is its location. Otherwise, "Start" is the location of /// the 'delete' token. /// /// \verbatim /// delete-expression: /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// \endverbatim ExprResult ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start); //===--------------------------------------------------------------------===// // C++ if/switch/while/for condition expression. /// ParseCXXCondition - if/switch/while condition expression. /// /// \verbatim /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list /// [Clang] type-specifier-seq ref-qualifier[opt] '[' identifier-list ']' /// brace-or-equal-initializer /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// \endverbatim /// /// In C++1z, a condition may in some contexts be preceded by an /// optional init-statement. This function will parse that too. /// /// \param InitStmt If non-null, an init-statement is permitted, and if /// present will be parsed and stored here. /// /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. /// /// \param MissingOK Whether an empty condition is acceptable here. Otherwise /// it is considered an error to be recovered from. /// /// \param FRI If non-null, a for range declaration is permitted, and if /// present will be parsed and stored here, and a null result will be /// returned. /// /// \param EnterForConditionScope If true, enter a continue/break scope at the /// appropriate moment for a 'for' loop. /// /// \returns The parsed condition. Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK, bool MissingOK, ForRangeInfo *FRI = nullptr, bool EnterForConditionScope = false); DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context, ParsedAttributes &Attrs); //===--------------------------------------------------------------------===// // C++ Coroutines /// Parse the C++ Coroutines co_yield expression. /// /// \verbatim /// co_yield-expression: /// 'co_yield' assignment-expression[opt] /// \endverbatim ExprResult ParseCoyieldExpression(); //===--------------------------------------------------------------------===// // C++ Concepts /// ParseRequiresExpression - Parse a C++2a requires-expression. /// C++2a [expr.prim.req]p1 /// A requires-expression provides a concise way to express requirements /// on template arguments. A requirement is one that can be checked by /// name lookup (6.4) or by checking properties of types and expressions. /// /// \verbatim /// requires-expression: /// 'requires' requirement-parameter-list[opt] requirement-body /// /// requirement-parameter-list: /// '(' parameter-declaration-clause[opt] ')' /// /// requirement-body: /// '{' requirement-seq '}' /// /// requirement-seq: /// requirement /// requirement-seq requirement /// /// requirement: /// simple-requirement /// type-requirement /// compound-requirement /// nested-requirement /// \endverbatim ExprResult ParseRequiresExpression(); /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know /// whether the parens contain an expression or a type-id. /// Returns true for a type-id and false for an expression. bool isTypeIdInParens(bool &isAmbiguous) { if (getLangOpts().CPlusPlus) return isCXXTypeId(TentativeCXXTypeIdContext::InParens, isAmbiguous); isAmbiguous = false; return isTypeSpecifierQualifier(); } bool isTypeIdInParens() { bool isAmbiguous; return isTypeIdInParens(isAmbiguous); } /// Finish parsing a C++ unqualified-id that is a template-id of /// some form. /// /// This routine is invoked when a '<' is encountered after an identifier or /// operator-function-id is parsed by \c ParseUnqualifiedId() to determine /// whether the unqualified-id is actually a template-id. This routine will /// then parse the template arguments and form the appropriate template-id to /// return to the caller. /// /// \param SS the nested-name-specifier that precedes this template-id, if /// we're actually parsing a qualified-id. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param ObjectHadErrors this unqualified-id occurs within a member access /// expression, indicates whether the original subexpressions had any errors. /// /// \param Name for constructor and destructor names, this is the actual /// identifier that may be a template-name. /// /// \param NameLoc the location of the class-name in a constructor or /// destructor. /// /// \param EnteringContext whether we're entering the scope of the /// nested-name-specifier. /// /// \param Id as input, describes the template-name or operator-function-id /// that precedes the '<'. If template arguments were parsed successfully, /// will be updated with the template-id. /// /// \param AssumeTemplateId When true, this routine will assume that the name /// refers to a template without performing name lookup to verify. /// /// \returns true if a parse error occurred, false otherwise. bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, UnqualifiedId &Id, bool AssumeTemplateId); /// Parse an operator-function-id or conversion-function-id as part /// of a C++ unqualified-id. /// /// This routine is responsible only for parsing the operator-function-id or /// conversion-function-id; it does not handle template arguments in any way. /// /// \verbatim /// operator-function-id: [C++ 13.5] /// 'operator' operator /// /// operator: one of /// new delete new[] delete[] /// + - * / % ^ & | ~ /// ! = < > += -= *= /= %= /// ^= &= |= << >> >>= <<= == != /// <= >= && || ++ -- , ->* -> /// () [] <=> /// /// conversion-function-id: [C++ 12.3.2] /// operator conversion-type-id /// /// conversion-type-id: /// type-specifier-seq conversion-declarator[opt] /// /// conversion-declarator: /// ptr-operator conversion-declarator[opt] /// \endverbatim /// /// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Result); //===--------------------------------------------------------------------===// // C++11/G++: Type Traits [Type-Traits.html in the GCC manual] /// Parse the built-in type-trait pseudo-functions that allow /// implementation of the TR1/C++11 type traits templates. /// /// \verbatim /// primary-expression: /// unary-type-trait '(' type-id ')' /// binary-type-trait '(' type-id ',' type-id ')' /// type-trait '(' type-id-seq ')' /// /// type-id-seq: /// type-id ...[opt] type-id-seq[opt] /// \endverbatim /// ExprResult ParseTypeTrait(); //===--------------------------------------------------------------------===// // Embarcadero: Arary and Expression Traits /// ParseArrayTypeTrait - Parse the built-in array type-trait /// pseudo-functions. /// /// \verbatim /// primary-expression: /// [Embarcadero] '__array_rank' '(' type-id ')' /// [Embarcadero] '__array_extent' '(' type-id ',' expression ')' /// \endverbatim /// ExprResult ParseArrayTypeTrait(); /// ParseExpressionTrait - Parse built-in expression-trait /// pseudo-functions like __is_lvalue_expr( xxx ). /// /// \verbatim /// primary-expression: /// [Embarcadero] expression-trait '(' expression ')' /// \endverbatim /// ExprResult ParseExpressionTrait(); ///@} // // // ------------------------------------------------------------------------- // // /// \name HLSL Constructs /// Implementations are in ParseHLSL.cpp ///@{ private: bool MaybeParseHLSLAnnotations(Declarator &D, SourceLocation *EndLoc = nullptr, bool CouldBeBitField = false) { assert(getLangOpts().HLSL && "MaybeParseHLSLAnnotations is for HLSL only"); if (Tok.is(tok::colon)) { ParsedAttributes Attrs(AttrFactory); ParseHLSLAnnotations(Attrs, EndLoc, CouldBeBitField); D.takeAttributesAppending(Attrs); return true; } return false; } void MaybeParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr) { assert(getLangOpts().HLSL && "MaybeParseHLSLAnnotations is for HLSL only"); if (Tok.is(tok::colon)) ParseHLSLAnnotations(Attrs, EndLoc); } struct ParsedSemantic { StringRef Name = ""; unsigned Index = 0; bool Explicit = false; }; ParsedSemantic ParseHLSLSemantic(); void ParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr, bool CouldBeBitField = false); Decl *ParseHLSLBuffer(SourceLocation &DeclEnd, ParsedAttributes &Attrs); ///@} // // // ------------------------------------------------------------------------- // // /// \name Initializers /// Implementations are in ParseInit.cpp ///@{ private: //===--------------------------------------------------------------------===// // C99 6.7.8: Initialization. /// ParseInitializer /// \verbatim /// initializer: [C99 6.7.8] /// assignment-expression /// '{' ... /// \endverbatim ExprResult ParseInitializer(Decl *DeclForInitializer = nullptr); /// MayBeDesignationStart - Return true if the current token might be the /// start of a designator. If we can tell it is impossible that it is a /// designator, return false. bool MayBeDesignationStart(); /// ParseBraceInitializer - Called when parsing an initializer that has a /// leading open brace. /// /// \verbatim /// initializer: [C99 6.7.8] /// '{' initializer-list '}' /// '{' initializer-list ',' '}' /// [C23] '{' '}' /// /// initializer-list: /// designation[opt] initializer ...[opt] /// initializer-list ',' designation[opt] initializer ...[opt] /// \endverbatim /// ExprResult ParseBraceInitializer(); struct DesignatorCompletionInfo { SmallVectorImpl &InitExprs; QualType PreferredBaseType; }; /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' /// production checking to see if the token stream starts with a designator. /// /// C99: /// /// \verbatim /// designation: /// designator-list '=' /// [GNU] array-designator /// [GNU] identifier ':' /// /// designator-list: /// designator /// designator-list designator /// /// designator: /// array-designator /// '.' identifier /// /// array-designator: /// '[' constant-expression ']' /// [GNU] '[' constant-expression '...' constant-expression ']' /// \endverbatim /// /// C++20: /// /// \verbatim /// designated-initializer-list: /// designated-initializer-clause /// designated-initializer-list ',' designated-initializer-clause /// /// designated-initializer-clause: /// designator brace-or-equal-initializer /// /// designator: /// '.' identifier /// \endverbatim /// /// We allow the C99 syntax extensions in C++20, but do not allow the C++20 /// extension (a braced-init-list after the designator with no '=') in C99. /// /// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an /// initializer (because it is an expression). We need to consider this case /// when parsing array designators. /// /// \p CodeCompleteCB is called with Designation parsed so far. ExprResult ParseInitializerWithPotentialDesignator(DesignatorCompletionInfo); ExprResult createEmbedExpr(); /// A SmallVector of expressions. typedef SmallVector ExprVector; // Return true if a comma (or closing brace) is necessary after the // __if_exists/if_not_exists statement. bool ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, bool &InitExprsOk); ///@} // // // ------------------------------------------------------------------------- // // /// \name Objective-C Constructs /// Implementations are in ParseObjc.cpp ///@{ public: friend class InMessageExpressionRAIIObject; friend class ObjCDeclContextSwitch; ObjCContainerDecl *getObjCDeclContext() const { return Actions.ObjC().getObjCDeclContext(); } /// Retrieve the underscored keyword (_Nonnull, _Nullable) that corresponds /// to the given nullability kind. IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability) { return Actions.getNullabilityKeyword(nullability); } private: /// Objective-C contextual keywords. IdentifierInfo *Ident_instancetype; /// Ident_super - IdentifierInfo for "super", to support fast /// comparison. IdentifierInfo *Ident_super; /// When true, we are directly inside an Objective-C message /// send expression. /// /// This is managed by the \c InMessageExpressionRAIIObject class, and /// should not be set directly. bool InMessageExpression; /// True if we are within an Objective-C container while parsing C-like decls. /// /// This is necessary because Sema thinks we have left the container /// to parse the C-like decls, meaning Actions.ObjC().getObjCDeclContext() /// will be NULL. bool ParsingInObjCContainer; /// Returns true if the current token is the identifier 'instancetype'. /// /// Should only be used in Objective-C language modes. bool isObjCInstancetype() { assert(getLangOpts().ObjC); if (Tok.isAnnotation()) return false; if (!Ident_instancetype) Ident_instancetype = PP.getIdentifierInfo("instancetype"); return Tok.getIdentifierInfo() == Ident_instancetype; } /// ObjCDeclContextSwitch - An object used to switch context from /// an objective-c decl context to its enclosing decl context and /// back. class ObjCDeclContextSwitch { Parser &P; ObjCContainerDecl *DC; SaveAndRestore WithinObjCContainer; public: explicit ObjCDeclContextSwitch(Parser &p) : P(p), DC(p.getObjCDeclContext()), WithinObjCContainer(P.ParsingInObjCContainer, DC != nullptr) { if (DC) P.Actions.ObjC().ActOnObjCTemporaryExitContainerContext(DC); } ~ObjCDeclContextSwitch() { if (DC) P.Actions.ObjC().ActOnObjCReenterContainerContext(DC); } }; void CheckNestedObjCContexts(SourceLocation AtLoc); void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod); // Objective-C External Declarations /// Skips attributes after an Objective-C @ directive. Emits a diagnostic. void MaybeSkipAttributes(tok::ObjCKeywordKind Kind); /// ParseObjCAtDirectives - Handle parts of the external-declaration /// production: /// \verbatim /// external-declaration: [C99 6.9] /// [OBJC] objc-class-definition /// [OBJC] objc-class-declaration /// [OBJC] objc-alias-declaration /// [OBJC] objc-protocol-definition /// [OBJC] objc-method-definition /// [OBJC] '@' 'end' /// \endverbatim DeclGroupPtrTy ParseObjCAtDirectives(ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs); /// /// \verbatim /// objc-class-declaration: /// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';' /// /// objc-class-forward-decl: /// identifier objc-type-parameter-list[opt] /// \endverbatim /// DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); /// /// \verbatim /// objc-interface: /// objc-class-interface-attributes[opt] objc-class-interface /// objc-category-interface /// /// objc-class-interface: /// '@' 'interface' identifier objc-type-parameter-list[opt] /// objc-superclass[opt] objc-protocol-refs[opt] /// objc-class-instance-variables[opt] /// objc-interface-decl-list /// @end /// /// objc-category-interface: /// '@' 'interface' identifier objc-type-parameter-list[opt] /// '(' identifier[opt] ')' objc-protocol-refs[opt] /// objc-interface-decl-list /// @end /// /// objc-superclass: /// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) /// __attribute__((visibility("hidden"))) /// __attribute__((deprecated)) /// __attribute__((unavailable)) /// __attribute__((objc_exception)) - used by NSException on 64-bit /// __attribute__((objc_root_class)) /// \endverbatim /// Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, ParsedAttributes &prefixAttrs); /// Class to handle popping type parameters when leaving the scope. class ObjCTypeParamListScope; /// Parse an objc-type-parameter-list. ObjCTypeParamList *parseObjCTypeParamList(); /// Parse an Objective-C type parameter list, if present, or capture /// the locations of the protocol identifiers for a list of protocol /// references. /// /// \verbatim /// objc-type-parameter-list: /// '<' objc-type-parameter (',' objc-type-parameter)* '>' /// /// objc-type-parameter: /// objc-type-parameter-variance? identifier objc-type-parameter-bound[opt] /// /// objc-type-parameter-bound: /// ':' type-name /// /// objc-type-parameter-variance: /// '__covariant' /// '__contravariant' /// \endverbatim /// /// \param lAngleLoc The location of the starting '<'. /// /// \param protocolIdents Will capture the list of identifiers, if the /// angle brackets contain a list of protocol references rather than a /// type parameter list. /// /// \param rAngleLoc The location of the ending '>'. ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs( ObjCTypeParamListScope &Scope, SourceLocation &lAngleLoc, SmallVectorImpl &protocolIdents, SourceLocation &rAngleLoc, bool mayBeProtocolList = true); void HelperActionsForIvarDeclarations(ObjCContainerDecl *interfaceDecl, SourceLocation atLoc, BalancedDelimiterTracker &T, SmallVectorImpl &AllIvarDecls, bool RBraceMissing); /// \verbatim /// objc-class-instance-variables: /// '{' objc-instance-variable-decl-list[opt] '}' /// /// objc-instance-variable-decl-list: /// objc-visibility-spec /// objc-instance-variable-decl ';' /// ';' /// objc-instance-variable-decl-list objc-visibility-spec /// objc-instance-variable-decl-list objc-instance-variable-decl ';' /// objc-instance-variable-decl-list static_assert-declaration /// objc-instance-variable-decl-list ';' /// /// objc-visibility-spec: /// @private /// @protected /// @public /// @package [OBJC2] /// /// objc-instance-variable-decl: /// struct-declaration /// \endverbatim /// void ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl, tok::ObjCKeywordKind visibility, SourceLocation atLoc); /// \verbatim /// objc-protocol-refs: /// '<' identifier-list '>' /// \endverbatim /// bool ParseObjCProtocolReferences( SmallVectorImpl &P, SmallVectorImpl &PLocs, bool WarnOnDeclarations, bool ForObjCContainer, SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc, bool consumeLastToken); /// Parse the first angle-bracket-delimited clause for an /// Objective-C object or object pointer type, which may be either /// type arguments or protocol qualifiers. /// /// \verbatim /// objc-type-arguments: /// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>' /// \endverbatim /// void parseObjCTypeArgsOrProtocolQualifiers( ParsedType baseType, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SmallVectorImpl &protocolLocs, SourceLocation &protocolRAngleLoc, bool consumeLastToken, bool warnOnIncompleteProtocols); /// Parse either Objective-C type arguments or protocol qualifiers; if the /// former, also parse protocol qualifiers afterward. void parseObjCTypeArgsAndProtocolQualifiers( ParsedType baseType, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SmallVectorImpl &protocolLocs, SourceLocation &protocolRAngleLoc, bool consumeLastToken); /// Parse a protocol qualifier type such as '', which is /// an anachronistic way of writing 'id'. TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc); /// Parse Objective-C type arguments and protocol qualifiers, extending the /// current type with the parsed result. TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc, ParsedType type, bool consumeLastToken, SourceLocation &endLoc); /// \verbatim /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] /// objc-interface-decl-list objc-method-requirement [OBJC2] /// objc-interface-decl-list objc-method-proto ';' /// objc-interface-decl-list declaration /// objc-interface-decl-list ';' /// /// objc-method-requirement: [OBJC2] /// @required /// @optional /// \endverbatim /// void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Decl *CDecl); /// \verbatim /// objc-protocol-declaration: /// objc-protocol-definition /// objc-protocol-forward-reference /// /// objc-protocol-definition: /// \@protocol identifier /// objc-protocol-refs[opt] /// objc-interface-decl-list /// \@end /// /// objc-protocol-forward-reference: /// \@protocol identifier-list ';' /// \endverbatim /// /// "\@protocol identifier ;" should be resolved as "\@protocol /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, ParsedAttributes &prefixAttrs); struct ObjCImplParsingDataRAII { Parser &P; Decl *Dcl; bool HasCFunction; typedef SmallVector LateParsedObjCMethodContainer; LateParsedObjCMethodContainer LateParsedObjCMethods; ObjCImplParsingDataRAII(Parser &parser, Decl *D) : P(parser), Dcl(D), HasCFunction(false) { P.CurParsedObjCImpl = this; Finished = false; } ~ObjCImplParsingDataRAII(); void finish(SourceRange AtEnd); bool isFinished() const { return Finished; } private: bool Finished; }; ObjCImplParsingDataRAII *CurParsedObjCImpl; /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them /// for later parsing. void StashAwayMethodOrFunctionBodyTokens(Decl *MDecl); /// \verbatim /// objc-implementation: /// objc-class-implementation-prologue /// objc-category-implementation-prologue /// /// objc-class-implementation-prologue: /// @implementation identifier objc-superclass[opt] /// objc-class-instance-variables[opt] /// /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) /// \endverbatim DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc, ParsedAttributes &Attrs); DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd); /// \verbatim /// compatibility-alias-decl: /// @compatibility_alias alias-name class-name ';' /// \endverbatim /// Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc); /// \verbatim /// property-synthesis: /// @synthesize property-ivar-list ';' /// /// property-ivar-list: /// property-ivar /// property-ivar-list ',' property-ivar /// /// property-ivar: /// identifier /// identifier '=' identifier /// \endverbatim /// Decl *ParseObjCPropertySynthesize(SourceLocation atLoc); /// \verbatim /// property-dynamic: /// @dynamic property-list /// /// property-list: /// identifier /// property-list ',' identifier /// \endverbatim /// Decl *ParseObjCPropertyDynamic(SourceLocation atLoc); /// \verbatim /// objc-selector: /// identifier /// one of /// enum struct union if else while do for switch case default /// break continue return goto asm sizeof typeof __alignof /// unsigned long const short volatile signed restrict _Complex /// in out inout bycopy byref oneway int char float double void _Bool /// \endverbatim /// IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); IdentifierInfo *ObjCTypeQuals[llvm::to_underlying(ObjCTypeQual::NumQuals)]; /// \verbatim /// objc-for-collection-in: 'in' /// \endverbatim /// bool isTokIdentifier_in() const; /// \verbatim /// objc-type-name: /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// \endverbatim /// ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, DeclaratorContext Ctx, ParsedAttributes *ParamAttrs); /// \verbatim /// objc-method-proto: /// objc-instance-method objc-method-decl objc-method-attributes[opt] /// objc-class-method objc-method-decl objc-method-attributes[opt] /// /// objc-instance-method: '-' /// objc-class-method: '+' /// /// objc-method-attributes: [OBJC2] /// __attribute__((deprecated)) /// \endverbatim /// Decl *ParseObjCMethodPrototype( tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, bool MethodDefinition = true); /// \verbatim /// objc-method-decl: /// objc-selector /// objc-keyword-selector objc-parmlist[opt] /// objc-type-name objc-selector /// objc-type-name objc-keyword-selector objc-parmlist[opt] /// /// objc-keyword-selector: /// objc-keyword-decl /// objc-keyword-selector objc-keyword-decl /// /// objc-keyword-decl: /// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier /// objc-selector ':' objc-keyword-attributes[opt] identifier /// ':' objc-type-name objc-keyword-attributes[opt] identifier /// ':' objc-keyword-attributes[opt] identifier /// /// objc-parmlist: /// objc-parms objc-ellipsis[opt] /// /// objc-parms: /// objc-parms , parameter-declaration /// /// objc-ellipsis: /// , ... /// /// objc-keyword-attributes: [OBJC2] /// __attribute__((unused)) /// \endverbatim /// Decl *ParseObjCMethodDecl( SourceLocation mLoc, tok::TokenKind mType, tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, bool MethodDefinition = true); /// Parse property attribute declarations. /// /// \verbatim /// property-attr-decl: '(' property-attrlist ')' /// property-attrlist: /// property-attribute /// property-attrlist ',' property-attribute /// property-attribute: /// getter '=' identifier /// setter '=' identifier ':' /// direct /// readonly /// readwrite /// assign /// retain /// copy /// nonatomic /// atomic /// strong /// weak /// unsafe_unretained /// nonnull /// nullable /// null_unspecified /// null_resettable /// class /// \endverbatim /// void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); /// \verbatim /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// \endverbatim /// Decl *ParseObjCMethodDefinition(); //===--------------------------------------------------------------------===// // Objective-C Expressions ExprResult ParseObjCAtExpression(SourceLocation AtLocation); ExprResult ParseObjCStringLiteral(SourceLocation AtLoc); /// ParseObjCCharacterLiteral - /// \verbatim /// objc-scalar-literal : '@' character-literal /// ; /// \endverbatim ExprResult ParseObjCCharacterLiteral(SourceLocation AtLoc); /// ParseObjCNumericLiteral - /// \verbatim /// objc-scalar-literal : '@' scalar-literal /// ; /// scalar-literal : | numeric-constant /* any numeric constant. */ /// ; /// \endverbatim ExprResult ParseObjCNumericLiteral(SourceLocation AtLoc); /// ParseObjCBooleanLiteral - /// \verbatim /// objc-scalar-literal : '@' boolean-keyword /// ; /// boolean-keyword: 'true' | 'false' | '__objc_yes' | '__objc_no' /// ; /// \endverbatim ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue); ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc); ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc); /// ParseObjCBoxedExpr - /// \verbatim /// objc-box-expression: /// @( assignment-expression ) /// \endverbatim ExprResult ParseObjCBoxedExpr(SourceLocation AtLoc); /// \verbatim /// objc-encode-expression: /// \@encode ( type-name ) /// \endverbatim ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); /// \verbatim /// objc-selector-expression /// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')' /// \endverbatim ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc); /// \verbatim /// objc-protocol-expression /// \@protocol ( protocol-name ) /// \endverbatim ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); /// Determine whether the parser is currently referring to a an /// Objective-C message send, using a simplified heuristic to avoid overhead. /// /// This routine will only return true for a subset of valid message-send /// expressions. bool isSimpleObjCMessageExpression(); /// \verbatim /// objc-message-expr: /// '[' objc-receiver objc-message-args ']' /// /// objc-receiver: [C] /// 'super' /// expression /// class-name /// type-name /// \endverbatim /// ExprResult ParseObjCMessageExpression(); /// Parse the remainder of an Objective-C message following the /// '[' objc-receiver. /// /// This routine handles sends to super, class messages (sent to a /// class name), and instance messages (sent to an object), and the /// target is represented by \p SuperLoc, \p ReceiverType, or \p /// ReceiverExpr, respectively. Only one of these parameters may have /// a valid value. /// /// \param LBracLoc The location of the opening '['. /// /// \param SuperLoc If this is a send to 'super', the location of the /// 'super' keyword that indicates a send to the superclass. /// /// \param ReceiverType If this is a class message, the type of the /// class we are sending a message to. /// /// \param ReceiverExpr If this is an instance message, the expression /// used to compute the receiver object. /// /// \verbatim /// objc-message-args: /// objc-selector /// objc-keywordarg-list /// /// objc-keywordarg-list: /// objc-keywordarg /// objc-keywordarg-list objc-keywordarg /// /// objc-keywordarg: /// selector-name[opt] ':' objc-keywordexpr /// /// objc-keywordexpr: /// nonempty-expr-list /// /// nonempty-expr-list: /// assignment-expression /// nonempty-expr-list , assignment-expression /// \endverbatim /// ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, Expr *ReceiverExpr); /// Parse the receiver of an Objective-C++ message send. /// /// This routine parses the receiver of a message send in /// Objective-C++ either as a type or as an expression. Note that this /// routine must not be called to parse a send to 'super', since it /// has no way to return such a result. /// /// \param IsExpr Whether the receiver was parsed as an expression. /// /// \param TypeOrExpr If the receiver was parsed as an expression (\c /// IsExpr is true), the parsed expression. If the receiver was parsed /// as a type (\c IsExpr is false), the parsed type. /// /// \returns True if an error occurred during parsing or semantic /// analysis, in which case the arguments do not have valid /// values. Otherwise, returns false for a successful parse. /// /// \verbatim /// objc-receiver: [C++] /// 'super' [not parsed here] /// expression /// simple-type-specifier /// typename-specifier /// \endverbatim bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr); //===--------------------------------------------------------------------===// // Objective-C Statements enum class ParsedStmtContext; StmtResult ParseObjCAtStatement(SourceLocation atLoc, ParsedStmtContext StmtCtx); /// \verbatim /// objc-try-catch-statement: /// @try compound-statement objc-catch-list[opt] /// @try compound-statement objc-catch-list[opt] @finally compound-statement /// /// objc-catch-list: /// @catch ( parameter-declaration ) compound-statement /// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement /// catch-parameter-declaration: /// parameter-declaration /// '...' [OBJC2] /// \endverbatim /// StmtResult ParseObjCTryStmt(SourceLocation atLoc); /// \verbatim /// objc-throw-statement: /// throw expression[opt]; /// \endverbatim /// StmtResult ParseObjCThrowStmt(SourceLocation atLoc); /// \verbatim /// objc-synchronized-statement: /// @synchronized '(' expression ')' compound-statement /// \endverbatim /// StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); /// \verbatim /// objc-autoreleasepool-statement: /// @autoreleasepool compound-statement /// \endverbatim /// StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc); /// ParseObjCTypeQualifierList - This routine parses the objective-c's type /// qualifier list and builds their bitmask representation in the input /// argument. /// /// \verbatim /// objc-type-qualifiers: /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// /// objc-type-qualifier: /// 'in' /// 'out' /// 'inout' /// 'oneway' /// 'bycopy's /// 'byref' /// 'nonnull' /// 'nullable' /// 'null_unspecified' /// \endverbatim /// void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, DeclaratorContext Context); /// Determine whether we are currently at the start of an Objective-C /// class message that appears to be missing the open bracket '['. bool isStartOfObjCClassMessageMissingOpenBracket(); ///@} // // // ------------------------------------------------------------------------- // // /// \name OpenACC Constructs /// Implementations are in ParseOpenACC.cpp ///@{ public: friend class ParsingOpenACCDirectiveRAII; /// Parse OpenACC directive on a declaration. /// /// Placeholder for now, should just ignore the directives after emitting a /// diagnostic. Eventually will be split into a few functions to parse /// different situations. DeclGroupPtrTy ParseOpenACCDirectiveDecl(AccessSpecifier &AS, ParsedAttributes &Attrs, DeclSpec::TST TagType, Decl *TagDecl); // Parse OpenACC Directive on a Statement. StmtResult ParseOpenACCDirectiveStmt(); private: /// Parsing OpenACC directive mode. bool OpenACCDirectiveParsing = false; /// Currently parsing a situation where an OpenACC array section could be /// legal, such as a 'var-list'. bool AllowOpenACCArraySections = false; /// RAII object to set reset OpenACC parsing a context where Array Sections /// are allowed. class OpenACCArraySectionRAII { Parser &P; public: OpenACCArraySectionRAII(Parser &P) : P(P) { assert(!P.AllowOpenACCArraySections); P.AllowOpenACCArraySections = true; } ~OpenACCArraySectionRAII() { assert(P.AllowOpenACCArraySections); P.AllowOpenACCArraySections = false; } }; /// A struct to hold the information that got parsed by ParseOpenACCDirective, /// so that the callers of it can use that to construct the appropriate AST /// nodes. struct OpenACCDirectiveParseInfo { OpenACCDirectiveKind DirKind; SourceLocation StartLoc; SourceLocation DirLoc; SourceLocation LParenLoc; SourceLocation RParenLoc; SourceLocation EndLoc; SourceLocation MiscLoc; OpenACCAtomicKind AtomicKind; SmallVector Exprs; SmallVector Clauses; // TODO OpenACC: As we implement support for the Atomic, Routine, and Cache // constructs, we likely want to put that information in here as well. }; struct OpenACCWaitParseInfo { bool Failed = false; Expr *DevNumExpr = nullptr; SourceLocation QueuesLoc; SmallVector QueueIdExprs; SmallVector getAllExprs() { SmallVector Out; Out.push_back(DevNumExpr); llvm::append_range(Out, QueueIdExprs); return Out; } }; struct OpenACCCacheParseInfo { bool Failed = false; SourceLocation ReadOnlyLoc; SmallVector Vars; }; /// Represents the 'error' state of parsing an OpenACC Clause, and stores /// whether we can continue parsing, or should give up on the directive. enum class OpenACCParseCanContinue { Cannot = 0, Can = 1 }; /// A type to represent the state of parsing an OpenACC Clause. Situations /// that result in an OpenACCClause pointer are a success and can continue /// parsing, however some other situations can also continue. /// FIXME: This is better represented as a std::expected when we get C++23. using OpenACCClauseParseResult = llvm::PointerIntPair; OpenACCClauseParseResult OpenACCCanContinue(); OpenACCClauseParseResult OpenACCCannotContinue(); OpenACCClauseParseResult OpenACCSuccess(OpenACCClause *Clause); /// Parses the OpenACC directive (the entire pragma) including the clause /// list, but does not produce the main AST node. OpenACCDirectiveParseInfo ParseOpenACCDirective(); /// Helper that parses an ID Expression based on the language options. ExprResult ParseOpenACCIDExpression(); /// Parses the variable list for the `cache` construct. /// /// OpenACC 3.3, section 2.10: /// In C and C++, the syntax of the cache directive is: /// /// #pragma acc cache ([readonly:]var-list) new-line OpenACCCacheParseInfo ParseOpenACCCacheVarList(); /// Tries to parse the 'modifier-list' for a 'copy', 'copyin', 'copyout', or /// 'create' clause. OpenACCModifierKind tryParseModifierList(OpenACCClauseKind CK); using OpenACCVarParseResult = std::pair; /// Parses a single variable in a variable list for OpenACC. /// /// OpenACC 3.3, section 1.6: /// In this spec, a 'var' (in italics) is one of the following: /// - a variable name (a scalar, array, or composite variable name) /// - a subarray specification with subscript ranges /// - an array element /// - a member of a composite variable /// - a common block name between slashes (fortran only) OpenACCVarParseResult ParseOpenACCVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK); /// Parses the variable list for the variety of places that take a var-list. llvm::SmallVector ParseOpenACCVarList(OpenACCDirectiveKind DK, OpenACCClauseKind CK); /// Parses any parameters for an OpenACC Clause, including required/optional /// parens. /// /// The OpenACC Clause List is a comma or space-delimited list of clauses (see /// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't /// really have its owner grammar and each individual one has its own /// definition. However, they all are named with a single-identifier (or /// auto/default!) token, followed in some cases by either braces or parens. OpenACCClauseParseResult ParseOpenACCClauseParams(ArrayRef ExistingClauses, OpenACCDirectiveKind DirKind, OpenACCClauseKind Kind, SourceLocation ClauseLoc); /// Parses a single clause in a clause-list for OpenACC. Returns nullptr on /// error. OpenACCClauseParseResult ParseOpenACCClause(ArrayRef ExistingClauses, OpenACCDirectiveKind DirKind); /// Parses the clause-list for an OpenACC directive. /// /// OpenACC 3.3, section 1.7: /// To simplify the specification and convey appropriate constraint /// information, a pqr-list is a comma-separated list of pdr items. The one /// exception is a clause-list, which is a list of one or more clauses /// optionally separated by commas. SmallVector ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); /// OpenACC 3.3, section 2.16: /// In this section and throughout the specification, the term wait-argument /// means: /// \verbatim /// [ devnum : int-expr : ] [ queues : ] async-argument-list /// \endverbatim OpenACCWaitParseInfo ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective); /// Parses the clause of the 'bind' argument, which can be a string literal or /// an identifier. std::variant ParseOpenACCBindClauseArgument(); /// A type to represent the state of parsing after an attempt to parse an /// OpenACC int-expr. This is useful to determine whether an int-expr list can /// continue parsing after a failed int-expr. using OpenACCIntExprParseResult = std::pair; /// Parses the clause kind of 'int-expr', which can be any integral /// expression. OpenACCIntExprParseResult ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc); /// Parses the argument list for 'num_gangs', which allows up to 3 /// 'int-expr's. bool ParseOpenACCIntExprList(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc, llvm::SmallVectorImpl &IntExprs); /// Parses the 'device-type-list', which is a list of identifiers. /// /// OpenACC 3.3 Section 2.4: /// The argument to the device_type clause is a comma-separated list of one or /// more device architecture name identifiers, or an asterisk. /// /// The syntax of the device_type clause is /// device_type( * ) /// device_type( device-type-list ) /// /// The device_type clause may be abbreviated to dtype. bool ParseOpenACCDeviceTypeList(llvm::SmallVector &Archs); /// Parses the 'async-argument', which is an integral value with two /// 'special' values that are likely negative (but come from Macros). /// /// OpenACC 3.3 section 2.16: /// In this section and throughout the specification, the term async-argument /// means a nonnegative scalar integer expression (int for C or C++, integer /// for Fortran), or one of the special values acc_async_noval or /// acc_async_sync, as defined in the C header file and the Fortran openacc /// module. The special values are negative values, so as not to conflict with /// a user-specified nonnegative async-argument. OpenACCIntExprParseResult ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc); /// Parses the 'size-expr', which is an integral value, or an asterisk. /// Asterisk is represented by a OpenACCAsteriskSizeExpr /// /// OpenACC 3.3 Section 2.9: /// size-expr is one of: /// * /// int-expr /// Note that this is specified under 'gang-arg-list', but also applies to /// 'tile' via reference. ExprResult ParseOpenACCSizeExpr(OpenACCClauseKind CK); /// Parses a comma delimited list of 'size-expr's. bool ParseOpenACCSizeExprList(OpenACCClauseKind CK, llvm::SmallVectorImpl &SizeExprs); /// Parses a 'gang-arg-list', used for the 'gang' clause. /// /// OpenACC 3.3 Section 2.9: /// /// where gang-arg is one of: /// \verbatim /// [num:]int-expr /// dim:int-expr /// static:size-expr /// \endverbatim bool ParseOpenACCGangArgList(SourceLocation GangLoc, llvm::SmallVectorImpl &GKs, llvm::SmallVectorImpl &IntExprs); using OpenACCGangArgRes = std::pair; /// Parses a 'gang-arg', used for the 'gang' clause. Returns a pair of the /// ExprResult (which contains the validity of the expression), plus the gang /// kind for the current argument. OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc); /// Parses a 'condition' expr, ensuring it results in a ExprResult ParseOpenACCConditionExpr(); DeclGroupPtrTy ParseOpenACCAfterRoutineDecl(AccessSpecifier &AS, ParsedAttributes &Attrs, DeclSpec::TST TagType, Decl *TagDecl, OpenACCDirectiveParseInfo &DirInfo); StmtResult ParseOpenACCAfterRoutineStmt(OpenACCDirectiveParseInfo &DirInfo); ///@} // // // ------------------------------------------------------------------------- // // /// \name OpenMP Constructs /// Implementations are in ParseOpenMP.cpp ///@{ private: friend class ParsingOpenMPDirectiveRAII; /// Parsing OpenMP directive mode. bool OpenMPDirectiveParsing = false; /// Current kind of OpenMP clause OpenMPClauseKind OMPClauseKind = llvm::omp::OMPC_unknown; void ReplayOpenMPAttributeTokens(CachedTokens &OpenMPTokens) { // If parsing the attributes found an OpenMP directive, emit those tokens // to the parse stream now. if (!OpenMPTokens.empty()) { PP.EnterToken(Tok, /*IsReinject*/ true); PP.EnterTokenStream(OpenMPTokens, /*DisableMacroExpansion*/ true, /*IsReinject*/ true); ConsumeAnyToken(/*ConsumeCodeCompletionTok*/ true); } } //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. /// Parse clauses for '#pragma omp declare simd'. DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc); /// Parse a property kind into \p TIProperty for the selector set \p Set and /// selector \p Selector. void parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, llvm::omp::TraitSelector Selector, llvm::StringMap &Seen); /// Parse a selector kind into \p TISelector for the selector set \p Set. void parseOMPTraitSelectorKind(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen); /// Parse a selector set kind into \p TISet. void parseOMPTraitSetKind(OMPTraitSet &TISet, llvm::StringMap &Seen); /// Parses an OpenMP context property. void parseOMPContextProperty(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen); /// Parses an OpenMP context selector. /// /// \verbatim /// ['('[] [, ]* ')'] /// \endverbatim void parseOMPContextSelector(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &SeenSelectors); /// Parses an OpenMP context selector set. /// /// \verbatim /// '=' '{' [, ]* '}' /// \endverbatim void parseOMPContextSelectorSet(OMPTraitSet &TISet, llvm::StringMap &SeenSets); /// Parse OpenMP context selectors: /// /// \verbatim /// [, ]* /// \endverbatim bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); /// Parse an 'append_args' clause for '#pragma omp declare variant'. bool parseOpenMPAppendArgs(SmallVectorImpl &InteropInfos); /// Parse a `match` clause for an '#pragma omp declare variant'. Return true /// if there was an error. bool parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI); /// Parse clauses for '#pragma omp declare variant ( variant-func-id ) /// clause'. void ParseOMPDeclareVariantClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc); /// Parse 'omp [begin] assume[s]' directive. /// /// `omp assumes` or `omp begin/end assumes` [[,]]... /// where /// /// \verbatim /// clause: /// 'ext_IMPL_DEFINED' /// 'absent' '(' directive-name [, directive-name]* ')' /// 'contains' '(' directive-name [, directive-name]* ')' /// 'holds' '(' scalar-expression ')' /// 'no_openmp' /// 'no_openmp_routines' /// 'no_openmp_constructs' (OpenMP 6.0) /// 'no_parallelism' /// \endverbatim /// void ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, SourceLocation Loc); /// Parse 'omp end assumes' directive. void ParseOpenMPEndAssumesDirective(SourceLocation Loc); /// Parses clauses for directive. /// /// \verbatim /// [clause[ [,] clause] ... ] /// /// clauses: for error directive /// 'at' '(' compilation | execution ')' /// 'severity' '(' fatal | warning ')' /// 'message' '(' msg-string ')' /// .... /// \endverbatim /// /// \param DKind Kind of current directive. /// \param clauses for current directive. /// \param start location for clauses of current directive void ParseOpenMPClauses(OpenMPDirectiveKind DKind, SmallVectorImpl &Clauses, SourceLocation Loc); /// Parse clauses for '#pragma omp [begin] declare target'. void ParseOMPDeclareTargetClauses(SemaOpenMP::DeclareTargetContextInfo &DTCI); /// Parse '#pragma omp end declare target'. void ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind BeginDKind, OpenMPDirectiveKind EndDKind, SourceLocation Loc); /// Skip tokens until a `annot_pragma_openmp_end` was found. Emit a warning if /// it is not the current token. void skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind); /// Check the \p FoundKind against the \p ExpectedKind, if not issue an error /// that the "end" matching the "begin" directive of kind \p BeginKind was not /// found. Finally, if the expected kind was found or if \p SkipUntilOpenMPEnd /// is set, skip ahead using the helper `skipUntilPragmaOpenMPEnd`. void parseOMPEndDirective(OpenMPDirectiveKind BeginKind, OpenMPDirectiveKind ExpectedKind, OpenMPDirectiveKind FoundKind, SourceLocation MatchingLoc, SourceLocation FoundLoc, bool SkipUntilOpenMPEnd); /// Parses declarative OpenMP directives. /// /// \verbatim /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// /// allocate-directive: /// annot_pragma_openmp 'allocate' simple-variable-list [] /// annot_pragma_openmp_end /// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' [...] /// annot_pragma_openmp_end /// /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] /// ')' [[[,] ] ... ] /// annot_pragma_openmp_end /// /// declare-simd-directive: /// annot_pragma_openmp 'declare simd' { [,]} /// annot_pragma_openmp_end /// /// /// requires directive: /// annot_pragma_openmp 'requires' [[[,] ] ... ] /// annot_pragma_openmp_end /// /// assumes directive: /// annot_pragma_openmp 'assumes' [[[,] ] ... ] /// annot_pragma_openmp_end /// or /// annot_pragma_openmp 'begin assumes' [[[,] ] ... ] /// annot_pragma_openmp 'end assumes' /// annot_pragma_openmp_end /// \endverbatim /// DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl( AccessSpecifier &AS, ParsedAttributes &Attrs, bool Delayed = false, DeclSpec::TST TagType = DeclSpec::TST_unspecified, Decl *TagDecl = nullptr); /// Parse 'omp declare reduction' construct. /// /// \verbatim /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' /// '(' ':' {',' } ':' ')' /// ['initializer' '(' ('omp_priv' '=' )| ')'] /// annot_pragma_openmp_end /// \endverbatim /// is either a base language identifier or one of the /// following operators: '+', '-', '*', '&', '|', '^', '&&' and '||'. /// DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS); /// Parses initializer for provided omp_priv declaration inside the reduction /// initializer. void ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm); /// Parses 'omp declare mapper' directive. /// /// \verbatim /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] /// ')' [[[,] ] ... ] /// annot_pragma_openmp_end /// \endverbatim /// and are base language identifiers. /// DeclGroupPtrTy ParseOpenMPDeclareMapperDirective(AccessSpecifier AS); /// Parses variable declaration in 'omp declare mapper' directive. TypeResult parseOpenMPDeclareMapperVarDecl(SourceRange &Range, DeclarationName &Name, AccessSpecifier AS = AS_none); /// Parses simple list of variables. /// /// \verbatim /// simple-variable-list: /// '(' id-expression {, id-expression} ')' /// \endverbatim /// /// \param Kind Kind of the directive. /// \param Callback Callback function to be called for the list elements. /// \param AllowScopeSpecifier true, if the variables can have fully /// qualified names. /// bool ParseOpenMPSimpleVarList( OpenMPDirectiveKind Kind, const llvm::function_ref &Callback, bool AllowScopeSpecifier); /// Parses declarative or executable directive. /// /// \verbatim /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// /// allocate-directive: /// annot_pragma_openmp 'allocate' simple-variable-list /// annot_pragma_openmp_end /// /// declare-reduction-directive: /// annot_pragma_openmp 'declare' 'reduction' '(' ':' /// {',' } ':' ')' ['initializer' '(' /// ('omp_priv' '=' |) ')'] /// annot_pragma_openmp_end /// /// declare-mapper-directive: /// annot_pragma_openmp 'declare' 'mapper' '(' [ ':'] /// ')' [[[,] ] ... ] /// annot_pragma_openmp_end /// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' ')' ] | /// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' /// | 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | /// 'error' | 'atomic' | 'for simd' | 'parallel for simd' | 'target' | /// 'target data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop /// simd' | 'master taskloop' | 'master taskloop simd' | 'parallel /// master taskloop' | 'parallel master taskloop simd' | 'distribute' /// | 'target enter data' | 'target exit data' | 'target parallel' | /// 'target parallel for' | 'target update' | 'distribute parallel /// for' | 'distribute paralle for simd' | 'distribute simd' | 'target /// parallel for simd' | 'target simd' | 'teams distribute' | 'teams /// distribute simd' | 'teams distribute parallel for simd' | 'teams /// distribute parallel for' | 'target teams' | 'target teams /// distribute' | 'target teams distribute parallel for' | 'target /// teams distribute parallel for simd' | 'target teams distribute /// simd' | 'masked' | 'parallel masked' {clause} /// annot_pragma_openmp_end /// \endverbatim /// /// /// \param StmtCtx The context in which we're parsing the directive. /// \param ReadDirectiveWithinMetadirective true if directive is within a /// metadirective and therefore ends on the closing paren. StmtResult ParseOpenMPDeclarativeOrExecutableDirective( ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective = false); /// Parses executable directive. /// /// \param StmtCtx The context in which we're parsing the directive. /// \param DKind The kind of the executable directive. /// \param Loc Source location of the beginning of the directive. /// \param ReadDirectiveWithinMetadirective true if directive is within a /// metadirective and therefore ends on the closing paren. StmtResult ParseOpenMPExecutableDirective(ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, bool ReadDirectiveWithinMetadirective); /// Parses informational directive. /// /// \param StmtCtx The context in which we're parsing the directive. /// \param DKind The kind of the informational directive. /// \param Loc Source location of the beginning of the directive. /// \param ReadDirectiveWithinMetadirective true if directive is within a /// metadirective and therefore ends on the closing paren. StmtResult ParseOpenMPInformationalDirective( ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, bool ReadDirectiveWithinMetadirective); /// Parses clause of kind \a CKind for directive of a kind \a Kind. /// /// \verbatim /// clause: /// if-clause | final-clause | num_threads-clause | safelen-clause | /// default-clause | private-clause | firstprivate-clause | /// shared-clause | linear-clause | aligned-clause | collapse-clause | /// bind-clause | lastprivate-clause | reduction-clause | /// proc_bind-clause | schedule-clause | copyin-clause | /// copyprivate-clause | untied-clause | mergeable-clause | flush-clause /// | read-clause | write-clause | update-clause | capture-clause | /// seq_cst-clause | device-clause | simdlen-clause | threads-clause | /// simd-clause | num_teams-clause | thread_limit-clause | /// priority-clause | grainsize-clause | nogroup-clause | /// num_tasks-clause | hint-clause | to-clause | from-clause | /// is_device_ptr-clause | task_reduction-clause | in_reduction-clause | /// allocator-clause | allocate-clause | acq_rel-clause | acquire-clause /// | release-clause | relaxed-clause | depobj-clause | destroy-clause | /// detach-clause | inclusive-clause | exclusive-clause | /// uses_allocators-clause | use_device_addr-clause | has_device_addr /// \endverbatim /// /// \param DKind Kind of current directive. /// \param CKind Kind of current clause. /// \param FirstClause true, if this is the first clause of a kind \a CKind /// in current directive. /// OMPClause *ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause); /// Parses clause with a single expression of a kind \a Kind. /// /// Parsing of OpenMP clauses with single expressions like 'final', /// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams', /// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks', 'hint' or /// 'detach'. /// /// \verbatim /// final-clause: /// 'final' '(' expression ')' /// /// num_threads-clause: /// 'num_threads' '(' expression ')' /// /// safelen-clause: /// 'safelen' '(' expression ')' /// /// simdlen-clause: /// 'simdlen' '(' expression ')' /// /// collapse-clause: /// 'collapse' '(' expression ')' /// /// priority-clause: /// 'priority' '(' expression ')' /// /// grainsize-clause: /// 'grainsize' '(' expression ')' /// /// num_tasks-clause: /// 'num_tasks' '(' expression ')' /// /// hint-clause: /// 'hint' '(' expression ')' /// /// allocator-clause: /// 'allocator' '(' expression ')' /// /// detach-clause: /// 'detach' '(' event-handler-expression ')' /// /// align-clause /// 'align' '(' positive-integer-constant ')' /// /// holds-clause /// 'holds' '(' expression ')' /// \endverbatim /// /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. /// OMPClause *ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, bool ParseOnly); /// Parses simple clause like 'default' or 'proc_bind' of a kind \a Kind. /// /// \verbatim /// default-clause: /// 'default' '(' 'none' | 'shared' | 'private' | 'firstprivate' ')' /// /// proc_bind-clause: /// 'proc_bind' '(' 'master' | 'close' | 'spread' ')' /// /// bind-clause: /// 'bind' '(' 'teams' | 'parallel' | 'thread' ')' /// /// update-clause: /// 'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' | /// 'inoutset' ')' /// \endverbatim /// /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. /// OMPClause *ParseOpenMPSimpleClause(OpenMPClauseKind Kind, bool ParseOnly); /// Parse indirect clause for '#pragma omp declare target' directive. /// 'indirect' '[' '(' invoked-by-fptr ')' ']' /// where invoked-by-fptr is a constant boolean expression that evaluates to /// true or false at compile time. /// \param ParseOnly true to skip the clause's semantic actions and return /// false; bool ParseOpenMPIndirectClause(SemaOpenMP::DeclareTargetContextInfo &DTCI, bool ParseOnly); /// Parses clause with a single expression and an additional argument /// of a kind \a Kind like 'schedule' or 'dist_schedule'. /// /// \verbatim /// schedule-clause: /// 'schedule' '(' [ modifier [ ',' modifier ] ':' ] kind [',' expression ] /// ')' /// /// if-clause: /// 'if' '(' [ directive-name-modifier ':' ] expression ')' /// /// defaultmap: /// 'defaultmap' '(' modifier [ ':' kind ] ')' /// /// device-clause: /// 'device' '(' [ device-modifier ':' ] expression ')' /// \endverbatim /// /// \param DKind Directive kind. /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. /// OMPClause *ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly); /// Parses the 'looprange' clause of a '#pragma omp fuse' directive. OMPClause *ParseOpenMPLoopRangeClause(); /// Parses the 'sizes' clause of a '#pragma omp tile' directive. OMPClause *ParseOpenMPSizesClause(); /// Parses the 'permutation' clause of a '#pragma omp interchange' directive. OMPClause *ParseOpenMPPermutationClause(); /// Parses clause without any additional arguments like 'ordered'. /// /// \verbatim /// ordered-clause: /// 'ordered' /// /// nowait-clause: /// 'nowait' /// /// untied-clause: /// 'untied' /// /// mergeable-clause: /// 'mergeable' /// /// read-clause: /// 'read' /// /// threads-clause: /// 'threads' /// /// simd-clause: /// 'simd' /// /// nogroup-clause: /// 'nogroup' /// \endverbatim /// /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. /// OMPClause *ParseOpenMPClause(OpenMPClauseKind Kind, bool ParseOnly = false); /// Parses clause with the list of variables of a kind \a Kind: /// 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction', /// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'. /// /// \verbatim /// private-clause: /// 'private' '(' list ')' /// firstprivate-clause: /// 'firstprivate' '(' list ')' /// lastprivate-clause: /// 'lastprivate' '(' list ')' /// shared-clause: /// 'shared' '(' list ')' /// linear-clause: /// 'linear' '(' linear-list [ ':' linear-step ] ')' /// aligned-clause: /// 'aligned' '(' list [ ':' alignment ] ')' /// reduction-clause: /// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')' /// task_reduction-clause: /// 'task_reduction' '(' reduction-identifier ':' list ')' /// in_reduction-clause: /// 'in_reduction' '(' reduction-identifier ':' list ')' /// copyprivate-clause: /// 'copyprivate' '(' list ')' /// flush-clause: /// 'flush' '(' list ')' /// depend-clause: /// 'depend' '(' in | out | inout : list | source ')' /// map-clause: /// 'map' '(' [ [ always [,] ] [ close [,] ] /// [ mapper '(' mapper-identifier ')' [,] ] /// to | from | tofrom | alloc | release | delete ':' ] list ')'; /// to-clause: /// 'to' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// from-clause: /// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// use_device_ptr-clause: /// 'use_device_ptr' '(' list ')' /// use_device_addr-clause: /// 'use_device_addr' '(' list ')' /// is_device_ptr-clause: /// 'is_device_ptr' '(' list ')' /// has_device_addr-clause: /// 'has_device_addr' '(' list ')' /// allocate-clause: /// 'allocate' '(' [ allocator ':' ] list ')' /// As of OpenMP 5.1 there's also /// 'allocate' '(' allocate-modifier: list ')' /// where allocate-modifier is: 'allocator' '(' allocator ')' /// nontemporal-clause: /// 'nontemporal' '(' list ')' /// inclusive-clause: /// 'inclusive' '(' list ')' /// exclusive-clause: /// 'exclusive' '(' list ')' /// \endverbatim /// /// For 'linear' clause linear-list may have the following forms: /// list /// modifier(list) /// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++). /// /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. /// OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly); /// Parses a clause consisting of a list of expressions. /// /// \param Kind The clause to parse. /// \param ClauseNameLoc [out] The location of the clause name. /// \param OpenLoc [out] The location of '('. /// \param CloseLoc [out] The location of ')'. /// \param Exprs [out] The parsed expressions. /// \param ReqIntConst If true, each expression must be an integer constant. /// /// \return Whether the clause was parsed successfully. bool ParseOpenMPExprListClause(OpenMPClauseKind Kind, SourceLocation &ClauseNameLoc, SourceLocation &OpenLoc, SourceLocation &CloseLoc, SmallVectorImpl &Exprs, bool ReqIntConst = false); /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. /// \verbatim /// = 'iterator' '(' { [ ] identifier = /// }+ ')' /// \endverbatim ExprResult ParseOpenMPIteratorsExpr(); /// Parses allocators and traits in the context of the uses_allocator clause. /// Expected format: /// \verbatim /// '(' { [ '(' ')' ] }+ ')' /// \endverbatim OMPClause *ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind); /// Parses the 'interop' parts of the 'append_args' and 'init' clauses. bool ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, OpenMPClauseKind Kind); /// Parses clause with an interop variable of kind \a Kind. /// /// \verbatim /// init-clause: /// init([interop-modifier, ]interop-type[[, interop-type] ... ]:interop-var) /// /// destroy-clause: /// destroy(interop-var) /// /// use-clause: /// use(interop-var) /// /// interop-modifier: /// prefer_type(preference-list) /// /// preference-list: /// foreign-runtime-id [, foreign-runtime-id]... /// /// foreign-runtime-id: /// | /// /// interop-type: /// target | targetsync /// \endverbatim /// /// \param Kind Kind of current clause. /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. // OMPClause *ParseOpenMPInteropClause(OpenMPClauseKind Kind, bool ParseOnly); /// Parses a ompx_attribute clause /// /// \param ParseOnly true to skip the clause's semantic actions and return /// nullptr. // OMPClause *ParseOpenMPOMPXAttributesClause(bool ParseOnly); public: /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. /// \param RLoc Returned location of right paren. ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc, bool IsAddressOfOperand = false); /// Parses a reserved locator like 'omp_all_memory'. bool ParseOpenMPReservedLocator(OpenMPClauseKind Kind, SemaOpenMP::OpenMPVarListDataTy &Data, const LangOptions &LangOpts); /// Parses clauses with list. bool ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, SmallVectorImpl &Vars, SemaOpenMP::OpenMPVarListDataTy &Data); /// Parses the mapper modifier in map, to, and from clauses. bool parseMapperModifier(SemaOpenMP::OpenMPVarListDataTy &Data); /// Parse map-type-modifiers in map clause. /// map([ [map-type-modifier[,] [map-type-modifier[,] ...] [map-type] : ] list) /// where, map-type-modifier ::= always | close | mapper(mapper-identifier) | /// present /// where, map-type ::= alloc | delete | from | release | to | tofrom bool parseMapTypeModifiers(SemaOpenMP::OpenMPVarListDataTy &Data); /// Parses 'omp begin declare variant' directive. /// The syntax is: /// \verbatim /// { #pragma omp begin declare variant clause } /// /// { #pragma omp end declare variant } /// \endverbatim /// bool ParseOpenMPDeclareBeginVariantDirective(SourceLocation Loc); ///@} // // // ------------------------------------------------------------------------- // // /// \name Pragmas /// Implementations are in ParsePragma.cpp ///@{ private: std::unique_ptr AlignHandler; std::unique_ptr GCCVisibilityHandler; std::unique_ptr OptionsHandler; std::unique_ptr PackHandler; std::unique_ptr MSStructHandler; std::unique_ptr UnusedHandler; std::unique_ptr WeakHandler; std::unique_ptr RedefineExtnameHandler; std::unique_ptr FPContractHandler; std::unique_ptr OpenCLExtensionHandler; std::unique_ptr OpenMPHandler; std::unique_ptr OpenACCHandler; std::unique_ptr PCSectionHandler; std::unique_ptr MSCommentHandler; std::unique_ptr MSDetectMismatchHandler; std::unique_ptr FPEvalMethodHandler; std::unique_ptr FloatControlHandler; std::unique_ptr MSPointersToMembers; std::unique_ptr MSVtorDisp; std::unique_ptr MSInitSeg; std::unique_ptr MSDataSeg; std::unique_ptr MSBSSSeg; std::unique_ptr MSConstSeg; std::unique_ptr MSCodeSeg; std::unique_ptr MSSection; std::unique_ptr MSStrictGuardStackCheck; std::unique_ptr MSRuntimeChecks; std::unique_ptr MSIntrinsic; std::unique_ptr MSFunction; std::unique_ptr MSOptimize; std::unique_ptr MSFenvAccess; std::unique_ptr MSAllocText; std::unique_ptr CUDAForceHostDeviceHandler; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; std::unique_ptr UnrollHintHandler; std::unique_ptr NoUnrollHintHandler; std::unique_ptr UnrollAndJamHintHandler; std::unique_ptr NoUnrollAndJamHintHandler; std::unique_ptr FPHandler; std::unique_ptr STDCFenvAccessHandler; std::unique_ptr STDCFenvRoundHandler; std::unique_ptr STDCCXLIMITHandler; std::unique_ptr STDCUnknownHandler; std::unique_ptr AttributePragmaHandler; std::unique_ptr MaxTokensHerePragmaHandler; std::unique_ptr MaxTokensTotalPragmaHandler; std::unique_ptr RISCVPragmaHandler; /// Initialize all pragma handlers. void initializePragmaHandlers(); /// Destroy and reset all pragma handlers. void resetPragmaHandlers(); /// Handle the annotation token produced for #pragma unused(...) /// /// Each annot_pragma_unused is followed by the argument token so e.g. /// "#pragma unused(x,y)" becomes: /// annot_pragma_unused 'x' annot_pragma_unused 'y' void HandlePragmaUnused(); /// Handle the annotation token produced for /// #pragma GCC visibility... void HandlePragmaVisibility(); /// Handle the annotation token produced for /// #pragma pack... void HandlePragmaPack(); /// Handle the annotation token produced for /// #pragma ms_struct... void HandlePragmaMSStruct(); void HandlePragmaMSPointersToMembers(); void HandlePragmaMSVtorDisp(); void HandlePragmaMSPragma(); bool HandlePragmaMSSection(StringRef PragmaName, SourceLocation PragmaLocation); bool HandlePragmaMSSegment(StringRef PragmaName, SourceLocation PragmaLocation); // #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} ) bool HandlePragmaMSInitSeg(StringRef PragmaName, SourceLocation PragmaLocation); // #pragma strict_gs_check(pop) // #pragma strict_gs_check(push, "on" | "off") // #pragma strict_gs_check("on" | "off") bool HandlePragmaMSStrictGuardStackCheck(StringRef PragmaName, SourceLocation PragmaLocation); bool HandlePragmaMSFunction(StringRef PragmaName, SourceLocation PragmaLocation); bool HandlePragmaMSAllocText(StringRef PragmaName, SourceLocation PragmaLocation); // #pragma optimize("gsty", on|off) bool HandlePragmaMSOptimize(StringRef PragmaName, SourceLocation PragmaLocation); // #pragma intrinsic("foo") bool HandlePragmaMSIntrinsic(StringRef PragmaName, SourceLocation PragmaLocation); /// Handle the annotation token produced for /// #pragma align... void HandlePragmaAlign(); /// Handle the annotation token produced for /// #pragma clang __debug dump... void HandlePragmaDump(); /// Handle the annotation token produced for /// #pragma weak id... void HandlePragmaWeak(); /// Handle the annotation token produced for /// #pragma weak id = id... void HandlePragmaWeakAlias(); /// Handle the annotation token produced for /// #pragma redefine_extname... void HandlePragmaRedefineExtname(); /// Handle the annotation token produced for /// #pragma STDC FP_CONTRACT... void HandlePragmaFPContract(); /// Handle the annotation token produced for /// #pragma STDC FENV_ACCESS... void HandlePragmaFEnvAccess(); /// Handle the annotation token produced for /// #pragma STDC FENV_ROUND... void HandlePragmaFEnvRound(); /// Handle the annotation token produced for /// #pragma STDC CX_LIMITED_RANGE... void HandlePragmaCXLimitedRange(); /// Handle the annotation token produced for /// #pragma float_control void HandlePragmaFloatControl(); /// \brief Handle the annotation token produced for /// #pragma clang fp ... void HandlePragmaFP(); /// Handle the annotation token produced for /// #pragma OPENCL EXTENSION... void HandlePragmaOpenCLExtension(); /// Handle the annotation token produced for /// #pragma clang __debug captured StmtResult HandlePragmaCaptured(); /// Handle the annotation token produced for /// #pragma clang loop and #pragma unroll. bool HandlePragmaLoopHint(LoopHint &Hint); bool ParsePragmaAttributeSubjectMatchRuleSet( attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc); void HandlePragmaAttribute(); ///@} // // // ------------------------------------------------------------------------- // // /// \name Statements /// Implementations are in ParseStmt.cpp ///@{ public: /// A SmallVector of statements. typedef SmallVector StmtVector; /// The location of the first statement inside an else that might /// have a missleading indentation. If there is no /// MisleadingIndentationChecker on an else active, this location is invalid. SourceLocation MisleadingIndentationElseLoc; private: /// Flags describing a context in which we're parsing a statement. enum class ParsedStmtContext { /// This context permits declarations in language modes where declarations /// are not statements. AllowDeclarationsInC = 0x1, /// This context permits standalone OpenMP directives. AllowStandaloneOpenMPDirectives = 0x2, /// This context is at the top level of a GNU statement expression. InStmtExpr = 0x4, /// The context of a regular substatement. SubStmt = 0, /// The context of a compound-statement. Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives, LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr) }; /// Act on an expression statement that might be the last statement in a /// GNU statement expression. Checks whether we are actually at the end of /// a statement expression and builds a suitable expression statement. StmtResult handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx); //===--------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. /// Parse a standalone statement (for instance, as the body of an 'if', /// 'while', or 'for'). StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr, ParsedStmtContext StmtCtx = ParsedStmtContext::SubStmt, LabelDecl *PrecedingLabel = nullptr); /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. /// \verbatim /// StatementOrDeclaration: /// statement /// declaration /// /// statement: /// labeled-statement /// compound-statement /// expression-statement /// selection-statement /// iteration-statement /// jump-statement /// [C++] declaration-statement /// [C++] try-block /// [MS] seh-try-block /// [OBC] objc-throw-statement /// [OBC] objc-try-catch-statement /// [OBC] objc-synchronized-statement /// [GNU] asm-statement /// [OMP] openmp-construct [TODO] /// /// labeled-statement: /// identifier ':' statement /// 'case' constant-expression ':' statement /// 'default' ':' statement /// /// selection-statement: /// if-statement /// switch-statement /// /// iteration-statement: /// while-statement /// do-statement /// for-statement /// /// expression-statement: /// expression[opt] ';' /// /// jump-statement: /// 'goto' identifier ';' /// 'continue' ';' /// 'break' ';' /// 'return' expression[opt] ';' /// [GNU] 'goto' '*' expression ';' /// /// [OBC] objc-throw-statement: /// [OBC] '@' 'throw' expression ';' /// [OBC] '@' 'throw' ';' /// \endverbatim /// StmtResult ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc = nullptr, LabelDecl *PrecedingLabel = nullptr); StmtResult ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, LabelDecl *PrecedingLabel); /// Parse an expression statement. StmtResult ParseExprStatement(ParsedStmtContext StmtCtx); /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// \verbatim /// label: /// identifier ':' /// [GNU] identifier ':' attributes[opt] /// /// labeled-statement: /// label statement /// \endverbatim /// StmtResult ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx); /// ParseCaseStatement /// \verbatim /// labeled-statement: /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// \endverbatim /// StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase = false, ExprResult Expr = ExprResult()); /// ParseDefaultStatement /// \verbatim /// labeled-statement: /// 'default' ':' statement /// \endverbatim /// Note that this does not parse the 'statement' at the end. /// StmtResult ParseDefaultStatement(ParsedStmtContext StmtCtx); StmtResult ParseCompoundStatement(bool isStmtExpr = false); /// ParseCompoundStatement - Parse a "{}" block. /// /// \verbatim /// compound-statement: [C99 6.8.2] /// { block-item-list[opt] } /// [GNU] { label-declarations block-item-list } [TODO] /// /// block-item-list: /// block-item /// block-item-list block-item /// /// block-item: /// declaration /// [GNU] '__extension__' declaration /// statement /// /// [GNU] label-declarations: /// [GNU] label-declaration /// [GNU] label-declarations label-declaration /// /// [GNU] label-declaration: /// [GNU] '__label__' identifier-list ';' /// \endverbatim /// StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags); /// Parse any pragmas at the start of the compound expression. We handle these /// separately since some pragmas (FP_CONTRACT) must appear before any C /// statement in the compound, but may be intermingled with other pragmas. void ParseCompoundStatementLeadingPragmas(); void DiagnoseLabelAtEndOfCompoundStatement(); /// Consume any extra semi-colons resulting in null statements, /// returning true if any tok::semi were consumed. bool ConsumeNullStmt(StmtVector &Stmts); /// ParseCompoundStatementBody - Parse a sequence of statements optionally /// followed by a label and invoke the ActOnCompoundStmt action. This expects /// the '{' to be the current token, and consume the '}' at the end of the /// block. It does not manipulate the scope stack. StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); /// ParseParenExprOrCondition: /// \verbatim /// [C ] '(' expression ')' /// [C++] '(' condition ')' /// [C++1z] '(' init-statement[opt] condition ')' /// \endverbatim /// /// This function parses and performs error recovery on the specified /// condition or expression (depending on whether we're in C++ or C mode). /// This function goes out of its way to recover well. It returns true if /// there was a parser error (the right paren couldn't be found), which /// indicates that the caller should try to recover harder. It returns false /// if the condition is successfully parsed. Note that a successful parse can /// still have semantic errors in the condition. Additionally, it will assign /// the location of the outer-most '(' and ')', to LParenLoc and RParenLoc, /// respectively. bool ParseParenExprOrCondition(StmtResult *InitStmt, Sema::ConditionResult &CondResult, SourceLocation Loc, Sema::ConditionKind CK, SourceLocation &LParenLoc, SourceLocation &RParenLoc); /// ParseIfStatement /// \verbatim /// if-statement: [C99 6.8.4.1] /// 'if' '(' expression ')' statement /// 'if' '(' expression ')' statement 'else' statement /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// [C++23] 'if' '!' [opt] consteval compound-statement /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement /// \endverbatim /// StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); /// ParseSwitchStatement /// \verbatim /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement /// \endverbatim StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc, LabelDecl *PrecedingLabel); /// ParseWhileStatement /// \verbatim /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement /// \endverbatim StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc, LabelDecl *PrecedingLabel); /// ParseDoStatement /// \verbatim /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// \endverbatim /// Note: this lets the caller parse the end ';'. StmtResult ParseDoStatement(LabelDecl *PrecedingLabel); /// ParseForStatement /// \verbatim /// for-statement: [C99 6.8.5.3] /// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' /// [C++] statement /// [C++0x] 'for' /// 'co_await'[opt] [Coroutines] /// '(' for-range-declaration ':' for-range-initializer ')' /// statement /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration /// [C++23] alias-declaration /// /// [C++0x] for-range-declaration: /// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] /// \endverbatim StmtResult ParseForStatement(SourceLocation *TrailingElseLoc, LabelDecl *PrecedingLabel); /// ParseGotoStatement /// \verbatim /// jump-statement: /// 'goto' identifier ';' /// [GNU] 'goto' '*' expression ';' /// \endverbatim /// /// Note: this lets the caller parse the end ';'. /// StmtResult ParseGotoStatement(); /// ParseContinueStatement /// \verbatim /// jump-statement: /// 'continue' ';' /// [C2y] 'continue' identifier ';' /// \endverbatim /// /// Note: this lets the caller parse the end ';'. /// StmtResult ParseContinueStatement(); /// ParseBreakStatement /// \verbatim /// jump-statement: /// 'break' ';' /// [C2y] 'break' identifier ';' /// \endverbatim /// /// Note: this lets the caller parse the end ';'. /// StmtResult ParseBreakStatement(); /// ParseReturnStatement /// \verbatim /// jump-statement: /// 'return' expression[opt] ';' /// 'return' braced-init-list ';' /// 'co_return' expression[opt] ';' /// 'co_return' braced-init-list ';' /// \endverbatim StmtResult ParseReturnStatement(); StmtResult ParseBreakOrContinueStatement(bool IsContinue); /// ParseDeferStatement /// \verbatim /// defer-statement: /// '_Defer' deferred-block /// /// deferred-block: /// unlabeled-statement /// \endverbatim StmtResult ParseDeferStatement(SourceLocation *TrailingElseLoc); StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx, SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs, LabelDecl *PrecedingLabel); void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks /// ParseCXXTryBlock - Parse a C++ try-block. /// /// \verbatim /// try-block: /// 'try' compound-statement handler-seq /// \endverbatim /// StmtResult ParseCXXTryBlock(); /// ParseCXXTryBlockCommon - Parse the common part of try-block and /// function-try-block. /// /// \verbatim /// try-block: /// 'try' compound-statement handler-seq /// /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// /// handler-seq: /// handler handler-seq[opt] /// /// [Borland] try-block: /// 'try' compound-statement seh-except-block /// 'try' compound-statement seh-finally-block /// \endverbatim /// StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false); /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the /// standard /// /// \verbatim /// handler: /// 'catch' '(' exception-declaration ')' compound-statement /// /// exception-declaration: /// attribute-specifier-seq[opt] type-specifier-seq declarator /// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt] /// '...' /// \endverbatim /// StmtResult ParseCXXCatchBlock(bool FnCatch = false); //===--------------------------------------------------------------------===// // MS: SEH Statements and Blocks /// ParseSEHTryBlockCommon /// /// \verbatim /// seh-try-block: /// '__try' compound-statement seh-handler /// /// seh-handler: /// seh-except-block /// seh-finally-block /// \endverbatim /// StmtResult ParseSEHTryBlock(); /// ParseSEHExceptBlock - Handle __except /// /// \verbatim /// seh-except-block: /// '__except' '(' seh-filter-expression ')' compound-statement /// \endverbatim /// StmtResult ParseSEHExceptBlock(SourceLocation Loc); /// ParseSEHFinallyBlock - Handle __finally /// /// \verbatim /// seh-finally-block: /// '__finally' compound-statement /// \endverbatim /// StmtResult ParseSEHFinallyBlock(SourceLocation Loc); StmtResult ParseSEHLeaveStatement(); Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); /// ParseFunctionTryBlock - Parse a C++ function-try-block. /// /// \verbatim /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// \endverbatim /// Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); /// When in code-completion, skip parsing of the function/method body /// unless the body contains the code-completion point. /// /// \returns true if the function body was skipped. bool trySkippingFunctionBody(); /// isDeclarationStatement - Disambiguates between a declaration or an /// expression statement, when parsing function bodies. /// /// \param DisambiguatingWithExpression - True to indicate that the purpose of /// this check is to disambiguate between an expression and a declaration. /// Returns true for declaration, false for expression. bool isDeclarationStatement(bool DisambiguatingWithExpression = false) { if (getLangOpts().CPlusPlus) return isCXXDeclarationStatement(DisambiguatingWithExpression); return isDeclarationSpecifier(ImplicitTypenameContext::No, true); } /// isForInitDeclaration - Disambiguates between a declaration or an /// expression in the context of the C 'clause-1' or the C++ // 'for-init-statement' part of a 'for' statement. /// Returns true for declaration, false for expression. bool isForInitDeclaration() { if (getLangOpts().OpenMP) Actions.OpenMP().startOpenMPLoop(); if (getLangOpts().CPlusPlus) return Tok.is(tok::kw_using) || isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); return isDeclarationSpecifier(ImplicitTypenameContext::No, true); } /// Determine whether this is a C++1z for-range-identifier. bool isForRangeIdentifier(); ///@} // // // ------------------------------------------------------------------------- // // /// \name `inline asm` Statement /// Implementations are in ParseStmtAsm.cpp ///@{ public: /// Parse an identifier in an MS-style inline assembly block. ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl &LineToks, unsigned &NumLineToksConsumed, bool IsUnevaluated); private: /// ParseAsmStatement - Parse a GNU extended asm statement. /// \verbatim /// asm-statement: /// gnu-asm-statement /// ms-asm-statement /// /// [GNU] gnu-asm-statement: /// 'asm' asm-qualifier-list[opt] '(' asm-argument ')' ';' /// /// [GNU] asm-argument: /// asm-string-literal /// asm-string-literal ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] /// ':' asm-clobbers /// /// [GNU] asm-clobbers: /// asm-string-literal /// asm-clobbers ',' asm-string-literal /// \endverbatim /// StmtResult ParseAsmStatement(bool &msAsm); /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, /// this routine is called to collect the tokens for an MS asm statement. /// /// \verbatim /// [MS] ms-asm-statement: /// ms-asm-block /// ms-asm-block ms-asm-statement /// /// [MS] ms-asm-block: /// '__asm' ms-asm-line '\n' /// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] /// /// [MS] ms-asm-instruction-block /// ms-asm-line /// ms-asm-line '\n' ms-asm-instruction-block /// \endverbatim /// StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); /// ParseAsmOperands - Parse the asm-operands production as used by /// asm-statement, assuming the leading ':' token was eaten. /// /// \verbatim /// [GNU] asm-operands: /// asm-operand /// asm-operands ',' asm-operand /// /// [GNU] asm-operand: /// asm-string-literal '(' expression ')' /// '[' identifier ']' asm-string-literal '(' expression ')' /// \endverbatim /// // FIXME: Avoid unnecessary std::string trashing. bool ParseAsmOperandsOpt(SmallVectorImpl &Names, SmallVectorImpl &Constraints, SmallVectorImpl &Exprs); class GNUAsmQualifiers { unsigned Qualifiers = AQ_unspecified; public: enum AQ { AQ_unspecified = 0, AQ_volatile = 1, AQ_inline = 2, AQ_goto = 4, }; static const char *getQualifierName(AQ Qualifier); bool setAsmQualifier(AQ Qualifier); inline bool isVolatile() const { return Qualifiers & AQ_volatile; }; inline bool isInline() const { return Qualifiers & AQ_inline; }; inline bool isGoto() const { return Qualifiers & AQ_goto; } }; // Determine if this is a GCC-style asm statement. bool isGCCAsmStatement(const Token &TokAfterAsm) const; bool isGNUAsmQualifier(const Token &TokAfterAsm) const; GNUAsmQualifiers::AQ getGNUAsmQualifier(const Token &Tok) const; /// parseGNUAsmQualifierListOpt - Parse a GNU extended asm qualifier list. /// \verbatim /// asm-qualifier: /// volatile /// inline /// goto /// /// asm-qualifier-list: /// asm-qualifier /// asm-qualifier-list asm-qualifier /// \endverbatim bool parseGNUAsmQualifierListOpt(GNUAsmQualifiers &AQ); ///@} // // // ------------------------------------------------------------------------- // // /// \name C++ Templates /// Implementations are in ParseTemplate.cpp ///@{ public: typedef SmallVector TemplateParameterLists; /// Re-enter a possible template scope, creating as many template parameter /// scopes as necessary. /// \return The number of template parameter scopes entered. unsigned ReenterTemplateScopes(MultiParseScope &S, Decl *D); private: /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; /// RAII class that manages the template parameter depth. class TemplateParameterDepthRAII { unsigned &Depth; unsigned AddedLevels; public: explicit TemplateParameterDepthRAII(unsigned &Depth) : Depth(Depth), AddedLevels(0) {} ~TemplateParameterDepthRAII() { Depth -= AddedLevels; } void operator++() { ++Depth; ++AddedLevels; } void addDepth(unsigned D) { Depth += D; AddedLevels += D; } void setAddedDepth(unsigned D) { Depth = Depth - AddedLevels + D; AddedLevels = D; } unsigned getDepth() const { return Depth; } unsigned getOriginalDepth() const { return Depth - AddedLevels; } }; /// Gathers and cleans up TemplateIdAnnotations when parsing of a /// top-level declaration is finished. SmallVector TemplateIds; /// Don't destroy template annotations in MaybeDestroyTemplateIds even if /// we're at the end of a declaration. Instead, we defer the destruction until /// after a top-level declaration. /// Use DelayTemplateIdDestructionRAII rather than setting it directly. bool DelayTemplateIdDestruction = false; void MaybeDestroyTemplateIds() { if (DelayTemplateIdDestruction) return; if (!TemplateIds.empty() && (Tok.is(tok::eof) || !PP.mightHavePendingAnnotationTokens())) DestroyTemplateIds(); } void DestroyTemplateIds(); /// RAII object to destroy TemplateIdAnnotations where possible, from a /// likely-good position during parsing. struct DestroyTemplateIdAnnotationsRAIIObj { Parser &Self; DestroyTemplateIdAnnotationsRAIIObj(Parser &Self) : Self(Self) {} ~DestroyTemplateIdAnnotationsRAIIObj() { Self.MaybeDestroyTemplateIds(); } }; struct DelayTemplateIdDestructionRAII { Parser &Self; bool PrevDelayTemplateIdDestruction; DelayTemplateIdDestructionRAII(Parser &Self, bool DelayTemplateIdDestruction) noexcept : Self(Self), PrevDelayTemplateIdDestruction(Self.DelayTemplateIdDestruction) { Self.DelayTemplateIdDestruction = DelayTemplateIdDestruction; } ~DelayTemplateIdDestructionRAII() noexcept { Self.DelayTemplateIdDestruction = PrevDelayTemplateIdDestruction; } }; /// Identifiers which have been declared within a tentative parse. SmallVector TentativelyDeclaredIdentifiers; /// Tracker for '<' tokens that might have been intended to be treated as an /// angle bracket instead of a less-than comparison. /// /// This happens when the user intends to form a template-id, but typoes the /// template-name or forgets a 'template' keyword for a dependent template /// name. /// /// We track these locations from the point where we see a '<' with a /// name-like expression on its left until we see a '>' or '>>' that might /// match it. struct AngleBracketTracker { /// Flags used to rank candidate template names when there is more than one /// '<' in a scope. enum Priority : unsigned short { /// A non-dependent name that is a potential typo for a template name. PotentialTypo = 0x0, /// A dependent name that might instantiate to a template-name. DependentName = 0x2, /// A space appears before the '<' token. SpaceBeforeLess = 0x0, /// No space before the '<' token NoSpaceBeforeLess = 0x1, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ DependentName) }; struct Loc { Expr *TemplateName; SourceLocation LessLoc; AngleBracketTracker::Priority Priority; unsigned short ParenCount, BracketCount, BraceCount; bool isActive(Parser &P) const { return P.ParenCount == ParenCount && P.BracketCount == BracketCount && P.BraceCount == BraceCount; } bool isActiveOrNested(Parser &P) const { return isActive(P) || P.ParenCount > ParenCount || P.BracketCount > BracketCount || P.BraceCount > BraceCount; } }; SmallVector Locs; /// Add an expression that might have been intended to be a template name. /// In the case of ambiguity, we arbitrarily select the innermost such /// expression, for example in 'foo < bar < baz', 'bar' is the current /// candidate. No attempt is made to track that 'foo' is also a candidate /// for the case where we see a second suspicious '>' token. void add(Parser &P, Expr *TemplateName, SourceLocation LessLoc, Priority Prio) { if (!Locs.empty() && Locs.back().isActive(P)) { if (Locs.back().Priority <= Prio) { Locs.back().TemplateName = TemplateName; Locs.back().LessLoc = LessLoc; Locs.back().Priority = Prio; } } else { Locs.push_back({TemplateName, LessLoc, Prio, P.ParenCount, P.BracketCount, P.BraceCount}); } } /// Mark the current potential missing template location as having been /// handled (this happens if we pass a "corresponding" '>' or '>>' token /// or leave a bracket scope). void clear(Parser &P) { while (!Locs.empty() && Locs.back().isActiveOrNested(P)) Locs.pop_back(); } /// Get the current enclosing expression that might hve been intended to be /// a template name. Loc *getCurrent(Parser &P) { if (!Locs.empty() && Locs.back().isActive(P)) return &Locs.back(); return nullptr; } }; AngleBracketTracker AngleBrackets; /// Contains information about any template-specific /// information that has been parsed prior to parsing declaration /// specifiers. struct ParsedTemplateInfo { ParsedTemplateInfo() : Kind(ParsedTemplateKind::NonTemplate), TemplateParams(nullptr) {} ParsedTemplateInfo(TemplateParameterLists *TemplateParams, bool isSpecialization, bool lastParameterListWasEmpty = false) : Kind(isSpecialization ? ParsedTemplateKind::ExplicitSpecialization : ParsedTemplateKind::Template), TemplateParams(TemplateParams), LastParameterListWasEmpty(lastParameterListWasEmpty) {} explicit ParsedTemplateInfo(SourceLocation ExternLoc, SourceLocation TemplateLoc) : Kind(ParsedTemplateKind::ExplicitInstantiation), TemplateParams(nullptr), ExternLoc(ExternLoc), TemplateLoc(TemplateLoc), LastParameterListWasEmpty(false) {} ParsedTemplateKind Kind; /// The template parameter lists, for template declarations /// and explicit specializations. TemplateParameterLists *TemplateParams; /// The location of the 'extern' keyword, if any, for an explicit /// instantiation SourceLocation ExternLoc; /// The location of the 'template' keyword, for an explicit /// instantiation. SourceLocation TemplateLoc; /// Whether the last template parameter list was empty. bool LastParameterListWasEmpty; SourceRange getSourceRange() const LLVM_READONLY; }; /// Lex a delayed template function for late parsing. void LexTemplateFunctionForLateParsing(CachedTokens &Toks); /// Late parse a C++ function template in Microsoft mode. void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT); static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT); /// We've parsed something that could plausibly be intended to be a template /// name (\p LHS) followed by a '<' token, and the following code can't /// possibly be an expression. Determine if this is likely to be a template-id /// and if so, diagnose it. bool diagnoseUnknownTemplateId(ExprResult TemplateName, SourceLocation Less); void checkPotentialAngleBracket(ExprResult &PotentialTemplateName); bool checkPotentialAngleBracketDelimiter(const AngleBracketTracker::Loc &, const Token &OpToken); bool checkPotentialAngleBracketDelimiter(const Token &OpToken) { if (auto *Info = AngleBrackets.getCurrent(*this)) return checkPotentialAngleBracketDelimiter(*Info, OpToken); return false; } //===--------------------------------------------------------------------===// // C++ 14: Templates [temp] /// Parse a template declaration, explicit instantiation, or /// explicit specialization. DeclGroupPtrTy ParseDeclarationStartingWithTemplate(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs); /// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists /// and either the function or class template declaration. Explicit /// specializations contain one or more 'template < >' prefixes /// followed by a (possibly templated) declaration. Since the /// syntactic form of both features is nearly identical, we parse all /// of the template headers together and let semantic analysis sort /// the declarations from the explicit specializations. /// /// \verbatim /// template-declaration: [C++ temp] /// 'export'[opt] 'template' '<' template-parameter-list '>' declaration /// /// template-declaration: [C++2a] /// template-head declaration /// template-head concept-definition /// /// TODO: requires-clause /// template-head: [C++2a] /// 'template' '<' template-parameter-list '>' /// requires-clause[opt] /// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration /// \endverbatim DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); clang::Parser::DeclGroupPtrTy ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, AccessSpecifier AS); /// Parse a single declaration that declares a template, /// template specialization, or explicit instantiation of a template. /// /// \param DeclEnd will receive the source location of the last token /// within this declaration. /// /// \param AS the access specifier associated with this /// declaration. Will be AS_none for namespace-scope declarations. /// /// \returns the new declaration. DeclGroupPtrTy ParseDeclarationAfterTemplate( DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); /// ParseTemplateParameters - Parses a template-parameter-list enclosed in /// angle brackets. Depth is the depth of this template-parameter-list, which /// is the number of template headers directly enclosing this template header. /// TemplateParams is the current list of template parameters we're building. /// The template parameter we parse will be added to this list. LAngleLoc and /// RAngleLoc will receive the positions of the '<' and '>', respectively, /// that enclose this template parameter list. /// /// \returns true if an error occurred, false otherwise. bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); /// ParseTemplateParameterList - Parse a template parameter list. If /// the parsing fails badly (i.e., closing bracket was left out), this /// will try to put the token stream in a reasonable position (closing /// a statement, etc.) and return false. /// /// \verbatim /// template-parameter-list: [C++ temp] /// template-parameter /// template-parameter-list ',' template-parameter /// \endverbatim bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); enum class TPResult; /// Determine whether the parser is at the start of a template /// type parameter. TPResult isStartOfTemplateTypeParameter(); /// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). /// /// \verbatim /// template-parameter: [C++ temp.param] /// type-parameter /// parameter-declaration /// /// type-parameter: (See below) /// type-parameter-key ...[opt] identifier[opt] /// type-parameter-key identifier[opt] = type-id /// (C++2a) type-constraint ...[opt] identifier[opt] /// (C++2a) type-constraint identifier[opt] = type-id /// 'template' '<' template-parameter-list '>' type-parameter-key /// ...[opt] identifier[opt] /// 'template' '<' template-parameter-list '>' type-parameter-key /// identifier[opt] '=' id-expression /// /// type-parameter-key: /// class /// typename /// \endverbatim /// NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). /// Other kinds of template parameters are parsed in /// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter. /// /// \verbatim /// type-parameter: [C++ temp.param] /// 'class' ...[opt][C++0x] identifier[opt] /// 'class' identifier[opt] '=' type-id /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id /// \endverbatim NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); /// ParseTemplateTemplateParameter - Handle the parsing of template /// template parameters. /// /// \verbatim /// type-parameter: [C++ temp.param] /// template-head type-parameter-key ...[opt] identifier[opt] /// template-head type-parameter-key identifier[opt] = id-expression /// type-parameter-key: /// 'class' /// 'typename' [C++1z] /// template-head: [C++2a] /// 'template' '<' template-parameter-list '>' /// requires-clause[opt] /// \endverbatim NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); /// ParseNonTypeTemplateParameter - Handle the parsing of non-type /// template parameters (e.g., in "template class array;"). /// /// \verbatim /// template-parameter: /// ... /// parameter-declaration /// \endverbatim NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); /// Check whether the current token is a template-id annotation denoting a /// type-constraint. bool isTypeConstraintAnnotation(); /// Try parsing a type-constraint at the current location. /// /// \verbatim /// type-constraint: /// nested-name-specifier[opt] concept-name /// nested-name-specifier[opt] concept-name /// '<' template-argument-list[opt] '>'[opt] /// \endverbatim /// /// \returns true if an error occurred, and false otherwise. bool TryAnnotateTypeConstraint(); void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, SourceLocation CorrectLoc, bool AlreadyHasEllipsis, bool IdentifierHasName); void DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, Declarator &D); // C++ 14.3: Template arguments [temp.arg] typedef SmallVector TemplateArgList; /// Parses a '>' at the end of a template list. /// /// If this function encounters '>>', '>>>', '>=', or '>>=', it tries /// to determine if these tokens were supposed to be a '>' followed by /// '>', '>>', '>=', or '>='. It emits an appropriate diagnostic if necessary. /// /// \param RAngleLoc the location of the consumed '>'. /// /// \param ConsumeLastToken if true, the '>' is consumed. /// /// \param ObjCGenericList if true, this is the '>' closing an Objective-C /// type parameter or type argument list, rather than a C++ template parameter /// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. bool ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList); /// Parses a template-id that after the template name has /// already been parsed. /// /// This routine takes care of parsing the enclosed template argument /// list ('<' template-parameter-list [opt] '>') and placing the /// results into a form that can be transferred to semantic analysis. /// /// \param ConsumeLastToken if true, then we will consume the last /// token that forms the template-id. Otherwise, we will leave the /// last token in the stream (e.g., so that it can be replaced with an /// annotation token). bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, SourceLocation &RAngleLoc, TemplateTy NameHint = nullptr); /// 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 TNK 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. /// /// \param TypeConstraint if true, then this is actually a type-constraint, /// meaning that the template argument list can be omitted (and the template /// in question must be a concept). /// /// If an unrecoverable parse error occurs and no annotation token can be /// formed, this function returns true. /// bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &TemplateName, bool AllowTypeAnnotation = true, bool TypeConstraint = false); /// 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. /// /// \param SS The scope specifier appearing before the template-id, if any. /// /// \param AllowImplicitTypename whether this is a context where T::type /// denotes a dependent type. /// \param IsClassName Is this template-id appearing in a context where we /// know it names a class, such as in an elaborated-type-specifier or /// base-specifier? ('typename' and 'template' are unneeded and disallowed /// in those contexts.) void AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, ImplicitTypenameContext AllowImplicitTypename, bool IsClassName = false); /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// /// \verbatim /// template-argument-list: [C++ 14.2] /// template-argument /// template-argument-list ',' template-argument /// \endverbatim /// /// \param Template is only used for code completion, and may be null. bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs, TemplateTy Template, SourceLocation OpenLoc); /// Parse a C++ template template argument. ParsedTemplateArgument ParseTemplateTemplateArgument(); /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). /// /// \verbatim /// template-argument: [C++ 14.2] /// constant-expression /// type-id /// id-expression /// braced-init-list [C++26, DR] /// \endverbatim /// ParsedTemplateArgument ParseTemplateArgument(); /// Parse a C++ explicit template instantiation /// (C++ [temp.explicit]). /// /// \verbatim /// explicit-instantiation: /// 'extern' [opt] 'template' declaration /// \endverbatim /// /// Note that the 'extern' is a GNU extension and C++11 feature. DeclGroupPtrTy ParseExplicitInstantiation(DeclaratorContext Context, SourceLocation ExternLoc, SourceLocation TemplateLoc, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); /// \brief Parse a single declaration that declares a concept. /// /// \param DeclEnd will receive the source location of the last token /// within this declaration. /// /// \returns the new declaration. Decl *ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, SourceLocation &DeclEnd); ///@} // // // ------------------------------------------------------------------------- // // /// \name Tentative Parsing /// Implementations are in ParseTentative.cpp ///@{ private: /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to /// either "commit the consumed tokens" or revert to the previously marked /// token position. Example: /// /// TentativeParsingAction TPA(*this); /// ConsumeToken(); /// .... /// TPA.Revert(); /// /// If the Unannotated parameter is true, any token annotations created /// during the tentative parse are reverted. class TentativeParsingAction { Parser &P; PreferredTypeBuilder PrevPreferredType; Token PrevTok; size_t PrevTentativelyDeclaredIdentifierCount; unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount; bool isActive; public: explicit TentativeParsingAction(Parser &p, bool Unannotated = false) : P(p), PrevPreferredType(P.PreferredType) { PrevTok = P.Tok; PrevTentativelyDeclaredIdentifierCount = P.TentativelyDeclaredIdentifiers.size(); PrevParenCount = P.ParenCount; PrevBracketCount = P.BracketCount; PrevBraceCount = P.BraceCount; P.PP.EnableBacktrackAtThisPos(Unannotated); isActive = true; } void Commit() { assert(isActive && "Parsing action was finished!"); P.TentativelyDeclaredIdentifiers.resize( PrevTentativelyDeclaredIdentifierCount); P.PP.CommitBacktrackedTokens(); isActive = false; } void Revert() { assert(isActive && "Parsing action was finished!"); P.PP.Backtrack(); P.PreferredType = PrevPreferredType; P.Tok = PrevTok; P.TentativelyDeclaredIdentifiers.resize( PrevTentativelyDeclaredIdentifierCount); P.ParenCount = PrevParenCount; P.BracketCount = PrevBracketCount; P.BraceCount = PrevBraceCount; isActive = false; } ~TentativeParsingAction() { assert(!isActive && "Forgot to call Commit or Revert!"); } }; /// A TentativeParsingAction that automatically reverts in its destructor. /// Useful for disambiguation parses that will always be reverted. class RevertingTentativeParsingAction : private Parser::TentativeParsingAction { public: using TentativeParsingAction::TentativeParsingAction; ~RevertingTentativeParsingAction() { Revert(); } }; /// isCXXDeclarationStatement - C++-specialized function that disambiguates /// between a declaration or an expression statement, when parsing function /// bodies. Returns true for declaration, false for expression. /// /// \verbatim /// declaration-statement: /// block-declaration /// /// block-declaration: /// simple-declaration /// asm-definition /// namespace-alias-definition /// using-declaration /// using-directive /// [C++0x] static_assert-declaration /// /// asm-definition: /// 'asm' '(' string-literal ')' ';' /// /// namespace-alias-definition: /// 'namespace' identifier = qualified-namespace-specifier ';' /// /// using-declaration: /// 'using' typename[opt] '::'[opt] nested-name-specifier /// unqualified-id ';' /// 'using' '::' unqualified-id ; /// /// using-directive: /// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] /// namespace-name ';' /// \endverbatim /// bool isCXXDeclarationStatement(bool DisambiguatingWithExpression = false); /// isCXXSimpleDeclaration - C++-specialized function that disambiguates /// between a simple-declaration or an expression-statement. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. /// Returns false if the statement is disambiguated as expression. /// /// \verbatim /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// decl-specifier-seq ref-qualifier[opt] '[' identifier-list ']' /// brace-or-equal-initializer ';' [C++17] /// \endverbatim /// /// (if AllowForRangeDecl specified) /// for ( for-range-declaration : for-range-initializer ) statement /// /// \verbatim /// for-range-declaration: /// decl-specifier-seq declarator /// decl-specifier-seq ref-qualifier[opt] '[' identifier-list ']' /// \endverbatim /// /// In any of the above cases there can be a preceding /// attribute-specifier-seq, but the caller is expected to handle that. bool isCXXSimpleDeclaration(bool AllowForRangeDecl); /// isCXXFunctionDeclarator - Disambiguates between a function declarator or /// a constructor-style initializer, when parsing declaration statements. /// Returns true for function declarator and false for constructor-style /// initializer. Sets 'IsAmbiguous' to true to indicate that this declaration /// might be a constructor-style initializer. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. /// /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// bool isCXXFunctionDeclarator(bool *IsAmbiguous = nullptr, ImplicitTypenameContext AllowImplicitTypename = ImplicitTypenameContext::No); struct ConditionDeclarationOrInitStatementState; enum class ConditionOrInitStatement { Expression, ///< Disambiguated as an expression (either kind). ConditionDecl, ///< Disambiguated as the declaration form of condition. InitStmtDecl, ///< Disambiguated as a simple-declaration init-statement. ForRangeDecl, ///< Disambiguated as a for-range declaration. Error ///< Can't be any of the above! }; /// Disambiguates between a declaration in a condition, a /// simple-declaration in an init-statement, and an expression for /// a condition of a if/switch statement. /// /// \verbatim /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// \endverbatim /// /// Note that, unlike isCXXSimpleDeclaration, we must disambiguate all the way /// to the ';' to disambiguate cases like 'int(x))' (an expression) from /// 'int(x);' (a simple-declaration in an init-statement). ConditionOrInitStatement isCXXConditionDeclarationOrInitStatement(bool CanBeInitStmt, bool CanBeForRangeDecl); /// Determine whether the next set of tokens contains a type-id. /// /// The context parameter states what context we're parsing right /// now, which affects how this routine copes with the token /// following the type-id. If the context is /// TentativeCXXTypeIdContext::InParens, we have already parsed the '(' and we /// will cease lookahead when we hit the corresponding ')'. If the context is /// TentativeCXXTypeIdContext::AsTemplateArgument, we've already parsed the /// '<' or ',' before this template argument, and will cease lookahead when we /// hit a /// '>', '>>' (in C++0x), or ','; or, in C++0x, an ellipsis immediately /// preceding such. Returns true for a type-id and false for an expression. /// If during the disambiguation process a parsing error is encountered, /// the function returns true to let the declaration parsing code handle it. /// /// \verbatim /// type-id: /// type-specifier-seq abstract-declarator[opt] /// \endverbatim /// bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous); bool isCXXTypeId(TentativeCXXTypeIdContext Context) { bool isAmbiguous; return isCXXTypeId(Context, isAmbiguous); } /// TPResult - Used as the result value for functions whose purpose is to /// disambiguate C++ constructs by "tentatively parsing" them. enum class TPResult { True, False, Ambiguous, Error }; /// Determine whether we could have an enum-base. /// /// \p AllowSemi If \c true, then allow a ';' after the enum-base; otherwise /// only consider this to be an enum-base if the next token is a '{'. /// /// \return \c false if this cannot possibly be an enum base; \c true /// otherwise. bool isEnumBase(bool AllowSemi); /// 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. /// /// Does not consume tokens. /// /// If InvalidAsDeclSpec is not null, some cases that would be ill-formed as /// declaration specifiers but possibly valid as some other kind of construct /// return TPResult::Ambiguous instead of TPResult::False. When this happens, /// the intent is to keep trying to disambiguate, on the basis that we might /// find a better reason to treat this construct as a declaration later on. /// When this happens and the name could possibly be valid in some other /// syntactic context, *InvalidAsDeclSpec is set to 'true'. The current cases /// that trigger this are: /// /// * When parsing X::Y (with no 'typename') where X is dependent /// * When parsing X where X is undeclared /// /// \verbatim /// decl-specifier: /// storage-class-specifier /// type-specifier /// function-specifier /// 'friend' /// 'typedef' /// [C++11] 'constexpr' /// [C++20] 'consteval' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: /// 'register' /// 'static' /// 'extern' /// 'mutable' /// 'auto' /// [GNU] '__thread' /// [C++11] 'thread_local' /// [C11] '_Thread_local' /// /// 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++11] 'auto' /// [GNU] '__auto_type' /// [C++11] 'decltype' ( expression ) /// [C++1y] 'decltype' ( 'auto' ) /// /// 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 /// \endverbatim /// TPResult isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, TPResult BracedCastResult = TPResult::False, bool *InvalidAsDeclSpec = nullptr); /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or /// \c TPResult::Ambiguous, determine whether the decl-specifier would be /// a type-specifier other than a cv-qualifier. bool isCXXDeclarationSpecifierAType(); /// Determine whether we might be looking at the '<' template-argument-list /// '>' of a template-id or simple-template-id, rather than a less-than /// comparison. This will often fail and produce an ambiguity, but should /// never be wrong if it returns True or False. TPResult isTemplateArgumentList(unsigned TokensToSkip); /// Determine whether an '(' after an 'explicit' keyword is part of a C++20 /// 'explicit(bool)' declaration, in earlier language modes where that is an /// extension. TPResult isExplicitBool(); /// Determine whether an identifier has been tentatively declared as a /// non-type. Such tentative declarations should not be found to name a type /// during a tentative parse, but also should not be annotated as a non-type. bool isTentativelyDeclared(IdentifierInfo *II); // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error. // Returning TPResult::True/False indicates that the ambiguity was // resolved and tentative parsing may stop. TPResult::Ambiguous indicates // that more tentative parsing is necessary for disambiguation. // They all consume tokens, so backtracking should be used after calling them. /// \verbatim /// simple-declaration: /// decl-specifier-seq init-declarator-list[opt] ';' /// /// (if AllowForRangeDecl specified) /// for ( for-range-declaration : for-range-initializer ) statement /// for-range-declaration: /// attribute-specifier-seqopt type-specifier-seq declarator /// \endverbatim /// TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); /// \verbatim /// [GNU] typeof-specifier: /// 'typeof' '(' expressions ')' /// 'typeof' '(' type-name ')' /// \endverbatim /// TPResult TryParseTypeofSpecifier(); /// [ObjC] protocol-qualifiers: /// '<' identifier-list '>' TPResult TryParseProtocolQualifiers(); TPResult TryParsePtrOperatorSeq(); /// \verbatim /// operator-function-id: /// 'operator' operator /// /// operator: one of /// new delete new[] delete[] + - * / % ^ [...] /// /// conversion-function-id: /// 'operator' conversion-type-id /// /// conversion-type-id: /// type-specifier-seq conversion-declarator[opt] /// /// conversion-declarator: /// ptr-operator conversion-declarator[opt] /// /// literal-operator-id: /// 'operator' string-literal identifier /// 'operator' user-defined-string-literal /// \endverbatim TPResult TryParseOperatorId(); /// Tentatively parse an init-declarator-list in order to disambiguate it from /// an expression. /// /// \verbatim /// init-declarator-list: /// init-declarator /// init-declarator-list ',' init-declarator /// /// init-declarator: /// declarator initializer[opt] /// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt] /// /// initializer: /// brace-or-equal-initializer /// '(' expression-list ')' /// /// brace-or-equal-initializer: /// '=' initializer-clause /// [C++11] braced-init-list /// /// initializer-clause: /// assignment-expression /// braced-init-list /// /// braced-init-list: /// '{' initializer-list ','[opt] '}' /// '{' '}' /// \endverbatim /// TPResult TryParseInitDeclaratorList(bool MayHaveTrailingReturnType = false); /// \verbatim /// declarator: /// direct-declarator /// ptr-operator declarator /// /// direct-declarator: /// declarator-id /// direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] /// direct-declarator '[' constant-expression[opt] ']' /// '(' declarator ')' /// [GNU] '(' attributes declarator ')' /// /// abstract-declarator: /// ptr-operator abstract-declarator[opt] /// direct-abstract-declarator /// /// direct-abstract-declarator: /// direct-abstract-declarator[opt] /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' /// '(' abstract-declarator ')' /// [C++0x] ... /// /// ptr-operator: /// '*' cv-qualifier-seq[opt] /// '&' /// [C++0x] '&&' [TODO] /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] /// /// cv-qualifier-seq: /// cv-qualifier cv-qualifier-seq[opt] /// /// cv-qualifier: /// 'const' /// 'volatile' /// /// declarator-id: /// '...'[opt] id-expression /// /// id-expression: /// unqualified-id /// qualified-id [TODO] /// /// unqualified-id: /// identifier /// operator-function-id /// conversion-function-id /// literal-operator-id /// '~' class-name [TODO] /// '~' decltype-specifier [TODO] /// template-id [TODO] /// \endverbatim /// TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier = true, bool mayHaveDirectInit = false, bool mayHaveTrailingReturnType = false); /// \verbatim /// parameter-declaration-clause: /// parameter-declaration-list[opt] '...'[opt] /// parameter-declaration-list ',' '...' /// /// parameter-declaration-list: /// parameter-declaration /// parameter-declaration-list ',' parameter-declaration /// /// parameter-declaration: /// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] /// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt] /// '=' assignment-expression /// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] /// attributes[opt] /// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt] /// attributes[opt] '=' assignment-expression /// \endverbatim /// TPResult TryParseParameterDeclarationClause( bool *InvalidAsDeclaration = nullptr, bool VersusTemplateArg = false, ImplicitTypenameContext AllowImplicitTypename = ImplicitTypenameContext::No); /// TryParseFunctionDeclarator - We parsed a '(' and we want to try to /// continue parsing as a function declarator. If TryParseFunctionDeclarator /// fully parsed the function declarator, it will return TPResult::Ambiguous, /// otherwise it will return either False() or Error(). /// /// \verbatim /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// /// exception-specification: /// 'throw' '(' type-id-list[opt] ')' /// \endverbatim /// TPResult TryParseFunctionDeclarator(bool MayHaveTrailingReturnType = false); // When parsing an identifier after an arrow it may be a member expression, // in which case we should not annotate it as an independant expression // so we just lookup that name, if it's not a type the construct is not // a function declaration. bool NameAfterArrowIsNonType(); /// \verbatim /// '[' constant-expression[opt] ']' /// \endverbatim /// TPResult TryParseBracketDeclarator(); /// Try to consume a token sequence that we've already identified as /// (potentially) starting a decl-specifier. TPResult TryConsumeDeclarationSpecifier(); /// Try to skip a possibly empty sequence of 'attribute-specifier's without /// full validation of the syntactic structure of attributes. bool TrySkipAttributes(); //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] /// Returns true if this is a C++11 attribute-specifier. Per /// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens /// always introduce an attribute. In Objective-C++11, this rule does not /// apply if either '[' begins a message-send. /// /// If Disambiguate is true, we try harder to determine whether a '[[' starts /// an attribute-specifier, and return /// CXX11AttributeKind::InvalidAttributeSpecifier if not. /// /// If OuterMightBeMessageSend is true, we assume the outer '[' is either an /// Obj-C message send or the start of an attribute. Otherwise, we assume it /// is not an Obj-C message send. /// /// C++11 [dcl.attr.grammar]: /// /// \verbatim /// attribute-specifier: /// '[' '[' attribute-list ']' ']' /// alignment-specifier /// /// attribute-list: /// attribute[opt] /// attribute-list ',' attribute[opt] /// attribute '...' /// attribute-list ',' attribute '...' /// /// attribute: /// attribute-token attribute-argument-clause[opt] /// /// attribute-token: /// identifier /// identifier '::' identifier /// /// attribute-argument-clause: /// '(' balanced-token-seq ')' /// \endverbatim CXX11AttributeKind isCXX11AttributeSpecifier(bool Disambiguate = false, bool OuterMightBeMessageSend = false); ///@} }; } // end namespace clang #endif