clang_cc1.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 "third_party/llvm/clang_cc1.h"
  5. #include <stdlib.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "clang/Basic/DiagnosticDriver.h"
  9. #include "clang/Basic/DiagnosticIDs.h"
  10. #include "clang/CodeGen/ObjectFilePCHContainerWriter.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Frontend/CompilerInvocation.h"
  13. #include "clang/Frontend/TextDiagnosticBuffer.h"
  14. #include "clang/Frontend/TextDiagnosticPrinter.h"
  15. #include "clang/FrontendTool/Utils.h"
  16. #include "clang/Serialization/ObjectFilePCHContainerReader.h"
  17. #include "clang/Serialization/PCHContainerOperations.h"
  18. #include "common/check.h"
  19. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  20. #include "llvm/ADT/STLExtras.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/ADT/Statistic.h"
  23. #include "llvm/Support/Allocator.h"
  24. #include "llvm/Support/BuryPointer.h"
  25. #include "llvm/Support/CommandLine.h"
  26. #include "llvm/Support/Error.h"
  27. #include "llvm/Support/TimeProfiler.h"
  28. #include "llvm/Support/Timer.h"
  29. #include "llvm/Support/raw_ostream.h"
  30. #include "toolchain/base/install_paths.h"
  31. namespace Carbon {
  32. auto RunClangCC1Main(const InstallPaths& installation,
  33. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  34. llvm::SmallVectorImpl<const char*>& cc1_args,
  35. bool enable_leaking) -> int {
  36. llvm::BumpPtrAllocator allocator;
  37. llvm::cl::ExpansionContext expansion_context(
  38. allocator, llvm::cl::TokenizeGNUCommandLine);
  39. if (llvm::Error error = expansion_context.expandResponseFiles(cc1_args)) {
  40. llvm::errs() << toString(std::move(error)) << '\n';
  41. return 1;
  42. }
  43. CARBON_CHECK(cc1_args[1] == llvm::StringRef("-cc1"));
  44. llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diag_ids =
  45. clang::DiagnosticIDs::create();
  46. // Register the support for object-file-wrapped Clang modules.
  47. auto pch_ops = std::make_shared<clang::PCHContainerOperations>();
  48. pch_ops->registerWriter(
  49. std::make_unique<clang::ObjectFilePCHContainerWriter>());
  50. pch_ops->registerReader(
  51. std::make_unique<clang::ObjectFilePCHContainerReader>());
  52. // Buffer diagnostics from argument parsing so that we can output them using a
  53. // well formed diagnostic object.
  54. clang::DiagnosticOptions diag_opts;
  55. clang::TextDiagnosticBuffer diag_buffer;
  56. clang::DiagnosticsEngine diags(diag_ids, diag_opts, &diag_buffer,
  57. /*ShouldOwnClient=*/false);
  58. // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs.
  59. if (llvm::find(cc1_args, llvm::StringRef("-Rround-trip-cc1-args")) !=
  60. cc1_args.end()) {
  61. diags.setSeverity(clang::diag::remark_cc1_round_trip_generated,
  62. clang::diag::Severity::Remark, {});
  63. }
  64. auto invocation = std::make_shared<clang::CompilerInvocation>();
  65. bool success = clang::CompilerInvocation::CreateFromArgs(
  66. *invocation, llvm::ArrayRef(cc1_args).slice(1), diags, cc1_args[0]);
  67. // Heap allocate the compiler instance so that if we disable freeing we can
  68. // discard the pointer without destroying or deallocating it.
  69. auto clang_instance = std::make_unique<clang::CompilerInstance>(
  70. std::move(invocation), std::move(pch_ops));
  71. // Override the disabling of free when we don't want to leak memory.
  72. if (!enable_leaking) {
  73. clang_instance->getFrontendOpts().DisableFree = false;
  74. clang_instance->getCodeGenOpts().DisableFree = false;
  75. }
  76. if (!clang_instance->getFrontendOpts().TimeTracePath.empty()) {
  77. llvm::timeTraceProfilerInitialize(
  78. clang_instance->getFrontendOpts().TimeTraceGranularity, cc1_args[0],
  79. clang_instance->getFrontendOpts().TimeTraceVerbose);
  80. }
  81. // TODO: These options should take priority over the actual compilation.
  82. // However, their implementation is currently not accessible from a library.
  83. // We should factor the implementation into a reusable location and then use
  84. // that here.
  85. CARBON_CHECK(!clang_instance->getFrontendOpts().PrintSupportedCPUs &&
  86. !clang_instance->getFrontendOpts().PrintSupportedExtensions &&
  87. !clang_instance->getFrontendOpts().PrintEnabledExtensions);
  88. // Infer the builtin include path if unspecified.
  89. if (clang_instance->getHeaderSearchOpts().UseBuiltinIncludes &&
  90. clang_instance->getHeaderSearchOpts().ResourceDir.empty()) {
  91. clang_instance->getHeaderSearchOpts().ResourceDir =
  92. installation.clang_resource_path();
  93. }
  94. // Create the filesystem.
  95. clang_instance->createVirtualFileSystem(std::move(fs), &diag_buffer);
  96. // Create the actual diagnostics engine.
  97. clang_instance->createDiagnostics();
  98. if (!clang_instance->hasDiagnostics()) {
  99. return EXIT_FAILURE;
  100. }
  101. // Now flush the buffered diagnostics into the Clang instance's diagnostic
  102. // engine. If we've already hit an error, we can exit early once that's done.
  103. diag_buffer.FlushDiagnostics(clang_instance->getDiagnostics());
  104. if (!success) {
  105. return EXIT_FAILURE;
  106. }
  107. // Execute the frontend actions.
  108. {
  109. llvm::TimeTraceScope time_scope("ExecuteCompiler");
  110. bool time_passes = clang_instance->getCodeGenOpts().TimePasses;
  111. if (time_passes) {
  112. clang_instance->createFrontendTimer();
  113. }
  114. llvm::TimeRegion timer(time_passes ? &clang_instance->getFrontendTimer()
  115. : nullptr);
  116. success = clang::ExecuteCompilerInvocation(clang_instance.get());
  117. }
  118. // If any timers were active but haven't been destroyed yet, print their
  119. // results now. This happens in -disable-free mode.
  120. std::unique_ptr<llvm::raw_ostream> io_file = llvm::CreateInfoOutputFile();
  121. if (clang_instance->getCodeGenOpts().TimePassesJson) {
  122. *io_file << "{\n";
  123. llvm::TimerGroup::printAllJSONValues(*io_file, "");
  124. *io_file << "\n}\n";
  125. } else if (!clang_instance->getCodeGenOpts().TimePassesStatsFile) {
  126. llvm::TimerGroup::printAll(*io_file);
  127. }
  128. llvm::TimerGroup::clearAll();
  129. if (llvm::timeTraceProfilerEnabled()) {
  130. // It is possible that the compiler instance doesn't own a file manager here
  131. // if we're compiling a module unit, since the file manager is owned by the
  132. // AST when we're compiling a module unit. So the file manager may be
  133. // invalid here.
  134. //
  135. // It should be fine to create file manager here since the file system
  136. // options are stored in the compiler invocation and we can recreate the VFS
  137. // from the compiler invocation.
  138. if (!clang_instance->hasFileManager()) {
  139. clang_instance->createFileManager();
  140. }
  141. if (auto profiler_output = clang_instance->createOutputFile(
  142. clang_instance->getFrontendOpts().TimeTracePath, /*Binary=*/false,
  143. /*RemoveFileOnSignal=*/false,
  144. /*useTemporary=*/false)) {
  145. llvm::timeTraceProfilerWrite(*profiler_output);
  146. profiler_output.reset();
  147. llvm::timeTraceProfilerCleanup();
  148. clang_instance->clearOutputFiles(false);
  149. }
  150. }
  151. // When running with -disable-free, don't do any destruction or shutdown.
  152. if (clang_instance->getFrontendOpts().DisableFree) {
  153. llvm::BuryPointer(std::move(clang_instance));
  154. }
  155. return success ? EXIT_SUCCESS : EXIT_FAILURE;
  156. }
  157. } // namespace Carbon