From e6fa0beb335ad8ecff005fef924c2a39ed748c56 Mon Sep 17 00:00:00 2001 From: Ian Simonson Date: Thu, 30 Apr 2020 08:38:36 +1000 Subject: [PATCH 1/2] Translate-C convert bools to int in complex expressions Pre-requisite for having a test case for #5062 In complex C statements which are outside of macros, it is valid C to perform e.g. a bitor between an integer and a boolean `5 | (8 == 9)` Currently this results in a zig error after translating as `c_int | bool` is invalid Zig. Detects if a sub-expression of a numeric operator is boolean and if so converts it to int --- src-self-hosted/translate_c.zig | 32 +++++++++++++++++++++- test/run_translated_c.zig | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index c821eb1ac3..e4a41f75e7 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1293,7 +1293,37 @@ fn transBinaryOperator( } const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true); + + const is_lhs_bool = isBoolRes(lhs_node); + const is_rhs_bool = isBoolRes(rhs_node); + + if (!is_lhs_bool and !is_rhs_bool) { + return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true); + } + + const lhs = if (is_lhs_bool) init: { + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); + try cast_node.params.push(lhs_node); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + break :init &cast_node.base; + } else lhs_node; + + const rhs = if (is_rhs_bool) init: { + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); + try cast_node.params.push(rhs_node); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + break :init &cast_node.base; + } else rhs_node; + + const node = try rp.c.a().create(ast.Node.InfixOp); + + node.* = .{ + .op_token = op_token, + .lhs = lhs, + .op = op_id, + .rhs = rhs, + }; + return maybeSuppressResult(rp, scope, result_used, &node.base); } fn transCompoundStmtInline( diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 629a850836..ec6a11b9b4 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -195,4 +195,52 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("case boolean expression converted to int", + \\#include + \\int main(int argc, char **argv) { + \\ int value = 1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9; + \\ if (value != 4224) abort(); + \\ return 0; + \\} + , ""); + + cases.add("case boolean expression on left converted to int", + \\#include + \\int main(int argc, char **argv) { + \\ int value = 8 == 9 | 1 + 2 * 3 + 4 * 5 + 6 << 7; + \\ if (value != 4224) abort(); + \\ return 0; + \\} + , ""); + + cases.add("case boolean and operator+ converts bool to int", + \\#include + \\int main(int argc, char **argv) { + \\ int value = (8 == 9) + 3; + \\ int value2 = 3 + (8 == 9); + \\ if (value != value2) abort(); + \\ return 0; + \\} + , ""); + + cases.add("case boolean and operator<", + \\#include + \\int main(int argc, char **argv) { + \\ int value = (8 == 9) < 3; + \\ if (value == 0) abort(); + \\ return 0; + \\} + , ""); + + cases.add("case boolean and operator*", + \\#include + \\int main(int argc, char **argv) { + \\ int value = (8 == 9) * 3; + \\ int value2 = 3 * (9 == 9); + \\ if (value != 0) abort(); + \\ if (value2 == 0) abort(); + \\ return 0; + \\} + , ""); } From a2c3ebb75615ea47052eeb5a99b9b6881bc71d11 Mon Sep 17 00:00:00 2001 From: Ian Simonson Date: Thu, 30 Apr 2020 19:10:10 +1000 Subject: [PATCH 2/2] Use transCreateNodeInfixOp instead of maybeSuppressResult --- src-self-hosted/translate_c.zig | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index e4a41f75e7..bda152f134 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1294,36 +1294,21 @@ fn transBinaryOperator( const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - const is_lhs_bool = isBoolRes(lhs_node); - const is_rhs_bool = isBoolRes(rhs_node); - - if (!is_lhs_bool and !is_rhs_bool) { - return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true); - } - - const lhs = if (is_lhs_bool) init: { + const lhs = if (isBoolRes(lhs_node)) init: { const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); try cast_node.params.push(lhs_node); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); break :init &cast_node.base; } else lhs_node; - const rhs = if (is_rhs_bool) init: { + const rhs = if (isBoolRes(rhs_node)) init: { const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); try cast_node.params.push(rhs_node); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); break :init &cast_node.base; } else rhs_node; - const node = try rp.c.a().create(ast.Node.InfixOp); - - node.* = .{ - .op_token = op_token, - .lhs = lhs, - .op = op_id, - .rhs = rhs, - }; - return maybeSuppressResult(rp, scope, result_used, &node.base); + return transCreateNodeInfixOp(rp, scope, lhs, op_id, op_token, rhs, result_used, true); } fn transCompoundStmtInline(