From 34a2e270f4412df2d829d5bc5892a6248713f321 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 4 Aug 2026 10:59:06 -0700 Subject: [PATCH] Fix C++ code generation in `--share-cpp-ast` mode (#7605) Instead of creating a CodeGenerator per CppDomain, and then crashing in lowering when we try to consume the same llvm Module multiple times, create a CodeGenerator for each CppFile within the domain. For now, we mulitplex all of Clang's ASTConsumer output to all code generators, which means that any strong external definitions within a Carbon file (for example, in an inline `Cpp` fragment) will be emitted to all output files in the same `CppDomain`, resulting in link errors due to symbol redefinitions. This will be addressed later. But this should be sufficient for Carbon compilations in which such symbols are not defined. We also don't yet attempt to classify which compilations will need C++ code generation, and instead create a clang `CodeGenerator` for every Carbon file that has C++ imports. For `carbom compile`, only one Carbon file will need code generation, and yet we still build multiple `CodeGenerator` objects in general. Fixing this requires more plumbing from the driver, and this will also be handled in a follow-up. Assisted-by: Gemini via Antigravity --- toolchain/check/check.cpp | 23 +- toolchain/check/cpp/domain.cpp | 14 +- toolchain/check/cpp/domain.h | 26 +- toolchain/check/cpp/generate_ast.cpp | 83 ++-- toolchain/check/cpp/generate_ast.h | 3 +- .../interop/cpp/basics/share_ast.carbon | 5 +- toolchain/driver/compile_driver.cpp | 28 +- toolchain/driver/compile_driver.h | 6 +- toolchain/lower/context.cpp | 19 +- toolchain/lower/context.h | 5 +- toolchain/lower/file_context.cpp | 30 +- toolchain/lower/file_context.h | 8 - toolchain/lower/handle_call.cpp | 11 +- toolchain/lower/lower.cpp | 2 +- .../testdata/function/generic/call.carbon | 6 +- .../function/generic/call_basic.carbon | 10 +- .../function/generic/call_deref_ptr.carbon | 10 +- .../generic/call_different_specific.carbon | 10 +- .../generic/call_specific_in_class.carbon | 20 +- .../interop/cpp/class/export/class.carbon | 6 +- .../interop/cpp/class/export/method.carbon | 4 +- .../cpp/class/import/constructor.carbon | 6 +- .../interop/cpp/class/import/method.carbon | 6 +- .../lower/testdata/interop/cpp/globals.carbon | 4 +- .../testdata/interop/cpp/operators.carbon | 94 ++--- .../testdata/interop/cpp/reference.carbon | 14 +- .../testdata/interop/cpp/share_ast.carbon | 364 ++++++++++++++++++ .../interop/cpp/std_initializer_list.carbon | 6 +- .../testdata/primitives/type_values.carbon | 14 +- toolchain/sem_ir/cpp_file.cpp | 14 +- toolchain/sem_ir/cpp_file.h | 20 +- toolchain/sem_ir/mangler.cpp | 2 +- 32 files changed, 641 insertions(+), 232 deletions(-) create mode 100644 toolchain/lower/testdata/interop/cpp/share_ast.carbon diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index b62ceb5ee2e4..899ae21eb7b9 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -507,14 +507,23 @@ auto CheckParseTrees( // Create C++ domains for Cpp imports. if (options.share_cpp_ast) { + llvm::SmallVector inputs; + for (auto& unit_info : unit_infos) { + if (unit_info.cpp_imports.empty()) { + continue; + } + inputs.push_back({.check_ir_id = unit_info.unit->sem_ir->check_ir_id(), + .filename = unit_info.unit->sem_ir->filename()}); + } // TODO: Remove dependence on properties of the first unit here. if (auto cpp_domain = InitializeCppDomain( - unit_infos.front().err_tracker, - unit_infos.front().unit->sem_ir->filename(), fs, + unit_infos.front().err_tracker, inputs, fs, unit_infos.front().unit->llvm_context, clang_invocation)) { cpp_domains.push_back(std::move(cpp_domain)); - for (auto& target_info : unit_infos) { - target_info.cpp_domain = cpp_domains.back().get(); + for (auto& unit_info : unit_infos) { + if (!unit_info.cpp_imports.empty()) { + unit_info.cpp_domain = cpp_domains.back().get(); + } } } } else { @@ -523,8 +532,10 @@ auto CheckParseTrees( continue; } if (auto cpp_domain = InitializeCppDomain( - unit_info.err_tracker, unit_info.unit->sem_ir->filename(), fs, - unit_info.unit->llvm_context, clang_invocation)) { + unit_info.err_tracker, + {{.check_ir_id = unit_info.unit->sem_ir->check_ir_id(), + .filename = unit_info.unit->sem_ir->filename()}}, + fs, unit_info.unit->llvm_context, clang_invocation)) { cpp_domains.push_back(std::move(cpp_domain)); unit_info.cpp_domain = cpp_domains.back().get(); } diff --git a/toolchain/check/cpp/domain.cpp b/toolchain/check/cpp/domain.cpp index 68a0f939fda3..527c7328706a 100644 --- a/toolchain/check/cpp/domain.cpp +++ b/toolchain/check/cpp/domain.cpp @@ -10,12 +10,20 @@ namespace Carbon::Check { CppDomain::CppDomain(std::shared_ptr clang_instance, std::unique_ptr parser, - clang::CodeGenerator* code_generator, + llvm::ArrayRef inputs, + llvm::ArrayRef code_generators, llvm::LLVMContext* llvm_context) : clang_instance_(std::move(clang_instance)), parser_(std::move(parser)), - code_generator_(code_generator), - llvm_context_(llvm_context) {} + llvm_context_(llvm_context) { + CARBON_CHECK(inputs.size() == code_generators.size()); + for (size_t i = 0; i < inputs.size(); ++i) { + auto res = + code_generators_.Insert(inputs[i].check_ir_id, code_generators[i]); + CARBON_CHECK(res.is_inserted(), "Duplicate CheckIRId {0} in CppDomain", + inputs[i].check_ir_id); + } +} CppDomain::~CppDomain() = default; diff --git a/toolchain/check/cpp/domain.h b/toolchain/check/cpp/domain.h index 8f08be69125e..1b586f7e4565 100644 --- a/toolchain/check/cpp/domain.h +++ b/toolchain/check/cpp/domain.h @@ -7,6 +7,11 @@ #include +#include "common/check.h" +#include "common/map.h" +#include "llvm/ADT/ArrayRef.h" +#include "toolchain/sem_ir/ids.h" + namespace clang { class CodeGenerator; class CompilerInstance; @@ -19,13 +24,20 @@ class LLVMContext; namespace Carbon::Check { +// An input Carbon file and its CheckIRId for C++ domain code generation. +struct CppInputFile { + SemIR::CheckIRId check_ir_id; + llvm::StringRef filename; +}; + // A C++ compilation domain, including a live Clang instance that can be used to // parse more code into that domain. May be shared across multiple Carbon files. class CppDomain { public: explicit CppDomain(std::shared_ptr clang_instance, std::unique_ptr parser, - clang::CodeGenerator* code_generator, + llvm::ArrayRef inputs, + llvm::ArrayRef code_generators, llvm::LLVMContext* llvm_context); ~CppDomain(); @@ -36,15 +48,19 @@ class CppDomain { return clang_instance_; } auto parser() const -> clang::Parser& { return *parser_; } - auto code_generator() const -> clang::CodeGenerator* { - return code_generator_; - } auto llvm_context() const -> llvm::LLVMContext* { return llvm_context_; } + auto GetCodeGenerator(SemIR::CheckIRId check_ir_id) const + -> clang::CodeGenerator* { + auto res = code_generators_.Lookup(check_ir_id); + CARBON_CHECK(res, "No CodeGenerator found for CheckIRId {0}", check_ir_id); + return res.value(); + } + private: std::shared_ptr clang_instance_; std::unique_ptr parser_; - clang::CodeGenerator* code_generator_ = nullptr; + Map code_generators_; llvm::LLVMContext* llvm_context_ = nullptr; }; diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index 36780e94e290..e46a03b2eb00 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -9,12 +9,14 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/FileManager.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/Parser.h" @@ -714,12 +716,12 @@ namespace { // from a set of Cpp imports. class GenerateASTAction : public clang::ASTFrontendAction { public: - explicit GenerateASTAction(llvm::StringRef filename, + explicit GenerateASTAction(llvm::ArrayRef inputs, llvm::LLVMContext* llvm_context) - : filename_(filename), llvm_context_(llvm_context) {} + : inputs_(inputs), llvm_context_(llvm_context) {} - auto code_generator() const -> clang::CodeGenerator* { - return code_generator_; + auto code_generators() const -> llvm::ArrayRef { + return code_generators_; } auto TakeParser() -> std::unique_ptr { @@ -733,15 +735,28 @@ class GenerateASTAction : public clang::ASTFrontendAction { if (!llvm_context_) { return std::make_unique(); } - auto code_generator = - std::unique_ptr(clang::CreateLLVMCodeGen( - clang_instance.getDiagnostics(), filename_, - clang_instance.getVirtualFileSystemPtr(), - clang_instance.getHeaderSearchOpts(), - clang_instance.getPreprocessorOpts(), - clang_instance.getCodeGenOpts(), *llvm_context_)); - code_generator_ = code_generator.get(); - return code_generator; + // Build a code generator for each object file we will be building. For now + // we assume that we want one object file per Carbon source file. + // TODO: Only build CodeGenerators for the files we're actually generating + // code for. + // TODO: Consider supporting generating code for multiple Carbon files into + // a single object file, for a faster `carbon build` mode. + std::vector> consumers; + for (const auto& input : inputs_) { + // TODO: Filter what goes into each code generator. If there are strong + // external C++ definitions in a Carbon file (for example, in inline C++ + // code), they should be emitted only in that one file. + auto code_generator = + std::unique_ptr(clang::CreateLLVMCodeGen( + clang_instance.getDiagnostics(), input.filename, + clang_instance.getVirtualFileSystemPtr(), + clang_instance.getHeaderSearchOpts(), + clang_instance.getPreprocessorOpts(), + clang_instance.getCodeGenOpts(), *llvm_context_)); + code_generators_.push_back(code_generator.get()); + consumers.push_back(std::move(code_generator)); + } + return std::make_unique(std::move(consumers)); } auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/) @@ -776,9 +791,9 @@ class GenerateASTAction : public clang::ASTFrontendAction { } private: - std::string filename_; + llvm::ArrayRef inputs_; llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* code_generator_ = nullptr; + llvm::SmallVector code_generators_; std::unique_ptr parser_; }; @@ -788,7 +803,7 @@ class GenerateASTAction : public clang::ASTFrontendAction { // creating a diagnostics engine, and parsing a dummy main file containing a // semicolon. Returns the initialized state, or null on failure. auto InitializeCppDomain( - Diagnostics::Consumer& consumer, llvm::StringRef filename, + Diagnostics::Consumer& consumer, llvm::ArrayRef inputs, llvm::IntrusiveRefCntPtr fs, llvm::LLVMContext* llvm_context, std::shared_ptr base_invocation) @@ -816,11 +831,12 @@ auto InitializeCppDomain( // Extract the input from the frontend invocation and make sure it makes // sense. - const auto& inputs = invocation->getFrontendOpts().Inputs; - CARBON_CHECK(inputs.size() == 1 && - inputs[0].getKind().getLanguage() == clang::Language::CXX && - inputs[0].getKind().getFormat() == clang::InputKind::Source); - llvm::StringRef file_name = inputs[0].getFile(); + const auto& clang_inputs = invocation->getFrontendOpts().Inputs; + CARBON_CHECK(clang_inputs.size() == 1); + CARBON_CHECK(clang_inputs[0].getKind().getLanguage() == clang::Language::CXX); + CARBON_CHECK(clang_inputs[0].getKind().getFormat() == + clang::InputKind::Source); + llvm::StringRef file_name = clang_inputs[0].getFile(); // Remap the input file to a dummy buffer containing a semicolon to start // with an empty AST. Clang requires at least one token in the main file @@ -841,8 +857,8 @@ auto InitializeCppDomain( return nullptr; } - GenerateASTAction action(filename, llvm_context); - if (!action.BeginSourceFile(*clang_instance, inputs[0])) { + GenerateASTAction action(inputs, llvm_context); + if (!action.BeginSourceFile(*clang_instance, clang_inputs[0])) { return nullptr; } @@ -880,9 +896,10 @@ auto InitializeCppDomain( auto parser = action.TakeParser(); CARBON_CHECK(parser); + CARBON_CHECK(action.code_generators().size() == inputs.size()); return std::make_unique(std::move(clang_instance), - std::move(parser), action.code_generator(), - llvm_context); + std::move(parser), inputs, + action.code_generators(), llvm_context); } auto GenerateAst(Context& context, @@ -900,23 +917,19 @@ auto GenerateAst(Context& context, auto clang_instance = domain.clang_instance_ptr(); + auto mangle_context = std::unique_ptr( + clang_instance->getASTContext().createMangleContext()); + // Set up CppFile for the current SemIR::File. - auto cpp_file = - std::make_unique(clang_instance, domain.llvm_context()); - if (domain.code_generator()) { - cpp_file->SetCodeGenerator(domain.code_generator()); - } - context.sem_ir().set_cpp_file(std::move(cpp_file)); + context.sem_ir().set_cpp_file(std::make_unique( + clang_instance, std::move(mangle_context), domain.llvm_context(), + domain.GetCodeGenerator(context.sem_ir().check_ir_id()))); // Set up CppContext for the current Context. context.set_cpp_context(std::make_unique( domain, MakeContextDiagnosticListener( *clang_instance->getDiagnostics().getClient(), context))); - // The AST context is now available, so the mangle context (used to compute - // stable identities for imported C++ types) can be created. - context.sem_ir().cpp_file()->CreateMangleContext(); - // Add an external source referring to this context. auto* multiplex_source = cast( context.ast_context().getExternalSource()); diff --git a/toolchain/check/cpp/generate_ast.h b/toolchain/check/cpp/generate_ast.h index 0a6794527be6..733c8eddba06 100644 --- a/toolchain/check/cpp/generate_ast.h +++ b/toolchain/check/cpp/generate_ast.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/VirtualFileSystem.h" #include "toolchain/check/context.h" +#include "toolchain/check/cpp/domain.h" #include "toolchain/parse/tree.h" #include "toolchain/sem_ir/ids.h" @@ -35,7 +36,7 @@ class CppDomain; // within one or more Carbon files. Returns the initialized state, or null on // failure. auto InitializeCppDomain( - Diagnostics::Consumer& consumer, llvm::StringRef filename, + Diagnostics::Consumer& consumer, llvm::ArrayRef inputs, llvm::IntrusiveRefCntPtr fs, llvm::LLVMContext* llvm_context, std::shared_ptr base_invocation) diff --git a/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon b/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon index d3efea075c01..3546bc8f8daa 100644 --- a/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon +++ b/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon @@ -2,9 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// ARGS: compile --phase=check --share-cpp-ast %s -// // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// EXTRA-ARGS: --share-cpp-ast // // AUTOUPDATE // TIP: To test this file alone, run: @@ -39,7 +38,7 @@ import Cpp; fn CallLeakedA() -> i32 { // This should not be found as we have not imported "a.h". - // CHECK:STDERR: fail_a_does_not_leak.carbon:[[@LINE+4]]:10: error: member name `GetA` not found in `Cpp` + // CHECK:STDERR: fail_a_does_not_leak.carbon:[[@LINE+4]]:10: error: member name `GetA` not found in `Cpp` [MemberNameNotFoundInInstScope] // CHECK:STDERR: return Cpp.GetA(); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/driver/compile_driver.cpp b/toolchain/driver/compile_driver.cpp index 506ff42d8c18..a5f1d3ce3981 100644 --- a/toolchain/driver/compile_driver.cpp +++ b/toolchain/driver/compile_driver.cpp @@ -40,13 +40,11 @@ namespace Carbon { -CompilationUnit::CompilationUnit(SemIR::CheckIRId check_ir_id, - int total_ir_count, DriverEnv* driver_env, - const CompileOptions* options, - Diagnostics::Consumer* consumer, - llvm::StringRef input_filename, - std::string output_filename, - const llvm::Target* target) +CompilationUnit::CompilationUnit( + SemIR::CheckIRId check_ir_id, int total_ir_count, DriverEnv* driver_env, + const CompileOptions* options, Diagnostics::Consumer* consumer, + llvm::StringRef input_filename, std::string output_filename, + const llvm::Target* target, llvm::LLVMContext* llvm_context) : check_ir_id_(check_ir_id), total_ir_count_(total_ir_count), driver_env_(driver_env), @@ -54,7 +52,8 @@ CompilationUnit::CompilationUnit(SemIR::CheckIRId check_ir_id, target_(target), input_filename_(input_filename), output_filename_(std::move(output_filename)), - vlog_stream_(driver_env_->vlog_stream) { + vlog_stream_(driver_env_->vlog_stream), + llvm_context_(llvm_context) { if (vlog_stream_ != nullptr || options_->stream_errors) { consumer_ = consumer; } else { @@ -150,14 +149,11 @@ auto CompilationUnit::GetCheckUnit() -> Check::Unit { }; sem_ir_.emplace(&*parse_tree_, check_ir_id_, parse_tree_->packaging_decl(), value_stores_, input_filename_); - if (!llvm_context_) { - llvm_context_ = std::make_unique(); - } return {.consumer = consumer_, .value_stores = &value_stores_, .timings = timings_ ? &*timings_ : nullptr, .sem_ir = &*sem_ir_, - .llvm_context = llvm_context_.get(), + .llvm_context = llvm_context_, .total_ir_count = total_ir_count_}; } @@ -180,9 +176,6 @@ auto CompilationUnit::PostCheck() -> void { auto CompilationUnit::RunLower() -> void { LogCall("Lower::LowerToLLVM", "lower", [&] { - if (!llvm_context_) { - llvm_context_ = std::make_unique(); - } Lower::LowerToLLVMOptions options; options.llvm_verifier_stream = options_->run_llvm_verifier ? driver_env_->error_stream : nullptr; @@ -498,6 +491,8 @@ auto CompileDriver::Initialize( } } + llvm_context_ = std::make_unique(); + // Prepare CompilationUnits before building scope exit handlers. int unit_index = -1; int total_unit_count = @@ -506,7 +501,8 @@ auto CompileDriver::Initialize( ++unit_index; return std::make_unique( SemIR::CheckIRId(unit_index), total_unit_count, &driver_env, options_, - driver_env.consumer, filename, map_input(filename), target); + driver_env.consumer, filename, map_input(filename), target, + llvm_context_.get()); }; llvm::append_range(units_, llvm::map_range(prelude, unit_builder)); llvm::append_range(units_, llvm::map_range(core_library, unit_builder)); diff --git a/toolchain/driver/compile_driver.h b/toolchain/driver/compile_driver.h index 35b3ee08a868..f421775683db 100644 --- a/toolchain/driver/compile_driver.h +++ b/toolchain/driver/compile_driver.h @@ -26,7 +26,8 @@ class CompilationUnit { Diagnostics::Consumer* consumer, llvm::StringRef input_filename, std::string output_filename, - const llvm::Target* target); + const llvm::Target* target, + llvm::LLVMContext* llvm_context); // Sets the multi-unit cache and initializes dependent member state. auto SetMultiUnitCache(MultiUnitCache* cache) -> void; @@ -146,7 +147,7 @@ class CompilationUnit { mutable std::optional parse_tree_and_subtrees_; std::optionalconst Parse::TreeAndSubtrees&>> tree_and_subtrees_getter_; - std::unique_ptr llvm_context_; + llvm::LLVMContext* llvm_context_ = nullptr; std::optional sem_ir_; std::unique_ptr module_; std::unique_ptr target_machine_; @@ -260,6 +261,7 @@ class CompileDriver { private: CompileOptions* options_; size_t input_filenames_index_ = 0; + std::unique_ptr llvm_context_; llvm::SmallVector, 256> units_; std::unique_ptr cache_; std::shared_ptr clang_invocation_; diff --git a/toolchain/lower/context.cpp b/toolchain/lower/context.cpp index db8b4a165f2d..915d270987fc 100644 --- a/toolchain/lower/context.cpp +++ b/toolchain/lower/context.cpp @@ -34,17 +34,16 @@ Context::Context( llvm::LLVMContext* llvm_context, llvm::IntrusiveRefCntPtr fs, bool want_debug_info, const Parse::GetTreeAndSubtreesStore* tree_and_subtrees_getters, - clang::CodeGenerator* clang_code_generator, llvm::StringRef module_name, + clang::CodeGenerator* cpp_code_generator, llvm::StringRef module_name, int total_ir_count, Lower::OptimizationLevel opt_level, bool mangle_string_fingerprint, llvm::raw_ostream* vlog_stream) : llvm_context_(llvm_context), - clang_code_generator_(clang_code_generator), - llvm_module_owner_( - clang_code_generator_ - ? nullptr - : std::make_unique(module_name, *llvm_context)), + cpp_code_generator_(cpp_code_generator), + llvm_module_owner_(cpp_code_generator_ ? nullptr + : std::make_unique( + module_name, *llvm_context)), llvm_module_(llvm_module_owner_ ? llvm_module_owner_.get() - : clang_code_generator_->GetModule()), + : cpp_code_generator_->GetModule()), file_system_(std::move(fs)), opt_level_(opt_level), di_builder_(*llvm_module_), @@ -95,9 +94,9 @@ auto Context::Finalize() && -> std::unique_ptr { "Debug Info Version", llvm::DEBUG_METADATA_VERSION); } - return clang_code_generator_ ? std::unique_ptr( - clang_code_generator_->ReleaseModule()) - : std::move(llvm_module_owner_); + return cpp_code_generator_ ? std::unique_ptr( + cpp_code_generator_->ReleaseModule()) + : std::move(llvm_module_owner_); } auto Context::BuildDICompileUnit(llvm::StringRef module_name, diff --git a/toolchain/lower/context.h b/toolchain/lower/context.h index 6a61f04ac2b1..60f9e0162553 100644 --- a/toolchain/lower/context.h +++ b/toolchain/lower/context.h @@ -121,6 +121,9 @@ class Context { auto file_system() -> llvm::IntrusiveRefCntPtr& { return file_system_; } + auto cpp_code_generator() -> clang::CodeGenerator* { + return cpp_code_generator_; + } auto opt_level() -> Lower::OptimizationLevel { return opt_level_; } auto di_builder() -> llvm::DIBuilder& { return di_builder_; } auto di_compile_unit() -> llvm::DICompileUnit* { return di_compile_unit_; } @@ -153,7 +156,7 @@ class Context { // State for building the LLVM IR. llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* clang_code_generator_; + clang::CodeGenerator* cpp_code_generator_; std::unique_ptr llvm_module_owner_; llvm::Module* llvm_module_; diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index a00b7b1247e4..11e64ec1bc7e 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -63,11 +63,6 @@ FileContext::FileContext(Context& context, const SemIR::File& sem_ir, coalescer_(vlog_stream_, sem_ir.specifics()), vtables_(decltype(vtables_)::MakeForOverwrite(sem_ir.vtables())), specific_vtables_(sem_ir.specifics(), nullptr) { - // Initialization that relies on invariants of the class. - cpp_code_generator_ = cpp_file() ? cpp_file()->GetCodeGenerator() : nullptr; - CARBON_CHECK( - !cpp_code_generator_ || - (&cpp_code_generator_->GetModule()->getContext() == &llvm_context())); CARBON_CHECK(!sem_ir.has_errors(), "Generating LLVM IR from invalid SemIR::File is unsupported."); } @@ -184,10 +179,14 @@ auto FileContext::LowerDefinitions() -> void { } auto FileContext::Finalize() -> void { - if (cpp_code_generator_) { + // TODO: This is an ugly way to check if we're supposed to finalize this code + // generator. Context::Finalize should finalize its own code generator, but + // doesn't have a reference to its `ASTContext`. + if (cpp_file() && + cpp_file()->code_generator() == context().cpp_code_generator()) { // Clang code generation should not actually modify the AST, but isn't // const-correct. - cpp_code_generator_->HandleTranslationUnit( + cpp_file()->code_generator()->HandleTranslationUnit( const_cast(cpp_file()->ast_context())); } @@ -316,9 +315,12 @@ auto FileContext::HandleReferencedCppFunction(clang::FunctionDecl* cpp_decl) // so that code generation (`CodeGenModule::EmitGlobal()`) would see this // function name (`CodeGenModule::getMangledName()`), and will generate // its definition. - auto* function_address = dyn_cast( - cpp_code_generator_->GetAddrOfGlobal(CreateGlobalDecl(cpp_decl), - /*isForDefinition=*/false)); + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + auto* function_address = + dyn_cast(context().cpp_code_generator()->GetAddrOfGlobal( + CreateGlobalDecl(cpp_decl), + /*isForDefinition=*/false)); CARBON_CHECK(function_address); return function_address; @@ -724,7 +726,9 @@ auto FileContext::BuildGlobalVariableDecl(SemIR::VarStorage var_storage) // llvm::GlobalVariable. if (const auto* clang_decl = sem_ir().clang_decls().Lookup(var_storage.pattern_id)) { - auto* constant = cpp_code_generator_->GetAddrOfGlobal( + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + auto* constant = context().cpp_code_generator()->GetAddrOfGlobal( CreateGlobalDecl(cast(clang_decl->decl())), /*isForDefinition=*/false); if (constant) { @@ -772,7 +776,9 @@ auto FileContext::BuildVtable(const SemIR::Vtable& vtable, if (!vtable.carbon_native_vtable) { auto* cxx_record_decl = cast( sem_ir().clang_decls().Lookup(class_info.latest_decl_id())->key.decl); - return cpp_code_generator_->GetAddrOfVTable( + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + return context().cpp_code_generator()->GetAddrOfVTable( clang::BaseSubobject(cxx_record_decl, clang::CharUnits::fromQuantity(0)), cxx_record_decl); diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index b135a2f517ff..cc9a18fc4d3c 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -166,10 +166,6 @@ class FileContext { auto context() -> Context& { return *context_; } auto llvm_context() -> llvm::LLVMContext& { return context().llvm_context(); } auto llvm_module() -> llvm::Module& { return context().llvm_module(); } - auto cpp_code_generator() -> clang::CodeGenerator& { - CARBON_CHECK(cpp_code_generator_); - return *cpp_code_generator_; - } auto sem_ir() const -> const SemIR::File& { return *sem_ir_; } auto cpp_file() -> const SemIR::CppFile* { return sem_ir().cpp_file(); } auto inst_namer() -> const SemIR::InstNamer* { return inst_namer_; } @@ -270,10 +266,6 @@ class FileContext { // The input SemIR. const SemIR::File* const sem_ir_; - // The Clang `CodeGenerator` to generate LLVM module from imported C++ - // code. Can be null if no C++ code is imported. - clang::CodeGenerator* cpp_code_generator_; - // The instruction namer, if given. const SemIR::InstNamer* const inst_namer_; diff --git a/toolchain/lower/handle_call.cpp b/toolchain/lower/handle_call.cpp index b37fa1d078b7..a5722af833ae 100644 --- a/toolchain/lower/handle_call.cpp +++ b/toolchain/lower/handle_call.cpp @@ -744,9 +744,17 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, // Lower args in the LLVM parameter order, rather than the SemIR parameter // order. std::vector args; + bool args_ok = true; + auto* callee_type = function_info->llvm_function->getFunctionType(); for (auto index : function_info->lowered_param_indices) { args.push_back(context.GetValue(arg_ids[index.index])); + + if (args.size() > callee_type->getNumParams() || + callee_type->getParamType(args.size() - 1) != args.back()->getType()) { + args_ok = false; + } } + args_ok &= args.size() == callee_type->getNumParams(); llvm::CallInst* call; if (function.virtual_index == -1) { @@ -765,8 +773,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, llvm_callee->print(out); return out.TakeStr(); }; - CARBON_CHECK(llvm_callee->arg_size() == args.size(), - "Argument count mismatch: {0}", describe_call()); + CARBON_CHECK(args_ok, "Argument mismatch: {0}", describe_call()); call = context.builder().CreateCall(llvm_callee, args); } else { call = HandleVirtualCall(context, args, function, *function_info); diff --git a/toolchain/lower/lower.cpp b/toolchain/lower/lower.cpp index 5101dd3cf83c..83d24b2c2243 100644 --- a/toolchain/lower/lower.cpp +++ b/toolchain/lower/lower.cpp @@ -23,7 +23,7 @@ auto LowerToLLVM( Context context( &llvm_context, std::move(fs), options.want_debug_info, &tree_and_subtrees_getters, - sem_ir.cpp_file() ? sem_ir.cpp_file()->GetCodeGenerator() : nullptr, + sem_ir.cpp_file() ? sem_ir.cpp_file()->code_generator() : nullptr, sem_ir.filename(), total_ir_count, options.opt_level, options.mangle_string_fingerprint, options.vlog_stream); diff --git a/toolchain/lower/testdata/function/generic/call.carbon b/toolchain/lower/testdata/function/generic/call.carbon index 7872988602b7..47af9f4c7f69 100644 --- a/toolchain/lower/testdata/function/generic/call.carbon +++ b/toolchain/lower/testdata/function/generic/call.carbon @@ -33,7 +33,7 @@ fn G() { // CHECK:STDOUT: ; ModuleID = 'call.carbon' // CHECK:STDOUT: source_filename = "call.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc20_3 = internal constant {} zeroinitializer // CHECK:STDOUT: @D.val.loc21_3 = internal constant {} zeroinitializer @@ -59,7 +59,7 @@ fn G() { // CHECK:STDOUT: call void @_CF.Main.84588f41d61dafba(i32 %.loc27), !dbg !14 // CHECK:STDOUT: %.loc28 = load double, ptr %m.var, align 8, !dbg !15 // CHECK:STDOUT: call void @_CF.Main.073fbce68be6103e(double %.loc28), !dbg !16 -// CHECK:STDOUT: call void @_CF.Main.5754c7a55c7cbe4a(%type zeroinitializer), !dbg !17 +// CHECK:STDOUT: call void @_CF.Main.5754c7a55c7cbe4a(%type.26 zeroinitializer), !dbg !17 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %m.var), !dbg !10 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %n.var), !dbg !9 // CHECK:STDOUT: call void @"_COp.7fd3b6c3a3c15807:core.Destroy.Core"(ptr %d.var), !dbg !8 @@ -116,7 +116,7 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr void @_CF.Main.5754c7a55c7cbe4a(%type %_) #0 !dbg !53 { +// CHECK:STDOUT: define linkonce_odr void @_CF.Main.5754c7a55c7cbe4a(%type.26 %_) #0 !dbg !53 { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void, !dbg !56 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/function/generic/call_basic.carbon b/toolchain/lower/testdata/function/generic/call_basic.carbon index c84994ed7438..1278139b46c9 100644 --- a/toolchain/lower/testdata/function/generic/call_basic.carbon +++ b/toolchain/lower/testdata/function/generic/call_basic.carbon @@ -59,7 +59,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_basic.carbon' // CHECK:STDOUT: source_filename = "call_basic.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc15_43 = internal constant {} zeroinitializer // CHECK:STDOUT: @@ -138,7 +138,7 @@ fn M() { // CHECK:STDOUT: %H.call.loc29 = call i32 @_CH.Main.5bd8d5767580997a(i32 %x), !dbg !51 // CHECK:STDOUT: store i32 %H.call.loc29, ptr %.loc29_6.3.temp, align 4, !dbg !51 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !51 -// CHECK:STDOUT: %H.call.loc30 = call %type @_CH.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !60 +// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !60 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !52 // CHECK:STDOUT: %G.call = call i32 @_CG.Main.58016a73bff04416(i32 %x), !dbg !52 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !53 @@ -195,7 +195,7 @@ fn M() { // CHECK:STDOUT: %H.call.loc29 = call double @_CH.Main.c27b765f2159c9a0(double %x), !dbg !77 // CHECK:STDOUT: store double %H.call.loc29, ptr %.loc29_6.3.temp, align 8, !dbg !77 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !77 -// CHECK:STDOUT: %H.call.loc30 = call %type @_CH.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !86 +// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !86 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !78 // CHECK:STDOUT: %G.call = call double @_CG.Main.fa1f0912a5bbe922(double %x), !dbg !78 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !79 @@ -237,9 +237,9 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CH.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !100 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !100 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !103 +// CHECK:STDOUT: ret %type.26 %x, !dbg !103 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon b/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon index 3b7850c12933..11997ae2eb3b 100644 --- a/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon +++ b/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon @@ -44,7 +44,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_deref_ptr.carbon' // CHECK:STDOUT: source_filename = "call_deref_ptr.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CM.Main() #0 !dbg !4 { @@ -80,7 +80,7 @@ fn M() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.58016a73bff04416(ptr %x) #0 !dbg !28 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !31 +// CHECK:STDOUT: %A.call = call %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !31 // CHECK:STDOUT: call void @_CB.Main.58016a73bff04416(ptr %x), !dbg !32 // CHECK:STDOUT: ret void, !dbg !33 // CHECK:STDOUT: } @@ -88,15 +88,15 @@ fn M() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.fa1f0912a5bbe922(ptr %x) #0 !dbg !34 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !37 +// CHECK:STDOUT: %A.call = call %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !37 // CHECK:STDOUT: call void @_CB.Main.fa1f0912a5bbe922(ptr %x), !dbg !38 // CHECK:STDOUT: ret void, !dbg !39 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CA.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !40 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !40 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !45 +// CHECK:STDOUT: ret %type.26 %x, !dbg !45 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_different_specific.carbon b/toolchain/lower/testdata/function/generic/call_different_specific.carbon index d10edc0dae35..dc454daec477 100644 --- a/toolchain/lower/testdata/function/generic/call_different_specific.carbon +++ b/toolchain/lower/testdata/function/generic/call_different_specific.carbon @@ -48,7 +48,7 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; ModuleID = 'call_different_specific.carbon' // CHECK:STDOUT: source_filename = "call_different_specific.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.58 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CM.Main(ptr %ptr_i32, ptr %ptr_f64) #0 !dbg !4 { @@ -73,7 +73,7 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.58016a73bff04416(ptr %x) #0 !dbg !27 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !30 +// CHECK:STDOUT: %A.call = call %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 zeroinitializer), !dbg !30 // CHECK:STDOUT: call void @_CB.Main.58016a73bff04416(ptr %x), !dbg !31 // CHECK:STDOUT: ret void, !dbg !32 // CHECK:STDOUT: } @@ -81,15 +81,15 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.fa1f0912a5bbe922(ptr %x) #0 !dbg !33 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !36 +// CHECK:STDOUT: %A.call = call %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 zeroinitializer), !dbg !36 // CHECK:STDOUT: call void @_CB.Main.fa1f0912a5bbe922(ptr %x), !dbg !37 // CHECK:STDOUT: ret void, !dbg !38 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CA.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !39 { +// CHECK:STDOUT: define linkonce_odr %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 %x) #0 !dbg !39 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !44 +// CHECK:STDOUT: ret %type.58 %x, !dbg !44 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon b/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon index db4d28deca30..11ed3eb270bb 100644 --- a/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon +++ b/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon @@ -48,7 +48,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_specific_in_class.carbon' // CHECK:STDOUT: source_filename = "call_specific_in_class.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define weak_odr void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %self) #0 !dbg !4 { @@ -86,7 +86,7 @@ fn M() { // CHECK:STDOUT: %.loc42_5 = load double, ptr %var_f64.var, align 8, !dbg !28 // CHECK:STDOUT: %F.call.loc42 = call double @_CF.Main.c27b765f2159c9a0(double %.loc42_5), !dbg !29 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !19 -// CHECK:STDOUT: %F.call.loc44 = call %type @_CF.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !30 +// CHECK:STDOUT: %F.call.loc44 = call %type.26 @_CF.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !30 // CHECK:STDOUT: call void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %_.var), !dbg !19 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %var_f64.var), !dbg !18 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %var_i32.var), !dbg !17 @@ -130,10 +130,10 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CF.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !62 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CF.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !62 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %G.call = call %type @_CG.Main.ee509b43cf4eb3c5(%type %x), !dbg !65 -// CHECK:STDOUT: ret %type %G.call, !dbg !66 +// CHECK:STDOUT: %G.call = call %type.26 @_CG.Main.ee509b43cf4eb3c5(%type.26 %x), !dbg !65 +// CHECK:STDOUT: ret %type.26 %G.call, !dbg !66 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind @@ -167,13 +167,13 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CG.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !85 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CG.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !85 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %c.var = alloca {}, align 1, !dbg !88 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !88 -// CHECK:STDOUT: %C.Cfn.call = call %type @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %c.var, %type %x), !dbg !89 +// CHECK:STDOUT: %C.Cfn.call = call %type.26 @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %c.var, %type.26 %x), !dbg !89 // CHECK:STDOUT: call void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %c.var), !dbg !88 -// CHECK:STDOUT: ret %type %C.Cfn.call, !dbg !90 +// CHECK:STDOUT: ret %type.26 %C.Cfn.call, !dbg !90 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind @@ -195,9 +195,9 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %self, %type %x) #0 !dbg !110 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %self, %type.26 %x) #0 !dbg !110 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !114 +// CHECK:STDOUT: ret %type.26 %x, !dbg !114 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives diff --git a/toolchain/lower/testdata/interop/cpp/class/export/class.carbon b/toolchain/lower/testdata/interop/cpp/class/export/class.carbon index 0f11fd76ebca..82ff728f5950 100644 --- a/toolchain/lower/testdata/interop/cpp/class/export/class.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/export/class.carbon @@ -458,7 +458,7 @@ fn G() { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %"class.Carbon::C" = type { i32, i32 } +// CHECK:STDOUT: %"class.Carbon::C.0" = type { i32, i32 } // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc19_3 = internal constant { i32, i32 } zeroinitializer // CHECK:STDOUT: @@ -468,10 +468,10 @@ fn G() { // CHECK:STDOUT: %c.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %c, ptr %c.addr, align 8, !tbaa !12 // CHECK:STDOUT: %0 = load ptr, ptr %c.addr, align 8, !tbaa !12, !nonnull !15, !align !16 -// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::C", ptr %0, i32 0, i32 0 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::C.0", ptr %0, i32 0, i32 0 // CHECK:STDOUT: store i32 12, ptr %a, align 4, !tbaa !17 // CHECK:STDOUT: %1 = load ptr, ptr %c.addr, align 8, !tbaa !12, !nonnull !15, !align !16 -// CHECK:STDOUT: %b = getelementptr inbounds nuw %"class.Carbon::C", ptr %1, i32 0, i32 1 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %"class.Carbon::C.0", ptr %1, i32 0, i32 1 // CHECK:STDOUT: store i32 34, ptr %b, align 4, !tbaa !19 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/class/export/method.carbon b/toolchain/lower/testdata/interop/cpp/class/export/method.carbon index 73a87ea14a8f..79f74f5f322e 100644 --- a/toolchain/lower/testdata/interop/cpp/class/export/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/export/method.carbon @@ -188,14 +188,14 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %"class.Carbon::A" = type {} +// CHECK:STDOUT: %"class.Carbon::A.0" = type {} // CHECK:STDOUT: // CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local noundef i32 @_Z5CallFv() #0 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1 +// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A.0", align 1 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: %call = call noundef i32 @_ZNK6Carbon1A1FEi(ptr noundef nonnull align 1 %ref.tmp, i32 noundef 123) // CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %ref.tmp) #4 diff --git a/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon b/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon index 6a544bf3cde2..8ae6417f3d19 100644 --- a/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon @@ -276,7 +276,7 @@ fn Four() { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %class.C = type { i32, i32 } +// CHECK:STDOUT: %class.C.18 = type { i32, i32 } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN1CC2Ev = comdat any // CHECK:STDOUT: @@ -321,9 +321,9 @@ fn Four() { // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !17 // CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 -// CHECK:STDOUT: %x_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 0 +// CHECK:STDOUT: %x_ = getelementptr inbounds nuw %class.C.18, ptr %this1, i32 0, i32 0 // CHECK:STDOUT: store i32 8, ptr %x_, align 4, !tbaa !30 -// CHECK:STDOUT: %y_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 1 +// CHECK:STDOUT: %y_ = getelementptr inbounds nuw %class.C.18, ptr %this1, i32 0, i32 1 // CHECK:STDOUT: store i32 9, ptr %y_, align 4, !tbaa !32 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/class/import/method.carbon b/toolchain/lower/testdata/interop/cpp/class/import/method.carbon index 8c7dd90ef293..477067ab5b44 100644 --- a/toolchain/lower/testdata/interop/cpp/class/import/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/import/method.carbon @@ -184,8 +184,8 @@ fn F(ref r: Cpp.A) { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %struct.A = type <{ %struct.Base, i32, [4 x i8] }> -// CHECK:STDOUT: %struct.Base = type { ptr } +// CHECK:STDOUT: %struct.A.18 = type <{ %struct.Base.19, i32, [4 x i8] }> +// CHECK:STDOUT: %struct.Base.19 = type { ptr } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN1A6by_refEv = comdat any // CHECK:STDOUT: @@ -211,7 +211,7 @@ fn F(ref r: Cpp.A) { // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !21 // CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 -// CHECK:STDOUT: %n = getelementptr inbounds nuw %struct.A, ptr %this1, i32 0, i32 1 +// CHECK:STDOUT: %n = getelementptr inbounds nuw %struct.A.18, ptr %this1, i32 0, i32 1 // CHECK:STDOUT: %0 = load i32, ptr %n, align 8, !tbaa !24 // CHECK:STDOUT: ret i32 %0 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/globals.carbon b/toolchain/lower/testdata/interop/cpp/globals.carbon index 0aedb0a9e113..97f39c42a0c7 100644 --- a/toolchain/lower/testdata/interop/cpp/globals.carbon +++ b/toolchain/lower/testdata/interop/cpp/globals.carbon @@ -528,10 +528,10 @@ fn ReadStaticVarTemplateWithConstructor() -> Cpp.Y* { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %struct.Y = type { i8 } +// CHECK:STDOUT: %struct.Y.26 = type { i8 } // CHECK:STDOUT: // CHECK:STDOUT: @_ZN1X11static_tmplIiEE = external global i32, align 4 -// CHECK:STDOUT: @_ZN1X11static_tmplI1YEE = external global %struct.Y, align 1 +// CHECK:STDOUT: @_ZN1X11static_tmplI1YEE = external global %struct.Y.26, align 1 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define i32 @_CReadStaticVarTemplate.Main() #0 !dbg !12 { diff --git a/toolchain/lower/testdata/interop/cpp/operators.carbon b/toolchain/lower/testdata/interop/cpp/operators.carbon index d1de98480052..610f3dad578a 100644 --- a/toolchain/lower/testdata/interop/cpp/operators.carbon +++ b/toolchain/lower/testdata/interop/cpp/operators.carbon @@ -290,7 +290,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %struct.A = type { i32 } +// CHECK:STDOUT: %struct.A.62 = type { i32 } // CHECK:STDOUT: // CHECK:STDOUT: $_Zlt1AS_ = comdat any // CHECK:STDOUT: @@ -313,8 +313,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -323,9 +323,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -339,8 +339,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -349,9 +349,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zle1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -365,8 +365,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -375,9 +375,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zgt1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -391,8 +391,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -401,9 +401,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zge1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -467,15 +467,15 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zlt1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 -// CHECK:STDOUT: %value = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %value = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %value, align 4, !tbaa !61 -// CHECK:STDOUT: %value2 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %value2 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %value2, align 4, !tbaa !61 // CHECK:STDOUT: %cmp = icmp slt i32 %0, %1 // CHECK:STDOUT: ret i1 %cmp @@ -487,19 +487,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zle1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: %lnot = xor i1 %call, true @@ -509,19 +509,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zgt1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: ret i1 %call @@ -530,19 +530,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zge1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: %lnot = xor i1 %call, true diff --git a/toolchain/lower/testdata/interop/cpp/reference.carbon b/toolchain/lower/testdata/interop/cpp/reference.carbon index 0527ddcd7764..b195c43b3b60 100644 --- a/toolchain/lower/testdata/interop/cpp/reference.carbon +++ b/toolchain/lower/testdata/interop/cpp/reference.carbon @@ -599,7 +599,7 @@ fn GetRefs() { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %class.ForceThunk = type { i8 } +// CHECK:STDOUT: %class.ForceThunk.23 = type { i8 } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CGetRefs.Main() #0 !dbg !12 { @@ -616,7 +616,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -624,7 +624,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -632,7 +632,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -640,7 +640,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -648,7 +648,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -656,7 +656,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/share_ast.carbon b/toolchain/lower/testdata/interop/cpp/share_ast.carbon new file mode 100644 index 000000000000..a0505dc25f11 --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/share_ast.carbon @@ -0,0 +1,364 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// EXTRA-ARGS: --share-cpp-ast +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/share_ast.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/share_ast.carbon + +// --- a.h +#ifndef A_H +#define A_H +struct A { + int a, b; +}; +inline A make_a() { return {1, 2}; } +#endif + +// --- b.h +#ifndef B_H +#define B_H +struct B { + int x, y; +}; +inline B make_b() { return {3, 4}; } +#endif + +// --- use_a.carbon +library "[[@TEST_NAME]]"; +import Cpp library "a.h"; + +fn Test() -> i32 { + var a: Cpp.A = Cpp.make_a(); + return a.b; +} + +// --- use_b.carbon +library "[[@TEST_NAME]]"; +import Cpp library "b.h"; + +fn Test() -> i32 { + var b: Cpp.B = Cpp.make_b(); + return b.x; +} + +// --- use_both.carbon +library "[[@TEST_NAME]]"; +import Cpp library "a.h"; +import Cpp library "b.h"; + +fn TestA() -> i32 { + var a: Cpp.A = Cpp.make_a(); + return a.b; +} + +fn TestB() -> i32 { + var b: Cpp.B = Cpp.make_b(); + return b.x; +} + + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_a.carbon' +// CHECK:STDOUT: source_filename = "use_a.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: %struct.A = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_av = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTest.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %a.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_av.carbon_thunk.(ptr %a.var), !dbg !17 +// CHECK:STDOUT: %.loc6_11.1.b = getelementptr inbounds nuw [8 x i8], ptr %a.var, i32 0, i32 4, !dbg !18 +// CHECK:STDOUT: %.loc6_11.2 = load i32, ptr %.loc6_11.1.b, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc6_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_av.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_av() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_av() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.A, align 4 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %struct.A, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %a, align 4, !tbaa !23 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %struct.A, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %b, align 4, !tbaa !25 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_a.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !1, line: 4, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 5, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 5, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 6, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1A", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = !{!24, !9, i64 0} +// CHECK:STDOUT: !24 = !{!"_ZTS1A", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !25 = !{!24, !9, i64 4} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_b.carbon' +// CHECK:STDOUT: source_filename = "use_b.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: %struct.B = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_bv = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTest.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %b.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_bv.carbon_thunk.(ptr %b.var), !dbg !17 +// CHECK:STDOUT: %.loc6_11.1.x = getelementptr inbounds nuw [8 x i8], ptr %b.var, i32 0, i32 0, !dbg !18 +// CHECK:STDOUT: %.loc6_11.2 = load i32, ptr %.loc6_11.1.x, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc6_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_bv.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_bv() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_bv() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.B, align 4 +// CHECK:STDOUT: %x = getelementptr inbounds nuw %struct.B, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 3, ptr %x, align 4, !tbaa !23 +// CHECK:STDOUT: %y = getelementptr inbounds nuw %struct.B, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 4, ptr %y, align 4, !tbaa !25 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_b.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !1, line: 4, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 5, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 5, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 6, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1B", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = !{!24, !9, i64 0} +// CHECK:STDOUT: !24 = !{!"_ZTS1B", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !25 = !{!24, !9, i64 4} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_both.carbon' +// CHECK:STDOUT: source_filename = "use_both.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: %struct.A.32 = type { i32, i32 } +// CHECK:STDOUT: %struct.B.33 = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_av = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_bv = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTestA.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %a.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_av.carbon_thunk.(ptr %a.var), !dbg !17 +// CHECK:STDOUT: %.loc7_11.1.b = getelementptr inbounds nuw [8 x i8], ptr %a.var, i32 0, i32 4, !dbg !18 +// CHECK:STDOUT: %.loc7_11.2 = load i32, ptr %.loc7_11.1.b, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc7_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_av.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_av() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTestB.Main() #0 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %b.var = alloca [8 x i8], align 4, !dbg !24 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b.var), !dbg !24 +// CHECK:STDOUT: call void @_Z6make_bv.carbon_thunk.(ptr %b.var), !dbg !25 +// CHECK:STDOUT: %.loc12_11.1.x = getelementptr inbounds nuw [8 x i8], ptr %b.var, i32 0, i32 0, !dbg !26 +// CHECK:STDOUT: %.loc12_11.2 = load i32, ptr %.loc12_11.1.x, align 4, !dbg !26 +// CHECK:STDOUT: ret i32 %.loc12_11.2, !dbg !27 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_bv.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !28 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !28 +// CHECK:STDOUT: %call = call i64 @_Z6make_bv() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_av() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.A.32, align 4 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %struct.A.32, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %a, align 4, !tbaa !30 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %struct.A.32, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %b, align 4, !tbaa !32 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_bv() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.B.33, align 4 +// CHECK:STDOUT: %x = getelementptr inbounds nuw %struct.B.33, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 3, ptr %x, align 4, !tbaa !33 +// CHECK:STDOUT: %y = getelementptr inbounds nuw %struct.B.33, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 4, ptr %y, align 4, !tbaa !35 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_both.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "TestA", linkageName: "_CTestA.Main", scope: null, file: !1, line: 5, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 6, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 7, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 7, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1A", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "TestB", linkageName: "_CTestB.Main", scope: null, file: !1, line: 10, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !24 = !DILocation(line: 11, column: 3, scope: !23) +// CHECK:STDOUT: !25 = !DILocation(line: 11, column: 18, scope: !23) +// CHECK:STDOUT: !26 = !DILocation(line: 12, column: 10, scope: !23) +// CHECK:STDOUT: !27 = !DILocation(line: 12, column: 3, scope: !23) +// CHECK:STDOUT: !28 = !{!29, !29, i64 0} +// CHECK:STDOUT: !29 = !{!"p1 _ZTS1B", !22, i64 0} +// CHECK:STDOUT: !30 = !{!31, !9, i64 0} +// CHECK:STDOUT: !31 = !{!"_ZTS1A", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !32 = !{!31, !9, i64 4} +// CHECK:STDOUT: !33 = !{!34, !9, i64 0} +// CHECK:STDOUT: !34 = !{!"_ZTS1B", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !35 = !{!34, !9, i64 4} +// CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon index 11571025a4ef..dd0d76773517 100644 --- a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon +++ b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon @@ -368,7 +368,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" // CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: %"class.std::initializer_list" = type { ptr, i64 } +// CHECK:STDOUT: %"class.std::initializer_list.64" = type { ptr, i64 } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN11vector_likeD2Ev = comdat any // CHECK:STDOUT: @@ -442,7 +442,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %list.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %"class.std::initializer_list", align 8 +// CHECK:STDOUT: %agg.tmp = alloca %"class.std::initializer_list.64", align 8 // CHECK:STDOUT: store ptr %list, ptr %list.addr, align 8, !tbaa !38 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !41 // CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !41 @@ -521,7 +521,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11vector_likeC2ESt16initializer_listIiE(ptr noundef nonnull align 1 dereferenceable(1) %this, ptr %list.coerce0, i64 %list.coerce1) unnamed_addr #2 comdat align 2 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %list = alloca %"class.std::initializer_list", align 8 +// CHECK:STDOUT: %list = alloca %"class.std::initializer_list.64", align 8 // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: %0 = getelementptr inbounds nuw { ptr, i64 }, ptr %list, i32 0, i32 0 // CHECK:STDOUT: store ptr %list.coerce0, ptr %0, align 8 diff --git a/toolchain/lower/testdata/primitives/type_values.carbon b/toolchain/lower/testdata/primitives/type_values.carbon index e689b5e65744..e9be58a34b96 100644 --- a/toolchain/lower/testdata/primitives/type_values.carbon +++ b/toolchain/lower/testdata/primitives/type_values.carbon @@ -29,24 +29,24 @@ fn F64() -> type { // CHECK:STDOUT: ; ModuleID = 'type_values.carbon' // CHECK:STDOUT: source_filename = "type_values.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CI32.Main() #0 !dbg !4 { +// CHECK:STDOUT: define %type.26 @_CI32.Main() #0 !dbg !4 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !8 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CI48.Main() #0 !dbg !9 { +// CHECK:STDOUT: define %type.26 @_CI48.Main() #0 !dbg !9 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !10 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !10 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CF64.Main() #0 !dbg !11 { +// CHECK:STDOUT: define %type.26 @_CF64.Main() #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !12 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } diff --git a/toolchain/sem_ir/cpp_file.cpp b/toolchain/sem_ir/cpp_file.cpp index f7e97a3d50c6..dabbfcc62b6c 100644 --- a/toolchain/sem_ir/cpp_file.cpp +++ b/toolchain/sem_ir/cpp_file.cpp @@ -12,8 +12,13 @@ namespace Carbon::SemIR { CppFile::CppFile(std::shared_ptr clang, - llvm::LLVMContext* llvm_context) - : clang_(std::move(clang)), llvm_context_(llvm_context) {} + std::unique_ptr mangle_context, + llvm::LLVMContext* llvm_context, + clang::CodeGenerator* code_generator) + : clang_(std::move(clang)), + mangle_context_(std::move(mangle_context)), + llvm_context_(llvm_context), + code_generator_(code_generator) {} CppFile::~CppFile() = default; @@ -45,11 +50,6 @@ auto CppFile::ast_context() const -> const clang::ASTContext& { return clang_->getASTContext(); } -auto CppFile::CreateMangleContext() -> void { - CARBON_CHECK(!mangle_context_); - mangle_context_.reset(ast_context().createMangleContext()); -} - auto CppFile::mangle_context() const -> clang::MangleContext& { return *mangle_context_; } diff --git a/toolchain/sem_ir/cpp_file.h b/toolchain/sem_ir/cpp_file.h index ecab3f701a2d..a046f1af71fb 100644 --- a/toolchain/sem_ir/cpp_file.h +++ b/toolchain/sem_ir/cpp_file.h @@ -29,7 +29,9 @@ namespace Carbon::SemIR { class CppFile { public: explicit CppFile(std::shared_ptr clang, - llvm::LLVMContext* llvm_context); + std::unique_ptr mangle_context, + llvm::LLVMContext* llvm_context, + clang::CodeGenerator* code_generator); ~CppFile(); // Access to compilation options. @@ -47,28 +49,18 @@ class CppFile { auto ast_context() -> clang::ASTContext&; auto ast_context() const -> const clang::ASTContext&; - // Creates the mangle context for this file's C++ AST. Must be called once the - // AST context is available (after the frontend begins the source file) and - // before `mangle_context()` is used. - auto CreateMangleContext() -> void; auto mangle_context() const -> clang::MangleContext&; auto llvm_context() const -> llvm::LLVMContext* { return llvm_context_; } - auto SetCodeGenerator(clang::CodeGenerator* code_generator) -> void { - code_generator_ = code_generator; - } - auto GetCodeGenerator() const -> clang::CodeGenerator* { - // Clang code generation should not actually modify the AST, but isn't - // const-correct. + auto code_generator() const -> clang::CodeGenerator* { return code_generator_; } private: std::shared_ptr clang_; - llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* code_generator_ = nullptr; - // Created by `CreateMangleContext()` once the AST context is available. std::unique_ptr mangle_context_; + llvm::LLVMContext* llvm_context_; + clang::CodeGenerator* code_generator_; }; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/mangler.cpp b/toolchain/sem_ir/mangler.cpp index 4dfc3900323a..7f49b410b1a8 100644 --- a/toolchain/sem_ir/mangler.cpp +++ b/toolchain/sem_ir/mangler.cpp @@ -271,7 +271,7 @@ auto Mangler::MangleWithPlatform(SemIR::FunctionId function_id, // The only platform mangling that's relevant for us is applying a global // prefix, if the platform has one. if (char prefix = sem_ir_.cpp_file() - ->GetCodeGenerator() + ->code_generator() ->GetModule() ->getDataLayout() .getGlobalPrefix()) {