ziglang / zig

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

translate-c can't translate int to function pointer casts #15893

Open vrischmann opened 1 year ago

vrischmann commented 1 year ago

Zig Version

0.11.0-dev.3312+ab37ab33c

Steps to Reproduce and Observed Behavior

sqlite has the following in its header:

typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC      ((sqlite3_destructor_type)0)
#define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)

I'm using these in zig-sqlite but at some point translate-c started to fail on this with the error:

└─ zig test native-Debug-multi Debug native 1 errors
   └─ options cached
/Users/vincent/local/lib/zig/std/zig/c_translation.zig:91:47: error: pointer type '?*const fn(?*anyopaque) callconv(.C) void' requires aligned address
            return @intToPtr(DestType, castInt(usize, target));
                                       ~~~~~~~^~~~~~~~~~~~~~~
/Users/vincent/local/lib/zig/std/zig/c_translation.zig:16:33: note: called from here
                return castToPtr(DestType, SourceType, target);
                       ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/vincent/dev/perso/projects/zig-sqlite/zig-cache/o/83df0f7fe0691c102580d8181ab36bc3/cimport.zig:2353:67: note: called from here
pub const SQLITE_TRANSIENT = @import("std").zig.c_translation.cast(sqlite3_destructor_type, -@as(c_int, 1));
                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here is a small reproducer. test.h:

typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC      ((sqlite3_destructor_type)0)
#define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)

main.zig:

const std = @import("std");

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

pub fn main() !void {
    const foo = c.SQLITE_TRANSIENT;
    _ = foo;
}

building this fails with the same error:

zig build-exe zig-translate-c Debug native: error: the following command failed with 1 compilation errors:
/Users/vincent/local/bin/zig build-exe /Users/vincent/tmp/zig-translate-c/src/main.zig --cache-dir /Users/vincent/tmp/zig-translate-c/zig-cache --global-cache-dir /Users/vincent/.cache/zig --name zig-translate-c -I /Users/vincent/tmp/zig-translate-c/src --listen=-
Build Summary: 0/3 steps succeeded; 1 failed (disable with -fno-summary)
install transitive failure
└─ install zig-translate-c transitive failure
   └─ zig build-exe zig-translate-c Debug native 1 errors
/Users/vincent/local/lib/zig/std/zig/c_translation.zig:91:47: error: pointer type '?*const fn(?*anyopaque) callconv(.C) void' requires aligned address
            return @intToPtr(DestType, castInt(usize, target));
                                       ~~~~~~~^~~~~~~~~~~~~~~
/Users/vincent/local/lib/zig/std/zig/c_translation.zig:16:33: note: called from here
                return castToPtr(DestType, SourceType, target);
                       ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/vincent/tmp/zig-translate-c/zig-cache/o/adc8fa5cb321020c0dc0e0006ed1e06f/cimport.zig:463:67: note: called from here
pub const SQLITE_TRANSIENT = @import("std").zig.c_translation.cast(sqlite3_destructor_type, -@as(c_int, 1));
                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Note: https://github.com/ziglang/zig/issues/8595 talks about SQLITE_TRANSIENT not being translated properly, but the issue is closed as fixed. I'm guessing something changed since then.

Expected Behavior

I expect the build to not fail.

vrischmann commented 1 year ago

I just realised looking at my CI this doesn't happen for all architectures, it looks like only aarch64 and riscv64 fail.

The same happens with the reproducer above:

$ zig build-exe -I. -target aarch64-linux-gnu main.zig
/home/vincent/local/lib/zig/std/zig/c_translation.zig:91:47: error: pointer type '?*const fn(?*anyopaque) callconv(.C) void' requires aligned address
            return @intToPtr(DestType, castInt(usize, target));
                                       ~~~~~~~^~~~~~~~~~~~~~~
/home/vincent/local/lib/zig/std/zig/c_translation.zig:16:33: note: called from here
                return castToPtr(DestType, SourceType, target);
                       ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/vincent/.cache/zig/o/22245410daa992b38a3f94e954fdef00/cimport.zig:434:67: note: called from here
pub const SQLITE_TRANSIENT = @import("std").zig.c_translation.cast(sqlite3_destructor_type, -@as(c_int, 1));
                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ zig build-exe -I. -target x86_64-linux-gnu main.zig
$
par5er commented 1 year ago

I am also having this issue with Zig on Asahi Linux. I have fixed it temporarily by changing the value of SQLITE_TRANSIENT to something that is properly aligned on both aarch64 and x86-based machines:

- #define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)
+ #define SQLITE_TRANSIENT   ((sqlite3_destructor_type)8)
Cloudef commented 7 months ago

While par5er's workaround works for compile, it changes ABI so if you use sqlite3 amalgamation, which redefines it in the sqlite3.c or you have some other sqlite3 code linked to your binary you are going to have bad time. For now I'm workarounding this by linking another .c file with a function that returns the SQLITE_TRANSIENT pointer :thinking: