diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 94d1928a4c..19b6146109 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -79,6 +79,7 @@ pub const ZigClangPreprocessingRecord = @OpaqueType(); pub const ZigClangFloatingLiteral = @OpaqueType(); pub const ZigClangConstantExpr = @OpaqueType(); pub const ZigClangCharacterLiteral = @OpaqueType(); +pub const ZigClangStmtExpr = @OpaqueType(); pub const ZigClangBO = extern enum { PtrMemD, @@ -1095,3 +1096,5 @@ pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiter pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; +pub extern fn ZigClangStmtExpr_getSubStmt( *const ZigClangStmtExpr) *const ZigClangCompoundStmt; + diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 4f8aa97bda..60eafc3596 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -855,6 +855,7 @@ fn transStmt( .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), + .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), else => { return revertAndWarn( rp, @@ -1165,12 +1166,9 @@ fn transImplicitCastExpr( const src_type = getExprQualType(c, sub_expr); return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); }, - .FunctionToPointerDecay, .ArrayToPointerDecay => { + .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => { return maybeSuppressResult(rp, scope, result_used, sub_expr_node); }, - .LValueToRValue, .NoOp => { - return transExpr(rp, scope, sub_expr, .used, .r_value); - }, .NullToPointer => { return try transCreateNodeNullLiteral(rp.c); }, @@ -1960,6 +1958,38 @@ fn transCharLiteral( } } +fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node { + const comp = ZigClangStmtExpr_getSubStmt(stmt); + if (used == .unused) { + return transCompoundStmt(rp, scope, comp); + } + const lparen = try appendToken(rp.c, .LParen, "("); + const block_scope = try Scope.Block.init(rp.c, scope, "blk"); + const block = try transCreateNodeBlock(rp.c, "blk"); + block_scope.block_node = block; + + var it = ZigClangCompoundStmt_body_begin(comp); + const end_it = ZigClangCompoundStmt_body_end(comp); + while (it != end_it - 1) : (it += 1) { + const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); + if (result != &block.base) + try block.statements.push(result); + } + const break_node = try transCreateNodeBreak(rp.c, "blk"); + break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); + _ = try appendToken(rp.c, .Semicolon, ";"); + try block.statements.push(&break_node.base); + block.rbrace = try appendToken(rp.c, .RBrace, "}"); + const rparen = try appendToken(rp.c, .RParen, ")"); + const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); + grouped_expr.* = .{ + .lparen = lparen, + .expr = &block.base, + .rparen = rparen, + }; + return maybeSuppressResult(rp, scope, used, &grouped_expr.base); +} + fn transCPtrCast( rp: RestorePoint, loc: ZigClangSourceLocation, diff --git a/test/translate_c.zig b/test/translate_c.zig index e925e384fa..475e066845 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1476,6 +1476,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("statement expression", + \\int foo(void) { + \\ return ({ + \\ int a = 1; + \\ a; + \\ a; + \\ }); + \\} + , &[_][]const u8{ + \\pub export fn foo() c_int { + \\ return (blk: { + \\ var a: c_int = 1; + \\ _ = a; + \\ break :blk a; + \\ }); + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.addAllowWarnings("simple data types", @@ -1723,22 +1741,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("statement expression", - \\int foo(void) { - \\ return ({ - \\ int a = 1; - \\ a; - \\ }); - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return x: { - \\ var a: c_int = 1; - \\ break :x a; - \\ }; - \\} - }); - cases.addC("__extension__ cast", \\int foo(void) { \\ return __extension__ 1; @@ -2609,4 +2611,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return (a & b) ^ (a | b); \\} }); + + cases.addC("statement expression", + \\int foo(void) { + \\ return ({ + \\ int a = 1; + \\ a; + \\ }); + \\} + , &[_][]const u8{ + \\pub export fn foo() c_int { + \\ return x: { + \\ var a: c_int = 1; + \\ break :x a; + \\ }; + \\} + }); }