ziglang / zig

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

stage2: translate-c reports error with bit shift #13277

Open mitchellh opened 2 years ago

mitchellh commented 2 years ago

Zig Version

0.10.0-dev.4544+0ae60f723

Steps to Reproduce

#include <stdint.h>

typedef __uint32_t uint32_t;

#define IOCPARM_MASK    0x1fff
#define IOCPARM_MAX     (IOCPARM_MASK + 1)
#define IOC_VOID        (__uint32_t)0x20000000

#define _IOC(inout, group, num, len) \
    (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define _IO(g, n)        _IOC(IOC_VOID, (g), (n), 0)

#define TIOCSCTTY        _IO('t', 97)
const std = @import("std");
const c = @cImport({
    @cInclude("test.h");
});

test {
    std.log.warn("result={}", .{c.TIOCSCTTY});
}
$ zig test -lc -I$(pwd) test.zig

Expected Behavior

Test [1/1] test ""... [default] (warn): result=536900705

This was working at some point in the past ~10 commits, and is newly broken. (Or it shouldn't have been working and a new bug is exposed)

Actual Behavior

/home/mitchellh/code/go/src/github.com/mitchellh/testproj/zig-cache/o/c3ca67650527d0342e79df62ae728743/cimport.zig:843:98: error: expected type 'c_uint', found 'c_int'
pub inline fn _IOC(inout: anytype, group: anytype, num: anytype, len: anytype) @TypeOf(((inout | ((len & IOCPARM_MASK) << @as(c_int, 16))) | (group << @as(c_int, 8))) | num) {
                                                                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/mitchellh/code/go/src/github.com/mitchellh/testproj/zig-cache/o/c3ca67650527d0342e79df62ae728743/cimport.zig:843:98: note: unsigned 32-bit int cannot represent all possible signed 32-bit values
referenced by:
    _IO: /home/mitchellh/code/go/src/github.com/mitchellh/testproj/zig-cache/o/c3ca67650527d0342e79df62ae728743/cimport.zig:846:51
    TIOCSCTTY: /home/mitchellh/code/go/src/github.com/mitchellh/testproj/zig-cache/o/c3ca67650527d0342e79df62ae728743/cimport.zig:849:23
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

The test passes with -fstage1

Here is the full generated cimport.zig if that is helpful: https://gist.github.com/mitchellh/f7ea026926326230e61f5d4601701e83

Vexu commented 2 years ago

After fixing a few stage2 bugs I reduced this to:

pub inline fn _IOC(inout: anytype, len: anytype) @TypeOf(inout | len) {
    return 0;
}
pub inline fn _IO() @TypeOf(_IOC(@as(u32, 0), @as(c_int, 0))) {
    return 0;
}
test {
    std.log.warn("result={}", .{_IO()});
}

which means that this stopped working due to 4e134f6dcb02000151c395718eb2c24977100013 but since I can reproduce it without using inline call arguments it's a bug in translate-c that has always existed:

// a.c
int a;
unsigned b;
#define FOO() (a | b)
const c = @cImport({
    @cInclude("a.c");
});
test {
    std.log.warn("result={}", .{c.FOO()});
}