mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 06:51:03 +01:00
Add initial support for exporting generic Carbon functions to C++ (#7462)
This allows C++ to call Carbon functions with generic type parameters,
with some conditions. Example:
```carbon
interface I {
fn Doit(self);
}
class A {
impl as I { fn Doit(unused self) {} }
}
class B {
impl as I { fn Doit(unused self) {} }
}
fn F[T:! I](t: T) {
t.Doit();
}
inline Cpp '''
void G() {
Carbon::A a;
Carbon::B b;
Carbon::F(a);
Carbon::F(b);
}
''';
```
The initial support is limited; only explicit parameters are handled
currently.
`CarbonExternalASTSource::GetOrExportFunctionToCpp` now generates a
`clang::FunctionTemplateDecl` for generic Carbon functions. If C++ code
attempts to call that templated function,
`CarbonExternalASTSource::LoadExternalSpecializations` will be called
with the template argument types of that call site. Then we can generate
a specialized thunk for those argument types for C++ to call.
This commit is contained in:
@@ -338,6 +338,21 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource {
|
||||
const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
|
||||
const clang::DeclContext* original_decl_context) -> bool override;
|
||||
|
||||
auto LoadExternalSpecializations(
|
||||
const clang::Decl* decl,
|
||||
llvm::ArrayRef<clang::TemplateArgument> template_args) -> bool override {
|
||||
const auto* function_template_decl =
|
||||
llvm::dyn_cast<clang::FunctionTemplateDecl>(decl);
|
||||
if (!function_template_decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ExportFunctionSpecializationToCpp(
|
||||
*context_,
|
||||
const_cast<clang::FunctionTemplateDecl*>(function_template_decl),
|
||||
template_args);
|
||||
}
|
||||
|
||||
auto CompleteType(clang::TagDecl* tag_decl) -> void override;
|
||||
|
||||
auto layoutRecordType(
|
||||
@@ -367,7 +382,7 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource {
|
||||
|
||||
auto GetOrExportFunctionToCpp(SemIR::InstId target_inst_id,
|
||||
SemIR::FunctionId function_id)
|
||||
-> clang::FunctionDecl*;
|
||||
-> clang::NamedDecl*;
|
||||
// Get a current best-effort location for the current position within C++
|
||||
// processing.
|
||||
auto GetCurrentCppLocId() -> SemIR::LocId {
|
||||
@@ -460,20 +475,29 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
|
||||
|
||||
auto CarbonExternalASTSource::GetOrExportFunctionToCpp(
|
||||
SemIR::InstId target_inst_id, SemIR::FunctionId function_id)
|
||||
-> clang::FunctionDecl* {
|
||||
-> clang::NamedDecl* {
|
||||
SemIR::Function& function = context_->functions().Get(function_id);
|
||||
if (const auto* clang_decl =
|
||||
context_->clang_decls().Lookup(function.first_decl_id())) {
|
||||
return cast<clang::FunctionDecl>(clang_decl->decl());
|
||||
return cast<clang::NamedDecl>(clang_decl->decl());
|
||||
}
|
||||
|
||||
auto* clang_function_decl =
|
||||
auto* named_decl =
|
||||
ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id), function_id);
|
||||
|
||||
if (!clang_function_decl) {
|
||||
if (!named_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto* function_template_decl =
|
||||
llvm::dyn_cast<clang::FunctionTemplateDecl>(named_decl)) {
|
||||
context_->clang_decls().Add(
|
||||
{.key = SemIR::ClangDeclKey::ForNonFunctionDecl(function_template_decl),
|
||||
.inst_id = function.first_decl_id()});
|
||||
return function_template_decl;
|
||||
}
|
||||
|
||||
auto* clang_function_decl = llvm::cast<clang::FunctionDecl>(named_decl);
|
||||
|
||||
SemIR::ClangDeclSignature thunk_signature;
|
||||
thunk_signature.kind = SemIR::ClangDeclSignature::Normal;
|
||||
thunk_signature.num_params =
|
||||
|
||||
Reference in New Issue
Block a user