mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Rudimentary virtual function call interop support (#6050)
This is Itanium-specific for now (explicitly downcasting to the itanium
vtable handling code in Clang) - though it doesn't look like it'd be a
big stretch to either have conditional/two codepaths down Itanium and
MSVC in Carbon, or maybe add a virtual function in clang to avoid
needing to conditional+downcast in Carbon.
Here's a working example:
`dynamic_type.h`:
```
#ifndef TEST_H
#define TEST_H
struct A {
virtual auto virt0() -> int;
virtual auto virt1() -> int;
};
auto GetVal() -> A* _Nonnull;
#endif
```
`test.carbon`:
```
library "test";
import Cpp library "dynamic_type.h";
import Core library "io";
fn Run() {
var a: Cpp.A* = Cpp.GetVal();
Core.Print(a->virt0());
Core.Print(a->virt1());
}
```
`dynamic_type.cpp`:
```
#include "dynamic_type.h"
auto A::virt0() -> int {
return 0;
}
auto A::virt1() -> int {
return 1;
}
struct B: A {
auto virt0() -> int override {
return 7;
}
auto virt1() -> int override {
return 42;
}
};
auto GetVal() -> A* _Nonnull {
static B b;
return &b;
}
```
```
$ ./bazel-bin/toolchain/carbon compile test.carbon
$ clang++-tot -g dynamic_type.cpp test.o --output=a.out
$ ./a.out
7
42
```
(linking with `carbon link` failed because we aren't linking to the C++
runtime yet, it seems, so: `ld.lld: error: undefined symbol: vtable for
__cxxabiv1::__class_type_info`)
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
This commit is contained in:
co-authored by
Dana Jansens
parent
cac3578b86
commit
bff0e5978b
@@ -13,6 +13,7 @@
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/UnresolvedSet.h"
|
||||
#include "clang/AST/VTableBuilder.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
@@ -1623,6 +1624,21 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
|
||||
AddPlaceholderInstInNoBlock(context, Parse::NodeId::None, function_decl);
|
||||
context.imports().push_back(decl_id);
|
||||
|
||||
auto virtual_modifier = SemIR::Function::VirtualModifier::None;
|
||||
int32_t virtual_index = -1;
|
||||
if (auto* method_decl = dyn_cast<clang::CXXMethodDecl>(clang_decl)) {
|
||||
if (method_decl->size_overridden_methods()) {
|
||||
virtual_modifier = SemIR::Function::VirtualModifier::Override;
|
||||
} else if (method_decl->isVirtual()) {
|
||||
virtual_modifier = SemIR::Function::VirtualModifier::Virtual;
|
||||
}
|
||||
if (virtual_modifier != SemIR::Function::VirtualModifier::None) {
|
||||
// TODO: Add support for Microsoft/non-Itanium vtables.
|
||||
virtual_index = dyn_cast<clang::ItaniumVTableContext>(
|
||||
context.ast_context().getVTableContext())
|
||||
->getMethodVTableIndex(method_decl);
|
||||
}
|
||||
}
|
||||
auto function_info = SemIR::Function{
|
||||
{.name_id = GetFunctionName(context, clang_decl),
|
||||
.parent_scope_id = GetParentNameScopeId(context, clang_decl),
|
||||
@@ -1640,7 +1656,8 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
|
||||
.definition_id = SemIR::InstId::None},
|
||||
{.call_params_id = function_params_insts->call_params_id,
|
||||
.return_slot_pattern_id = function_params_insts->return_slot_pattern_id,
|
||||
.virtual_modifier = SemIR::FunctionFields::VirtualModifier::None,
|
||||
.virtual_modifier = virtual_modifier,
|
||||
.virtual_index = virtual_index,
|
||||
.self_param_id = FindSelfPattern(
|
||||
context, function_params_insts->implicit_param_patterns_id),
|
||||
.clang_decl_id = context.sem_ir().clang_decls().Add(
|
||||
@@ -1675,14 +1692,6 @@ auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
if (auto* method_decl = dyn_cast<clang::CXXMethodDecl>(clang_decl)) {
|
||||
if (method_decl->isVirtual()) {
|
||||
context.TODO(loc_id, "Unsupported: Virtual function");
|
||||
MarkFailedDecl(context, clang_decl);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
|
||||
CARBON_CHECK(clang_decl->getFunctionType()->isFunctionProtoType(),
|
||||
"Not Prototype function (non-C++ code)");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user