xref: /openbsd-src/gnu/llvm/clang/lib/Parse/ParseAST.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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