generate_ast.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/cpp/generate_ast.h"
  5. #include <memory>
  6. #include <string>
  7. #include "clang/AST/ASTContext.h"
  8. #include "clang/Basic/FileManager.h"
  9. #include "clang/CodeGen/ModuleBuilder.h"
  10. #include "clang/Frontend/CompilerInstance.h"
  11. #include "clang/Frontend/CompilerInvocation.h"
  12. #include "clang/Frontend/FrontendAction.h"
  13. #include "clang/Frontend/TextDiagnostic.h"
  14. #include "clang/Lex/PreprocessorOptions.h"
  15. #include "clang/Parse/Parser.h"
  16. #include "clang/Sema/ExternalSemaSource.h"
  17. #include "clang/Sema/MultiplexExternalSemaSource.h"
  18. #include "clang/Sema/Sema.h"
  19. #include "common/check.h"
  20. #include "common/raw_string_ostream.h"
  21. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  22. #include "llvm/ADT/StringRef.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. #include "toolchain/check/context.h"
  25. #include "toolchain/diagnostics/diagnostic.h"
  26. #include "toolchain/diagnostics/emitter.h"
  27. #include "toolchain/diagnostics/format_providers.h"
  28. #include "toolchain/parse/node_ids.h"
  29. #include "toolchain/sem_ir/cpp_file.h"
  30. namespace Carbon::Check {
  31. // Add a line marker directive pointing at the location of the `import Cpp`
  32. // declaration in the Carbon source file. This will cause Clang's diagnostics
  33. // machinery to track and report the location in Carbon code where the import
  34. // was written.
  35. static auto GenerateLineMarker(Context& context, llvm::raw_ostream& out,
  36. int line) {
  37. out << "# " << line << " \""
  38. << FormatEscaped(context.tokens().source().filename()) << "\"\n";
  39. }
  40. // Generates C++ file contents to #include all requested imports.
  41. static auto GenerateCppIncludesHeaderCode(
  42. Context& context, llvm::ArrayRef<Parse::Tree::PackagingNames> imports)
  43. -> std::string {
  44. std::string code;
  45. llvm::raw_string_ostream code_stream(code);
  46. for (const Parse::Tree::PackagingNames& import : imports) {
  47. if (import.inline_body_id.has_value()) {
  48. // Expand `import Cpp inline "code";` directly into the specified code.
  49. auto code_token = context.parse_tree().node_token(import.inline_body_id);
  50. // Compute the line number on which the C++ code starts. Usually the code
  51. // is specified as a block string literal and starts on the line after the
  52. // start of the string token.
  53. // TODO: Determine if this is a block string literal without calling
  54. // `GetTokenText`, which re-lexes the string.
  55. int line = context.tokens().GetLineNumber(code_token);
  56. if (context.tokens().GetTokenText(code_token).contains('\n')) {
  57. ++line;
  58. }
  59. GenerateLineMarker(context, code_stream, line);
  60. code_stream << context.string_literal_values().Get(
  61. context.tokens().GetStringLiteralValue(code_token))
  62. << "\n";
  63. // TODO: Inject a clang pragma here to produce an error if there are
  64. // unclosed scopes at the end of this inline C++ fragment.
  65. } else if (import.library_id.has_value()) {
  66. // Translate `import Cpp library "foo.h";` into `#include "foo.h"`.
  67. GenerateLineMarker(context, code_stream,
  68. context.tokens().GetLineNumber(
  69. context.parse_tree().node_token(import.node_id)));
  70. auto name = context.string_literal_values().Get(import.library_id);
  71. if (name.starts_with('<') && name.ends_with('>')) {
  72. code_stream << "#include <"
  73. << FormatEscaped(name.drop_front().drop_back()) << ">\n";
  74. } else {
  75. code_stream << "#include \"" << FormatEscaped(name) << "\"\n";
  76. }
  77. }
  78. }
  79. // Inject a declaration of placement operator new, because the code we
  80. // generate in thunks depends on it for placement new expressions. Clang has
  81. // special-case logic for lowering a new-expression using this, so a
  82. // definition is not required.
  83. // TODO: This is a hack. We should be able to directly generate Clang AST to
  84. // construct objects in-place without this.
  85. // TODO: Once we can rely on libc++ being available, consider including
  86. // `<__new/placement_new_delete.h>` instead.
  87. code_stream << R"(# 1 "<carbon-internal>"
  88. #undef constexpr
  89. #if __cplusplus > 202302L
  90. constexpr
  91. #endif
  92. #undef void
  93. #undef operator
  94. #undef new
  95. void* operator new(__SIZE_TYPE__, void*)
  96. #if __cplusplus < 201103L
  97. #undef throw
  98. throw()
  99. #else
  100. #undef noexcept
  101. noexcept
  102. #endif
  103. ;
  104. )";
  105. return code;
  106. }
  107. // Adds the given source location and an `ImportIRInst` referring to it in
  108. // `ImportIRId::Cpp`.
  109. static auto AddImportIRInst(SemIR::File& file,
  110. clang::SourceLocation clang_source_loc)
  111. -> SemIR::ImportIRInstId {
  112. SemIR::ClangSourceLocId clang_source_loc_id =
  113. file.clang_source_locs().Add(clang_source_loc);
  114. return file.import_ir_insts().Add(SemIR::ImportIRInst(clang_source_loc_id));
  115. }
  116. namespace {
  117. // Used to convert Clang diagnostics to Carbon diagnostics.
  118. //
  119. // Handling of Clang notes is a little subtle: as far as Clang is concerned,
  120. // notes are separate diagnostics, not connected to the error or warning that
  121. // precedes them. But in Carbon's diagnostics system, notes are part of the
  122. // enclosing diagnostic. To handle this, we buffer Clang diagnostics until we
  123. // reach a point where we know we're not in the middle of a diagnostic, and then
  124. // emit a diagnostic along with all of its notes. This is triggered when adding
  125. // or removing a Carbon context note, which could otherwise get attached to the
  126. // wrong C++ diagnostics, and at the end of the Carbon program.
  127. class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
  128. public:
  129. // Creates an instance with the location that triggers calling Clang. The
  130. // `context` is not stored here, and the diagnostics consumer is expected to
  131. // outlive it.
  132. explicit CarbonClangDiagnosticConsumer(
  133. Context& context, std::shared_ptr<clang::CompilerInvocation> invocation)
  134. : sem_ir_(&context.sem_ir()),
  135. emitter_(&context.emitter()),
  136. invocation_(std::move(invocation)) {
  137. emitter_->AddFlushFn([this] { EmitDiagnostics(); });
  138. }
  139. ~CarbonClangDiagnosticConsumer() override {
  140. // Do not inspect `emitter_` here; it's typically destroyed before the
  141. // consumer is.
  142. // TODO: If Clang produces diagnostics after check finishes, they'll get
  143. // added to the list of pending diagnostics and never emitted.
  144. CARBON_CHECK(diagnostic_infos_.empty(),
  145. "Missing flush before destroying diagnostic consumer");
  146. }
  147. // Generates a Carbon warning for each Clang warning and a Carbon error for
  148. // each Clang error or fatal.
  149. auto HandleDiagnostic(clang::DiagnosticsEngine::Level diag_level,
  150. const clang::Diagnostic& info) -> void override {
  151. DiagnosticConsumer::HandleDiagnostic(diag_level, info);
  152. SemIR::ImportIRInstId clang_import_ir_inst_id =
  153. AddImportIRInst(*sem_ir_, info.getLocation());
  154. llvm::SmallString<256> message;
  155. info.FormatDiagnostic(message);
  156. // Render a code snippet including any highlighted ranges and fixit hints.
  157. // TODO: Also include the #include stack and macro expansion stack in the
  158. // diagnostic output in some way.
  159. RawStringOstream snippet_stream;
  160. if (!info.hasSourceManager()) {
  161. // If we don't have a source manager, this is an error from early in the
  162. // frontend. Don't produce a snippet.
  163. CARBON_CHECK(info.getLocation().isInvalid());
  164. } else {
  165. CodeContextRenderer(snippet_stream, invocation_->getLangOpts(),
  166. invocation_->getDiagnosticOpts())
  167. .emitDiagnostic(
  168. clang::FullSourceLoc(info.getLocation(), info.getSourceManager()),
  169. diag_level, message, info.getRanges(), info.getFixItHints());
  170. }
  171. diagnostic_infos_.push_back({.level = diag_level,
  172. .import_ir_inst_id = clang_import_ir_inst_id,
  173. .message = message.str().str(),
  174. .snippet = snippet_stream.TakeStr()});
  175. }
  176. // Returns the diagnostic to use for a given Clang diagnostic level.
  177. static auto GetDiagnostic(clang::DiagnosticsEngine::Level level)
  178. -> const Diagnostics::DiagnosticBase<std::string>& {
  179. switch (level) {
  180. case clang::DiagnosticsEngine::Ignored: {
  181. CARBON_FATAL("Emitting an ignored diagnostic");
  182. break;
  183. }
  184. case clang::DiagnosticsEngine::Note: {
  185. CARBON_DIAGNOSTIC(CppInteropParseNote, Note, "{0}", std::string);
  186. return CppInteropParseNote;
  187. }
  188. case clang::DiagnosticsEngine::Remark:
  189. case clang::DiagnosticsEngine::Warning: {
  190. // TODO: Add a distinct Remark level to Carbon diagnostics, and stop
  191. // mapping remarks to warnings.
  192. CARBON_DIAGNOSTIC(CppInteropParseWarning, Warning, "{0}", std::string);
  193. return CppInteropParseWarning;
  194. }
  195. case clang::DiagnosticsEngine::Error:
  196. case clang::DiagnosticsEngine::Fatal: {
  197. CARBON_DIAGNOSTIC(CppInteropParseError, Error, "{0}", std::string);
  198. return CppInteropParseError;
  199. }
  200. }
  201. }
  202. // Outputs Carbon diagnostics based on the collected Clang diagnostics. Must
  203. // be called after the AST is set in the context.
  204. auto EmitDiagnostics() -> void {
  205. CARBON_CHECK(
  206. sem_ir_->cpp_file(),
  207. "Attempted to emit C++ diagnostics before the C++ file is set");
  208. for (size_t i = 0; i != diagnostic_infos_.size(); ++i) {
  209. const ClangDiagnosticInfo& info = diagnostic_infos_[i];
  210. auto builder = emitter_->Build(SemIR::LocId(info.import_ir_inst_id),
  211. GetDiagnostic(info.level), info.message);
  212. builder.OverrideSnippet(info.snippet);
  213. for (; i + 1 < diagnostic_infos_.size() &&
  214. diagnostic_infos_[i + 1].level == clang::DiagnosticsEngine::Note;
  215. ++i) {
  216. const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1];
  217. builder
  218. .Note(SemIR::LocId(note_info.import_ir_inst_id),
  219. GetDiagnostic(note_info.level), note_info.message)
  220. .OverrideSnippet(note_info.snippet);
  221. }
  222. // TODO: This will apply all current Carbon annotation functions. We
  223. // should instead track how Clang's context notes and Carbon's annotation
  224. // functions are interleaved, and interleave the notes in the same order.
  225. builder.Emit();
  226. }
  227. diagnostic_infos_.clear();
  228. }
  229. private:
  230. // A diagnostics renderer based on clang's TextDiagnostic that captures just
  231. // the code context (the snippet).
  232. class CodeContextRenderer : public clang::TextDiagnostic {
  233. protected:
  234. using TextDiagnostic::TextDiagnostic;
  235. void emitDiagnosticMessage(
  236. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  237. clang::DiagnosticsEngine::Level /*level*/, llvm::StringRef /*message*/,
  238. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/,
  239. clang::DiagOrStoredDiag /*info*/) override {}
  240. void emitDiagnosticLoc(
  241. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  242. clang::DiagnosticsEngine::Level /*level*/,
  243. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/) override {}
  244. // emitCodeContext is inherited from clang::TextDiagnostic.
  245. void emitIncludeLocation(clang::FullSourceLoc /*loc*/,
  246. clang::PresumedLoc /*ploc*/) override {}
  247. void emitImportLocation(clang::FullSourceLoc /*loc*/,
  248. clang::PresumedLoc /*ploc*/,
  249. llvm::StringRef /*module_name*/) override {}
  250. void emitBuildingModuleLocation(clang::FullSourceLoc /*loc*/,
  251. clang::PresumedLoc /*ploc*/,
  252. llvm::StringRef /*module_name*/) override {}
  253. // beginDiagnostic and endDiagnostic are inherited from
  254. // clang::TextDiagnostic in case it wants to do any setup / teardown work.
  255. };
  256. // Information on a Clang diagnostic that can be converted to a Carbon
  257. // diagnostic.
  258. struct ClangDiagnosticInfo {
  259. // The Clang diagnostic level.
  260. clang::DiagnosticsEngine::Level level;
  261. // The ID of the ImportIR instruction referring to the Clang source
  262. // location.
  263. SemIR::ImportIRInstId import_ir_inst_id;
  264. // The Clang diagnostic textual message.
  265. std::string message;
  266. // The code snippet produced by clang.
  267. std::string snippet;
  268. };
  269. // The Carbon file that this C++ compilation is attached to.
  270. SemIR::File* sem_ir_;
  271. // The diagnostic emitter that we're emitting diagnostics into.
  272. DiagnosticEmitterBase* emitter_;
  273. // The compiler invocation that is producing the diagnostics.
  274. std::shared_ptr<clang::CompilerInvocation> invocation_;
  275. // Collects the information for all Clang diagnostics to be converted to
  276. // Carbon diagnostics after the context has been initialized with the Clang
  277. // AST.
  278. llvm::SmallVector<ClangDiagnosticInfo> diagnostic_infos_;
  279. };
  280. // A wrapper around a clang::CompilerInvocation that allows us to make a shallow
  281. // copy of most of the invocation and only make a deep copy of the parts that we
  282. // want to change.
  283. //
  284. // clang::CowCompilerInvocation almost allows this, but doesn't derive from
  285. // CompilerInvocation or support shallow copies from a CompilerInvocation, so is
  286. // not useful to us as we can't build an ASTUnit from it.
  287. class ShallowCopyCompilerInvocation : public clang::CompilerInvocation {
  288. public:
  289. explicit ShallowCopyCompilerInvocation(
  290. const clang::CompilerInvocation& invocation) {
  291. shallow_copy_assign(invocation);
  292. // Make a deep copy of options that we modify.
  293. FrontendOpts = std::make_shared<clang::FrontendOptions>(*FrontendOpts);
  294. PPOpts = std::make_shared<clang::PreprocessorOptions>(*PPOpts);
  295. }
  296. };
  297. class CarbonExternalASTSource : public clang::ExternalASTSource {
  298. public:
  299. explicit CarbonExternalASTSource(clang::ASTContext* ast_context)
  300. : ast_context_(*ast_context) {}
  301. auto FindExternalVisibleDeclsByName(
  302. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  303. const clang::DeclContext* original_decl_context) -> bool override;
  304. auto StartTranslationUnit(clang::ASTConsumer* consumer) -> void override;
  305. private:
  306. clang::ASTContext& ast_context_;
  307. };
  308. void CarbonExternalASTSource::StartTranslationUnit(
  309. clang::ASTConsumer* /*Consumer*/) {
  310. auto& translation_unit = *ast_context_.getTranslationUnitDecl();
  311. // Mark the translation unit as having external storage so we get a query for
  312. // the `Carbon` namespace in the top level/translation unit scope.
  313. translation_unit.setHasExternalVisibleStorage();
  314. }
  315. auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
  316. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  317. const clang::DeclContext* /*OriginalDC*/) -> bool {
  318. if (decl_context->getDeclKind() != clang::Decl::Kind::TranslationUnit) {
  319. return false;
  320. }
  321. static const llvm::StringLiteral carbon_namespace_name = "Carbon";
  322. if (auto* identifier = decl_name.getAsIdentifierInfo();
  323. !identifier || !identifier->isStr(carbon_namespace_name)) {
  324. return false;
  325. }
  326. auto& ast_context = decl_context->getParentASTContext();
  327. auto& mutable_tu_decl_context = *ast_context.getTranslationUnitDecl();
  328. SetExternalVisibleDeclsForName(
  329. decl_context, decl_name,
  330. {
  331. clang::NamespaceDecl::Create(
  332. ast_context, &mutable_tu_decl_context, false,
  333. clang::SourceLocation(), clang::SourceLocation(),
  334. &ast_context.Idents.get(carbon_namespace_name), nullptr, false),
  335. });
  336. return true;
  337. }
  338. // An action and a set of registered Clang callbacks used to generate an AST
  339. // from a set of Cpp imports.
  340. class GenerateASTAction : public clang::ASTFrontendAction {
  341. public:
  342. explicit GenerateASTAction(Context& context) : context_(&context) {}
  343. protected:
  344. auto CreateASTConsumer(clang::CompilerInstance& clang_instance,
  345. llvm::StringRef /*file*/)
  346. -> std::unique_ptr<clang::ASTConsumer> override {
  347. auto& cpp_file = *context_->sem_ir().cpp_file();
  348. if (!cpp_file.llvm_context()) {
  349. return std::make_unique<clang::ASTConsumer>();
  350. }
  351. auto code_generator =
  352. std::unique_ptr<clang::CodeGenerator>(clang::CreateLLVMCodeGen(
  353. cpp_file.diagnostics(), context_->sem_ir().filename(),
  354. clang_instance.getVirtualFileSystemPtr(),
  355. clang_instance.getHeaderSearchOpts(),
  356. clang_instance.getPreprocessorOpts(),
  357. clang_instance.getCodeGenOpts(), *cpp_file.llvm_context()));
  358. cpp_file.SetCodeGenerator(code_generator.get());
  359. return code_generator;
  360. }
  361. auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
  362. -> bool override {
  363. // TODO: `clang.getPreprocessor().enableIncrementalProcessing();` to avoid
  364. // the TU scope getting torn down before we're done parsing macros.
  365. return true;
  366. }
  367. // Parse the imports and inline C++ fragments. This is notionally very similar
  368. // to `clang::ParseAST`, which `ASTFrontendAction::ExecuteAction` calls, but
  369. // this version doesn't parse C++20 modules and stops just before reaching the
  370. // end of the translation unit.
  371. auto ExecuteAction() -> void override {
  372. clang::CompilerInstance& clang_instance = getCompilerInstance();
  373. clang_instance.createSema(getTranslationUnitKind(),
  374. /*CompletionConsumer=*/nullptr);
  375. auto parser_ptr = std::make_unique<clang::Parser>(
  376. clang_instance.getPreprocessor(), clang_instance.getSema(),
  377. /*SkipFunctionBodies=*/false);
  378. auto& parser = *parser_ptr;
  379. clang_instance.getPreprocessor().EnterMainSourceFile();
  380. if (auto* source = clang_instance.getASTContext().getExternalSource()) {
  381. source->StartTranslationUnit(&clang_instance.getASTConsumer());
  382. }
  383. parser.Initialize();
  384. clang_instance.getSema().ActOnStartOfTranslationUnit();
  385. context_->set_cpp_context(
  386. std::make_unique<CppContext>(clang_instance, std::move(parser_ptr)));
  387. // Don't allow C++20 module declarations in inline Cpp code fragments.
  388. auto module_import_state = clang::Sema::ModuleImportState::NotACXX20Module;
  389. // Parse top-level declarations until we see EOF. Do not parse EOF, as that
  390. // will cause the parser to end the translation unit prematurely.
  391. while (parser.getCurToken().isNot(clang::tok::eof)) {
  392. clang::Parser::DeclGroupPtrTy decl_group;
  393. bool eof = parser.ParseTopLevelDecl(decl_group, module_import_state);
  394. CARBON_CHECK(!eof);
  395. if (decl_group && !clang_instance.getASTConsumer().HandleTopLevelDecl(
  396. decl_group.get())) {
  397. break;
  398. }
  399. }
  400. }
  401. private:
  402. Context* context_;
  403. };
  404. } // namespace
  405. auto GenerateAst(Context& context,
  406. llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
  407. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  408. llvm::LLVMContext* llvm_context,
  409. std::shared_ptr<clang::CompilerInvocation> base_invocation)
  410. -> bool {
  411. CARBON_CHECK(!context.cpp_context());
  412. CARBON_CHECK(!context.sem_ir().cpp_file());
  413. auto invocation =
  414. std::make_shared<ShallowCopyCompilerInvocation>(*base_invocation);
  415. // Ask Clang to not leak memory.
  416. invocation->getFrontendOpts().DisableFree = false;
  417. // Build a diagnostics engine.
  418. llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(
  419. clang::CompilerInstance::createDiagnostics(
  420. *fs, invocation->getDiagnosticOpts(),
  421. new CarbonClangDiagnosticConsumer(context, invocation),
  422. /*ShouldOwnClient=*/true));
  423. // Extract the input from the frontend invocation and make sure it makes
  424. // sense.
  425. const auto& inputs = invocation->getFrontendOpts().Inputs;
  426. CARBON_CHECK(inputs.size() == 1 &&
  427. inputs[0].getKind().getLanguage() == clang::Language::CXX &&
  428. inputs[0].getKind().getFormat() == clang::InputKind::Source);
  429. llvm::StringRef file_name = inputs[0].getFile();
  430. // Remap the imports file name to the corresponding `#include`s.
  431. // TODO: Modify the frontend options to specify this memory buffer as input
  432. // instead of remapping the file.
  433. std::string includes = GenerateCppIncludesHeaderCode(context, imports);
  434. auto includes_buffer =
  435. llvm::MemoryBuffer::getMemBufferCopy(includes, file_name);
  436. invocation->getPreprocessorOpts().addRemappedFile(file_name,
  437. includes_buffer.release());
  438. auto clang_instance_ptr =
  439. std::make_unique<clang::CompilerInstance>(invocation);
  440. auto& clang_instance = *clang_instance_ptr;
  441. context.sem_ir().set_cpp_file(std::make_unique<SemIR::CppFile>(
  442. std::move(clang_instance_ptr), llvm_context));
  443. clang_instance.setDiagnostics(diags);
  444. clang_instance.setVirtualFileSystem(fs);
  445. clang_instance.createFileManager();
  446. clang_instance.createSourceManager();
  447. if (!clang_instance.createTarget()) {
  448. return false;
  449. }
  450. GenerateASTAction action(context);
  451. if (!action.BeginSourceFile(clang_instance, inputs[0])) {
  452. return false;
  453. }
  454. auto& ast = clang_instance.getASTContext();
  455. // TODO: Clang's modules support is implemented as an ExternalASTSource
  456. // (ASTReader) and there's no multiplexing support for ExternalASTSources at
  457. // the moment - so registering CarbonExternalASTSource breaks Clang modules
  458. // support. Implement multiplexing support (possibly in Clang) to restore
  459. // modules functionality.
  460. ast.setExternalSource(
  461. llvm::makeIntrusiveRefCnt<CarbonExternalASTSource>(&ast));
  462. if (llvm::Error error = action.Execute()) {
  463. // `Execute` currently never fails, but its contract allows it to.
  464. context.TODO(SemIR::LocId::None, "failed to execute clang action: " +
  465. llvm::toString(std::move(error)));
  466. return false;
  467. }
  468. // Flush any diagnostics. We know we're not part-way through emitting a
  469. // diagnostic now.
  470. context.emitter().Flush();
  471. return true;
  472. }
  473. auto FinishAst(Context& context) -> void {
  474. if (!context.cpp_context()) {
  475. return;
  476. }
  477. context.cpp_context()->sema().ActOnEndOfTranslationUnit();
  478. // We don't call FrontendAction::EndSourceFile, because that destroys the AST.
  479. context.set_cpp_context(nullptr);
  480. context.emitter().Flush();
  481. }
  482. } // namespace Carbon::Check