| author | |
| committer | |
| log | 830bc41b1f71d5366037f3944d35618d8ca46e51 |
| tree | c253e0e2c163bf1f221930232aff4297924ed2a4 |
| parent | 9f33984119ee698a9b344ad0df7b498b334e0f6e |
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 u1 | 2162 | // @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, ")"); |
| 2166 | 2169 | ||
| 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, ")"); | ||
| 2176 | 2175 | ||
| 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 | }); |
| 2973 | 2973 |