1e5dd7070Spatrick //===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the clang::ParseAST method.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/Parse/ParseAST.h"
14e5dd7070Spatrick #include "clang/AST/ASTConsumer.h"
15e5dd7070Spatrick #include "clang/AST/ASTContext.h"
16e5dd7070Spatrick #include "clang/AST/ExternalASTSource.h"
17e5dd7070Spatrick #include "clang/AST/Stmt.h"
18e5dd7070Spatrick #include "clang/Parse/ParseDiagnostic.h"
19e5dd7070Spatrick #include "clang/Parse/Parser.h"
20e5dd7070Spatrick #include "clang/Sema/CodeCompleteConsumer.h"
21e5dd7070Spatrick #include "clang/Sema/Sema.h"
22e5dd7070Spatrick #include "clang/Sema/SemaConsumer.h"
23e5dd7070Spatrick #include "clang/Sema/TemplateInstCallback.h"
24e5dd7070Spatrick #include "llvm/Support/CrashRecoveryContext.h"
25e5dd7070Spatrick #include "llvm/Support/TimeProfiler.h"
26e5dd7070Spatrick #include <cstdio>
27e5dd7070Spatrick #include <memory>
28e5dd7070Spatrick
29e5dd7070Spatrick using namespace clang;
30e5dd7070Spatrick
31e5dd7070Spatrick namespace {
32e5dd7070Spatrick
33e5dd7070Spatrick /// Resets LLVM's pretty stack state so that stack traces are printed correctly
34e5dd7070Spatrick /// when there are nested CrashRecoveryContexts and the inner one recovers from
35e5dd7070Spatrick /// a crash.
36e5dd7070Spatrick class ResetStackCleanup
37e5dd7070Spatrick : public llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup,
38e5dd7070Spatrick const void> {
39e5dd7070Spatrick public:
ResetStackCleanup(llvm::CrashRecoveryContext * Context,const void * Top)40e5dd7070Spatrick ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top)
41e5dd7070Spatrick : llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>(
42e5dd7070Spatrick Context, Top) {}
recoverResources()43e5dd7070Spatrick void recoverResources() override {
44e5dd7070Spatrick llvm::RestorePrettyStackState(resource);
45e5dd7070Spatrick }
46e5dd7070Spatrick };
47e5dd7070Spatrick
48e5dd7070Spatrick /// If a crash happens while the parser is active, an entry is printed for it.
49e5dd7070Spatrick class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
50e5dd7070Spatrick const Parser &P;
51e5dd7070Spatrick public:
PrettyStackTraceParserEntry(const Parser & p)52e5dd7070Spatrick PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
53e5dd7070Spatrick void print(raw_ostream &OS) const override;
54e5dd7070Spatrick };
55e5dd7070Spatrick
56e5dd7070Spatrick /// If a crash happens while the parser is active, print out a line indicating
57e5dd7070Spatrick /// what the current token is.
print(raw_ostream & OS) const58e5dd7070Spatrick void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
59e5dd7070Spatrick const Token &Tok = P.getCurToken();
60e5dd7070Spatrick if (Tok.is(tok::eof)) {
61e5dd7070Spatrick OS << "<eof> parser at end of file\n";
62e5dd7070Spatrick return;
63e5dd7070Spatrick }
64e5dd7070Spatrick
65e5dd7070Spatrick if (Tok.getLocation().isInvalid()) {
66e5dd7070Spatrick OS << "<unknown> parser at unknown location\n";
67e5dd7070Spatrick return;
68e5dd7070Spatrick }
69e5dd7070Spatrick
70e5dd7070Spatrick const Preprocessor &PP = P.getPreprocessor();
71e5dd7070Spatrick Tok.getLocation().print(OS, PP.getSourceManager());
72e5dd7070Spatrick if (Tok.isAnnotation()) {
73e5dd7070Spatrick OS << ": at annotation token\n";
74e5dd7070Spatrick } else {
75e5dd7070Spatrick // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
76e5dd7070Spatrick // allocate memory.
77e5dd7070Spatrick bool Invalid = false;
78e5dd7070Spatrick const SourceManager &SM = P.getPreprocessor().getSourceManager();
79e5dd7070Spatrick unsigned Length = Tok.getLength();
80e5dd7070Spatrick const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
81e5dd7070Spatrick if (Invalid) {
82e5dd7070Spatrick OS << ": unknown current parser token\n";
83e5dd7070Spatrick return;
84e5dd7070Spatrick }
85e5dd7070Spatrick OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
86e5dd7070Spatrick }
87e5dd7070Spatrick }
88e5dd7070Spatrick
89e5dd7070Spatrick } // namespace
90e5dd7070Spatrick
91e5dd7070Spatrick //===----------------------------------------------------------------------===//
92e5dd7070Spatrick // Public interface to the file
93e5dd7070Spatrick //===----------------------------------------------------------------------===//
94e5dd7070Spatrick
95e5dd7070Spatrick /// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
96e5dd7070Spatrick /// the file is parsed. This inserts the parsed decls into the translation unit
97e5dd7070Spatrick /// held by Ctx.
98e5dd7070Spatrick ///
ParseAST(Preprocessor & PP,ASTConsumer * Consumer,ASTContext & Ctx,bool PrintStats,TranslationUnitKind TUKind,CodeCompleteConsumer * CompletionConsumer,bool SkipFunctionBodies)99e5dd7070Spatrick void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
100e5dd7070Spatrick ASTContext &Ctx, bool PrintStats,
101e5dd7070Spatrick TranslationUnitKind TUKind,
102e5dd7070Spatrick CodeCompleteConsumer *CompletionConsumer,
103e5dd7070Spatrick bool SkipFunctionBodies) {
104e5dd7070Spatrick
105e5dd7070Spatrick std::unique_ptr<Sema> S(
106e5dd7070Spatrick new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
107e5dd7070Spatrick
108e5dd7070Spatrick // Recover resources if we crash before exiting this method.
109e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
110e5dd7070Spatrick
111e5dd7070Spatrick ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
112e5dd7070Spatrick }
113e5dd7070Spatrick
ParseAST(Sema & S,bool PrintStats,bool SkipFunctionBodies)114e5dd7070Spatrick void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
115e5dd7070Spatrick // Collect global stats on Decls/Stmts (until we have a module streamer).
116e5dd7070Spatrick if (PrintStats) {
117e5dd7070Spatrick Decl::EnableStatistics();
118e5dd7070Spatrick Stmt::EnableStatistics();
119e5dd7070Spatrick }
120e5dd7070Spatrick
121e5dd7070Spatrick // Also turn on collection of stats inside of the Sema object.
122e5dd7070Spatrick bool OldCollectStats = PrintStats;
123e5dd7070Spatrick std::swap(OldCollectStats, S.CollectStats);
124e5dd7070Spatrick
125e5dd7070Spatrick // Initialize the template instantiation observer chain.
126e5dd7070Spatrick // FIXME: See note on "finalize" below.
127e5dd7070Spatrick initialize(S.TemplateInstCallbacks, S);
128e5dd7070Spatrick
129e5dd7070Spatrick ASTConsumer *Consumer = &S.getASTConsumer();
130e5dd7070Spatrick
131e5dd7070Spatrick std::unique_ptr<Parser> ParseOP(
132e5dd7070Spatrick new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
133e5dd7070Spatrick Parser &P = *ParseOP.get();
134e5dd7070Spatrick
135e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<const void, ResetStackCleanup>
136e5dd7070Spatrick CleanupPrettyStack(llvm::SavePrettyStackState());
137e5dd7070Spatrick PrettyStackTraceParserEntry CrashInfo(P);
138e5dd7070Spatrick
139e5dd7070Spatrick // Recover resources if we crash before exiting this method.
140e5dd7070Spatrick llvm::CrashRecoveryContextCleanupRegistrar<Parser>
141e5dd7070Spatrick CleanupParser(ParseOP.get());
142e5dd7070Spatrick
143e5dd7070Spatrick S.getPreprocessor().EnterMainSourceFile();
144e5dd7070Spatrick ExternalASTSource *External = S.getASTContext().getExternalSource();
145e5dd7070Spatrick if (External)
146e5dd7070Spatrick External->StartTranslationUnit(Consumer);
147e5dd7070Spatrick
148e5dd7070Spatrick // If a PCH through header is specified that does not have an include in
149e5dd7070Spatrick // the source, or a PCH is being created with #pragma hdrstop with nothing
150e5dd7070Spatrick // after the pragma, there won't be any tokens or a Lexer.
151e5dd7070Spatrick bool HaveLexer = S.getPreprocessor().getCurrentLexer();
152e5dd7070Spatrick
153e5dd7070Spatrick if (HaveLexer) {
154e5dd7070Spatrick llvm::TimeTraceScope TimeScope("Frontend");
155e5dd7070Spatrick P.Initialize();
156e5dd7070Spatrick Parser::DeclGroupPtrTy ADecl;
157*12c85518Srobert Sema::ModuleImportState ImportState;
158*12c85518Srobert EnterExpressionEvaluationContext PotentiallyEvaluated(
159*12c85518Srobert S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
160*12c85518Srobert
161*12c85518Srobert for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
162*12c85518Srobert AtEOF = P.ParseTopLevelDecl(ADecl, ImportState)) {
163e5dd7070Spatrick // If we got a null return and something *was* parsed, ignore it. This
164e5dd7070Spatrick // is due to a top-level semicolon, an action override, or a parse error
165e5dd7070Spatrick // skipping something.
166e5dd7070Spatrick if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
167e5dd7070Spatrick return;
168e5dd7070Spatrick }
169e5dd7070Spatrick }
170e5dd7070Spatrick
171e5dd7070Spatrick // Process any TopLevelDecls generated by #pragma weak.
172e5dd7070Spatrick for (Decl *D : S.WeakTopLevelDecls())
173e5dd7070Spatrick Consumer->HandleTopLevelDecl(DeclGroupRef(D));
174e5dd7070Spatrick
175*12c85518Srobert // For C++20 modules, the codegen for module initializers needs to be altered
176*12c85518Srobert // and to be able to use a name based on the module name.
177*12c85518Srobert
178*12c85518Srobert // At this point, we should know if we are building a non-header C++20 module.
179*12c85518Srobert if (S.getLangOpts().CPlusPlusModules) {
180*12c85518Srobert // If we are building the module from source, then the top level module
181*12c85518Srobert // will be here.
182*12c85518Srobert Module *CodegenModule = S.getCurrentModule();
183*12c85518Srobert bool Interface = true;
184*12c85518Srobert if (CodegenModule)
185*12c85518Srobert // We only use module initializers for importable module (including
186*12c85518Srobert // partition implementation units).
187*12c85518Srobert Interface = S.currentModuleIsInterface();
188*12c85518Srobert else if (S.getLangOpts().isCompilingModuleInterface())
189*12c85518Srobert // If we are building the module from a PCM file, then the module can be
190*12c85518Srobert // found here.
191*12c85518Srobert CodegenModule = S.getPreprocessor().getCurrentModule();
192*12c85518Srobert
193*12c85518Srobert if (Interface && CodegenModule)
194*12c85518Srobert S.getASTContext().setModuleForCodeGen(CodegenModule);
195*12c85518Srobert }
196e5dd7070Spatrick Consumer->HandleTranslationUnit(S.getASTContext());
197e5dd7070Spatrick
198e5dd7070Spatrick // Finalize the template instantiation observer chain.
199e5dd7070Spatrick // FIXME: This (and init.) should be done in the Sema class, but because
200e5dd7070Spatrick // Sema does not have a reliable "Finalize" function (it has a
201e5dd7070Spatrick // destructor, but it is not guaranteed to be called ("-disable-free")).
202e5dd7070Spatrick // So, do the initialization above and do the finalization here:
203e5dd7070Spatrick finalize(S.TemplateInstCallbacks, S);
204e5dd7070Spatrick
205e5dd7070Spatrick std::swap(OldCollectStats, S.CollectStats);
206e5dd7070Spatrick if (PrintStats) {
207e5dd7070Spatrick llvm::errs() << "\nSTATISTICS:\n";
208e5dd7070Spatrick if (HaveLexer) P.getActions().PrintStats();
209e5dd7070Spatrick S.getASTContext().PrintStats();
210e5dd7070Spatrick Decl::PrintStats();
211e5dd7070Spatrick Stmt::PrintStats();
212e5dd7070Spatrick Consumer->PrintStats();
213e5dd7070Spatrick }
214e5dd7070Spatrick }
215