authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-02-11 09:43:30-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-12 01:40:43+02:00
logd98f09e4f67fb2848be6052466db035450326605
tree736c6f57967ddaaa9e386026d0114c66c1dba5fd
parent61bcac108cecba0ab8e1b442bd71c51306c0e9fc

translate-c: comma operator should introduce a new scope

This prevents inadvertent side-effects when an expression is not evaluated due to boolean short-circuiting Fixes #7989

3 files changed, 49 insertions(+), 29 deletions(-)

src/translate_c.zig+14-19
...@@ -1438,30 +1438,25 @@ fn transBinaryOperator(...@@ -1438,30 +1438,25 @@ fn transBinaryOperator(
1438 switch (op) {1438 switch (op) {
1439 .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()),1439 .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()),
1440 .Comma => {1440 .Comma => {
1441 const block_scope = try scope.findBlockScope(rp.c);1441 var block_scope = try Scope.Block.init(rp.c, scope, true);
1442 const expr = block_scope.base.parent == scope;1442 const lparen = try appendToken(rp.c, .LParen, "(");
1443 const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined;
14441443
1445 const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value);1444 const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value);
1446 try block_scope.statements.append(lhs);1445 try block_scope.statements.append(lhs);
14471446
1448 const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value);1447 const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value);
1449 if (expr) {1448 _ = try appendToken(rp.c, .Semicolon, ";");
1450 _ = try appendToken(rp.c, .Semicolon, ";");1449 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);
1451 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);1450 try block_scope.statements.append(&break_node.base);
1452 try block_scope.statements.append(&break_node.base);1451 const block_node = try block_scope.complete(rp.c);
1453 const block_node = try block_scope.complete(rp.c);1452 const rparen = try appendToken(rp.c, .RParen, ")");
1454 const rparen = try appendToken(rp.c, .RParen, ")");1453 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1455 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);1454 grouped_expr.* = .{
1456 grouped_expr.* = .{1455 .lparen = lparen,
1457 .lparen = lparen,1456 .expr = block_node,
1458 .expr = block_node,1457 .rparen = rparen,
1459 .rparen = rparen,1458 };
1460 };1459 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
1461 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
1462 } else {
1463 return maybeSuppressResult(rp, scope, result_used, rhs);
1464 }
1465 },1460 },
1466 .Div => {1461 .Div => {
1467 if (cIsSignedInteger(qt)) {1462 if (cIsSignedInteger(qt)) {
test/run_translated_c.zig+13
...@@ -909,4 +909,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -909,4 +909,17 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
909 \\ return 1 != 1;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,11 +1723,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1723 \\}1723 \\}
1724 , &[_][]const u8{1724 , &[_][]const u8{
1725 \\pub export fn foo() c_int {1725 \\pub export fn foo() c_int {
1726 \\ _ = @as(c_int, 2);1726 \\ _ = (blk: {
1727 \\ _ = @as(c_int, 4);1727 \\ _ = @as(c_int, 2);
1728 \\ _ = @as(c_int, 2);1728 \\ break :blk @as(c_int, 4);
1729 \\ _ = @as(c_int, 4);1729 \\ });
1730 \\ return @as(c_int, 6);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 });
17331739
...@@ -1774,8 +1780,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1774,8 +1780,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1774 \\ while (true) {1780 \\ while (true) {
1775 \\ var a_1: c_int = 4;1781 \\ var a_1: c_int = 4;
1776 \\ a_1 = 9;1782 \\ a_1 = 9;
1777 \\ _ = @as(c_int, 6);1783 \\ return (blk: {
1778 \\ return a_1;1784 \\ _ = @as(c_int, 6);
1785 \\ break :blk a_1;
1786 \\ });
1779 \\ }1787 \\ }
1780 \\ while (true) {1788 \\ while (true) {
1781 \\ var a_1: c_int = 2;1789 \\ var a_1: c_int = 2;
...@@ -1805,9 +1813,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1805,9 +1813,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1805 \\ var b: c_int = 4;1813 \\ var b: c_int = 4;
1806 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {1814 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
1807 \\ var a: c_int = 2;1815 \\ var a: c_int = 2;
1808 \\ a = 6;1816 \\ _ = (blk: {
1809 \\ _ = @as(c_int, 5);1817 \\ _ = (blk_1: {
1810 \\ _ = @as(c_int, 7);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 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));1825 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));