Add support for C++ calling Carbon functions with parameters (#7024)

This works by generating two thunks, one in C++ and one in Carbon. For
example, given this input:
```c++
// Carbon:
fn Callme(f: f32) {}

// C++:
void F() {
  // This will call `Callme__cpp_thunk`
  Carbon::Callme(1.0);
}
```

These functions are generated:
```c++
// Carbon:
fn Callme__carbon_thunk(ref f: f32) {
  // Call the target function.
  Callme(f);
}

// C++:

// C++ declaration for the Carbon thunk.
void Callme__carbon_thunk(float& f);

void Callme__cpp_thunk(float f) {
  // Call the Carbon thunk with args passed by reference.
  Callme__carbon_thunk(f);
}
```

For now, all arguments are passed by reference, even if they are simple
types like pointers or i32.

Functions with non-void return types are not supported yet.
This commit is contained in:
Nicholas Bishop
2026-04-07 23:25:57 +00:00
committed by GitHub
parent d1dc8e820d
commit 0635f4628f
10 changed files with 571 additions and 81 deletions
+5 -44
View File
@@ -28,6 +28,7 @@
#include "llvm/Support/raw_ostream.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/context.h"
#include "toolchain/check/cpp/export.h"
#include "toolchain/check/cpp/import.h"
#include "toolchain/check/import_ref.h"
#include "toolchain/check/name_lookup.h"
@@ -36,7 +37,6 @@
#include "toolchain/diagnostics/format_providers.h"
#include "toolchain/parse/node_ids.h"
#include "toolchain/sem_ir/cpp_file.h"
#include "toolchain/sem_ir/mangler.h"
namespace Carbon::Check {
@@ -432,56 +432,17 @@ auto CarbonExternalASTSource::MapInstIdToClangDecl(
if (!callee_function) {
return nullptr;
}
const SemIR::Function& function =
context_->functions().Get(callee_function->function_id);
if (function.clang_decl_id.has_value()) {
return cast<clang::NamedDecl>(
context_->clang_decls().Get(function.clang_decl_id).key.decl);
}
auto* identifier_info =
GetClangIdentifierInfo(*context_, function.name_id);
CARBON_CHECK(identifier_info, "function with non-identifier name {0}",
function.name_id);
if (function.call_param_ranges.explicit_size() != 0) {
context_->TODO(target_inst_id,
"unsupported: C++ calling a Carbon function with "
"parameters");
return nullptr;
}
if (function.return_type_inst_id != SemIR::TypeInstId::None) {
context_->TODO(target_inst_id,
"unsupported: C++ calling a Carbon function with "
"return type other than `()`");
return nullptr;
}
// TODO: support non-empty parameter lists.
llvm::SmallVector<clang::QualType> cpp_param_types;
// TODO: support non-void return types.
auto cpp_return_type = ast_context_->VoidTy;
auto cpp_function_type = ast_context_->getFunctionType(
cpp_return_type, cpp_param_types,
clang::FunctionProtoType::ExtProtoInfo());
auto* function_decl = clang::FunctionDecl::Create(
*ast_context_, &decl_context,
/*StartLoc=*/clang::SourceLocation(),
/*NLoc=*/clang::SourceLocation(),
clang::DeclarationName(identifier_info), cpp_function_type,
/*TInfo=*/nullptr, clang::SC_Extern);
// Mangle the function name and attach it to the `FunctionDecl`.
SemIR::Mangler m(context_->sem_ir(), context_->total_ir_count());
std::string mangled_name =
m.Mangle(callee_function->function_id, SemIR::SpecificId::None);
function_decl->addAttr(
clang::AsmLabelAttr::Create(*ast_context_, mangled_name));
return function_decl;
return GetReverseInteropFunctionDecl(
*context_, SemIR::LocId(target_inst_id), decl_context,
callee_function->function_id);
}
default:
return nullptr;