Skip to content

Commit d79a374

Browse files
authored
Skip vptr when performing object initialization (#4490)
The cehck for vptr could be done differently (is this class dynamic and its base class non-dynamic), and if we change the layout (to put the vptr after any base) then this code will break (could add an assertion that the vptr isn't present apart from at the start of the field list if that'd seem worthwhile). There's still later issues with lowering (if this patch causes crashes in lowering, do they result in fuzz failures/need to be avoided before this change is submitted?)
1 parent fcabeb6 commit d79a374

File tree

2 files changed

+21
-12
lines changed

2 files changed

+21
-12
lines changed

toolchain/check/convert.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,12 @@ static auto ConvertStructToStructOrClass(Context& context,
392392
auto& sem_ir = context.sem_ir();
393393
auto src_elem_fields = sem_ir.inst_blocks().Get(src_type.fields_id);
394394
auto dest_elem_fields = sem_ir.inst_blocks().Get(dest_type.fields_id);
395+
bool dest_has_vptr =
396+
!dest_elem_fields.empty() &&
397+
sem_ir.insts()
398+
.GetAs<SemIR::StructTypeField>(dest_elem_fields.front())
399+
.name_id == SemIR::NameId::Vptr;
400+
auto dest_elem_fields_size = dest_elem_fields.size() - dest_has_vptr;
395401

396402
auto value = sem_ir.insts().Get(value_id);
397403
auto value_loc_id = sem_ir.insts().GetLocId(value_id);
@@ -411,14 +417,14 @@ static auto ConvertStructToStructOrClass(Context& context,
411417
// Check that the structs are the same size.
412418
// TODO: If not, include the name of the first source field that doesn't
413419
// exist in the destination or vice versa in the diagnostic.
414-
if (src_elem_fields.size() != dest_elem_fields.size()) {
420+
if (src_elem_fields.size() != dest_elem_fields_size) {
415421
CARBON_DIAGNOSTIC(
416422
StructInitElementCountMismatch, Error,
417423
"cannot initialize {0:class|struct} with {1} field{1:s} from struct "
418424
"with {2} field{2:s}",
419425
BoolAsSelect, IntAsSelect, IntAsSelect);
420426
context.emitter().Emit(value_loc_id, StructInitElementCountMismatch,
421-
ToClass, dest_elem_fields.size(),
427+
ToClass, dest_elem_fields_size,
422428
src_elem_fields.size());
423429
return SemIR::InstId::BuiltinError;
424430
}
@@ -449,14 +455,19 @@ static auto ConvertStructToStructOrClass(Context& context,
449455
// of the source.
450456
// TODO: Annotate diagnostics coming from here with the element index.
451457
auto new_block =
452-
literal_elems_id.is_valid()
458+
literal_elems_id.is_valid() && !dest_has_vptr
453459
? SemIR::CopyOnWriteInstBlock(sem_ir, literal_elems_id)
454460
: SemIR::CopyOnWriteInstBlock(
455461
sem_ir, SemIR::CopyOnWriteInstBlock::UninitializedBlock{
456-
src_elem_fields.size()});
462+
dest_elem_fields.size()});
457463
for (auto [i, dest_field_id] : llvm::enumerate(dest_elem_fields)) {
458464
auto dest_field =
459465
sem_ir.insts().GetAs<SemIR::StructTypeField>(dest_field_id);
466+
if (dest_field.name_id == SemIR::NameId::Vptr) {
467+
// TODO: Initialize the vptr to point to a vtable.
468+
new_block.Set(i, SemIR::InstId::BuiltinError);
469+
continue;
470+
}
460471

461472
// Find the matching source field.
462473
auto src_field_index = i;

toolchain/check/testdata/class/virtual_modifiers.carbon

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,13 @@ base class Derived {
3737
extend base: Modifiers.Base;
3838
}
3939

40-
// --- fail_todo_init.carbon
40+
// --- init.carbon
4141

4242
package Init;
4343

4444
import Modifiers;
4545

4646
fn F() {
47-
// TODO: The vptr shouldn't be counted for programmer-facing behavior.
48-
// CHECK:STDERR: fail_todo_init.carbon:[[@LINE+3]]:27: error: cannot initialize class with 1 field from struct with 0 fields [StructInitElementCountMismatch]
49-
// CHECK:STDERR: var v: Modifiers.Base = {};
50-
// CHECK:STDERR: ^~
5147
var v: Modifiers.Base = {};
5248
}
5349

@@ -190,7 +186,7 @@ fn F() {
190186
// CHECK:STDOUT:
191187
// CHECK:STDOUT: virtual fn @F();
192188
// CHECK:STDOUT:
193-
// CHECK:STDOUT: --- fail_todo_init.carbon
189+
// CHECK:STDOUT: --- init.carbon
194190
// CHECK:STDOUT:
195191
// CHECK:STDOUT: constants {
196192
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
@@ -243,8 +239,10 @@ fn F() {
243239
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%import_ref.1 [template = constants.%Base]
244240
// CHECK:STDOUT: %v.var: ref %Base = var v
245241
// CHECK:STDOUT: %v: ref %Base = bind_name v, %v.var
246-
// CHECK:STDOUT: %.loc11: %.6 = struct_literal ()
247-
// CHECK:STDOUT: assign %v.var, <error>
242+
// CHECK:STDOUT: %.loc7_28.1: %.6 = struct_literal ()
243+
// CHECK:STDOUT: %.loc7_28.2: init %Base = class_init (<error>), %v.var [template = <error>]
244+
// CHECK:STDOUT: %.loc7_29: init %Base = converted %.loc7_28.1, %.loc7_28.2 [template = <error>]
245+
// CHECK:STDOUT: assign %v.var, %.loc7_29
248246
// CHECK:STDOUT: return
249247
// CHECK:STDOUT: }
250248
// CHECK:STDOUT:

0 commit comments

Comments
 (0)