generate_ast.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  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/AST/Decl.h"
  9. #include "clang/Basic/FileManager.h"
  10. #include "clang/CodeGen/ModuleBuilder.h"
  11. #include "clang/Frontend/CompilerInstance.h"
  12. #include "clang/Frontend/CompilerInvocation.h"
  13. #include "clang/Frontend/FrontendAction.h"
  14. #include "clang/Frontend/TextDiagnostic.h"
  15. #include "clang/Lex/PreprocessorOptions.h"
  16. #include "clang/Parse/Parser.h"
  17. #include "clang/Sema/ExternalSemaSource.h"
  18. #include "clang/Sema/MultiplexExternalSemaSource.h"
  19. #include "clang/Sema/Sema.h"
  20. #include "common/check.h"
  21. #include "common/map.h"
  22. #include "common/raw_string_ostream.h"
  23. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  24. #include "llvm/ADT/StringRef.h"
  25. #include "llvm/Support/raw_ostream.h"
  26. #include "toolchain/base/kind_switch.h"
  27. #include "toolchain/check/context.h"
  28. #include "toolchain/check/cpp/access.h"
  29. #include "toolchain/check/cpp/export.h"
  30. #include "toolchain/check/cpp/import.h"
  31. #include "toolchain/check/cpp/location.h"
  32. #include "toolchain/check/cpp/type_mapping.h"
  33. #include "toolchain/check/import_ref.h"
  34. #include "toolchain/check/name_lookup.h"
  35. #include "toolchain/check/type_completion.h"
  36. #include "toolchain/diagnostics/diagnostic.h"
  37. #include "toolchain/diagnostics/emitter.h"
  38. #include "toolchain/diagnostics/format_providers.h"
  39. #include "toolchain/parse/node_ids.h"
  40. #include "toolchain/sem_ir/cpp_file.h"
  41. #include "toolchain/sem_ir/typed_insts.h"
  42. namespace Carbon::Check {
  43. // Add a line marker directive pointing at the location of the `import Cpp`
  44. // declaration in the Carbon source file. This will cause Clang's diagnostics
  45. // machinery to track and report the location in Carbon code where the import
  46. // was written.
  47. static auto GenerateLineMarker(Context& context, llvm::raw_ostream& out,
  48. int line) {
  49. out << "# " << line << " \""
  50. << FormatEscaped(context.tokens().source().filename()) << "\"\n";
  51. }
  52. // Appends a line marker and the specified `code` to `out`, adjusting the
  53. // `line` number if the `code_token` represents a block string literal.
  54. static auto AppendInlineCode(Context& context, llvm::raw_ostream& out,
  55. Lex::TokenIndex code_token, llvm::StringRef code)
  56. -> void {
  57. // Compute the line number on which the C++ code starts. Usually the code
  58. // is specified as a block string literal and starts on the line after the
  59. // start of the string token.
  60. // TODO: Determine if this is a block string literal without calling
  61. // `GetTokenText`, which re-lexes the string.
  62. int line = context.tokens().GetLineNumber(code_token);
  63. if (context.tokens().GetTokenText(code_token).contains('\n')) {
  64. ++line;
  65. }
  66. GenerateLineMarker(context, out, line);
  67. out << code << "\n";
  68. }
  69. // Generates C++ file contents to #include all requested imports.
  70. static auto GenerateCppIncludesHeaderCode(
  71. Context& context, llvm::ArrayRef<Parse::Tree::PackagingNames> imports)
  72. -> std::string {
  73. RawStringOstream code_stream;
  74. for (const Parse::Tree::PackagingNames& import : imports) {
  75. if (import.inline_body_id.has_value()) {
  76. // Expand `import Cpp inline "code";` directly into the specified code.
  77. auto code_token = context.parse_tree().node_token(import.inline_body_id);
  78. AppendInlineCode(context, code_stream, code_token,
  79. context.string_literal_values().Get(
  80. context.tokens().GetStringLiteralValue(code_token)));
  81. // TODO: Inject a clang pragma here to produce an error if there are
  82. // unclosed scopes at the end of this inline C++ fragment.
  83. } else if (import.library_id.has_value()) {
  84. // Translate `import Cpp library "foo.h";` into `#include "foo.h"`.
  85. GenerateLineMarker(context, code_stream,
  86. context.tokens().GetLineNumber(
  87. context.parse_tree().node_token(import.node_id)));
  88. auto name = context.string_literal_values().Get(import.library_id);
  89. if (name.starts_with('<') && name.ends_with('>')) {
  90. code_stream << "#include <"
  91. << FormatEscaped(name.drop_front().drop_back()) << ">\n";
  92. } else {
  93. code_stream << "#include \"" << FormatEscaped(name) << "\"\n";
  94. }
  95. }
  96. }
  97. return code_stream.TakeStr();
  98. }
  99. // Adds the given source location and an `ImportIRInst` referring to it in
  100. // `ImportIRId::Cpp`.
  101. static auto AddImportIRInst(SemIR::File& file,
  102. clang::SourceLocation clang_source_loc)
  103. -> SemIR::ImportIRInstId {
  104. SemIR::ClangSourceLocId clang_source_loc_id =
  105. file.clang_source_locs().Add(clang_source_loc);
  106. return file.import_ir_insts().Add(SemIR::ImportIRInst(clang_source_loc_id));
  107. }
  108. namespace {
  109. // Used to convert Clang diagnostics to Carbon diagnostics.
  110. //
  111. // Handling of Clang notes is a little subtle: as far as Clang is concerned,
  112. // notes are separate diagnostics, not connected to the error or warning that
  113. // precedes them. But in Carbon's diagnostics system, notes are part of the
  114. // enclosing diagnostic. To handle this, we buffer Clang diagnostics until we
  115. // reach a point where we know we're not in the middle of a diagnostic, and then
  116. // emit a diagnostic along with all of its notes. This is triggered when adding
  117. // or removing a Carbon context note, which could otherwise get attached to the
  118. // wrong C++ diagnostics, and at the end of the Carbon program.
  119. class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
  120. public:
  121. // Creates an instance with the location that triggers calling Clang. The
  122. // `context` is not stored here, and the diagnostics consumer is expected to
  123. // outlive it.
  124. explicit CarbonClangDiagnosticConsumer(
  125. Context& context, std::shared_ptr<clang::CompilerInvocation> invocation)
  126. : sem_ir_(&context.sem_ir()),
  127. emitter_(&context.emitter()),
  128. invocation_(std::move(invocation)) {
  129. emitter_->AddFlushFn([this] { EmitDiagnostics(); });
  130. }
  131. ~CarbonClangDiagnosticConsumer() override {
  132. // Do not inspect `emitter_` here; it's typically destroyed before the
  133. // consumer is.
  134. // TODO: If Clang produces diagnostics after check finishes, they'll get
  135. // added to the list of pending diagnostics and never emitted.
  136. CARBON_CHECK(diagnostic_infos_.empty(),
  137. "Missing flush before destroying diagnostic consumer");
  138. }
  139. // Generates a Carbon warning for each Clang warning and a Carbon error for
  140. // each Clang error or fatal.
  141. auto HandleDiagnostic(clang::DiagnosticsEngine::Level diag_level,
  142. const clang::Diagnostic& info) -> void override {
  143. DiagnosticConsumer::HandleDiagnostic(diag_level, info);
  144. SemIR::ImportIRInstId clang_import_ir_inst_id =
  145. AddImportIRInst(*sem_ir_, info.getLocation());
  146. llvm::SmallString<256> message;
  147. info.FormatDiagnostic(message);
  148. // Render a code snippet including any highlighted ranges and fixit hints.
  149. // TODO: Also include the #include stack and macro expansion stack in the
  150. // diagnostic output in some way.
  151. RawStringOstream snippet_stream;
  152. if (!info.hasSourceManager()) {
  153. // If we don't have a source manager, this is an error from early in the
  154. // frontend. Don't produce a snippet.
  155. CARBON_CHECK(info.getLocation().isInvalid());
  156. } else {
  157. CodeContextRenderer(snippet_stream, invocation_->getLangOpts(),
  158. invocation_->getDiagnosticOpts())
  159. .emitDiagnostic(
  160. clang::FullSourceLoc(info.getLocation(), info.getSourceManager()),
  161. diag_level, message, info.getRanges(), info.getFixItHints());
  162. }
  163. diagnostic_infos_.push_back({.level = diag_level,
  164. .import_ir_inst_id = clang_import_ir_inst_id,
  165. .message = message.str().str(),
  166. .snippet = snippet_stream.TakeStr()});
  167. }
  168. // Returns the diagnostic to use for a given Clang diagnostic level.
  169. static auto GetDiagnostic(clang::DiagnosticsEngine::Level level)
  170. -> const Diagnostics::DiagnosticBase<std::string>& {
  171. switch (level) {
  172. case clang::DiagnosticsEngine::Ignored: {
  173. CARBON_FATAL("Emitting an ignored diagnostic");
  174. break;
  175. }
  176. case clang::DiagnosticsEngine::Note: {
  177. CARBON_DIAGNOSTIC(CppInteropParseNote, Note, "{0}", std::string);
  178. return CppInteropParseNote;
  179. }
  180. case clang::DiagnosticsEngine::Remark:
  181. case clang::DiagnosticsEngine::Warning: {
  182. // TODO: Add a distinct Remark level to Carbon diagnostics, and stop
  183. // mapping remarks to warnings.
  184. CARBON_DIAGNOSTIC(CppInteropParseWarning, Warning, "{0}", std::string);
  185. return CppInteropParseWarning;
  186. }
  187. case clang::DiagnosticsEngine::Error:
  188. case clang::DiagnosticsEngine::Fatal: {
  189. CARBON_DIAGNOSTIC(CppInteropParseError, Error, "{0}", std::string);
  190. return CppInteropParseError;
  191. }
  192. }
  193. }
  194. // Outputs Carbon diagnostics based on the collected Clang diagnostics. Must
  195. // be called after the AST is set in the context.
  196. auto EmitDiagnostics() -> void {
  197. CARBON_CHECK(
  198. sem_ir_->cpp_file(),
  199. "Attempted to emit C++ diagnostics before the C++ file is set");
  200. for (size_t i = 0; i != diagnostic_infos_.size(); ++i) {
  201. const ClangDiagnosticInfo& info = diagnostic_infos_[i];
  202. auto builder = emitter_->Build(SemIR::LocId(info.import_ir_inst_id),
  203. GetDiagnostic(info.level), info.message);
  204. builder.OverrideSnippet(info.snippet);
  205. for (; i + 1 < diagnostic_infos_.size() &&
  206. diagnostic_infos_[i + 1].level == clang::DiagnosticsEngine::Note;
  207. ++i) {
  208. const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1];
  209. builder
  210. .Note(SemIR::LocId(note_info.import_ir_inst_id),
  211. GetDiagnostic(note_info.level), note_info.message)
  212. .OverrideSnippet(note_info.snippet);
  213. }
  214. // TODO: This will apply all current Carbon annotation functions. We
  215. // should instead track how Clang's context notes and Carbon's annotation
  216. // functions are interleaved, and interleave the notes in the same order.
  217. builder.Emit();
  218. }
  219. diagnostic_infos_.clear();
  220. }
  221. private:
  222. // A diagnostics renderer based on clang's TextDiagnostic that captures just
  223. // the code context (the snippet).
  224. class CodeContextRenderer : public clang::TextDiagnostic {
  225. protected:
  226. using TextDiagnostic::TextDiagnostic;
  227. void emitDiagnosticMessage(
  228. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  229. clang::DiagnosticsEngine::Level /*level*/, llvm::StringRef /*message*/,
  230. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/,
  231. clang::DiagOrStoredDiag /*info*/) override {}
  232. void emitDiagnosticLoc(
  233. clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/,
  234. clang::DiagnosticsEngine::Level /*level*/,
  235. llvm::ArrayRef<clang::CharSourceRange> /*ranges*/) override {}
  236. // emitCodeContext is inherited from clang::TextDiagnostic.
  237. void emitIncludeLocation(clang::FullSourceLoc /*loc*/,
  238. clang::PresumedLoc /*ploc*/) override {}
  239. void emitImportLocation(clang::FullSourceLoc /*loc*/,
  240. clang::PresumedLoc /*ploc*/,
  241. llvm::StringRef /*module_name*/) override {}
  242. void emitBuildingModuleLocation(clang::FullSourceLoc /*loc*/,
  243. clang::PresumedLoc /*ploc*/,
  244. llvm::StringRef /*module_name*/) override {}
  245. // beginDiagnostic and endDiagnostic are inherited from
  246. // clang::TextDiagnostic in case it wants to do any setup / teardown work.
  247. };
  248. // Information on a Clang diagnostic that can be converted to a Carbon
  249. // diagnostic.
  250. struct ClangDiagnosticInfo {
  251. // The Clang diagnostic level.
  252. clang::DiagnosticsEngine::Level level;
  253. // The ID of the ImportIR instruction referring to the Clang source
  254. // location.
  255. SemIR::ImportIRInstId import_ir_inst_id;
  256. // The Clang diagnostic textual message.
  257. std::string message;
  258. // The code snippet produced by clang.
  259. std::string snippet;
  260. };
  261. // The Carbon file that this C++ compilation is attached to.
  262. SemIR::File* sem_ir_;
  263. // The diagnostic emitter that we're emitting diagnostics into.
  264. DiagnosticEmitterBase* emitter_;
  265. // The compiler invocation that is producing the diagnostics.
  266. std::shared_ptr<clang::CompilerInvocation> invocation_;
  267. // Collects the information for all Clang diagnostics to be converted to
  268. // Carbon diagnostics after the context has been initialized with the Clang
  269. // AST.
  270. llvm::SmallVector<ClangDiagnosticInfo> diagnostic_infos_;
  271. };
  272. // A wrapper around a clang::CompilerInvocation that allows us to make a shallow
  273. // copy of most of the invocation and only make a deep copy of the parts that we
  274. // want to change.
  275. //
  276. // clang::CowCompilerInvocation almost allows this, but doesn't derive from
  277. // CompilerInvocation or support shallow copies from a CompilerInvocation, so is
  278. // not useful to us as we can't build an ASTUnit from it.
  279. class ShallowCopyCompilerInvocation : public clang::CompilerInvocation {
  280. public:
  281. explicit ShallowCopyCompilerInvocation(
  282. const clang::CompilerInvocation& invocation) {
  283. shallow_copy_assign(invocation);
  284. // Make a deep copy of options that we modify.
  285. FrontendOpts = std::make_shared<clang::FrontendOptions>(*FrontendOpts);
  286. PPOpts = std::make_shared<clang::PreprocessorOptions>(*PPOpts);
  287. }
  288. };
  289. // Provides clang AST nodes representing Carbon SemIR entities.
  290. class CarbonExternalASTSource : public clang::ExternalASTSource {
  291. public:
  292. explicit CarbonExternalASTSource(Context* context) : context_(context) {}
  293. auto StartTranslationUnit(clang::ASTConsumer* consumer) -> void override;
  294. // Look up decls for `decl_name` inside `decl_context`, adding the decls to
  295. // `decl_context`. Returns true if any decls were added.
  296. auto FindExternalVisibleDeclsByName(
  297. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  298. const clang::DeclContext* original_decl_context) -> bool override;
  299. auto CompleteType(clang::TagDecl* tag_decl) -> void override;
  300. auto layoutRecordType(
  301. const clang::RecordDecl* record_decl, uint64_t& size, uint64_t& alignment,
  302. llvm::DenseMap<const clang::FieldDecl*, uint64_t>& field_offsets,
  303. llvm::DenseMap<const clang::CXXRecordDecl*, clang::CharUnits>&
  304. base_offsets,
  305. llvm::DenseMap<const clang::CXXRecordDecl*, clang::CharUnits>&
  306. vbase_offsets) -> bool override;
  307. private:
  308. // Builds the top-level C++ namespace `Carbon` and adds it to the translation
  309. // unit.
  310. auto BuildCarbonNamespace() -> void;
  311. // Map a Carbon entity to a Clang NamedDecl. Returns null if the entity cannot
  312. // currently be represented in C++.
  313. auto MapInstIdToClangDeclOrType(LookupResult lookup)
  314. -> std::variant<clang::NamedDecl*, clang::QualType>;
  315. // Get a current best-effort location for the current position within C++
  316. // processing.
  317. auto GetCurrentCppLocId() -> SemIR::LocId {
  318. auto* cpp_context = context_->cpp_context();
  319. CARBON_CHECK(cpp_context);
  320. // Use the current token location when parsing.
  321. auto clang_source_loc = cpp_context->parser().getCurToken().getLocation();
  322. if (auto& code_synthesis_contexts =
  323. cpp_context->sema().CodeSynthesisContexts;
  324. !code_synthesis_contexts.empty()) {
  325. // Use the current point of instantiation during template instantiation.
  326. clang_source_loc = code_synthesis_contexts.back().PointOfInstantiation;
  327. }
  328. // TODO: Refactor with AddImportIRInst in import.cpp.
  329. SemIR::ClangSourceLocId clang_source_loc_id =
  330. context_->sem_ir().clang_source_locs().Add(clang_source_loc);
  331. return context_->import_ir_insts().Add(
  332. SemIR::ImportIRInst(clang_source_loc_id));
  333. }
  334. Check::Context* context_;
  335. };
  336. } // namespace
  337. void CarbonExternalASTSource::StartTranslationUnit(
  338. clang::ASTConsumer* /*Consumer*/) {
  339. BuildCarbonNamespace();
  340. }
  341. auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
  342. -> std::variant<clang::NamedDecl*, clang::QualType> {
  343. auto target_inst_id = lookup.scope_result.target_inst_id();
  344. auto target_const_id = context_->constant_values().Get(target_inst_id);
  345. auto target_inst = context_->constant_values().GetInst(target_const_id);
  346. if (target_inst.type_id() == SemIR::TypeType::TypeId) {
  347. auto type_id =
  348. context_->types().GetTypeIdForTypeConstantId(target_const_id);
  349. auto type = MapToCppType(*context_, type_id);
  350. if (type.isNull()) {
  351. context_->TODO(GetCurrentCppLocId(), "interop with unsupported type");
  352. return nullptr;
  353. }
  354. return type;
  355. }
  356. CARBON_KIND_SWITCH(target_inst) {
  357. case CARBON_KIND(SemIR::Namespace namespace_info): {
  358. auto* decl_context =
  359. ExportNameScopeToCpp(*context_, SemIR::LocId(target_inst_id),
  360. namespace_info.name_scope_id);
  361. if (!decl_context) {
  362. return nullptr;
  363. }
  364. if (isa<clang::TranslationUnitDecl>(decl_context)) {
  365. context_->TODO(GetCurrentCppLocId(),
  366. "interop with translation unit decl");
  367. return nullptr;
  368. }
  369. return cast<clang::NamedDecl>(decl_context);
  370. }
  371. case SemIR::StructValue::Kind: {
  372. auto callee = GetCallee(context_->sem_ir(), target_inst_id);
  373. auto* callee_function = std::get_if<SemIR::CalleeFunction>(&callee);
  374. if (!callee_function) {
  375. return nullptr;
  376. }
  377. const SemIR::Function& function =
  378. context_->functions().Get(callee_function->function_id);
  379. if (function.clang_decl_id.has_value()) {
  380. return cast<clang::NamedDecl>(
  381. context_->clang_decls().Get(function.clang_decl_id).key.decl);
  382. }
  383. return ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id),
  384. callee_function->function_id);
  385. }
  386. case CARBON_KIND(SemIR::FieldDecl field_decl): {
  387. return ExportFieldToCpp(*context_, target_inst_id, field_decl);
  388. }
  389. default:
  390. return nullptr;
  391. }
  392. }
  393. auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
  394. static const llvm::StringLiteral carbon_namespace_name = "Carbon";
  395. auto& ast_context = context_->ast_context();
  396. auto* identifier = &ast_context.Idents.get(carbon_namespace_name);
  397. // Create the namespace and add it to the translation unit scope.
  398. auto* decl_context = ast_context.getTranslationUnitDecl();
  399. auto* carbon_cpp_namespace = clang::NamespaceDecl::Create(
  400. ast_context, decl_context, /*Inline=*/false, clang::SourceLocation(),
  401. clang::SourceLocation(), identifier, /*PrevDecl=*/nullptr,
  402. /*Nested=*/false);
  403. decl_context->addDecl(carbon_cpp_namespace);
  404. // We provide custom lookup results within this namespace.
  405. carbon_cpp_namespace->setHasExternalVisibleStorage();
  406. // Register this file's package scope as corresponding to the `Carbon`
  407. // namespace in C++.
  408. // TODO: For mangling purposes, include the package as a sub-namespace.
  409. auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(carbon_cpp_namespace);
  410. auto clang_decl_id = context_->clang_decls().Add(
  411. {.key = key, .inst_id = SemIR::Namespace::PackageInstId});
  412. context_->name_scopes()
  413. .Get(SemIR::NameScopeId::Package)
  414. .set_clang_decl_context_id(clang_decl_id, /*is_cpp_scope=*/false);
  415. }
  416. auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
  417. const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
  418. const clang::DeclContext* /*OriginalDC*/) -> bool {
  419. // Find the Carbon declaration corresponding to this Clang declaration.
  420. auto* decl = cast<clang::Decl>(
  421. const_cast<clang::DeclContext*>(decl_context->getPrimaryContext()));
  422. auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(decl);
  423. auto decl_id = context_->clang_decls().Lookup(key);
  424. CARBON_CHECK(
  425. decl_id.has_value(),
  426. "The DeclContext should already be associated with a Carbon InstId.");
  427. auto decl_context_inst_id = context_->clang_decls().Get(decl_id).inst_id;
  428. llvm::SmallVector<Check::LookupScope> lookup_scopes;
  429. // LocId::None seems fine here because we shouldn't produce any diagnostics
  430. // here - completeness should've been checked by clang before this point.
  431. if (!AppendLookupScopesForConstant(
  432. *context_, SemIR::LocId::None,
  433. context_->constant_values().Get(decl_context_inst_id),
  434. SemIR::ConstantId::None, &lookup_scopes)) {
  435. return false;
  436. }
  437. auto* identifier = decl_name.getAsIdentifierInfo();
  438. if (!identifier) {
  439. // Only supporting identifiers for now.
  440. return false;
  441. }
  442. auto name_id = AddIdentifierName(*context_, identifier->getName());
  443. // `required=false` so Carbon doesn't diagnose a failure, let Clang diagnose
  444. // it or even SFINAE.
  445. LookupResult result =
  446. LookupQualifiedName(*context_, SemIR::LocId::None, name_id, lookup_scopes,
  447. /*required=*/false);
  448. if (!result.scope_result.is_found()) {
  449. return false;
  450. }
  451. // Map the found Carbon entity to a Clang NamedDecl.
  452. CARBON_KIND_SWITCH(MapInstIdToClangDeclOrType(result)) {
  453. case CARBON_KIND(clang::NamedDecl* clang_decl): {
  454. if (clang_decl) {
  455. SetExternalVisibleDeclsForName(decl_context, decl_name, {clang_decl});
  456. return true;
  457. } else {
  458. SetNoExternalVisibleDeclsForName(decl_context, decl_name);
  459. return false;
  460. }
  461. }
  462. case CARBON_KIND(clang::QualType type): {
  463. // Create a typedef declaration to model the type result.
  464. // TODO: If the type is a tag type that was declared with this name in
  465. // this context, use the tag decl directly.
  466. auto& ast_context = context_->ast_context();
  467. auto loc = GetCppLocation(
  468. *context_, SemIR::LocId(result.scope_result.target_inst_id()));
  469. auto* typedef_decl = clang::TypedefDecl::Create(
  470. ast_context, const_cast<clang::DeclContext*>(decl_context), loc, loc,
  471. identifier, ast_context.getTrivialTypeSourceInfo(type, loc));
  472. if (isa<clang::CXXRecordDecl>(decl_context)) {
  473. typedef_decl->setAccess(
  474. MapToCppAccess(result.scope_result.access_kind()));
  475. }
  476. SetExternalVisibleDeclsForName(decl_context, decl_name, {typedef_decl});
  477. return true;
  478. }
  479. }
  480. }
  481. // If this declaration declares a class type that is "owned" by Carbon, and not
  482. // imported from C++, returns the corresponding type ID and `ClassType`.
  483. // Otherwise returns `nullopt`.
  484. static auto GetAsCarbonOwnedClass(Context& context,
  485. const clang::TagDecl* tag_decl)
  486. -> std::optional<std::pair<SemIR::TypeId, SemIR::ClassType>> {
  487. // Quickly check whether we could possibly own this class.
  488. // TODO: Once we multiplex with the ASTReader, handle
  489. // ASTReader::completeVisibleDeclsMap setting this to `false`.
  490. if (!tag_decl->hasExternalVisibleStorage()) {
  491. return std::nullopt;
  492. }
  493. auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(
  494. const_cast<clang::TagDecl*>(tag_decl->getFirstDecl()));
  495. auto clang_decl_id = context.clang_decls().Lookup(key);
  496. if (!clang_decl_id.has_value()) {
  497. return std::nullopt;
  498. }
  499. auto inst_id = context.clang_decls().Get(clang_decl_id).inst_id;
  500. auto const_id = context.constant_values().Get(inst_id);
  501. if (!const_id.has_value()) {
  502. return std::nullopt;
  503. }
  504. auto class_type =
  505. context.constant_values().TryGetInstAs<SemIR::ClassType>(const_id);
  506. if (!class_type) {
  507. return std::nullopt;
  508. }
  509. // Determine whether this class was imported from C++.
  510. // TODO: This currently can't happen, because only Carbon classes have
  511. // external lexical storage, but will happen once we support importing C++
  512. // classes from AST files. Add a test once that is supported.
  513. // TODO: Consider setting `extern_library_id` on classes imported from C++ to
  514. // indicate the current file does not own them.
  515. const auto& class_info = context.classes().Get(class_type->class_id);
  516. if (class_info.parent_scope_id.has_value() &&
  517. context.name_scopes().Get(class_info.parent_scope_id).is_cpp_scope()) {
  518. return std::nullopt;
  519. }
  520. auto class_type_id = context.types().GetTypeIdForTypeConstantId(const_id);
  521. return std::make_pair(class_type_id, *class_type);
  522. }
  523. auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void {
  524. auto* class_decl = dyn_cast<clang::CXXRecordDecl>(tag_decl);
  525. if (!class_decl) {
  526. // TODO: If we start producing clang EnumTypes, we may have to handle them
  527. // here too.
  528. return;
  529. }
  530. auto carbon_class_info = GetAsCarbonOwnedClass(*context_, tag_decl);
  531. if (!carbon_class_info) {
  532. return;
  533. }
  534. auto& [class_type_id, class_type] = *carbon_class_info;
  535. auto context_fn = [](DiagnosticContextBuilder& /*builder*/) -> void {};
  536. if (!RequireCompleteType(*context_, class_type_id, GetCurrentCppLocId(),
  537. context_fn)) {
  538. return;
  539. }
  540. auto& class_info = context_->classes().Get(class_type.class_id);
  541. class_decl->startDefinition();
  542. CARBON_CHECK(class_decl->hasDefinition());
  543. // If the Carbon class has a base class that we can map into C++, add that as
  544. // a C++ base class.
  545. auto base_type_id =
  546. class_info.GetBaseType(context_->sem_ir(), class_type.specific_id);
  547. if (base_type_id.has_value()) {
  548. auto base_loc = GetCppLocation(*context_, SemIR::LocId(class_info.base_id));
  549. if (auto base_type = MapToCppType(*context_, base_type_id);
  550. !base_type.isNull() && base_type->isStructureOrClassType() &&
  551. !context_->clang_sema().RequireCompleteType(
  552. base_loc, base_type, clang::diag::err_incomplete_base_class)) {
  553. bool is_virtual = false;
  554. bool is_base_of_class = true;
  555. clang::CXXBaseSpecifier base(
  556. clang::SourceRange(base_loc, base_loc), is_virtual, is_base_of_class,
  557. clang::AS_public,
  558. context_->ast_context().getTrivialTypeSourceInfo(base_type, base_loc),
  559. /*EllipsisLoc=*/clang::SourceLocation());
  560. clang::CXXBaseSpecifier* bases[1] = {&base};
  561. CARBON_CHECK(class_decl->hasDefinition());
  562. class_decl->setBases(bases, 1);
  563. }
  564. }
  565. ExportAllFieldsToCpp(*context_, class_info);
  566. // TODO: Import any special member functions that affect class properties.
  567. class_decl->completeDefinition();
  568. }
  569. auto CarbonExternalASTSource::layoutRecordType(
  570. const clang::RecordDecl* record_decl, uint64_t& size, uint64_t& alignment,
  571. llvm::DenseMap<const clang::FieldDecl*, uint64_t>& field_offsets,
  572. llvm::DenseMap<const clang::CXXRecordDecl*, clang::CharUnits>& base_offsets,
  573. llvm::DenseMap<const clang::CXXRecordDecl*, clang::CharUnits>&
  574. vbase_offsets) -> bool {
  575. auto carbon_class_info = GetAsCarbonOwnedClass(*context_, record_decl);
  576. if (!carbon_class_info) {
  577. return false;
  578. }
  579. auto& [class_type_id, class_type] = *carbon_class_info;
  580. // Clang should not have asked for the layout of an incomplete type, but check
  581. // now to be sure, and to generate a specific definition if needed.
  582. // TODO: Add a test for layout of a specific class once they're supported in
  583. // general.
  584. CompleteTypeOrCheckFail(*context_, class_type_id);
  585. // Set the overall size and alignment. We round up the size to an integer
  586. // number of bytes in order to avoid surprising Clang too much.
  587. auto layout = context_->sem_ir()
  588. .types()
  589. .GetCompleteTypeInfo(class_type_id)
  590. .object_layout;
  591. size = layout.size.bytes() * 8;
  592. alignment = layout.alignment.bits();
  593. // Fill in `field_offsets`.
  594. CalculateCppFieldOffsets(*context_, class_type.class_id, field_offsets);
  595. // Add offset for base class, if any.
  596. if (const auto* class_decl = dyn_cast<clang::CXXRecordDecl>(record_decl);
  597. class_decl && !class_decl->bases().empty()) {
  598. CARBON_CHECK(class_decl->getNumBases() == 1,
  599. "Carbon class with multiple bases");
  600. const auto& base = *class_decl->bases_begin();
  601. // TODO: If this class introduced a vptr, the base will be at an offset of
  602. // `sizeof(void*)`, not 0.
  603. base_offsets.insert(
  604. {base.getType()->getAsCXXRecordDecl()->getCanonicalDecl(),
  605. clang::CharUnits::Zero()});
  606. // TODO: Support deriving from a C++ class with virtual bases.
  607. CARBON_CHECK(class_decl->getNumVBases() == 0,
  608. "Carbon class with multiple bases");
  609. static_cast<void>(vbase_offsets);
  610. }
  611. return true;
  612. }
  613. // Parses a sequence of top-level declarations and forms a corresponding
  614. // representation in the Clang AST. Unlike clang::ParseAST, does not finish the
  615. // translation unit when EOF is reached.
  616. static auto ParseTopLevelDecls(clang::Parser& parser,
  617. clang::ASTConsumer& consumer) -> void {
  618. // Don't allow C++20 module declarations in inline Cpp code fragments.
  619. auto module_import_state = clang::Sema::ModuleImportState::NotACXX20Module;
  620. // Parse top-level declarations until we see EOF. Do not parse EOF, as that
  621. // will cause the parser to end the translation unit prematurely.
  622. while (parser.getCurToken().isNot(clang::tok::eof)) {
  623. clang::Parser::DeclGroupPtrTy decl_group;
  624. bool eof = parser.ParseTopLevelDecl(decl_group, module_import_state);
  625. CARBON_CHECK(!eof, "Should not parse decls at EOF");
  626. if (decl_group && !consumer.HandleTopLevelDecl(decl_group.get())) {
  627. // If the consumer rejects the declaration, bail out of parsing.
  628. //
  629. // TODO: In this case, we shouldn't parse any more declarations even in
  630. // separate inline C++ fragments. But our current AST consumer only ever
  631. // returns true.
  632. break;
  633. }
  634. }
  635. }
  636. namespace {
  637. // An action and a set of registered Clang callbacks used to generate an AST
  638. // from a set of Cpp imports.
  639. class GenerateASTAction : public clang::ASTFrontendAction {
  640. public:
  641. explicit GenerateASTAction(Context& context) : context_(&context) {}
  642. protected:
  643. auto CreateASTConsumer(clang::CompilerInstance& clang_instance,
  644. llvm::StringRef /*file*/)
  645. -> std::unique_ptr<clang::ASTConsumer> override {
  646. auto& cpp_file = *context_->sem_ir().cpp_file();
  647. if (!cpp_file.llvm_context()) {
  648. return std::make_unique<clang::ASTConsumer>();
  649. }
  650. auto code_generator =
  651. std::unique_ptr<clang::CodeGenerator>(clang::CreateLLVMCodeGen(
  652. cpp_file.diagnostics(), context_->sem_ir().filename(),
  653. clang_instance.getVirtualFileSystemPtr(),
  654. clang_instance.getHeaderSearchOpts(),
  655. clang_instance.getPreprocessorOpts(),
  656. clang_instance.getCodeGenOpts(), *cpp_file.llvm_context()));
  657. cpp_file.SetCodeGenerator(code_generator.get());
  658. return code_generator;
  659. }
  660. auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
  661. -> bool override {
  662. // TODO: `clang.getPreprocessor().enableIncrementalProcessing();` to avoid
  663. // the TU scope getting torn down before we're done parsing macros.
  664. return true;
  665. }
  666. // Parse the imports and inline C++ fragments. This is notionally very similar
  667. // to `clang::ParseAST`, which `ASTFrontendAction::ExecuteAction` calls, but
  668. // this version doesn't parse C++20 modules and stops just before reaching the
  669. // end of the translation unit.
  670. auto ExecuteAction() -> void override {
  671. clang::CompilerInstance& clang_instance = getCompilerInstance();
  672. clang_instance.createSema(getTranslationUnitKind(),
  673. /*CompletionConsumer=*/nullptr);
  674. auto parser_ptr = std::make_unique<clang::Parser>(
  675. clang_instance.getPreprocessor(), clang_instance.getSema(),
  676. /*SkipFunctionBodies=*/false);
  677. auto& parser = *parser_ptr;
  678. clang_instance.getPreprocessor().EnterMainSourceFile();
  679. parser.Initialize();
  680. context_->set_cpp_context(
  681. std::make_unique<CppContext>(clang_instance, std::move(parser_ptr)));
  682. if (auto* source = clang_instance.getASTContext().getExternalSource()) {
  683. source->StartTranslationUnit(&clang_instance.getASTConsumer());
  684. }
  685. clang_instance.getSema().ActOnStartOfTranslationUnit();
  686. ParseTopLevelDecls(parser, clang_instance.getASTConsumer());
  687. }
  688. private:
  689. Context* context_;
  690. };
  691. } // namespace
  692. auto GenerateAst(Context& context,
  693. llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
  694. llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
  695. llvm::LLVMContext* llvm_context,
  696. std::shared_ptr<clang::CompilerInvocation> base_invocation)
  697. -> bool {
  698. CARBON_CHECK(!context.cpp_context());
  699. CARBON_CHECK(!context.sem_ir().cpp_file());
  700. auto invocation =
  701. std::make_shared<ShallowCopyCompilerInvocation>(*base_invocation);
  702. // Ask Clang to not leak memory.
  703. invocation->getFrontendOpts().DisableFree = false;
  704. // Build a diagnostics engine.
  705. llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(
  706. clang::CompilerInstance::createDiagnostics(
  707. *fs, invocation->getDiagnosticOpts(),
  708. new CarbonClangDiagnosticConsumer(context, invocation),
  709. /*ShouldOwnClient=*/true));
  710. // Extract the input from the frontend invocation and make sure it makes
  711. // sense.
  712. const auto& inputs = invocation->getFrontendOpts().Inputs;
  713. CARBON_CHECK(inputs.size() == 1 &&
  714. inputs[0].getKind().getLanguage() == clang::Language::CXX &&
  715. inputs[0].getKind().getFormat() == clang::InputKind::Source);
  716. llvm::StringRef file_name = inputs[0].getFile();
  717. // Remap the imports file name to the corresponding `#include`s.
  718. // TODO: Modify the frontend options to specify this memory buffer as input
  719. // instead of remapping the file.
  720. std::string includes = GenerateCppIncludesHeaderCode(context, imports);
  721. auto includes_buffer =
  722. llvm::MemoryBuffer::getMemBufferCopy(includes, file_name);
  723. invocation->getPreprocessorOpts().addRemappedFile(file_name,
  724. includes_buffer.release());
  725. auto clang_instance_ptr =
  726. std::make_unique<clang::CompilerInstance>(invocation);
  727. auto& clang_instance = *clang_instance_ptr;
  728. context.sem_ir().set_cpp_file(std::make_unique<SemIR::CppFile>(
  729. std::move(clang_instance_ptr), llvm_context));
  730. clang_instance.setDiagnostics(diags);
  731. clang_instance.setVirtualFileSystem(fs);
  732. clang_instance.createFileManager();
  733. clang_instance.createSourceManager();
  734. if (!clang_instance.createTarget()) {
  735. return false;
  736. }
  737. GenerateASTAction action(context);
  738. if (!action.BeginSourceFile(clang_instance, inputs[0])) {
  739. return false;
  740. }
  741. auto& ast = clang_instance.getASTContext();
  742. // TODO: Clang's modules support is implemented as an ExternalASTSource
  743. // (ASTReader) and there's no multiplexing support for ExternalASTSources at
  744. // the moment - so registering CarbonExternalASTSource breaks Clang modules
  745. // support. Implement multiplexing support (possibly in Clang) to restore
  746. // modules functionality.
  747. ast.setExternalSource(
  748. llvm::makeIntrusiveRefCnt<CarbonExternalASTSource>(&context));
  749. if (llvm::Error error = action.Execute()) {
  750. // `Execute` currently never fails, but its contract allows it to.
  751. context.TODO(SemIR::LocId::None, "failed to execute clang action: " +
  752. llvm::toString(std::move(error)));
  753. return false;
  754. }
  755. // Flush any diagnostics. We know we're not part-way through emitting a
  756. // diagnostic now.
  757. context.emitter().Flush();
  758. return true;
  759. }
  760. auto InjectAstFromInlineCode(Context& context, SemIR::LocId loc_id,
  761. llvm::StringRef source_code) -> void {
  762. auto* cpp_context = context.cpp_context();
  763. CARBON_CHECK(cpp_context);
  764. clang::Sema& sema = cpp_context->sema();
  765. clang::Preprocessor& preprocessor = sema.getPreprocessor();
  766. clang::Parser& parser = cpp_context->parser();
  767. RawStringOstream code_stream;
  768. AppendInlineCode(context, code_stream,
  769. context.parse_tree().node_token(loc_id.node_id()),
  770. source_code);
  771. auto buffer = llvm::MemoryBuffer::getMemBufferCopy(code_stream.TakeStr(),
  772. "<inline c++>");
  773. clang::FileID file_id =
  774. preprocessor.getSourceManager().createFileID(std::move(buffer));
  775. if (preprocessor.EnterSourceFile(file_id, nullptr, clang::SourceLocation())) {
  776. // Clang will have generated a suitable error. There's nothing more to do
  777. // here.
  778. return;
  779. }
  780. // The parser will typically have an EOF as its cached current token; consume
  781. // that so we can reach the newly-injected tokens.
  782. if (parser.getCurToken().is(clang::tok::eof)) {
  783. parser.ConsumeToken();
  784. }
  785. ParseTopLevelDecls(parser, sema.getASTConsumer());
  786. }
  787. auto FinishAst(Context& context) -> void {
  788. if (!context.cpp_context()) {
  789. return;
  790. }
  791. context.cpp_context()->sema().ActOnEndOfTranslationUnit();
  792. // We don't call FrontendAction::EndSourceFile, because that destroys the AST.
  793. context.set_cpp_context(nullptr);
  794. context.emitter().Flush();
  795. }
  796. } // namespace Carbon::Check