ziglang / zig

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

C translation issue with boolean expression #20005

Open eknkc opened 3 months ago

eknkc commented 3 months ago

Zig Version

0.12.0

Steps to Reproduce and Observed Behavior

Given the C header file:

typedef struct
{
  int a;
} bar;

bar test_bool(int b)
{
  return (bar){.a = b != 0};
}

Zig translates this to:

pub export fn test_bool(arg_b: c_int) bar {
    var b = arg_b;
    _ = &b;
    return bar{
        .a = b != @as(c_int, 0),
    };
}

Which in turn results in

cimport.zig:64:12: error: expected type 'c_int', found 'bool'
        .a = b != @as(c_int, 0),
        ~~~^~~~~~~~~~~~~~~~~~~~

Expected Behavior

Translation shold probably use @intFromBool while assigning the int variable.

ProkopRandacek commented 3 months ago

Relevant quote from the c99 standard

Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false.92) The result has type int

6.5.8.6

The translation to zig needs to depend on how the result is used, since in other situations the bool result is correct and int would be wrong:

_Bool test(int a)
{
  return a != 0 && a != 4;
}

translates correctly to

pub export fn t(arg_a: c_int) bool {
    var a = arg_a;
    _ = &a;
    return (a != @as(c_int, 0)) and (a != @as(c_int, 4));
}
f-cozzocrea commented 3 months ago

I can successfully reproduce the issue on master. It looks like it's specifically a bug for implicit casting for a record field. The translation is correct for variables.

eknkc commented 3 months ago

I can successfully reproduce the issue on master. It looks like it's specifically a bug for implicit casting for a record field. The translation is correct for variables.

Can confirm. I was trying to come up with the absolute minimal repro sample but could not trigger it on variables. Just with a struct field.

f-cozzocrea commented 3 months ago

I've been testing this a bit, and I'm pretty sure this is a bug in Clang. Clang is identifying the init expression class as BinaryOperator instead of ImplicitCastExpr. The expression is correctly identified as an implicit cast in every other situation (such as struct field access). I'll file an upstream bug.

f-cozzocrea commented 3 months ago

Upstream issue is here: llvm/llvm-project#93393

@Vexu Would you mind adding labels to this issue? Probably translate-c and upstream.