| ... | @@ -1063,6 +1063,7 @@ fn transStmt( | ... | @@ -1063,6 +1063,7 @@ fn transStmt( |
| 1063 | const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt); | 1063 | const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt); |
| 1064 | return transExpr(c, scope, gen_sel.getResultExpr(), result_used); | 1064 | return transExpr(c, scope, gen_sel.getResultExpr(), result_used); |
| 1065 | }, | 1065 | }, |
| | 1066 | // When adding new cases here, see comment for maybeBlockify() |
| 1066 | else => { | 1067 | else => { |
| 1067 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); | 1068 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); |
| 1068 | }, | 1069 | }, |
| ... | @@ -2242,6 +2243,35 @@ fn transImplicitValueInitExpr( | ... | @@ -2242,6 +2243,35 @@ fn transImplicitValueInitExpr( |
| 2242 | return transZeroInitExpr(c, scope, source_loc, ty); | 2243 | return transZeroInitExpr(c, scope, source_loc, ty); |
| 2243 | } | 2244 | } |
| 2244 | | 2245 | |
| | 2246 | /// If a statement can possibly translate to a Zig assignment (either directly because it's |
| | 2247 | /// an assignment in C or indirectly via result assignment to `_`) AND it's the sole statement |
| | 2248 | /// in the body of an if statement or loop, then we need to put the statement into its own block. |
| | 2249 | /// The `else` case here corresponds to statements that could result in an assignment. If a statement |
| | 2250 | /// class never needs a block, add its enum to the top prong. |
| | 2251 | fn maybeBlockify(c: *Context, scope: *Scope, stmt: *const clang.Stmt) TransError!Node { |
| | 2252 | switch (stmt.getStmtClass()) { |
| | 2253 | .BreakStmtClass, |
| | 2254 | .CompoundStmtClass, |
| | 2255 | .ContinueStmtClass, |
| | 2256 | .DeclRefExprClass, |
| | 2257 | .DeclStmtClass, |
| | 2258 | .DoStmtClass, |
| | 2259 | .ForStmtClass, |
| | 2260 | .IfStmtClass, |
| | 2261 | .ReturnStmtClass, |
| | 2262 | .NullStmtClass, |
| | 2263 | .WhileStmtClass, |
| | 2264 | => return transStmt(c, scope, stmt, .unused), |
| | 2265 | else => { |
| | 2266 | var block_scope = try Scope.Block.init(c, scope, false); |
| | 2267 | defer block_scope.deinit(); |
| | 2268 | const result = try transStmt(c, &block_scope.base, stmt, .unused); |
| | 2269 | try block_scope.statements.append(result); |
| | 2270 | return block_scope.complete(c); |
| | 2271 | }, |
| | 2272 | } |
| | 2273 | } |
| | 2274 | |
| 2245 | fn transIfStmt( | 2275 | fn transIfStmt( |
| 2246 | c: *Context, | 2276 | c: *Context, |
| 2247 | scope: *Scope, | 2277 | scope: *Scope, |
| ... | @@ -2259,9 +2289,10 @@ fn transIfStmt( | ... | @@ -2259,9 +2289,10 @@ fn transIfStmt( |
| 2259 | const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond()); | 2289 | const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond()); |
| 2260 | const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); | 2290 | const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); |
| 2261 | | 2291 | |
| 2262 | const then_body = try transStmt(c, scope, stmt.getThen(), .unused); | 2292 | const then_body = try maybeBlockify(c, scope, stmt.getThen()); |
| | 2293 | |
| 2263 | const else_body = if (stmt.getElse()) |expr| | 2294 | const else_body = if (stmt.getElse()) |expr| |
| 2264 | try transStmt(c, scope, expr, .unused) | 2295 | try maybeBlockify(c, scope, expr) |
| 2265 | else | 2296 | else |
| 2266 | null; | 2297 | null; |
| 2267 | return Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body }); | 2298 | return Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body }); |
| ... | @@ -2286,7 +2317,7 @@ fn transWhileLoop( | ... | @@ -2286,7 +2317,7 @@ fn transWhileLoop( |
| 2286 | .parent = scope, | 2317 | .parent = scope, |
| 2287 | .id = .loop, | 2318 | .id = .loop, |
| 2288 | }; | 2319 | }; |
| 2289 | const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused); | 2320 | const body = try maybeBlockify(c, &loop_scope, stmt.getBody()); |
| 2290 | return Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null }); | 2321 | return Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null }); |
| 2291 | } | 2322 | } |
| 2292 | | 2323 | |
| ... | @@ -2312,7 +2343,7 @@ fn transDoWhileLoop( | ... | @@ -2312,7 +2343,7 @@ fn transDoWhileLoop( |
| 2312 | const if_not_break = switch (cond.tag()) { | 2343 | const if_not_break = switch (cond.tag()) { |
| 2313 | .false_literal => return transStmt(c, scope, stmt.getBody(), .unused), | 2344 | .false_literal => return transStmt(c, scope, stmt.getBody(), .unused), |
| 2314 | .true_literal => { | 2345 | .true_literal => { |
| 2315 | const body_node = try transStmt(c, scope, stmt.getBody(), .unused); | 2346 | const body_node = try maybeBlockify(c, scope, stmt.getBody()); |
| 2316 | return Tag.while_true.create(c.arena, body_node); | 2347 | return Tag.while_true.create(c.arena, body_node); |
| 2317 | }, | 2348 | }, |
| 2318 | else => try Tag.if_not_break.create(c.arena, cond), | 2349 | else => try Tag.if_not_break.create(c.arena, cond), |
| ... | @@ -2388,7 +2419,7 @@ fn transForLoop( | ... | @@ -2388,7 +2419,7 @@ fn transForLoop( |
| 2388 | else | 2419 | else |
| 2389 | null; | 2420 | null; |
| 2390 | | 2421 | |
| 2391 | const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused); | 2422 | const body = try maybeBlockify(c, &loop_scope, stmt.getBody()); |
| 2392 | const while_node = try Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr }); | 2423 | const while_node = try Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr }); |
| 2393 | if (block_scope) |*bs| { | 2424 | if (block_scope) |*bs| { |
| 2394 | try bs.statements.append(while_node); | 2425 | try bs.statements.append(while_node); |