generate_ast.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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/map.h"
  21. #include "common/raw_string_ostream.h"
  22. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  23. #include "llvm/ADT/StringRef.h"
  24. #include "llvm/Support/raw_ostream.h"
  25. #include "toolchain/base/kind_switch.h"
  26. #include "toolchain/check/context.h"
  27. #include "toolchain/check/cpp/import.h"
  28. #include "toolchain/check/import_ref.h"
  29. #include "toolchain/check/name_lookup.h"
  30. #include "toolchain/diagnostics/diagnostic.h"
  31. #include "toolchain/diagnostics/emitter.h"
  32. #include "toolchain/diagnostics/format_providers.h"
  33. #include "toolchain/parse/node_ids.h"
  34. #include "toolchain/sem_ir/cpp_file.h"
  35. #include "toolchain/sem_ir/mangler.h"
  36. namespace Carbon::Check {
  37. // Add a line marker directive pointing at the location of the `import Cpp`
  38. // declaration in the Carbon source file. This will cause Clang's diagnostics
  39. // machinery to track and report the location in Carbon code where the import
  40. // was written.
  41. static auto GenerateLineMarker(Context& context, llvm::raw_ostream& out,
  42. int line) {
  43. out << "# " << line << " \""
  44. << FormatEscaped(context.tokens().source().filename()) << "\"\n";
  45. }
  46. // Generates C++ file contents to #include all requested imports.
  47. static auto GenerateCppIncludesHeaderCode(
  48. Context& context, llvm::ArrayRef<Parse::Tree::PackagingNames> imports)
  49. -> std::string {
  50. std::string code;
  51. llvm::raw_string_ostream code_stream(code);
  52. for (const Parse::Tree::PackagingNames& import : imports) {
  53. if (import.inline_body_id.has_value()) {
  54. // Expand `import Cpp inline "code";` directly into the specified code.
  55. auto code_token = context.parse_tree().node_token(import.inline_body_id);
  56. // Compute the line number on which the C++ code starts. Usually the code
  57. // is specified as a block string literal and starts on the line after the
  58. // start of the string token.
  59. // TODO: Determine if this is a block string literal without calling
  60. // `GetTokenText`, which re-lexes the string.
  61. int line = context.tokens().GetLineNumber(code_token);
  62. if (context.tokens().GetTokenText(code_token).contains('\n')) {
  63. ++line;
  64. }
  65. GenerateLineMarker(context, code_stream, line);
  66. code_stream << context.string_literal_values().Get(
  67. context.tokens().GetStringLiteralValue(code_token))
  68. << "\n";
  69. // TODO: Inject a clang pragma here to produce an error if there are
  70. // unclosed scopes at the end of this inline C++ fragment.
  71. } else if (import.library_id.has_value()) {
  72. // Translate `import Cpp library "foo.h";` into `#include "foo.h"`.
  73. GenerateLineMarker(context, code_stream,
  74. context.tokens().GetLineNumber(
  75. context.parse_tree().node_token(import.node_id)));
  76. auto name = context.string_literal_values().Get(import.library_id);
  77. if (name.starts_with('<') && name.ends_with('>')) {
  78. code_stream << "#include <"
  79. << FormatEscaped(name.drop_front().drop_back()) << ">\n";
  80. } else {
  81. code_stream << "#include \"" << FormatEscaped(name) << "\"\n";
  82. }
  83. }
  84. }
  85. return code;
  86. }
  87. // Adds the given source location and an `ImportIRInst` referring to it in
  88. // `ImportIRId::Cpp`.
  89. static auto AddImportIRInst(SemIR::File& file,
  90. clang::SourceLocation clang_source_loc)
  91. -> SemIR::ImportIRInstId {
  92. SemIR::ClangSourceLocId clang_source_loc_id =
  93. file.clang_source_locs().Add(clang_source_loc);
  94. return file.import_ir_insts().Add(SemIR::ImportIRInst(clang_source_loc_id));
  95. }
  96. namespace {
  97. // Used to convert Clang diagnostics to Carbon diagnostics.
  98. //
  99. // Handling of Clang notes is a little subtle: as far as Clang is concerned,
  100. // notes are separate diagnostics, not connected to the error or warning that
  101. // precedes them. But in Carbon's diagnostics system, notes are part of the
  102. // enclosing diagnostic. To handle this, we buffer Clang diagnostics until we
  103. // reach a point where we know we're not in the middle of a diagnostic, and then
  104. // emit a diagnostic along with all of its notes. This is triggered when adding
  105. // or removing a Carbon context note, which could otherwise get attached to the
  106. // wrong C++ diagnostics, and at the end of the Carbon program.
  107. class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
  108. public:
  109. // Creates an instance with the location that triggers calling Clang. The
  110. // `context` is not stored here, and the diagnostics consumer is expected to
  111. // outlive it.
  112. explicit CarbonClangDiagnosticConsumer(
  113. Context& context, std::shared_ptr<clang::CompilerInvocation> invocation)
  114. : sem_ir_(&context.sem_ir()),
  115. emitter_(&context.emitter()),
  116. invocation_(std::move(invocation)) {
  117. emitter_->AddFlushFn([this] { EmitDiagnostics(); });
  118. }
  119. ~CarbonClangDiagnosticConsumer() override {
  120. // Do not inspect `emitter_` here; it's typically destroyed before the
  121. // consumer is.
  122. // TODO: If Clang produces diagnostics after check finishes, they'll get
  123. // added to the list of pending diagnostics and never emitted.
  124. CARBON_CHECK(diagnostic_infos_.empty(),
  125. "Missing flush before destroying diagnostic consumer");
  126. }
  127. // Generates a Carbon warning for each Clang warning and a Carbon error for
  128. // each Clang error or fatal.
  129. auto HandleDiagnostic(clang::DiagnosticsEngine::Level diag_level,
  130. const clang::Diagnostic& info) -> void override {
  131. DiagnosticConsumer::HandleDiagnostic(diag_level, info);
  132. SemIR::ImportIRInstId clang_import_ir_inst_id =
  133. AddImportIRInst(*sem_ir_, info.getLocation());
  134. llvm::SmallString<256> message;
  135. info.FormatDiagnostic(message);
  136. // Render a code snippet including any highlighted ranges and fixit hints.
  137. // TODO: Also include the #include stack and macro expansion stack in the
  138. // diagnostic output in some way.
  139. RawStringOstream snippet_stream;
  140. if (!info.hasSourceManager()) {
  141. // If we don't have a source manager, this is an error from early in the
  142. // frontend. Don't produce a snippet.
  143. CARBON_CHECK(info.getLocation().isInvalid());
  144. } else {
  145. CodeContextRenderer(snippet_stream, invocation_->getLangOpts(),
  146. invocation_->getDiagnosticOpts())
  147. .emitDiagnostic(
  148. clang::FullSourceLoc(info.getLocation(), info.getSourceManager()),
  149. diag_level, message, info.getRanges(), info.getFixItHints());
  150. }
  151. diagnostic_infos_.push_back({.level = diag_level,
  152. .import_ir_inst_id = clang_import_ir_inst_id,
  153. .message = message.str().str(),
  154. .snippet = snippet_stream.TakeStr()});
  155. }
  156. // Returns the diagnostic to use for a given Clang diagnostic level.
  157. static auto GetDiagnostic(clang::DiagnosticsEngine::Level level)
  158. -> const Diagnostics::DiagnosticBase<std::string>& {
  159. switch (level) {
  160. case clang::DiagnosticsEngine::Ignored: {
  161. CARBON_FATAL("Emitting an ignored diagnostic");
  162. break;
  163. }
  164. case clang::DiagnosticsEngine::Note: {
  165. CARBON_DIAGNOSTIC(CppInteropParseNote, Note, "{0}", std::string);
  166. return CppInteropParseNote;
  167. }
  168. case clang::DiagnosticsEngine::Remark:
  169. case clang::DiagnosticsEngine::Warning: {
  170. // TODO: Add a distinct Remark level to Carbon diagnostics, and stop
  171. // mapping remarks to warnings.
  172. CARBON_DIAGNOSTIC(CppInteropParseWarning, Warning, "{0}", std::string);
  173. return CppInteropParseWarning;
  174. }
  175. case clang::DiagnosticsEngine::Error:
  176. case clang::DiagnosticsEngine::Fatal: {
  177. CARBON_DIAGNOSTIC(CppInteropParseError, Error, "{0}", std::string);
  178. return CppInteropParseError;
  179. }
  180. }
  181. }
  182. // Outputs Carbon diagnostics based on the collected Clang diagnostics. Must
  183. // be called after the AST is set in the context.
  184. auto EmitDiagnostics() -> void {
  185. CARBON_CHECK(
  186. sem_ir_->cpp_file(),
  187. "Attempted to emit C++ diagnostics before the C++ file is set");
  188. for (size_t i = 0; i != diagnostic_infos_.size(); ++i) {
  189. const ClangDiagnosticInfo& info = diagnostic_infos_[i];
  190. auto builder = emitter_->Build(SemIR::LocId(info.import_ir_inst_id),
  191. GetDiagnostic(info.level), info.message);
  192. builder.OverrideSnippet(info.snippet);
  193. for (; i + 1 < diagnostic_infos_.size() &&
  194. diagnostic_infos_[i + 1].level == clang::DiagnosticsEngine::Note;
  195. ++i) {
  196. const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1];
  197. builder
  198. .Note(SemIR::LocId(note_info.import_ir_inst_id),
  199. GetDiagnostic(note_info.level), note_info.message)
  200. .OverrideSnippet(note_info.snippet);
  201. }
  202. // TODO: This will apply all current Carbon annotation functions. We
  203. // should instead track how Clang's context notes and Carbon's annotation
  204. // functions are interleaved, and interleave the notes in the same order.
  205. builder.Emit();
  206. }
  207. diagnostic_infos_.clear();
  208. }
  209. private:
  210. // A diagnostics renderer based on clang's TextDiagnostic that captures just
  211. // the code context (the snippet).
  212. class CodeContextRenderer : public clang::TextDiagnostic {
  213. protected:
  214. using TextDiagnostic::TextDiagnostic;
  215. void emitDiagnosticMessage(
  216. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  217. clang::DiagnosticsEngine::Level /*level*/, llvm::StringRef /*message*/,
  218. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/,
  219. clang::DiagOrStoredDiag /*info*/) override {}
  220. void emitDiagnosticLoc(
  221. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  222. clang::DiagnosticsEngine::Level /*level*/,
  223. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/) override {}
  224. // emitCodeContext is inherited from clang::TextDiagnostic.
  225. void emitIncludeLocation(clang::FullSourceLoc /*loc*/,
  226. clang::PresumedLoc /*ploc*/) override {}
  227. void emitImportLocation(clang::FullSourceLoc /*loc*/,
  228. clang::PresumedLoc /*ploc*/,
  229. llvm::StringRef /*module_name*/) override {}
  230. void emitBuildingModuleLocation(clang::FullSourceLoc /*loc*/,
  231. clang::PresumedLoc /*ploc*/,
  232. llvm::StringRef /*module_name*/) override {}
  233. // beginDiagnostic and endDiagnostic are inherited from
  234. // clang::TextDiagnostic in case it wants to do any setup / teardown work.
  235. };
  236. // Information on a Clang diagnostic that can be converted to a Carbon
  237. // diagnostic.
  238. struct ClangDiagnosticInfo {
  239. // The Clang diagnostic level.
  240. clang::DiagnosticsEngine::Level level;
  241. // The ID of the ImportIR instruction referring to the Clang source
  242. // location.
  243. SemIR::ImportIRInstId import_ir_inst_id;
  244. // The Clang diagnostic textual message.
  245. std::string message;
  246. // The code snippet produced by clang.
  247. std::string snippet;
  248. };
  249. // The Carbon file that this C++ compilation is attached to.
  250. SemIR::File* sem_ir_;
  251. // The diagnostic emitter that we're emitting diagnostics into.
  252. DiagnosticEmitterBase* emitter_;
  253. // The compiler invocation that is producing the diagnostics.
  254. std::shared_ptr<clang::CompilerInvocation> invocation_;
  255. // Collects the information for all Clang diagnostics to be converted to
  256. // Carbon diagnostics after the context has been initialized with the Clang
  257. // AST.
  258. llvm::SmallVector<ClangDiagnosticInfo> diagnostic_infos_;
  259. };
  260. // A wrapper around a clang::CompilerInvocation that allows us to make a shallow
  261. // copy of most of the invocation and only make a deep copy of the parts that we
  262. // want to change.
  263. //
  264. // clang::CowCompilerInvocation almost allows this, but doesn't derive from
  265. // CompilerInvocation or support shallow copies from a CompilerInvocation, so is
  266. // not useful to us as we can't build an ASTUnit from it.
  267. class ShallowCopyCompilerInvocation : public clang::CompilerInvocation {
  268. public:
  269. explicit ShallowCopyCompilerInvocation(
  270. const clang::CompilerInvocation& invocation) {
  271. shallow_copy_assign(invocation);
  272. // Make a deep copy of options that we modify.
  273. FrontendOpts = std::make_shared<clang::FrontendOptions>(*FrontendOpts);
  274. PPOpts = std::make_shared<clang::PreprocessorOptions>(*PPOpts);
  275. }
  276. };
  277. // Provides clang AST nodes representing Carbon SemIR entities.
  278. class CarbonExternalASTSource : public clang::ExternalASTSource {
  279. public:
  280. explicit CarbonExternalASTSource(Context* context,
  281. clang::ASTContext* ast_context)
  282. : context_(context), ast_context_(ast_context) {}
  283. // Look up decls for `decl_name` inside `decl_context`, adding the decls to
  284. // `decl_context`. Returns true if any decls were added.
  285. auto FindExternalVisibleDeclsByName(
  286. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  287. const clang::DeclContext* original_decl_context) -> bool override;
  288. // See clang::ExternalASTSource.
  289. auto StartTranslationUnit(clang::ASTConsumer* consumer) -> void override;
  290. private:
  291. // Map a Carbon entity to a Clang NamedDecl. Returns null if the entity cannot
  292. // currently be represented in C++.
  293. auto MapInstIdToClangDecl(clang::DeclContext& decl_context,
  294. LookupResult lookup) -> clang::NamedDecl*;
  295. Check::Context* context_;
  296. clang::ASTContext* ast_context_;
  297. // The association between clang DeclContexts and the corresponding
  298. // SemIR::Namespaces in Carbon.
  299. // TODO: reuse the SemIR::File::ClangDeclStore to avoid duplicates, and to
  300. // enable roundtripping through forward and reverse interop (once we have
  301. // syntax/support for that).
  302. Map<clang::DeclContext*, SemIR::InstId> scope_map_;
  303. // Has the "Carbon" C++ namespace been created yet
  304. // (this could be replaced with `!scope_map_.empty()` if Carbon::Map supported
  305. // `empty()`)
  306. bool root_scope_initialized_ = false;
  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::MapInstIdToClangDecl(
  316. clang::DeclContext& decl_context, LookupResult lookup)
  317. -> clang::NamedDecl* {
  318. auto target_inst_id = lookup.scope_result.target_inst_id();
  319. auto target_constant =
  320. context_->constant_values().GetConstantInstId(target_inst_id);
  321. auto target_inst = context_->insts().Get(target_constant);
  322. CARBON_KIND_SWITCH(target_inst) {
  323. case CARBON_KIND(SemIR::Namespace namespace_info): {
  324. auto& name_scope =
  325. context_->name_scopes().Get(namespace_info.name_scope_id);
  326. auto* identifier_info =
  327. GetClangIdentifierInfo(*context_, name_scope.name_id());
  328. // TODO: Don't immediately use the decl_context - build any intermediate
  329. // namespaces iteratively.
  330. // Eventually add a mapping and use that/populate it/keep it up to date.
  331. // decl_context could be prepopulated in that mapping and not passed
  332. // explicitly to MapInstIdToClangDecl.
  333. auto* namespace_decl = clang::NamespaceDecl::Create(
  334. *ast_context_, &decl_context, false, clang::SourceLocation(),
  335. clang::SourceLocation(), identifier_info, nullptr, false);
  336. auto result = scope_map_.Insert(namespace_decl->getPrimaryContext(),
  337. target_inst_id);
  338. CARBON_CHECK(result.is_inserted(), "Inserting over an existing entry.");
  339. namespace_decl->setHasExternalVisibleStorage();
  340. return namespace_decl;
  341. }
  342. case CARBON_KIND(SemIR::ClassType class_type): {
  343. const auto& class_info = context_->classes().Get(class_type.class_id);
  344. auto* identifier_info =
  345. GetClangIdentifierInfo(*context_, class_info.name_id);
  346. return clang::CXXRecordDecl::Create(
  347. *ast_context_, clang::TagTypeKind::Class, &decl_context,
  348. clang::SourceLocation(), clang::SourceLocation(), identifier_info);
  349. }
  350. case SemIR::StructValue::Kind: {
  351. auto callee = GetCallee(context_->sem_ir(), target_constant);
  352. auto* callee_function = std::get_if<SemIR::CalleeFunction>(&callee);
  353. if (!callee_function) {
  354. return nullptr;
  355. }
  356. const SemIR::Function& function =
  357. context_->functions().Get(callee_function->function_id);
  358. auto* identifier_info =
  359. GetClangIdentifierInfo(*context_, function.name_id);
  360. if (function.call_param_ranges.explicit_size() != 0) {
  361. context_->TODO(target_inst_id,
  362. "unsupported: C++ calling a Carbon function with "
  363. "parameters");
  364. return nullptr;
  365. }
  366. if (function.return_type_inst_id != SemIR::TypeInstId::None) {
  367. context_->TODO(target_inst_id,
  368. "unsupported: C++ calling a Carbon function with "
  369. "return type other than `()`");
  370. return nullptr;
  371. }
  372. // TODO: support non-empty parameter lists.
  373. llvm::SmallVector<clang::QualType> cpp_param_types;
  374. // TODO: support non-void return types.
  375. auto cpp_return_type = ast_context_->VoidTy;
  376. auto cpp_function_type = ast_context_->getFunctionType(
  377. cpp_return_type, cpp_param_types,
  378. clang::FunctionProtoType::ExtProtoInfo());
  379. auto* function_decl = clang::FunctionDecl::Create(
  380. *ast_context_, &decl_context,
  381. /*StartLoc=*/clang::SourceLocation(),
  382. /*NLoc=*/clang::SourceLocation(),
  383. clang::DeclarationName(identifier_info), cpp_function_type,
  384. /*TInfo=*/nullptr, clang::SC_Extern);
  385. // Mangle the function name and attach it to the `FunctionDecl`.
  386. SemIR::Mangler m(context_->sem_ir(), context_->total_ir_count());
  387. std::string mangled_name =
  388. m.Mangle(callee_function->function_id, SemIR::SpecificId::None);
  389. function_decl->addAttr(
  390. clang::AsmLabelAttr::Create(*ast_context_, mangled_name));
  391. return function_decl;
  392. }
  393. default:
  394. return nullptr;
  395. }
  396. }
  397. auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
  398. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  399. const clang::DeclContext* /*OriginalDC*/) -> bool {
  400. if (decl_context->getDeclKind() == clang::Decl::Kind::TranslationUnit) {
  401. // If the context doesn't already have a mapping between C++ and Carbon,
  402. // check if this is the root mapping (for the "Carbon" namespace in the
  403. // translation unit scope) and if so, create that mapping.
  404. if (root_scope_initialized_) {
  405. return false;
  406. }
  407. static const llvm::StringLiteral carbon_namespace_name = "Carbon";
  408. if (auto* identifier = decl_name.getAsIdentifierInfo();
  409. !identifier || !identifier->isStr(carbon_namespace_name)) {
  410. return false;
  411. }
  412. // Build the top level 'Carbon' namespace
  413. auto& ast_context = decl_context->getParentASTContext();
  414. auto& mutable_tu_decl_context = *ast_context.getTranslationUnitDecl();
  415. auto* carbon_cpp_namespace = clang::NamespaceDecl::Create(
  416. ast_context, &mutable_tu_decl_context, false, clang::SourceLocation(),
  417. clang::SourceLocation(), &ast_context.Idents.get(carbon_namespace_name),
  418. nullptr, false);
  419. carbon_cpp_namespace->setHasExternalVisibleStorage();
  420. auto result = scope_map_.Insert(carbon_cpp_namespace->getPrimaryContext(),
  421. SemIR::Namespace::PackageInstId);
  422. CARBON_CHECK(result.is_inserted(), "Inserting over an existing entry.");
  423. SetExternalVisibleDeclsForName(decl_context, decl_name,
  424. {carbon_cpp_namespace});
  425. root_scope_initialized_ = true;
  426. return true;
  427. }
  428. auto decl_context_inst_id =
  429. scope_map_.Lookup(decl_context->getPrimaryContext());
  430. CARBON_CHECK(
  431. decl_context_inst_id,
  432. "The DeclContext should already be associated with a Carbon InstId.");
  433. llvm::SmallVector<Check::LookupScope> lookup_scopes;
  434. // LocId::None seems fine here because we shouldn't produce any diagnostics
  435. // here - completeness should've been checked by clang before this point.
  436. if (!AppendLookupScopesForConstant(
  437. *context_, SemIR::LocId::None,
  438. context_->constant_values().Get(decl_context_inst_id.value()),
  439. SemIR::ConstantId::None, &lookup_scopes)) {
  440. return false;
  441. }
  442. auto* identifier = decl_name.getAsIdentifierInfo();
  443. if (!identifier) {
  444. // Only supporting identifiers for now.
  445. return false;
  446. }
  447. auto name_id = AddIdentifierName(*context_, identifier->getName());
  448. // `required=false` so Carbon doesn't diagnose a failure, let Clang diagnose
  449. // it or even SFINAE.
  450. LookupResult result =
  451. LookupQualifiedName(*context_, SemIR::LocId::None, name_id, lookup_scopes,
  452. /*required=*/false);
  453. if (!result.scope_result.is_found()) {
  454. return false;
  455. }
  456. // Map the found Carbon entity to a Clang NamedDecl.
  457. // Use the key to reach the owned, mutable copy of decl_context.
  458. auto* clang_decl = MapInstIdToClangDecl(*decl_context_inst_id.key(), result);
  459. if (!clang_decl) {
  460. return false;
  461. }
  462. SetExternalVisibleDeclsForName(decl_context, decl_name, {clang_decl});
  463. return true;
  464. }
  465. // An action and a set of registered Clang callbacks used to generate an AST
  466. // from a set of Cpp imports.
  467. class GenerateASTAction : public clang::ASTFrontendAction {
  468. public:
  469. explicit GenerateASTAction(Context& context) : context_(&context) {}
  470. protected:
  471. auto CreateASTConsumer(clang::CompilerInstance& clang_instance,
  472. llvm::StringRef /*file*/)
  473. -> std::unique_ptr<clang::ASTConsumer> override {
  474. auto& cpp_file = *context_->sem_ir().cpp_file();
  475. if (!cpp_file.llvm_context()) {
  476. return std::make_unique<clang::ASTConsumer>();
  477. }
  478. auto code_generator =
  479. std::unique_ptr<clang::CodeGenerator>(clang::CreateLLVMCodeGen(
  480. cpp_file.diagnostics(), context_->sem_ir().filename(),
  481. clang_instance.getVirtualFileSystemPtr(),
  482. clang_instance.getHeaderSearchOpts(),
  483. clang_instance.getPreprocessorOpts(),
  484. clang_instance.getCodeGenOpts(), *cpp_file.llvm_context()));
  485. cpp_file.SetCodeGenerator(code_generator.get());
  486. return code_generator;
  487. }
  488. auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
  489. -> bool override {
  490. // TODO: `clang.getPreprocessor().enableIncrementalProcessing();` to avoid
  491. // the TU scope getting torn down before we're done parsing macros.
  492. return true;
  493. }
  494. // Parse the imports and inline C++ fragments. This is notionally very similar
  495. // to `clang::ParseAST`, which `ASTFrontendAction::ExecuteAction` calls, but
  496. // this version doesn't parse C++20 modules and stops just before reaching the
  497. // end of the translation unit.
  498. auto ExecuteAction() -> void override {
  499. clang::CompilerInstance& clang_instance = getCompilerInstance();
  500. clang_instance.createSema(getTranslationUnitKind(),
  501. /*CompletionConsumer=*/nullptr);
  502. auto parser_ptr = std::make_unique<clang::Parser>(
  503. clang_instance.getPreprocessor(), clang_instance.getSema(),
  504. /*SkipFunctionBodies=*/false);
  505. auto& parser = *parser_ptr;
  506. clang_instance.getPreprocessor().EnterMainSourceFile();
  507. if (auto* source = clang_instance.getASTContext().getExternalSource()) {
  508. source->StartTranslationUnit(&clang_instance.getASTConsumer());
  509. }
  510. parser.Initialize();
  511. clang_instance.getSema().ActOnStartOfTranslationUnit();
  512. context_->set_cpp_context(
  513. std::make_unique<CppContext>(clang_instance, std::move(parser_ptr)));
  514. // Don't allow C++20 module declarations in inline Cpp code fragments.
  515. auto module_import_state = clang::Sema::ModuleImportState::NotACXX20Module;
  516. // Parse top-level declarations until we see EOF. Do not parse EOF, as that
  517. // will cause the parser to end the translation unit prematurely.
  518. while (parser.getCurToken().isNot(clang::tok::eof)) {
  519. clang::Parser::DeclGroupPtrTy decl_group;
  520. bool eof = parser.ParseTopLevelDecl(decl_group, module_import_state);
  521. CARBON_CHECK(!eof);
  522. if (decl_group && !clang_instance.getASTConsumer().HandleTopLevelDecl(
  523. decl_group.get())) {
  524. break;
  525. }
  526. }
  527. }
  528. private:
  529. Context* context_;
  530. };
  531. } // namespace
  532. auto GenerateAst(Context& context,
  533. llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
  534. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  535. llvm::LLVMContext* llvm_context,
  536. std::shared_ptr<clang::CompilerInvocation> base_invocation)
  537. -> bool {
  538. CARBON_CHECK(!context.cpp_context());
  539. CARBON_CHECK(!context.sem_ir().cpp_file());
  540. auto invocation =
  541. std::make_shared<ShallowCopyCompilerInvocation>(*base_invocation);
  542. // Ask Clang to not leak memory.
  543. invocation->getFrontendOpts().DisableFree = false;
  544. // Build a diagnostics engine.
  545. llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(
  546. clang::CompilerInstance::createDiagnostics(
  547. *fs, invocation->getDiagnosticOpts(),
  548. new CarbonClangDiagnosticConsumer(context, invocation),
  549. /*ShouldOwnClient=*/true));
  550. // Extract the input from the frontend invocation and make sure it makes
  551. // sense.
  552. const auto& inputs = invocation->getFrontendOpts().Inputs;
  553. CARBON_CHECK(inputs.size() == 1 &&
  554. inputs[0].getKind().getLanguage() == clang::Language::CXX &&
  555. inputs[0].getKind().getFormat() == clang::InputKind::Source);
  556. llvm::StringRef file_name = inputs[0].getFile();
  557. // Remap the imports file name to the corresponding `#include`s.
  558. // TODO: Modify the frontend options to specify this memory buffer as input
  559. // instead of remapping the file.
  560. std::string includes = GenerateCppIncludesHeaderCode(context, imports);
  561. auto includes_buffer =
  562. llvm::MemoryBuffer::getMemBufferCopy(includes, file_name);
  563. invocation->getPreprocessorOpts().addRemappedFile(file_name,
  564. includes_buffer.release());
  565. auto clang_instance_ptr =
  566. std::make_unique<clang::CompilerInstance>(invocation);
  567. auto& clang_instance = *clang_instance_ptr;
  568. context.sem_ir().set_cpp_file(std::make_unique<SemIR::CppFile>(
  569. std::move(clang_instance_ptr), llvm_context));
  570. clang_instance.setDiagnostics(diags);
  571. clang_instance.setVirtualFileSystem(fs);
  572. clang_instance.createFileManager();
  573. clang_instance.createSourceManager();
  574. if (!clang_instance.createTarget()) {
  575. return false;
  576. }
  577. GenerateASTAction action(context);
  578. if (!action.BeginSourceFile(clang_instance, inputs[0])) {
  579. return false;
  580. }
  581. auto& ast = clang_instance.getASTContext();
  582. // TODO: Clang's modules support is implemented as an ExternalASTSource
  583. // (ASTReader) and there's no multiplexing support for ExternalASTSources at
  584. // the moment - so registering CarbonExternalASTSource breaks Clang modules
  585. // support. Implement multiplexing support (possibly in Clang) to restore
  586. // modules functionality.
  587. ast.setExternalSource(
  588. llvm::makeIntrusiveRefCnt<CarbonExternalASTSource>(&context, &ast));
  589. if (llvm::Error error = action.Execute()) {
  590. // `Execute` currently never fails, but its contract allows it to.
  591. context.TODO(SemIR::LocId::None, "failed to execute clang action: " +
  592. llvm::toString(std::move(error)));
  593. return false;
  594. }
  595. // Flush any diagnostics. We know we're not part-way through emitting a
  596. // diagnostic now.
  597. context.emitter().Flush();
  598. return true;
  599. }
  600. auto FinishAst(Context& context) -> void {
  601. if (!context.cpp_context()) {
  602. return;
  603. }
  604. context.cpp_context()->sema().ActOnEndOfTranslationUnit();
  605. // We don't call FrontendAction::EndSourceFile, because that destroys the AST.
  606. context.set_cpp_context(nullptr);
  607. context.emitter().Flush();
  608. }
  609. } // namespace Carbon::Check