|
|
@@ -666,6 +666,62 @@ static auto AddStructTypeFields(
|
|
|
return fields_id;
|
|
|
}
|
|
|
|
|
|
+// Builds and returns a vtable for the current class. Assumes that the virtual
|
|
|
+// functions for the class are listed as the top element of the `vtable_stack`.
|
|
|
+static auto BuildVtable(Context& context, Parse::NodeId node_id,
|
|
|
+ SemIR::InstId base_vtable_id) -> SemIR::InstId {
|
|
|
+ llvm::SmallVector<SemIR::InstId> vtable;
|
|
|
+ if (base_vtable_id.has_value()) {
|
|
|
+ LoadImportRef(context, base_vtable_id);
|
|
|
+ auto canonical_base_vtable_id =
|
|
|
+ context.constant_values().GetConstantInstId(base_vtable_id);
|
|
|
+ if (canonical_base_vtable_id == SemIR::ErrorInst::SingletonInstId) {
|
|
|
+ return SemIR::ErrorInst::SingletonInstId;
|
|
|
+ }
|
|
|
+ auto base_vtable_inst_block = context.inst_blocks().Get(
|
|
|
+ context.insts()
|
|
|
+ .GetAs<SemIR::Vtable>(canonical_base_vtable_id)
|
|
|
+ .virtual_functions_id);
|
|
|
+ // TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
|
|
|
+ // elements of the top of `vtable_stack`.
|
|
|
+ for (auto fn_decl_id : base_vtable_inst_block) {
|
|
|
+ auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id);
|
|
|
+ const auto& fn = context.functions().Get(fn_decl.function_id);
|
|
|
+ for (auto override_fn_decl_id :
|
|
|
+ context.vtable_stack().PeekCurrentBlockContents()) {
|
|
|
+ auto override_fn_decl =
|
|
|
+ context.insts().GetAs<SemIR::FunctionDecl>(override_fn_decl_id);
|
|
|
+ const auto& override_fn =
|
|
|
+ context.functions().Get(override_fn_decl.function_id);
|
|
|
+ if (override_fn.virtual_modifier ==
|
|
|
+ SemIR::FunctionFields::VirtualModifier::Impl &&
|
|
|
+ override_fn.name_id == fn.name_id) {
|
|
|
+ // TODO: Support generic base classes, rather than passing
|
|
|
+ // `SpecificId::None`.
|
|
|
+ CheckFunctionTypeMatches(context, override_fn, fn,
|
|
|
+ SemIR::SpecificId::None,
|
|
|
+ /*check_syntax=*/false,
|
|
|
+ /*check_self=*/false);
|
|
|
+ fn_decl_id = override_fn_decl_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vtable.push_back(fn_decl_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (auto inst_id : context.vtable_stack().PeekCurrentBlockContents()) {
|
|
|
+ auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
|
|
|
+ const auto& fn = context.functions().Get(fn_decl.function_id);
|
|
|
+ if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
|
|
|
+ vtable.push_back(inst_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return AddInst<SemIR::Vtable>(
|
|
|
+ context, node_id,
|
|
|
+ {.type_id = GetSingletonType(context, SemIR::VtableType::SingletonInstId),
|
|
|
+ .virtual_functions_id = context.inst_blocks().Add(vtable)});
|
|
|
+}
|
|
|
+
|
|
|
// Checks that the specified finished class definition is valid and builds and
|
|
|
// returns a corresponding complete type witness instruction.
|
|
|
static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
|
|
|
@@ -709,54 +765,9 @@ static auto CheckCompleteClassType(Context& context, Parse::NodeId node_id,
|
|
|
}
|
|
|
|
|
|
if (class_info.is_dynamic) {
|
|
|
- llvm::SmallVector<SemIR::InstId> vtable;
|
|
|
- if (!defining_vptr) {
|
|
|
- LoadImportRef(context, base_class_info->vtable_id);
|
|
|
- auto base_vtable_id = context.constant_values().GetConstantInstId(
|
|
|
- base_class_info->vtable_id);
|
|
|
- auto base_vtable_inst_block =
|
|
|
- context.inst_blocks().Get(context.insts()
|
|
|
- .GetAs<SemIR::Vtable>(base_vtable_id)
|
|
|
- .virtual_functions_id);
|
|
|
- // TODO: Avoid quadratic search. Perhaps build a map from `NameId` to the
|
|
|
- // elements of the top of `vtable_stack`.
|
|
|
- for (auto fn_decl_id : base_vtable_inst_block) {
|
|
|
- auto fn_decl = GetCalleeFunction(context.sem_ir(), fn_decl_id);
|
|
|
- const auto& fn = context.functions().Get(fn_decl.function_id);
|
|
|
- for (auto override_fn_decl_id :
|
|
|
- context.vtable_stack().PeekCurrentBlockContents()) {
|
|
|
- auto override_fn_decl =
|
|
|
- context.insts().GetAs<SemIR::FunctionDecl>(override_fn_decl_id);
|
|
|
- const auto& override_fn =
|
|
|
- context.functions().Get(override_fn_decl.function_id);
|
|
|
- if (override_fn.virtual_modifier ==
|
|
|
- SemIR::FunctionFields::VirtualModifier::Impl &&
|
|
|
- override_fn.name_id == fn.name_id) {
|
|
|
- // TODO: Support generic base classes, rather than passing
|
|
|
- // `SpecificId::None`.
|
|
|
- CheckFunctionTypeMatches(context, override_fn, fn,
|
|
|
- SemIR::SpecificId::None,
|
|
|
- /*check_syntax=*/false,
|
|
|
- /*check_self=*/false);
|
|
|
- fn_decl_id = override_fn_decl_id;
|
|
|
- }
|
|
|
- }
|
|
|
- vtable.push_back(fn_decl_id);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (auto inst_id : context.vtable_stack().PeekCurrentBlockContents()) {
|
|
|
- auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
|
|
|
- const auto& fn = context.functions().Get(fn_decl.function_id);
|
|
|
- if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
|
|
|
- vtable.push_back(inst_id);
|
|
|
- }
|
|
|
- }
|
|
|
- class_info.vtable_id = AddInst<SemIR::Vtable>(
|
|
|
+ class_info.vtable_id = BuildVtable(
|
|
|
context, node_id,
|
|
|
- {.type_id =
|
|
|
- GetSingletonType(context, SemIR::VtableType::SingletonInstId),
|
|
|
- .virtual_functions_id = context.inst_blocks().Add(vtable)});
|
|
|
+ defining_vptr ? SemIR::InstId::None : base_class_info->vtable_id);
|
|
|
}
|
|
|
|
|
|
return AddInst<SemIR::CompleteTypeWitness>(
|