ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.72k stars 2.53k forks source link

Coercing typed tuple to struct causes index OOB in Sema #19529

Closed InKryption closed 3 months ago

InKryption commented 7 months ago

Zig Version

0.12.0-dev.3518+d2be725e4

Steps to Reproduce and Observed Behavior

Minimum reproduction:

comptime {
    _ = @as(struct { fizz: void }, struct { void }{{}});
}

Notes:

Expected Behavior

A proper compile error about not being able to coerce a tuple to a struct.

InKryption commented 7 months ago

Stack trace with zig test repro.zig using debug build:

thread 77010 panic: index out of bounds: index 0, len 0
Analyzing repro.zig: repro.zig:comptime_0
      %2 = extended(struct_decl(hash(3e2d6bfb240330d048bafab267843b98) anon, {}, auto, {}, {
        fizz: @void_type,
      }) node_offset:3:13 to :3:34
      %3 = extended(struct_decl(hash(340b6ff9897bf15e42239147ac815784) tuple, anon, {}, auto, {}, {
        @"0": @void_type,
      }) node_offset:3:36 to :3:51
      %4 = validate_array_init_ty(%3, 1) node_offset:3:36 to :3:55
      %5 = array_init_elem_type(%3, 0)
      %6 = array_init(%3{@void_value}) node_offset:3:36 to :3:55
    > %7 = as_node(%2, %6) node_offset:3:36 to :3:55
      %8 = ensure_result_non_error(%7) node_offset:3:9 to :3:56
      %9 = break_inline(%1, @void_value)
    For full context, use the command
      zig ast-check -t repro.zig

/home/inkryption/ziglang/zig/src/Sema.zig:32265:86: 0x65ce475 in coerceTupleToStruct (zig)
            .struct_type => ip.loadStructType(inst_ty.toIntern()).field_names.get(ip)[field_i],
                                                                                     ^
/home/inkryption/ziglang/zig/src/Sema.zig:29453:48: 0x61fab21 in coerceExtra (zig)
                return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {
                                               ^
/home/inkryption/ziglang/zig/src/Sema.zig:10140:28: 0x6e4f840 in analyzeAs (zig)
    return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) {
                           ^
/home/inkryption/ziglang/zig/src/Sema.zig:10097:26: 0x69a867c in zirAsNode (zig)
    return sema.analyzeAs(block, src, extra.dest_type, extra.operand, false);
                         ^
/home/inkryption/ziglang/zig/src/Sema.zig:1004:64: 0x64bcfe2 in analyzeBodyInner (zig)
            .as_node                      => try sema.zirAsNode(block, inst),
                                                               ^
/home/inkryption/ziglang/zig/src/Sema.zig:911:30: 0x61f0137 in analyzeInlineBody (zig)
    if (sema.analyzeBodyInner(block, body)) |_| {
                             ^
/home/inkryption/ziglang/zig/src/Sema.zig:937:39: 0x5f3f8fe in resolveInlineBody (zig)
    return (try sema.analyzeInlineBody(block, body, break_target)) orelse .unreachable_value;
                                      ^
/home/inkryption/ziglang/zig/src/Module.zig:3638:50: 0x5f3cba6 in semaDecl (zig)
    const result_ref = try sema.resolveInlineBody(&block_scope, decl_bodies.value_body, decl_inst);
                                                 ^
/home/inkryption/ziglang/zig/src/Module.zig:3016:32: 0x5d1bf21 in ensureDeclAnalyzed (zig)
        break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
                               ^
/home/inkryption/ziglang/zig/src/Compilation.zig:3485:38: 0x5f17398 in processOneJob (zig)
            module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {
                                     ^
/home/inkryption/ziglang/zig/src/Compilation.zig:3359:30: 0x5d47eda in performAllTheWork (zig)
            try processOneJob(comp, work_item, main_progress_node);
                             ^
/home/inkryption/ziglang/zig/src/Compilation.zig:2132:31: 0x5d43412 in update (zig)
    try comp.performAllTheWork(main_progress_node);
                              ^
/home/inkryption/ziglang/zig/src/main.zig:4503:24: 0x5d74b4f in updateModule (zig)
        try comp.update(main_progress_node);
                       ^
/home/inkryption/ziglang/zig/src/main.zig:3414:17: 0x5ddd579 in buildOutputType (zig)
    updateModule(comp, color) catch |err| switch (err) {
                ^
/home/inkryption/ziglang/zig/src/main.zig:266:31: 0x5c25b1b in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .zig_test);
                              ^
/home/inkryption/ziglang/zig/src/main.zig:206:20: 0x5c22885 in main (zig)
    return mainArgs(gpa, arena, args);
                   ^
/home/inkryption/ziglang/zig/zig-out/lib/zig/std/start.zig:511:37: 0x5c2231e in main (zig)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x77f44bb0cccf in ??? (libc.so.6)
Unwind information for `libc.so.6:0x77f44bb0cccf` was not available, trace may be incomplete

And the error message using a ReleaseFast build of the compiler:

repro.zig:3:51: error: no field named 'd' in struct 'repro.comptime_0__struct_249'
    _ = @as(struct { fizz: void }, struct { void }{{}});
                                   ~~~~~~~~~~~~~~~^~~~
repro.zig:3:13: note: struct declared here
    _ = @as(struct { fizz: void }, struct { void }{{}});