mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Support signature mismatch between virtual fn and override fn. (#7198)
For now, hide `override fn`s from name lookup, so that the base class version is always used, as the derived-class version does not have its own vptr entry and so would not do the right thing if a further-derived class adds a new override. This is implemented via a new access kind of `Hidden`. When checking the overriding function, pass in the expected `Self` type and check the `self` parameter against that; the signature that we generate for the thunk in the derived class is the base class signature with the `self` parameter's type changed to the derived class. When we generate a thunk for a virtual function, the thunk is assigned a `virtual_index`, and the virtual function itself is not. When the thunk makes a direct call to the virtual function, recognize this situation by checking for a `virtual_index`, and perform a non-virtual call if there isn't one. Assisted-by: Gemini via Antigravity
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "toolchain/check/name_ref.h"
|
||||
#include "toolchain/check/pattern.h"
|
||||
#include "toolchain/check/pattern_match.h"
|
||||
#include "toolchain/check/thunk.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/builtin_function_kind.h"
|
||||
@@ -207,13 +208,25 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
|
||||
auto override_fn_id =
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(*i).function_id;
|
||||
implemented_impls.Insert(override_fn_id);
|
||||
auto& override_fn = context.functions().Get(override_fn_id);
|
||||
CheckFunctionTypeMatches(context, override_fn, fn, specific_id,
|
||||
/*check_syntax=*/false,
|
||||
/*check_self=*/false);
|
||||
derived_vtable_entry_id = build_specific_function(*i);
|
||||
override_fn.virtual_index = vtable.size();
|
||||
CARBON_CHECK(override_fn.virtual_index == fn.virtual_index);
|
||||
|
||||
// TODO: When the base class is a C++ class, we could have multiple
|
||||
// potential functions to override. Check against each of them rather
|
||||
// than trying to override them all.
|
||||
auto override_or_thunk_id =
|
||||
BuildThunk(context, fn_id, specific_id, class_info.self_type_id, *i,
|
||||
/*defer_definition=*/true);
|
||||
if (override_or_thunk_id != SemIR::ErrorInst::InstId) {
|
||||
auto override_or_thunk_fn_id =
|
||||
context.insts()
|
||||
.GetAs<SemIR::FunctionDecl>(override_or_thunk_id)
|
||||
.function_id;
|
||||
auto& override_or_thunk_fn =
|
||||
context.functions().Get(override_or_thunk_fn_id);
|
||||
derived_vtable_entry_id =
|
||||
build_specific_function(override_or_thunk_id);
|
||||
override_or_thunk_fn.virtual_index = vtable.size();
|
||||
CARBON_CHECK(override_or_thunk_fn.virtual_index == fn.virtual_index);
|
||||
}
|
||||
} else if (auto base_vtable_specific_function =
|
||||
context.insts().TryGetAs<SemIR::SpecificFunction>(
|
||||
derived_vtable_entry_id)) {
|
||||
|
||||
Reference in New Issue
Block a user