Repository: carbon-language/carbon-lang
File: toolchain/lower/file_context.cpp (C++)

Code before:
                                    llvm::Function* llvm_function,
                                    SemIR::SpecificId specific_id) -> void {
  const auto& body_block_ids = function.body_block_ids;
  CARBON_DCHECK(llvm_function, "LLVM Function not found when lowering body.");

  if (function.cpp_decl) {
    clang::FunctionDecl* cpp_def = function.cpp_decl->getDefinition();
    CARBON_DCHECK(cpp_def, "No Clang function body found during lowering");

    // Create the LLVM function (`CodeGenModule::GetOrCreateLLVMFunction()`) so
    // that code generation (`CodeGenModule::EmitGlobal()`) would see this
    // function name (`CodeGenModule::getMangledName()`), and will generate its
    // definition.
    CARBON_DCHECK(
        cpp_code_generator_->GetAddrOfGlobal(clang::GlobalDecl(cpp_def),
                                             /*isForDefinition=*/false));

    // Emit the function code.
    cpp_code_generator_->HandleTopLevelDecl(clang::DeclGroupRef(cpp_def));
    return;
  }

  CARBON_DCHECK(!body_block_ids.empty(),
                "No function body blocks found during lowering.");

  FunctionContext function_lowering(*this, llvm_function, specific_id,
                                    BuildDISubprogram(function, llvm_function),
                                    vlog_stream_);

  // Add parameters to locals.
  // TODO: This duplicates the mapping between sem_ir instructions and LLVM
  // function parameters that was already computed in BuildFunctionDecl.
  // We should only do that once.
  auto call_param_ids =
      sem_ir().inst_blocks().GetOrEmpty(function.call_params_id);
  int param_index = 0;

  // TODO: Find a way to ensure this code and the function-call lowering use
  // the same parameter ordering.

  // Lowers the given parameter. Must be called in LLVM calling convention
  // parameter order.
  auto lower_param = [&](SemIR::InstId param_id) {
    // Get the value of the parameter from the function argument.
    auto param_inst = sem_ir().insts().GetAs<SemIR::AnyParam>(param_id);
    llvm::Value* param_value;

    if (SemIR::ValueRepr::ForType(sem_ir(), param_inst.type_id).kind !=
        SemIR::ValueRepr::None) {
      param_value = llvm_function->getArg(param_index);
      ++param_index;

Review comment (suggestion):
If this call is necessary, are we able to handle the case where an inline function calls another inline function? Eg:
```c++
// --- inline_function_with_call.h

inline void bar() {}
inline void foo() { bar(); }
```
```carbon
// --- import_inline_function_decl.carbon

library "[[@TEST_NAME]]";

import Cpp library "inline_function_decl.h";

fn MyF() {
  // Should cause both `foo` and `bar` to be emitted.
  Cpp.foo();
}
```

Code after:
auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id,
                                    const SemIR::Function& function,
                                    llvm::Function* llvm_function,
                                    SemIR::SpecificId specific_id) -> void {
  const auto& body_block_ids = function.body_block_ids;
  CARBON_DCHECK(llvm_function, "LLVM Function not found when lowering body.");

  if (function.cpp_decl) {
    // TODO: To support recursive inline functions, collect all calls to
    // `HandleTopLevelDecl()` in a custom `ASTConsumer` configured in the
    // `ASTUnit`, and replay them in lowering in the `CodeGenerator`. See
    // https://discord.com/channels/655572317891461132/768530752592805919/1370509111585935443
    clang::FunctionDecl* cpp_def = function.cpp_decl->getDefinition();
    CARBON_DCHECK(cpp_def, "No Clang function body found during lowering");

    // Create the LLVM function (`CodeGenModule::GetOrCreateLLVMFunction()`) so
    // that code generation (`CodeGenModule::EmitGlobal()`) would see this
    // function name (`CodeGenModule::getMangledName()`), and will generate its
    // definition.
    llvm::Constant* function_address =
        cpp_code_generator_->GetAddrOfGlobal(clang::GlobalDecl(cpp_def),
                                             /*isForDefinition=*/false);
    CARBON_DCHECK(function_address);

    // Emit the function code.
    cpp_code_generator_->HandleTopLevelDecl(clang::DeclGroupRef(cpp_def));
    return;
  }

  CARBON_DCHECK(!body_block_ids.empty(),
                "No function body blocks found during lowering.");

  FunctionContext function_lowering(*this, llvm_function, specific_id,
                                    BuildDISubprogram(function, llvm_function),
                                    vlog_stream_);

  // Add parameters to locals.
  // TODO: This duplicates the mapping between sem_ir instructions and LLVM
  // function parameters that was already computed in BuildFunctionDecl.
  // We should only do that once.
  auto call_param_ids =
      sem_ir().inst_blocks().GetOrEmpty(function.call_params_id);
  int param_index = 0;

  // TODO: Find a way to ensure this code and the function-call lowering use
  // the same parameter ordering.

  // Lowers the given parameter. Must be called in LLVM calling convention
  // parameter order.
  auto lower_param = [&](SemIR::InstId param_id) {
    // Get the value of the parameter from the function argument.