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