Correctly cast bool to signed int in translate-c

Previously casting a bool to an int would result in the following Zig code:

    @intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(b))));

This is incorrect if `b` is true, since bitcasting a `u1` with the value 1
to an `i1` will result in the value -1. Instead, generate the following code:

    @as(c_int, @boolToInt(b));

Since @boolToInt returns a `u1`, this is only disallowed if the destination
type is one-bit and signed, which can only happen if it's a bitfield
(currently not supported by translate-c)
This commit is contained in:
Evan Haas 2020-12-23 20:46:46 -08:00 committed by Veikka Tuominen
parent 9f33984119
commit 830bc41b1f
3 changed files with 24 additions and 24 deletions

View File

@ -2160,33 +2160,20 @@ fn transCCast(
}
if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {
// @boolToInt returns either a comptime_int or a u1
// TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast
// instead of @as
const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
builtin_node.params()[0] = expr;
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2);
inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1");
const as_node = try rp.c.createBuiltinCall("@as", 2);
as_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
inner_cast_node.params()[1] = &builtin_node.base;
inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
as_node.params()[1] = &builtin_node.base;
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
cast_node.params()[0] = try transQualType(rp, dst_type, loc);
_ = try appendToken(rp.c, .Comma, ",");
if (cIsSignedInteger(dst_type)) {
const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2);
bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1");
_ = try appendToken(rp.c, .Comma, ",");
bitcast_node.params()[1] = &inner_cast_node.base;
bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
cast_node.params()[1] = &bitcast_node.base;
} else {
cast_node.params()[1] = &inner_cast_node.base;
}
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &cast_node.base;
return &as_node.base;
}
if (cIsEnum(dst_type)) {
const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);

View File

@ -644,4 +644,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
cases.add("assign bool result to int or char",
\\#include <stdlib.h>
\\#include <stdbool.h>
\\bool foo() { return true; }
\\int main() {
\\ int x = foo();
\\ if (x != 1) abort();
\\ signed char c = foo();
\\ if (c != 1) abort();
\\ return 0;
\\}
, "");
}

View File

@ -2964,10 +2964,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub export fn foo(arg_x: bool) bool {
\\ var x = arg_x;
\\ var a: bool = (@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(x)))) != @as(c_int, 1));
\\ var b: bool = (@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(a)))) != @as(c_int, 0));
\\ var a: bool = (@as(c_int, @boolToInt(x)) != @as(c_int, 1));
\\ var b: bool = (@as(c_int, @boolToInt(a)) != @as(c_int, 0));
\\ var c: bool = @ptrToInt(foo) != 0;
\\ return foo((@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(c)))) != @intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(b))))));
\\ return foo((@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))));
\\}
});