Commit 830bc41b1f

Evan Haas <evan@lagerdata.com>
2020-12-24 05:46:46
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)
1 parent 9f33984
src/translate_c.zig
@@ -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");
-        _ = try appendToken(rp.c, .Comma, ",");
-        inner_cast_node.params()[1] = &builtin_node.base;
-        inner_cast_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);
+        const as_node = try rp.c.createBuiltinCall("@as", 2);
+        as_node.params()[0] = try transQualType(rp, dst_type, loc);
         _ = try appendToken(rp.c, .Comma, ",");
+        as_node.params()[1] = &builtin_node.base;
+        as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
 
-        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);
test/run_translated_c.zig
@@ -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;
+        \\}
+    , "");
 }
test/translate_c.zig
@@ -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))));
         \\}
     });