ziglang / zig

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

translate-c breaks on stb_image #15924

Open ethernetsellout opened 1 year ago

ethernetsellout commented 1 year ago

Zig Version

0.11.0-dev.3333+32e719e07

Steps to Reproduce and Observed Behavior

git clone https://github.com/nothings/stb
zig translate-c stb/stb_image.h -lc -DSTB_IMAGE_IMPLEMENTATION >> stb_image.zig
zig run main.zig

main.zig:

const stb = @import("stb_image.zig");

pub fn main() void {
    _ = stb.stbi__gif_parse_colortable(null, null, 0, 0);
}

output:

stb_image.zig:11999:63: error: expected type '[4]u8', found 'u8'  
            }).*[@intCast(c_uint, @as(c_int, 2))] = stbi__get8(s);
                                                    ~~~~~~~~~~^~~ 
referenced by:
    main: m.zig:4:12
    callMain: C:\Users\peter\cmd\zig\lib\std\start.zig:599:17
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Expected Behavior

No error.

ethernetsellout commented 11 months ago

The most I was able to reduce the C code to:

void a(char pal[1][1]) {
    int i = 0;
    pal[i][0] = 0;
}

main.zig:

const c = @import("c.zig");

pub fn main() void {
    var array: [1][1]u8 = .{.{0}};
    _ = c.a(&array);
}

If I get rid of the i variable, write to pal[0][0] explicitly, or make pal a variable instead of an argument, the compile error goes away.

hsequeda commented 4 months ago

I fixed that problem doing this: https://github.com/ziglang/zig/issues/17302#issuecomment-1737417445

ethernetsellout commented 4 months ago

I fixed that problem doing this: #17302 (comment)

I filed this issue not realizing there were workarounds, but this seems to be a bug with translate-c. Take the reduction above:

void a(char pal[1][1]) {
    int i = 0;
    pal[i][0] = 0;
}

The original code indexes the ith array of pal, and then indexes the zeroth element of that array. The translated code does this:

pub export fn a(arg_pal: [*c][1]u8) void {
    var pal = arg_pal;
    _ = &pal;
    var i: c_int = 0;
    _ = &i;
    (blk: {
        const tmp = i;
        if (tmp >= 0) break :blk pal + @as(usize, @intCast(tmp)) else break :blk pal - ~@as(usize, @bitCast(@as(isize, @intCast(tmp)) +% -1));
    }).*[@as(c_uint, @intCast(@as(c_int, 0)))] = 0;
}

Bit harder to parse, but it does pointer arithmetic with pal, breaking from blk with a pointer. Crucially, it doesn't index the pointer, and so when it goes to take the zeroth index, it is indexing the wrong object. This causes a type mismatch.

Curiously, the bug goes away when I remove the runtime index i. No idea what could be causing this.