ziglang/zig

Compiler crash with empty slice in comptime generic

dweiller opened this issue · 0 comments

Zig Version

0.12.0 and 0.13.0-dev.46+3648d7df1

Steps to Reproduce and Observed Behavior

I haven't yet been able to make a minimal repro, but setting up a project with the following reproduces it.

build.zig.zon:

.{
    .name = "zig-bug",
    .version = "0.0.0",

    .dependencies = .{
        .zli = .{
            .url = "https://github.com/dweiller/zli/archive/cbb288b2129ab5ec8181d55cc40dd02371ef5d2b.tar.gz",
            .hash = "1220d7b865aa88f0f98dd85e3317006aff163fb9c7485d50a326d90b5b6b85c763fd",
        },
    },

    .paths = .{""},
}

build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "zig-bug",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    exe.root_module.addImport("zli", b.dependency("zli", .{}).module("zli"));

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());

    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

src/main.zig:

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    const parse_result = try Cli.parse(allocator);

    switch (parse_result) {
        .ok => |params| _ = params,
        .err => |err| {
            err.renderToStdErr();
            std.process.exit(1);
        },
    }
}

const arg_spec = [_]zli.Arg{};

const version: std.SemanticVersion = .{
    .major = 0,
    .minor = 0,
    .patch = 0,
};

const Cli = zli.CliCommand("buggy", version, .{ .parameters = &arg_spec });

const zli = @import("zli");
const std = @import("std");

This diff avoids the crash:

- const Cli = zli.CliCommand("buggy", version, .{ .parameters = &arg_spec });
+ const Cli = zli.CliCommand("buggy", version, .{});

(note that the default values of the .parameters field is an empty slice).

I have bisected the crash to commit d0e74ff from #19630.

A debug build of the compiler reports:

error: thread 26925 panic: reached unreachable code
Analyzing /zig-global-cache/zig/p/1220d7b865aa88f0f98dd85e3317006aff163fb9c7485d50a326d90b5b6b85c763fd/src/root.zig: root.zig:CliCommand
      %31 = dbg_stmt(6, 5)
      %32 = decl_val("checkNameClash") token_offset:15:5 to :15:19
      %33 = dbg_stmt(6, 19)
      %34 = call(nodiscard .auto, %32, [
        {
          %35 = dbg_stmt(6, 27)
          %36 = field_val(%30, "parameters") node_offset:15:20 to :15:38
          %37 = break_inline(%34, %36)
        },
        {
          %38 = dbg_stmt(6, 47)
          %39 = field_val(%30, "include_help") node_offset:15:40 to :15:60
          %40 = break_inline(%34, %39)
        },
        {
          %41 = dbg_stmt(6, 69)
          %42 = field_val(%30, "include_version") node_offset:15:62 to :15:85
          %43 = break_inline(%34, %42)
        },
      ]) node_offset:15:5 to :15:86
      %44 = dbg_stmt(8, 5)
    > %45 = extended(struct_decl(hash(2f03488edf70f049e11a99171a65c4a6) func, { %30, %23, %27 }, auto, {
        %46 = declaration('args' line(+8) hash(1d2945674f7572f65a83b8147c0c5e20) value={%47..%59}) node_offset:18:9 to :18:14
        %60 = declaration(pub 'ParsedResult' line(+13) hash(36ef7bcac61577fd88901246e9dff81a) value={%61..%67}) node_offset:23:9 to :23:65
        %68 = declaration(pub 'Params' line(+14) hash(3625003312157a5b49ab3cbbe721ab7a) value={%69..%71}) node_offset:24:9 to :24:47
        %72 = declaration('longest_arg_name' line(+16) hash(b2c32eeafb79828b1d4aae9055886a50) value={%73, %109}) node_offset:26:9 to :26:14
        %110 = declaration(pub 'parse' line(+27) hash(9cf3f5dd5feb9c07656303cc5ab34951) value={%113..%159}) node_offset:37:9 to :37:72
        %160 = declaration(pub 'parseOrExit' line(+34) hash(51efb330960d110fab034c2668a55eab) value={%163..%230}) node_offset:44:9 to :44:74
        %231 = declaration(pub 'parseWithArgs' line(+44) hash(c7b05011c33bc66be7e91c91c1c51af1) value={%234..%523}) node_offset:54:9 to :54:15
      }, {}, {}) node_offset:17:12 to :17:18
      %524 = restore_err_ret_index_unconditional(.none) node_offset:17:5 to :17:11
      %525 = dbg_stmt(8, 5)
      %526 = ret_node(%45) node_offset:17:5 to :17:11
    For full context, use the command
      zig ast-check -t /zig-global-cache/zig/p/1220d7b865aa88f0f98dd85e3317006aff163fb9c7485d50a326d90b5b6b85c763fd/src/root.zig

  in src/main.zig: main.zig:Cli
    > %85 = field_call(.compile_time, %83, "CliCommand", [
        {%86, %87},
        {%88, %89},
        {%90..%95},
      ]) node_offset:25:13 to :25:75
  in src/main.zig: main.zig:main
    > %29 = decl_ref("Cli") token_offset:6:30 to :6:33
  in /path/to/zig/lib/std/start.zig: start.zig:callMain
    > %1824 = is_non_err(%1823) 
  in /path/to/zig/lib/std/start.zig: start.zig:callMain
    > %1826 = block({%1821..%1825}) 
  in /path/to/zig/lib/std/start.zig: start.zig:callMain
    > %1772 = switch_block(%1770,
        else => {%1915, %1918},
        %1773 => {%1774..%1778},
        %1779 => {%1780..%1788},
        by_val %1789 => {%1790..%1818},
        %1819 => {%1820..%1914}) 
  in /path/to/zig/lib/std/start.zig: start.zig:callMainWithArgs
    > %1577 = call(.auto, %1575, []) 
  in /path/to/zig/lib/std/start.zig: start.zig:posixCallMainAndExit
    > %1414 = call(.auto, %1412, [
        {%1415},
        {%1416},
        {%1417},
      ]) 
  in /path/to/zig/lib/std/start.zig: start.zig:posixCallMainAndExit
    > %1411 = field_call(nodiscard .auto, %1409, "exit", [
        {%1412..%1418},
      ]) 

/path/to/zig/src/type.zig:1039:35: 0x5ff28c6 in abiAlignmentAdvanced (zig)
                        .eager => unreachable, // struct alignment not resolved
                                  ^
/path/to/zig/src/type.zig:904:84: 0x5ff0789 in abiAlignmentAdvanced (zig)
                    return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
                                                                                   ^
/path/to/zig/src/type.zig:851:40: 0x5ff3a49 in abiAlignment (zig)
        return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
                                       ^
/path/to/zig/src/Module.zig:655:72: 0x66e9d36 in declPtrType (zig)
                .alignment = if (decl.alignment == decl_ty.abiAlignment(zcu))
                                                                       ^
/path/to/zig/src/Value.zig:4003:66: 0x66e9fd4 in ptrType (zig)
            inline .eu_payload_ptr, .opt_payload_ptr, .field_ptr, .elem_ptr => |x| x.result_ptr_ty,
                                                                 ^
/path/to/zig/src/Value.zig:4141:68: 0x66ebb1e in pointerDerivationAdvanced (zig)
    if (need_child.comptimeOnly(zcu)) {
                                                                   ^
/path/to/zig/src/print_value.zig:288:61: 0x7ef84dd in printPtr__anon_132272 (zig)
    try printPtrDerivation(derivation, writer, level, zcu, opt_sema);
                                                            ^
/path/to/zig/src/print_value.zig:130:25: 0x7c1f101 in print__anon_127410 (zig)
            try writer.writeAll("[0..");
                        ^
/path/to/zig/src/print_value.zig:205:26: 0x7ef8fbb in printAggregate__anon_132273 (zig)
            }
                         ^
/path/to/zig/src/print_value.zig:155:53: 0x7c1f686 in print__anon_127410 (zig)
        .un => |un| {
                                                    ^
/path/to/zig/src/print_value.zig:32:17: 0x7c1d3ea in format__anon_127409 (zig)
        error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
                ^
/path/to/zig/lib/std/fmt.zig:1480:26: 0x76df5e0 in format__anon_119546 (zig)
            try format_fn(self.data, fmt, options, writer);
                         ^
/path/to/zig/lib/std/fmt.zig:494:32: 0x71d26f2 in formatType__anon_111404 (zig)
        return try value.format(actual_fmt, options, writer);
                               ^
/path/to/zig/lib/std/fmt.zig:185:23: 0x74b62e0 in format__anon_116429 (zig)
        try formatType(
                      ^
/path/to/zig/lib/std/io/Writer.zig:23:26: 0x6fb9f30 in print__anon_103294 (zig)
    return std.fmt.format(self, format, args);
                         ^
/path/to/zig/lib/std/io.zig:324:47: 0x6fb8a86 in createAnonymousDeclTypeNamed (zig)
            return @errorCast(self.any().print(format, args));
                                              ^
/path/to/zig/src/Sema.zig:2827:65: 0x6af54be in zirStructDecl (zig)
    const new_decl_index = try sema.createAnonymousDeclTypeNamed(
                                                                ^
/path/to/zig/src/Sema.zig:1215:66: 0x6580b6f in analyzeBodyInner (zig)
                    .struct_decl        => try sema.zirStructDecl(        block, extended, inst),
                                                                 ^
/path/to/zig/src/Sema.zig:892:26: 0x6578921 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/path/to/zig/src/Sema.zig:7922:35: 0x6beb7ef in analyzeCall (zig)
                // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
                                  ^
/path/to/zig/src/Sema.zig:7125:43: 0x6a80c0e in zirCall__anon_93540 (zig)

                                          ^
/path/to/zig/src/Sema.zig:1015:62: 0x6579d83 in analyzeBodyInner (zig)
            .field_call                   => try sema.zirCall(block, inst, .field),
                                                             ^
/path/to/zig/src/Sema.zig:910:30: 0x62ad5c7 in analyzeInlineBody (zig)
    if (sema.analyzeBodyInner(block, body)) |_| {
                             ^
/path/to/zig/src/Sema.zig:936:39: 0x600918e in resolveInlineBody (zig)
    return (try sema.analyzeInlineBody(block, body, break_target)) orelse .unreachable_value;
                                      ^
/path/to/zig/src/Module.zig:3650:50: 0x600526d in semaDecl (zig)
    const result_ref = try sema.resolveInlineBody(&block_scope, decl_bodies.value_body, decl_inst);
                                                 ^
/path/to/zig/src/Module.zig:3015:32: 0x5de17f1 in ensureDeclAnalyzed (zig)
        break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
                               ^
/path/to/zig/src/Sema.zig:31901:27: 0x6000ff9 in ensureDeclAnalyzed (zig)
            ip.funcAnalysis(sema.owner_func_index).state = .dependency_failure;
                          ^
/path/to/zig/src/Sema.zig:31946:32: 0x6bee05a in analyzeDeclRefInner (zig)
            .is_const = if (decl_val.getVariable(mod)) |variable| variable.is_const else true,
                               ^
/path/to/zig/src/Sema.zig:31937:36: 0x66a97ce in analyzeDeclRef (zig)
        .func => |func| func.owner_decl,
                                   ^
/path/to/zig/src/Sema.zig:6795:31: 0x6a831ad in zirDeclRef (zig)

                              ^
/path/to/zig/src/Sema.zig:1022:65: 0x657a24b in analyzeBodyInner (zig)
            .decl_ref                     => try sema.zirDeclRef(block, inst),
                                                                ^
/path/to/zig/src/Sema.zig:892:26: 0x6578921 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/path/to/zig/src/Module.zig:4633:23: 0x626cafb in analyzeFnBody (zig)
    sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) {
                      ^
/path/to/zig/src/Module.zig:3143:32: 0x5fe10d8 in ensureFuncBodyAnalyzed (zig)
    var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
                               ^
/path/to/zig/src/Sema.zig:31914:31: 0x6bf8edd in ensureFuncBodyAnalyzed (zig)
        .val = if (opt_val) |val| (try mod.getCoerced(
                              ^
/path/to/zig/src/Sema.zig:35927:40: 0x66944bd in resolveInferredErrorSet (zig)
) CompileError!void {
                                       ^
/path/to/zig/src/Sema.zig:32275:69: 0x6b3779d in analyzeIsNonErrComptimeOnly (zig)
            return .bool_true;
                                                                    ^
/path/to/zig/src/Sema.zig:32304:56: 0x6f54659 in analyzeIsNonErr (zig)
    const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand);
                                                       ^
/path/to/zig/src/Sema.zig:19189:32: 0x6a8e6df in zirIsNonErr (zig)

                               ^
/path/to/zig/src/Sema.zig:1056:66: 0x657b726 in analyzeBodyInner (zig)
            .is_non_err                   => try sema.zirIsNonErr(block, inst),
                                                                 ^
/path/to/zig/src/Sema.zig:6165:34: 0x6f7de7b in resolveBlockBody (zig)
                            .body_len = @intCast(child_block.instructions.items.len),
                                 ^
/path/to/zig/src/Sema.zig:6142:33: 0x6b3a62e in zirBlock (zig)
    merges: *Block.Merges,
                                ^
/path/to/zig/src/Sema.zig:1559:49: 0x658815f in analyzeBodyInner (zig)
                    break :blk try sema.zirBlock(block, inst, tags[@intFromEnum(inst)] == .block_comptime);
                                                ^
/path/to/zig/src/Sema.zig:6165:34: 0x6f7de7b in resolveBlockBody (zig)
                            .body_len = @intCast(child_block.instructions.items.len),
                                 ^
/path/to/zig/src/Sema.zig:11017:45: 0x6f74b40 in resolveProngComptime (zig)
                    return .unreachable_value;
                                            ^
/path/to/zig/src/Sema.zig:13156:48: 0x6f733a9 in resolveSwitchComptime (zig)
        var multi_i: usize = 0;
                                               ^
/path/to/zig/src/Sema.zig:12395:37: 0x6a9ea00 in zirSwitchBlock (zig)

                                    ^
/path/to/zig/src/Sema.zig:1079:69: 0x657c552 in analyzeBodyInner (zig)
            .switch_block                 => try sema.zirSwitchBlock(block, inst, false),
                                                                    ^
/path/to/zig/src/Sema.zig:892:26: 0x6578921 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/path/to/zig/src/Sema.zig:7922:35: 0x6beb7ef in analyzeCall (zig)
                // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
                                  ^
/path/to/zig/src/Sema.zig:7125:43: 0x6a7f99e in zirCall__anon_93539 (zig)

                                          ^
/path/to/zig/src/Sema.zig:1014:62: 0x6579ce6 in analyzeBodyInner (zig)
            .call                         => try sema.zirCall(block, inst, .direct),
                                                             ^
/path/to/zig/src/Sema.zig:892:26: 0x6578921 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/path/to/zig/src/Sema.zig:7922:35: 0x6beb7ef in analyzeCall (zig)
                // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
                                  ^
/path/to/zig/src/Sema.zig:7125:43: 0x6a7f99e in zirCall__anon_93539 (zig)

                                          ^
/path/to/zig/src/Sema.zig:1014:62: 0x6579ce6 in analyzeBodyInner (zig)
            .call                         => try sema.zirCall(block, inst, .direct),
                                                             ^
/path/to/zig/src/Sema.zig:910:30: 0x62ad5c7 in analyzeInlineBody (zig)
    if (sema.analyzeBodyInner(block, body)) |_| {
                             ^
/path/to/zig/src/Sema.zig:936:39: 0x600918e in resolveInlineBody (zig)
    return (try sema.analyzeInlineBody(block, body, break_target)) orelse .unreachable_value;
                                      ^
/path/to/zig/src/Sema.zig:7414:65: 0x715c437 in analyzeArg (zig)
        switch (param_ty.toIntern()) {
                                                                ^
/path/to/zig/src/Sema.zig:7977:49: 0x6bec57e in analyzeCall (zig)
            if (mod.intern_pool.isFuncBody(func_val.toIntern())) {
                                                ^
/path/to/zig/src/Sema.zig:7125:43: 0x6a80c0e in zirCall__anon_93540 (zig)

                                          ^
/path/to/zig/src/Sema.zig:1015:62: 0x6579d83 in analyzeBodyInner (zig)
            .field_call                   => try sema.zirCall(block, inst, .field),
                                                             ^
/path/to/zig/src/Sema.zig:892:26: 0x6578921 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/path/to/zig/src/Module.zig:4633:23: 0x626cafb in analyzeFnBody (zig)
    sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) {
                      ^
/path/to/zig/src/Module.zig:3143:32: 0x5fe10d8 in ensureFuncBodyAnalyzed (zig)
    var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
                               ^
/path/to/zig/src/Compilation.zig:3419:42: 0x5fdede2 in processOneJob (zig)
            module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
                                         ^
/path/to/zig/src/Compilation.zig:3359:30: 0x5e0db3a in performAllTheWork (zig)
            try processOneJob(comp, work_item, main_progress_node);
                             ^
/path/to/zig/src/Compilation.zig:2132:31: 0x5e09072 in update (zig)
    try comp.performAllTheWork(main_progress_node);
                              ^
/path/to/zig/src/main.zig:4085:36: 0x5e83f4c in serve (zig)
                    continue;
                                   ^
/path/to/zig/src/main.zig:3362:22: 0x5ea2681 in buildOutputType (zig)
    if (show_builtin) {
                     ^
/path/to/zig/src/main.zig:260:31: 0x5ceb331 in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .{ .build = .Exe });
                              ^
/path/to/zig/src/main.zig:206:20: 0x5ce82c5 in main (zig)
    return mainArgs(gpa, arena, args);
                   ^
/path/to/zig/lib/std/start.zig:511:37: 0x5ce7d5e in main (zig)
            const result = root.main() catch |err| {
                                    ^
../sysdeps/nptl/libc_start_call_main.h:58:16: 0x7f10145aad8f in __libc_start_call_main (../sysdeps/x86/libc-start.c)
../csu/libc-start.c:392:3: 0x7f10145aae3f in __libc_start_main_impl (../sysdeps/x86/libc-start.c)
???:?:?: 0x5ce79a4 in ??? (???)
???:?:?: 0x0 in ??? (???)

Expected Behavior

The compiler shouldn't crash - the stack trace makes it look like it's hitting unreachable, but it also looks like the trace isn't printing quite correctly (arrows pointing to odd columns, some arrows don't have a line their pointing to etc), so not sure how much it can be trusted. The stack trace was generated by a debug build of zig version 0.12.1-dev.17+600b65282.