translate_c: prevent a while under an if from stealing the else

This commit is contained in:
Matthew Borkowski 2021-10-19 03:45:18 -04:00 committed by Andrew Kelley
parent 135cb529de
commit 2d7b55aa0a
2 changed files with 40 additions and 9 deletions

View file

@ -2808,14 +2808,16 @@ fn maybeBlockify(c: *Context, scope: *Scope, stmt: *const clang.Stmt) TransError
.NullStmtClass, .NullStmtClass,
.WhileStmtClass, .WhileStmtClass,
=> return transStmt(c, scope, stmt, .unused), => return transStmt(c, scope, stmt, .unused),
else => { 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); var block_scope = try Scope.Block.init(c, scope, false);
defer block_scope.deinit(); defer block_scope.deinit();
const result = try transStmt(c, &block_scope.base, stmt, .unused); const result = try transStmt(c, &block_scope.base, stmt, .unused);
try block_scope.statements.append(result); try block_scope.statements.append(result);
return block_scope.complete(c); return block_scope.complete(c);
},
}
} }
fn transIfStmt( fn transIfStmt(
@ -2835,9 +2837,21 @@ fn transIfStmt(
const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond()); const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); 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 else_body = if (stmt.getElse()) |expr| const then_body = if (must_blockify)
try blockify(c, scope, then_stmt)
else
try maybeBlockify(c, scope, then_stmt);
const else_body = if (else_stmt) |expr|
try maybeBlockify(c, scope, expr) try maybeBlockify(c, scope, expr)
else else
null; null;

View file

@ -1767,4 +1767,21 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0; \\ 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;
\\}
, "");
} }