Commit 2d7b55aa0a

Matthew Borkowski <matthew.h.borkowski@gmail.com>
2021-10-19 09:45:18
translate_c: prevent a while under an if from stealing the else
1 parent 135cb52
Changed files (2)
src/translate_c.zig
@@ -2808,16 +2808,18 @@ fn maybeBlockify(c: *Context, scope: *Scope, stmt: *const clang.Stmt) TransError
         .NullStmtClass,
         .WhileStmtClass,
         => return transStmt(c, scope, stmt, .unused),
-        else => {
-            var block_scope = try Scope.Block.init(c, scope, false);
-            defer block_scope.deinit();
-            const result = try transStmt(c, &block_scope.base, stmt, .unused);
-            try block_scope.statements.append(result);
-            return block_scope.complete(c);
-        },
+        else => return blockify(c, scope, stmt),
     }
 }
 
+fn blockify(c: *Context, scope: *Scope, stmt: *const clang.Stmt) TransError!Node {
+    var block_scope = try Scope.Block.init(c, scope, false);
+    defer block_scope.deinit();
+    const result = try transStmt(c, &block_scope.base, stmt, .unused);
+    try block_scope.statements.append(result);
+    return block_scope.complete(c);
+}
+
 fn transIfStmt(
     c: *Context,
     scope: *Scope,
@@ -2835,9 +2837,21 @@ fn transIfStmt(
     const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
     const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
 
-    const then_body = try maybeBlockify(c, scope, stmt.getThen());
+    const then_stmt = stmt.getThen();
+    const else_stmt = stmt.getElse();
+    const then_class = then_stmt.getStmtClass();
+    // block needed to keep else statement from attaching to inner while
+    const must_blockify = (else_stmt != null) and switch (then_class) {
+        .DoStmtClass, .ForStmtClass, .WhileStmtClass => true,
+        else => false,
+    };
+
+    const then_body = if (must_blockify)
+        try blockify(c, scope, then_stmt)
+    else
+        try maybeBlockify(c, scope, then_stmt);
 
-    const else_body = if (stmt.getElse()) |expr|
+    const else_body = if (else_stmt) |expr|
         try maybeBlockify(c, scope, expr)
     else
         null;
test/run_translated_c.zig
@@ -1767,4 +1767,21 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\   return 0;
         \\}
     , "");
+
+    cases.add("Ensure while loop under an if doesn't steal the else. Issue #9953",
+        \\#include <stdio.h>
+        \\void doWork(int id) { }
+        \\int reallyDelete(int id) { printf("deleted %d\n", id); return 1; }
+        \\int process(int id, int n, int delete) {
+        \\    if(!delete)
+        \\        while(n-- > 0) doWork(id);
+        \\    else
+        \\        return reallyDelete(id);
+        \\    return 0;
+        \\}
+        \\int main(void) {
+        \\    process(99, 3, 0);
+        \\    return 0;
+        \\}
+    , "");
 }