authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2020-12-23 20:46:46-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-12-25 14:38:31+02:00
log830bc41b1f71d5366037f3944d35618d8ca46e51
treec253e0e2c163bf1f221930232aff4297924ed2a4
parent9f33984119ee698a9b344ad0df7b498b334e0f6e

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)

3 files changed, 24 insertions(+), 24 deletions(-)

src/translate_c.zig+8-21
...@@ -2160,33 +2160,20 @@ fn transCCast(...@@ -2160,33 +2160,20 @@ fn transCCast(
2160 }2160 }
2161 if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {2161 if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {
2162 // @boolToInt returns either a comptime_int or a u12162 // @boolToInt returns either a comptime_int or a u1
2163 // TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast
2164 // instead of @as
2165
2163 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);2166 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
2164 builtin_node.params()[0] = expr;2167 builtin_node.params()[0] = expr;
2165 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2168 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
21662169
2167 const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2);2170 const as_node = try rp.c.createBuiltinCall("@as", 2);
2168 inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1");2171 as_node.params()[0] = try transQualType(rp, dst_type, loc);
2169 _ = try appendToken(rp.c, .Comma, ",");
2170 inner_cast_node.params()[1] = &builtin_node.base;
2171 inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2172
2173 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2174 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
2175 _ = try appendToken(rp.c, .Comma, ",");2172 _ = try appendToken(rp.c, .Comma, ",");
2173 as_node.params()[1] = &builtin_node.base;
2174 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
21762175
2177 if (cIsSignedInteger(dst_type)) {2176 return &as_node.base;
2178 const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2);
2179 bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1");
2180 _ = try appendToken(rp.c, .Comma, ",");
2181 bitcast_node.params()[1] = &inner_cast_node.base;
2182 bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2183 cast_node.params()[1] = &bitcast_node.base;
2184 } else {
2185 cast_node.params()[1] = &inner_cast_node.base;
2186 }
2187 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2188
2189 return &cast_node.base;
2190 }2177 }
2191 if (cIsEnum(dst_type)) {2178 if (cIsEnum(dst_type)) {
2192 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);2179 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);
test/run_translated_c.zig+13
...@@ -644,4 +644,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -644,4 +644,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
644 \\ return 0;644 \\ return 0;
645 \\}645 \\}
646 , "");646 , "");
647
648 cases.add("assign bool result to int or char",
649 \\#include <stdlib.h>
650 \\#include <stdbool.h>
651 \\bool foo() { return true; }
652 \\int main() {
653 \\ int x = foo();
654 \\ if (x != 1) abort();
655 \\ signed char c = foo();
656 \\ if (c != 1) abort();
657 \\ return 0;
658 \\}
659 , "");
647}660}
test/translate_c.zig+3-3
...@@ -2964,10 +2964,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2964,10 +2964,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2964 , &[_][]const u8{2964 , &[_][]const u8{
2965 \\pub export fn foo(arg_x: bool) bool {2965 \\pub export fn foo(arg_x: bool) bool {
2966 \\ var x = arg_x;2966 \\ var x = arg_x;
2967 \\ var a: bool = (@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(x)))) != @as(c_int, 1));2967 \\ var a: bool = (@as(c_int, @boolToInt(x)) != @as(c_int, 1));
2968 \\ var b: bool = (@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(a)))) != @as(c_int, 0));2968 \\ var b: bool = (@as(c_int, @boolToInt(a)) != @as(c_int, 0));
2969 \\ var c: bool = @ptrToInt(foo) != 0;2969 \\ var c: bool = @ptrToInt(foo) != 0;
2970 \\ return foo((@intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(c)))) != @intCast(c_int, @bitCast(i1, @intCast(u1, @boolToInt(b))))));2970 \\ return foo((@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))));
2971 \\}2971 \\}
2972 });2972 });
29732973