zig icon indicating copy to clipboard operation
zig copied to clipboard

InternPool unreachable when coercing extern function (`// use getExternFunc() instead`)

Open unisgn opened this issue 1 year ago • 4 comments

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

const c = @cImport({
    @cInclude("pwd.h");
});

pub fn main() !void {
    callback(c.getpwuid);
}

fn callback(cb: fn (c.uid_t) callconv(.C) ?*c.passwd) void {
    _ = cb(0);
}

this code works in some previous version, but panic compiler in 0.13.0.

change ?*c.passwd to [*c]c.passwd can fix the problem.

Expected Behavior

give some error tips rather than panic

unisgn avatar Jul 16 '24 11:07 unisgn

Cannot reproduce on 0.14.0-dev.302+d404d8a36:

a.zig:19:15: error: expected type 'fn (c_uint) ?*cimport.struct_passwd', found 'fn (c_uint) callconv(.C) [*c]cimport.struct_passwd'
    callback(c.getpwuid);
             ~^~~~~~~~~
a.zig:19:15: note: calling convention 'C' cannot cast into calling convention 'Unspecified'
a.zig:22:17: note: parameter type declared here
fn callback(cb: fn (c.uid_t) ?*c.passwd) void {
                ^~~~~~~~~~~~~~~~~~~~~~~

Vexu avatar Jul 16 '24 13:07 Vexu

Cannot reproduce on 0.14.0-dev.302+d404d8a36:

a.zig:19:15: error: expected type 'fn (c_uint) ?*cimport.struct_passwd', found 'fn (c_uint) callconv(.C) [*c]cimport.struct_passwd'
    callback(c.getpwuid);
             ~^~~~~~~~~
a.zig:19:15: note: calling convention 'C' cannot cast into calling convention 'Unspecified'
a.zig:22:17: note: parameter type declared here
fn callback(cb: fn (c.uid_t) ?*c.passwd) void {
                ^~~~~~~~~~~~~~~~~~~~~~~

oh, forget the callconv(.C). this panics compiler fn callback(cb: fn (c.uid_t) callconv(.C) ?*c.passwd) void { _ = cb(0); }

unisgn avatar Jul 16 '24 17:07 unisgn

thread 15270 panic: reached unreachable code
Analyzing a.zig
      %61 = ret_type() node_offset:18:1 to :18:7
      %62 = dbg_stmt(2, 5)
      %63 = decl_val("callback") token_offset:19:5 to :19:13
      %64 = dbg_stmt(2, 13)
    > %65 = call(nodiscard .auto, %63, [
        {
          %66 = decl_val("c") token_offset:19:14 to :19:15
          %67 = dbg_stmt(2, 15)
          %68 = field_val(%66, "getpwuid") node_offset:19:14 to :19:24
          %69 = break_inline(%65, %68)
        },
      ]) node_offset:19:5 to :19:25
      %70 = restore_err_ret_index_unconditional(.none) node_offset:18:1 to :18:7
      %71 = ret_implicit(@void_value) token_offset:20:1 to :20:1
    For full context, use the command
      zig ast-check -t a.zig

  in lib/std/start.zig
    > %1888 = is_non_err(%1887) node_offset:513:28 to :513:45
  in lib/std/start.zig
    > %1890 = block({%1885..%1889}) node_offset:513:28 to :513:45
  in lib/std/start.zig
    > %1852 = switch_block(%1848,
        else => {%1870..%1949},
        @void_type => {%1853..%1861},
        @noreturn_type, @u8_type => {%1862..%1869}) node_offset:502:5 to :502:11
  in lib/std/start.zig
    > %1653 = call(.auto, %1651, []) node_offset:473:12 to :473:22
  in lib/std/start.zig
    > %1772 = call(.auto, %1770, [
        {%1773..%1776},
        {%1777..%1784},
        {%1785},
      ]) node_offset:488:12 to :488:99

/home/vexu/Documents/zig/zig/src/InternPool.zig:6908:25: 0xa095e0d in get (zig)
        .extern_func => unreachable, // use getExternFunc() instead
                        ^
/home/vexu/Documents/zig/zig/src/InternPool.zig:9436:26: 0xa93ac23 in getCoerced (zig)
            return ip.get(gpa, tid, .{ .extern_func = .{
                         ^
/home/vexu/Documents/zig/zig/src/Zcu/PerThread.zig:2752:64: 0xa5f52b9 in getCoerced (zig)
    return Value.fromInterned(try pt.zcu.intern_pool.getCoerced(pt.zcu.gpa, pt.tid, val.toIntern(), new_ty.toIntern()));
                                                               ^
/home/vexu/Documents/zig/zig/src/Sema.zig:29866:53: 0xa8e410c in coerceInMemory (zig)
    return Air.internedToRef((try sema.pt.getCoerced(val, dst_ty)).toIntern());
                                                    ^
/home/vexu/Documents/zig/zig/src/Sema.zig:29195:39: 0xa57c201 in coerceExtra (zig)
            return sema.coerceInMemory(val, dest_ty);
                                      ^
/home/vexu/Documents/zig/zig/src/Sema.zig:7399:44: 0xb2c7300 in analyzeArg (zig)
            else => return sema.coerceExtra(
                                           ^
/home/vexu/Documents/zig/zig/src/Sema.zig:8301:49: 0xb2c9679 in instantiateGenericCall (zig)
        const arg_ref = try args_info.analyzeArg(sema, block, arg_index, param_ty, generic_owner_ty_info, func);
                                                ^
/home/vexu/Documents/zig/zig/src/Sema.zig:7606:40: 0xae0a2e7 in analyzeCall (zig)
        if (sema.instantiateGenericCall(
                                       ^
/home/vexu/Documents/zig/zig/src/Sema.zig:7088:43: 0xad36884 in zirCall__anon_95166 (zig)
    const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
                                          ^
/home/vexu/Documents/zig/zig/src/Sema.zig:1044:62: 0xa8a9ba0 in analyzeBodyInner (zig)
            .call                         => try sema.zirCall(block, inst, .direct),
                                                             ^
/home/vexu/Documents/zig/zig/src/Sema.zig:914:26: 0xb17a381 in analyzeFnBody (zig)
    sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                         ^
/home/vexu/Documents/zig/zig/src/Zcu/PerThread.zig:2187:23: 0xacded2d in analyzeFnBody (zig)
    sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) {
                      ^

Vexu avatar Jul 16 '24 20:07 Vexu

A better repro:

extern fn foo() [*c]u32;

pub fn main() !void {
    _ = @as(fn () callconv(.C) ?*u32, foo);
}

Rexicon226 avatar Jul 17 '24 01:07 Rexicon226