| author | |
| committer | |
| log | d98f09e4f67fb2848be6052466db035450326605 |
| tree | 736c6f57967ddaaa9e386026d0114c66c1dba5fd |
| parent | 61bcac108cecba0ab8e1b442bd71c51306c0e9fc |
This prevents inadvertent side-effects when an expression is not evaluated
due to boolean short-circuiting
Fixes #79893 files changed, 49 insertions(+), 29 deletions(-)
src/translate_c.zig+14-19| ... | ... | @@ -1438,30 +1438,25 @@ fn transBinaryOperator( |
| 1438 | 1438 | switch (op) { |
| 1439 | 1439 | .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()), |
| 1440 | 1440 | .Comma => { |
| 1441 | const block_scope = try scope.findBlockScope(rp.c); | |
| 1442 | const expr = block_scope.base.parent == scope; | |
| 1443 | const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined; | |
| 1441 | var block_scope = try Scope.Block.init(rp.c, scope, true); | |
| 1442 | const lparen = try appendToken(rp.c, .LParen, "("); | |
| 1444 | 1443 | |
| 1445 | 1444 | const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value); |
| 1446 | 1445 | try block_scope.statements.append(lhs); |
| 1447 | 1446 | |
| 1448 | 1447 | const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value); |
| 1449 | if (expr) { | |
| 1450 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1451 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); | |
| 1452 | try block_scope.statements.append(&break_node.base); | |
| 1453 | const block_node = try block_scope.complete(rp.c); | |
| 1454 | const rparen = try appendToken(rp.c, .RParen, ")"); | |
| 1455 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); | |
| 1456 | grouped_expr.* = .{ | |
| 1457 | .lparen = lparen, | |
| 1458 | .expr = block_node, | |
| 1459 | .rparen = rparen, | |
| 1460 | }; | |
| 1461 | return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); | |
| 1462 | } else { | |
| 1463 | return maybeSuppressResult(rp, scope, result_used, rhs); | |
| 1464 | } | |
| 1448 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1449 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); | |
| 1450 | try block_scope.statements.append(&break_node.base); | |
| 1451 | const block_node = try block_scope.complete(rp.c); | |
| 1452 | const rparen = try appendToken(rp.c, .RParen, ")"); | |
| 1453 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); | |
| 1454 | grouped_expr.* = .{ | |
| 1455 | .lparen = lparen, | |
| 1456 | .expr = block_node, | |
| 1457 | .rparen = rparen, | |
| 1458 | }; | |
| 1459 | return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); | |
| 1465 | 1460 | }, |
| 1466 | 1461 | .Div => { |
| 1467 | 1462 | if (cIsSignedInteger(qt)) { |
test/run_translated_c.zig+13| ... | ... | @@ -909,4 +909,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 909 | 909 | \\ return 1 != 1; |
| 910 | 910 | \\} |
| 911 | 911 | , ""); |
| 912 | ||
| 913 | cases.add("Comma operator should create new scope; issue #7989", | |
| 914 | \\#include <stdlib.h> | |
| 915 | \\#include <stdio.h> | |
| 916 | \\int main(void) { | |
| 917 | \\ if (1 || (abort(), 1)) {} | |
| 918 | \\ if (0 && (1, printf("do not print\n"))) {} | |
| 919 | \\ int x = 0; | |
| 920 | \\ x = (x = 3, 4, x + 1); | |
| 921 | \\ if (x != 4) abort(); | |
| 922 | \\ return 0; | |
| 923 | \\} | |
| 924 | , ""); | |
| 912 | 925 | } |
test/translate_c.zig+22-10| ... | ... | @@ -1723,11 +1723,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1723 | 1723 | \\} |
| 1724 | 1724 | , &[_][]const u8{ |
| 1725 | 1725 | \\pub export fn foo() c_int { |
| 1726 | \\ _ = @as(c_int, 2); | |
| 1727 | \\ _ = @as(c_int, 4); | |
| 1728 | \\ _ = @as(c_int, 2); | |
| 1729 | \\ _ = @as(c_int, 4); | |
| 1730 | \\ return @as(c_int, 6); | |
| 1726 | \\ _ = (blk: { | |
| 1727 | \\ _ = @as(c_int, 2); | |
| 1728 | \\ break :blk @as(c_int, 4); | |
| 1729 | \\ }); | |
| 1730 | \\ return (blk: { | |
| 1731 | \\ _ = (blk_1: { | |
| 1732 | \\ _ = @as(c_int, 2); | |
| 1733 | \\ break :blk_1 @as(c_int, 4); | |
| 1734 | \\ }); | |
| 1735 | \\ break :blk @as(c_int, 6); | |
| 1736 | \\ }); | |
| 1731 | 1737 | \\} |
| 1732 | 1738 | }); |
| 1733 | 1739 | |
| ... | ... | @@ -1774,8 +1780,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1774 | 1780 | \\ while (true) { |
| 1775 | 1781 | \\ var a_1: c_int = 4; |
| 1776 | 1782 | \\ a_1 = 9; |
| 1777 | \\ _ = @as(c_int, 6); | |
| 1778 | \\ return a_1; | |
| 1783 | \\ return (blk: { | |
| 1784 | \\ _ = @as(c_int, 6); | |
| 1785 | \\ break :blk a_1; | |
| 1786 | \\ }); | |
| 1779 | 1787 | \\ } |
| 1780 | 1788 | \\ while (true) { |
| 1781 | 1789 | \\ var a_1: c_int = 2; |
| ... | ... | @@ -1805,9 +1813,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1805 | 1813 | \\ var b: c_int = 4; |
| 1806 | 1814 | \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) { |
| 1807 | 1815 | \\ var a: c_int = 2; |
| 1808 | \\ a = 6; | |
| 1809 | \\ _ = @as(c_int, 5); | |
| 1810 | \\ _ = @as(c_int, 7); | |
| 1816 | \\ _ = (blk: { | |
| 1817 | \\ _ = (blk_1: { | |
| 1818 | \\ a = 6; | |
| 1819 | \\ break :blk_1 @as(c_int, 5); | |
| 1820 | \\ }); | |
| 1821 | \\ break :blk @as(c_int, 7); | |
| 1822 | \\ }); | |
| 1811 | 1823 | \\ } |
| 1812 | 1824 | \\ } |
| 1813 | 1825 | \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2))); |