zig icon indicating copy to clipboard operation
zig copied to clipboard

Bogus error message mutating OPV struct field of tuple

Open mlugg opened this issue 2 years ago • 3 comments

Zig Version

0.12.0-dev.293+f33bb0228

Steps to Reproduce and Observed Behavior

test {
    const S = struct {};
    const T = struct { S };
    var t: T = undefined;
    t[0] = .{};
}
[mlugg@vega help]$ zig test repro.zig
repro.zig:5:10: error: value stored in comptime field does not match the default value of the field
    t[0] = .{};
    ~~~~~^~~~~

Expected Behavior

No error message: this mutation is legal.

S and T are both OPV types. The error does not occur if S contains any non-OPV fields, or if T is struct { void }. It does not occur if T is not a tuple. It does still occur if T contains other, non-zero-bit, fields.

mlugg avatar Sep 09 '23 20:09 mlugg

I get an assertion failure on a debug build:

thread 5264 panic: reached unreachable code
Analyzing a.zig: a.zig:test_0
      %3 = dbg_block_begin()
      %4 = dbg_stmt(2, 5)
      %5 = extended(struct_decl(dbg_var, Auto, {}, {}, {}) node_offset:2:15 to :2:24
      %6 = dbg_var_val(%5, "S")
      %7 = dbg_stmt(3, 5)
      %8 = extended(struct_decl(tuple, dbg_var, Auto, {}, {
        @"0": {%10, %11},
      }) node_offset:3:15 to :3:27
      %9 = closure_capture(%5) token_offset:2:11 to :2:12
      %12 = dbg_var_val(%8, "T")
      %13 = dbg_stmt(4, 5)
      %14 = block_comptime({
        %15 = break(%14, %8)
      }) node_offset:4:12 to :4:13
      %16 = alloc_mut(%14) node_offset:4:5 to :4:25
      %17 = store_node(%16, @InternPool.Index.undef) node_offset:4:16 to :4:25
      %18 = dbg_var_ptr(%16, "t")
      %19 = dbg_stmt(5, 5)
      %20 = as_node(@InternPool.Index.usize_type, @InternPool.Index.zero) node_offset:5:7 to :5:8
      %21 = dbg_stmt(5, 6)
      %22 = elem_ptr_node(%16, %20) node_offset:5:5 to :5:9
    > %23 = store_node(%22, @InternPool.Index.empty_struct) node_offset:5:5 to :5:15
      %24 = dbg_block_end()
      %25 = restore_err_ret_index(%2, %4294967211)
      %26 = break(%2, @InternPool.Index.void_value)
    For full context, use the command
      zig ast-check -t a.zig

  in a.zig: a.zig:test_0
    > %2 = block({%3..%26}) node_offset:1:6 to :1:7

/home/vexu/Documents/zig/zig/lib/std/debug.zig:342:14: 0x82f0e8c in assert (zig)
    if (!ok) unreachable; // assertion failure
             ^
/home/vexu/Documents/zig/zig/src/value.zig:409:15: 0x8408fba in toIntern (zig)
        assert(val.ip_index != .none);
              ^
/home/vexu/Documents/zig/zig/src/value.zig:1429:49: 0x8c6e0a1 in eql (zig)
        assert(mod.intern_pool.typeOf(b.toIntern()) == ty.toIntern());
                                                ^
/home/vexu/Documents/zig/zig/src/Sema.zig:29376:37: 0x901f33c in storePtrVal (zig)
                if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
                                    ^
/home/vexu/Documents/zig/zig/src/Sema.zig:29279:33: 0x8b092bd in storePtr2 (zig)
            try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
                                ^
/home/vexu/Documents/zig/zig/src/Sema.zig:5413:26: 0x8c2e972 in zirStoreNode (zig)
    return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
                         ^

Vexu avatar Sep 10 '23 16:09 Vexu

Bug is in comptime pointer mutation: Sema.beginComptimePtrMutation may return un-interned values due to prior mutations, so Sema.storePtrVal should not assume the returned value is interned (but does in the equality check with operand_val). I have a WIP branch which likely resolves this.

mlugg avatar Sep 10 '23 17:09 mlugg

also an issue for anonymous structs:

test {
    // workaround, explicitly type t: T
    // const T = struct { s: u8 };
    var t = .{
        .s = @as(u8, 0),
    };
    t.s = 1;
}
$ zig test repo.zig
repo.zig:7:9: error: value stored in comptime field does not match the default value of the field
    t.s = 1;
    ~~~~^~~

Pyrolistical avatar May 07 '24 21:05 Pyrolistical