//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// // // 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 clang::ParseAST method. // //===----------------------------------------------------------------------===// #include "clang/Parse/ParseAST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/TimeProfiler.h" #include #include using namespace clang; namespace { /// Resets LLVM's pretty stack state so that stack traces are printed correctly /// when there are nested CrashRecoveryContexts and the inner one recovers from /// a crash. class ResetStackCleanup : public llvm::CrashRecoveryContextCleanupBase { public: ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top) : llvm::CrashRecoveryContextCleanupBase( Context, Top) {} void recoverResources() override { llvm::RestorePrettyStackState(resource); } }; /// If a crash happens while the parser is active, an entry is printed for it. class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { const Parser &P; public: PrettyStackTraceParserEntry(const Parser &p) : P(p) {} void print(raw_ostream &OS) const override; }; /// If a crash happens while the parser is active, print out a line indicating /// what the current token is. void PrettyStackTraceParserEntry::print(raw_ostream &OS) const { const Token &Tok = P.getCurToken(); if (Tok.is(tok::eof)) { OS << " parser at end of file\n"; return; } if (Tok.getLocation().isInvalid()) { OS << " parser at unknown location\n"; return; } const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); if (Tok.isAnnotation()) { OS << ": at annotation token\n"; } else { // Do the equivalent of PP.getSpelling(Tok) except for the parts that would // allocate memory. bool Invalid = false; const SourceManager &SM = P.getPreprocessor().getSourceManager(); unsigned Length = Tok.getLength(); const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid); if (Invalid) { OS << ": unknown current parser token\n"; return; } OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n"; } } } // namespace //===----------------------------------------------------------------------===// // Public interface to the file //===----------------------------------------------------------------------===// /// ParseAST - Parse the entire file specified, notifying the ASTConsumer as /// the file is parsed. This inserts the parsed decls into the translation unit /// held by Ctx. /// void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer, bool SkipFunctionBodies) { std::unique_ptr S( new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CleanupSema(S.get()); ParseAST(*S.get(), PrintStats, SkipFunctionBodies); } void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { Decl::EnableStatistics(); Stmt::EnableStatistics(); } // Also turn on collection of stats inside of the Sema object. bool OldCollectStats = PrintStats; std::swap(OldCollectStats, S.CollectStats); // Initialize the template instantiation observer chain. // FIXME: See note on "finalize" below. initialize(S.TemplateInstCallbacks, S); ASTConsumer *Consumer = &S.getASTConsumer(); std::unique_ptr ParseOP( new Parser(S.getPreprocessor(), S, SkipFunctionBodies)); Parser &P = *ParseOP.get(); llvm::CrashRecoveryContextCleanupRegistrar CleanupPrettyStack(llvm::SavePrettyStackState()); PrettyStackTraceParserEntry CrashInfo(P); // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CleanupParser(ParseOP.get()); S.getPreprocessor().EnterMainSourceFile(); ExternalASTSource *External = S.getASTContext().getExternalSource(); if (External) External->StartTranslationUnit(Consumer); // If a PCH through header is specified that does not have an include in // the source, or a PCH is being created with #pragma hdrstop with nothing // after the pragma, there won't be any tokens or a Lexer. bool HaveLexer = S.getPreprocessor().getCurrentLexer(); if (HaveLexer) { llvm::TimeTraceScope TimeScope("Frontend"); P.Initialize(); Parser::DeclGroupPtrTy ADecl; Sema::ModuleImportState ImportState; EnterExpressionEvaluationContext PotentiallyEvaluated( S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; AtEOF = P.ParseTopLevelDecl(ADecl, ImportState)) { // If we got a null return and something *was* parsed, ignore it. This // is due to a top-level semicolon, an action override, or a parse error // skipping something. if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) return; } } // Process any TopLevelDecls generated by #pragma weak. for (Decl *D : S.WeakTopLevelDecls()) Consumer->HandleTopLevelDecl(DeclGroupRef(D)); // For C++20 modules, the codegen for module initializers needs to be altered // and to be able to use a name based on the module name. // At this point, we should know if we are building a non-header C++20 module. if (S.getLangOpts().CPlusPlusModules && !S.getLangOpts().IsHeaderFile && !S.getLangOpts().CurrentModule.empty()) { // If we are building the module from source, then the top level module // will be here. Module *CodegenModule = S.getCurrentModule(); bool Interface = true; if (CodegenModule) // We only use module initializers for interfaces (including partition // implementation units). Interface = S.currentModuleIsInterface(); else // If we are building the module from a PCM file, then the module can be // found here. CodegenModule = S.getPreprocessor().getCurrentModule(); // If neither. then .... assert(CodegenModule && "codegen for a module, but don't know which?"); if (Interface) S.getASTContext().setModuleForCodeGen(CodegenModule); } Consumer->HandleTranslationUnit(S.getASTContext()); // Finalize the template instantiation observer chain. // FIXME: This (and init.) should be done in the Sema class, but because // Sema does not have a reliable "Finalize" function (it has a // destructor, but it is not guaranteed to be called ("-disable-free")). // So, do the initialization above and do the finalization here: finalize(S.TemplateInstCallbacks, S); std::swap(OldCollectStats, S.CollectStats); if (PrintStats) { llvm::errs() << "\nSTATISTICS:\n"; if (HaveLexer) P.getActions().PrintStats(); S.getASTContext().PrintStats(); Decl::PrintStats(); Stmt::PrintStats(); Consumer->PrintStats(); } }