From 28383d4d985cd04c897f6b6a63bd2107d8e2a8e9 Mon Sep 17 00:00:00 2001 From: WillLillis Date: Thu, 25 Jul 2024 20:52:49 -0400 Subject: [PATCH] fix(Sema): patch segfault in `finishStructInit` --- src/Sema.zig | 20 +++++++++++++++---- .../compile_time_struct_field.zig | 19 ++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 test/cases/compile_errors/compile_time_struct_field.zig diff --git a/src/Sema.zig b/src/Sema.zig index 491e6ec491..a72c749f2e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20345,7 +20345,12 @@ fn structInitEmpty( defer gpa.free(field_inits); @memset(field_inits, .none); - return sema.finishStructInit(block, init_src, dest_src, field_inits, struct_ty, struct_ty, false); + // Maps field index in the struct declaration to the field index in the initialization expression. + const field_assign_idxs = try gpa.alloc(?usize, struct_ty.structFieldCount(zcu)); + defer gpa.free(field_assign_idxs); + @memset(field_assign_idxs, null); + + return sema.finishStructInit(block, init_src, dest_src, field_inits, field_assign_idxs, struct_ty, struct_ty, false); } fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { @@ -20456,6 +20461,11 @@ fn zirStructInit( defer gpa.free(field_inits); @memset(field_inits, .none); + // Maps field index in the struct declaration to the field index in the initialization expression. + const field_assign_idxs = try gpa.alloc(?usize, resolved_ty.structFieldCount(zcu)); + defer gpa.free(field_assign_idxs); + @memset(field_assign_idxs, null); + var field_i: u32 = 0; var extra_index = extra.end; @@ -20478,6 +20488,7 @@ fn zirStructInit( else try sema.structFieldIndex(block, resolved_ty, field_name, field_src); assert(field_inits[field_index] == .none); + field_assign_idxs[field_index] = field_i; found_fields[field_index] = item.data.field_type; const uncoerced_init = try sema.resolveInst(item.data.init); const field_ty = resolved_ty.fieldType(field_index, zcu); @@ -20498,7 +20509,7 @@ fn zirStructInit( } } - return sema.finishStructInit(block, src, src, field_inits, resolved_ty, result_ty, is_ref); + return sema.finishStructInit(block, src, src, field_inits, field_assign_idxs, resolved_ty, result_ty, is_ref); } else if (resolved_ty.zigTypeTag(zcu) == .@"union") { if (extra.data.fields_len != 1) { return sema.fail(block, src, "union initialization expects exactly one field", .{}); @@ -20583,6 +20594,7 @@ fn finishStructInit( init_src: LazySrcLoc, dest_src: LazySrcLoc, field_inits: []Air.Inst.Ref, + field_assign_idxs: []?usize, struct_ty: Type, result_ty: Type, is_ref: bool, @@ -20684,9 +20696,9 @@ fn finishStructInit( } // Find which field forces the expression to be runtime, if any. - const opt_runtime_index = for (field_inits, 0..) |field_init, i| { + const opt_runtime_index = for (field_inits, field_assign_idxs) |field_init, field_assign| { if (!(try sema.isComptimeKnown(field_init))) { - break i; + break field_assign; } } else null; diff --git a/test/cases/compile_errors/compile_time_struct_field.zig b/test/cases/compile_errors/compile_time_struct_field.zig new file mode 100644 index 0000000000..8ca502f645 --- /dev/null +++ b/test/cases/compile_errors/compile_time_struct_field.zig @@ -0,0 +1,19 @@ +const S = struct { + comptime_field: comptime_int = 2, + normal_ptr: *u32, +}; + +export fn a() void { + var value: u32 = 3; + const comptimeStruct = S { + .normal_ptr = &value, + }; + _ = comptimeStruct; +} + +// error +// backend=stage2 +// target=native +// +// 9:6: error: unable to resolve comptime value +// 9:6: note: initializer of comptime only struct must be comptime-known