//===--- Parser.cpp - C Language Family Parser ----------------------------===// // // 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 implements the Parser interfaces. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/FileManager.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaCodeCompletion.h" #include "llvm/Support/Path.h" #include "llvm/Support/TimeProfiler.h" usingnamespaceclang; namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. class ActionCommentHandler : public CommentHandler { … }; } // end anonymous namespace IdentifierInfo *Parser::getSEHExceptKeyword() { … } Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) : … { … } DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) { … } DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) { … } /// 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 Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange) { … } static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { … } bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, StringRef Msg) { … } bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) { … } void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) { … } bool Parser::expectIdentifier() { … } void Parser::checkCompoundToken(SourceLocation FirstTokLoc, tok::TokenKind FirstTokKind, CompoundToken Op) { … } //===----------------------------------------------------------------------===// // Error recovery. //===----------------------------------------------------------------------===// static bool HasFlagsSet(Parser::SkipUntilFlags L, Parser::SkipUntilFlags R) { … } /// 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 Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { … } //===----------------------------------------------------------------------===// // Scope manipulation //===----------------------------------------------------------------------===// /// EnterScope - Start a new scope. void Parser::EnterScope(unsigned ScopeFlags) { … } /// ExitScope - Pop a scope off the scope stack. void Parser::ExitScope() { … } /// Set the flags for the current scope to ScopeFlags. If ManageFlags is false, /// this object does nothing. Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags) : … { … } /// Restore the flags for the current scope to what they were before this /// object overrode them. Parser::ParseScopeFlags::~ParseScopeFlags() { … } //===----------------------------------------------------------------------===// // C99 6.9: External Definitions. //===----------------------------------------------------------------------===// Parser::~Parser() { … } /// Initialize - Warm up the parser. /// void Parser::Initialize() { … } void Parser::DestroyTemplateIds() { … } /// Parse the first top-level declaration in a translation unit. /// /// 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] /// /// Note that in C, it is an error if there is no first declaration. bool Parser::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. /// /// top-level-declaration: /// declaration /// [C++20] module-import-declaration bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result, Sema::ModuleImportState &ImportState) { … } /// ParseExternalDeclaration: /// /// The `Attrs` that are passed in are C++11 attributes and appertain to the /// declaration. /// /// 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 /// Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS) { … } /// Determine whether the current token, if it occurs after a /// declarator, continues a declaration or declaration list. bool Parser::isDeclarationAfterDeclarator() { … } /// Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) { … } /// 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. /// /// 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] /// Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal( ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec &DS, AccessSpecifier AS) { … } Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs, ParsingDeclSpec *DS, AccessSpecifier AS) { … } /// 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. /// /// 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 /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, LateParsedAttrList *LateParsedAttrs) { … } void Parser::SkipFunctionBody() { … } /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { … } /// 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. /// /// [GNU] asm-string-literal: /// string-literal /// ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { … } /// ParseSimpleAsm /// /// [GNU] simple-asm-expr: /// 'asm' '(' asm-string-literal ')' /// ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) { … } /// 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 *Parser::takeTemplateIdAnnotation(const Token &tok) { … } void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) { … } /// 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). Parser::AnnotatedNameKind Parser::TryAnnotateName(CorrectionCandidateCallback *CCC, ImplicitTypenameContext AllowImplicitTypename) { … } bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { … } /// 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 Parser::TryAnnotateTypeOrScopeToken( ImplicitTypenameContext AllowImplicitTypename) { … } /// 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 Parser::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 Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { … } bool Parser::isTokenEqualOrEqualTypo() { … } SourceLocation Parser::handleUnexpectedCodeCompletionToken() { … } // Code-completion pass-through functions void Parser::CodeCompleteDirective(bool InConditional) { … } void Parser::CodeCompleteInConditionalExclusion() { … } void Parser::CodeCompleteMacroName(bool IsDefinition) { … } void Parser::CodeCompletePreprocessorExpression() { … } void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex) { … } void Parser::CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled) { … } void Parser::CodeCompleteNaturalLanguage() { … } bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { … } void Parser::ParseMicrosoftIfExistsExternalDeclaration() { … } /// Parse a declaration beginning with the 'module' keyword or C++20 /// context-sensitive keyword (optionally preceded by 'export'). /// /// 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] Parser::DeclGroupPtrTy Parser::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++). /// /// [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] ';' Decl *Parser::ParseModuleImport(SourceLocation AtLoc, Sema::ModuleImportState &ImportState) { … } /// Parse a C++ / Objective-C module name (both forms use the same /// grammar). /// /// module-name: /// module-name-qualifier[opt] identifier /// module-name-qualifier: /// module-name-qualifier[opt] identifier '.' bool Parser::ParseModuleName( SourceLocation UseLoc, SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &Path, bool IsImport) { … } /// 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 Parser::parseMisplacedModuleImport() { … } void Parser::diagnoseUseOfC11Keyword(const Token &Tok) { … } bool BalancedDelimiterTracker::diagnoseOverflow() { … } bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, const char *Msg, tok::TokenKind SkipToTok) { … } bool BalancedDelimiterTracker::diagnoseMissingClose() { … } void BalancedDelimiterTracker::skipToEnd() { … }