diff --git a/src/translate_c.cpp b/src/translate_c.cpp index f192779826..6ca51b13d9 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -690,6 +690,13 @@ static bool qual_type_child_is_fn_proto(const clang::QualType &qt) { static AstNode* trans_c_cast(Context *c, const clang::SourceLocation &source_location, clang::QualType dest_type, clang::QualType src_type, AstNode *expr) { + // The only way void pointer casts are valid C code, is if + // the value of the expression is ignored. We therefore just + // return the expr, and let the system that ignores values + // translate this correctly. + if (qual_type_canon(dest_type)->isVoidType()) { + return expr; + } if (qual_types_equal(dest_type, src_type)) { return expr; } @@ -1225,6 +1232,31 @@ static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const clang:: return child_scope_block->node; } +static AstNode *trans_stmt_expr(Context *c, ResultUsed result_used, TransScope *scope, + const clang::StmtExpr *stmt, TransScope **out_node_scope) +{ + AstNode *block = trans_compound_stmt(c, scope, stmt->getSubStmt(), out_node_scope); + if (block == nullptr) + return block; + assert(block->type == NodeTypeBlock); + if (block->data.block.statements.length == 0) + return block; + + Buf *label = buf_create_from_str("x"); + block->data.block.name = label; + AstNode *return_expr = block->data.block.statements.pop(); + if (return_expr->type == NodeTypeBinOpExpr && + return_expr->data.bin_op_expr.bin_op == BinOpTypeAssign && + return_expr->data.bin_op_expr.op1->type == NodeTypeSymbol) + { + Buf *symbol_buf = return_expr->data.bin_op_expr.op1->data.symbol_expr.symbol; + if (strcmp("_", buf_ptr(symbol_buf)) == 0) + return_expr = return_expr->data.bin_op_expr.op2; + } + block->data.block.statements.append(trans_create_node_break(c, label, return_expr)); + return maybe_suppress_result(c, result_used, block); +} + static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::ReturnStmt *stmt) { const clang::Expr *value_expr = stmt->getRetValue(); if (value_expr == nullptr) { @@ -1238,13 +1270,15 @@ static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::Re } } -static AstNode *trans_integer_literal(Context *c, const clang::IntegerLiteral *stmt) { +static AstNode *trans_integer_literal(Context *c, ResultUsed result_used, const clang::IntegerLiteral *stmt) { llvm::APSInt result; if (!stmt->EvaluateAsInt(result, *reinterpret_cast(c->ctx))) { emit_warning(c, stmt->getLocStart(), "invalid integer literal"); return nullptr; } - return trans_create_node_apint(c, result); + + AstNode *node = trans_create_node_apint(c, result); + return maybe_suppress_result(c, result_used, node); } static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope, @@ -1381,14 +1415,17 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS case clang::BO_Cmp: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: clang::BO_Cmp"); return nullptr; - case clang::BO_Mul: - return trans_create_bin_op(c, scope, stmt->getLHS(), + case clang::BO_Mul: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } case clang::BO_Div: if (qual_type_has_wrapping_overflow(c, stmt->getType())) { // unsigned/float division uses the operator - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); } else { // signed integer division uses @divTrunc AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); @@ -1398,12 +1435,13 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); if (rhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(rhs); - return fn_call; + return maybe_suppress_result(c, result_used, fn_call); } case clang::BO_Rem: if (qual_type_has_wrapping_overflow(c, stmt->getType())) { // unsigned/float division uses the operator - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); } else { // signed integer division uses @rem AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); @@ -1413,42 +1451,72 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); if (rhs == nullptr) return nullptr; fn_call->data.fn_call_expr.params.append(rhs); - return fn_call; + return maybe_suppress_result(c, result_used, fn_call); } - case clang::BO_Add: - return trans_create_bin_op(c, scope, stmt->getLHS(), + case clang::BO_Add: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, stmt->getRHS()); - case clang::BO_Sub: - return trans_create_bin_op(c, scope, stmt->getLHS(), + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_Sub: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, stmt->getRHS()); - case clang::BO_Shl: - return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); - case clang::BO_Shr: - return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); - case clang::BO_LT: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); - case clang::BO_GT: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); - case clang::BO_LE: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); - case clang::BO_GE: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); - case clang::BO_EQ: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); - case clang::BO_NE: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); - case clang::BO_And: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); - case clang::BO_Xor: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); - case clang::BO_Or: - return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); - case clang::BO_LAnd: - return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); - case clang::BO_LOr: - return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_Shl: { + AstNode *node = trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_Shr: { + AstNode *node = trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_LT: { + AstNode *node =trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_GT: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_LE: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_GE: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_EQ: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_NE: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_And: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_Xor: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_Or: { + AstNode *node = trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_LAnd: { + AstNode *node = trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } + case clang::BO_LOr: { + AstNode *node = trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); + return maybe_suppress_result(c, result_used, node); + } case clang::BO_Assign: return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS()); case clang::BO_Comma: @@ -1460,13 +1528,15 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue); if (lhs == nullptr) return nullptr; - scope_block->node->data.block.statements.append(maybe_suppress_result(c, ResultUsedNo, lhs)); + scope_block->node->data.block.statements.append(lhs); - AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue); + AstNode *rhs = trans_expr(c, ResultUsedYes, &scope_block->base, stmt->getRHS(), TransRValue); if (rhs == nullptr) return nullptr; - scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs))); - return scope_block->node; + + rhs = trans_create_node_break(c, label_name, rhs); + scope_block->node->data.block.statements.append(rhs); + return maybe_suppress_result(c, result_used, scope_block->node); } case clang::BO_MulAssign: case clang::BO_DivAssign: @@ -1692,7 +1762,7 @@ static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_use zig_unreachable(); } -static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const clang::ImplicitCastExpr *stmt) { +static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { case clang::CK_LValueToRValue: return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); @@ -1701,8 +1771,9 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const cl AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) return nullptr; - return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), + AstNode *node = trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), stmt->getSubExpr()->getType(), target_node); + return maybe_suppress_result(c, result_used, node); } case clang::CK_FunctionToPointerDecay: case clang::CK_ArrayToPointerDecay: @@ -1710,7 +1781,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const cl AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) return nullptr; - return target_node; + return maybe_suppress_result(c, result_used, target_node); } case clang::CK_BitCast: { @@ -1727,7 +1798,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const cl AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); node->data.fn_call_expr.params.append(dest_type_node); node->data.fn_call_expr.params.append(target_node); - return node; + return maybe_suppress_result(c, result_used, node); } case clang::CK_NullToPointer: return trans_create_node_unsigned(c, 0); @@ -2103,8 +2174,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Imag"); return nullptr; case clang::UO_Extension: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Extension"); - return nullptr; + return trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue); case clang::UO_Coawait: emit_warning(c, stmt->getLocStart(), "TODO handle C translation clang::UO_Coawait"); return nullptr; @@ -2721,7 +2791,9 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * return node; } -static AstNode *trans_member_expr(Context *c, TransScope *scope, const clang::MemberExpr *stmt) { +static AstNode *trans_member_expr(Context *c, ResultUsed result_used, TransScope *scope, + const clang::MemberExpr *stmt) +{ AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); if (container_node == nullptr) return nullptr; @@ -2733,10 +2805,10 @@ static AstNode *trans_member_expr(Context *c, TransScope *scope, const clang::Me const char *name = decl_name(stmt->getMemberDecl()); AstNode *node = trans_create_node_field_access_str(c, container_node, name); - return node; + return maybe_suppress_result(c, result_used, node); } -static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const clang::ArraySubscriptExpr *stmt) { +static AstNode *trans_array_subscript_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::ArraySubscriptExpr *stmt) { AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); if (container_node == nullptr) return nullptr; @@ -2749,21 +2821,25 @@ static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); node->data.array_access_expr.array_ref_expr = container_node; node->data.array_access_expr.subscript = idx_node; - return node; + return maybe_suppress_result(c, result_used, node); } static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::CStyleCastExpr *stmt, TransLRValue lrvalue) { - AstNode *sub_expr_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), lrvalue); + AstNode *sub_expr_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), lrvalue); if (sub_expr_node == nullptr) return nullptr; - return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node); + AstNode *cast = trans_c_cast(c, stmt->getLocStart(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node); + if (cast == nullptr) + return nullptr; + + return maybe_suppress_result(c, result_used, cast); } -static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope, - const clang::UnaryExprOrTypeTraitExpr *stmt) +static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, ResultUsed result_used, + TransScope *scope, const clang::UnaryExprOrTypeTraitExpr *stmt) { AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); if (type_node == nullptr) @@ -2771,7 +2847,7 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scop AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); node->data.fn_call_expr.params.append(type_node); - return node; + return maybe_suppress_result(c, result_used, node); } static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang::DoStmt *stmt) { @@ -3049,11 +3125,13 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const clan return ErrorNone; } -static AstNode *trans_string_literal(Context *c, TransScope *scope, const clang::StringLiteral *stmt) { +static AstNode *trans_string_literal(Context *c, ResultUsed result_used, TransScope *scope, const clang::StringLiteral *stmt) { switch (stmt->getKind()) { case clang::StringLiteral::Ascii: - case clang::StringLiteral::UTF8: - return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString())); + case clang::StringLiteral::UTF8: { + AstNode *node = trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString())); + return maybe_suppress_result(c, result_used, node); + } case clang::StringLiteral::UTF16: emit_warning(c, stmt->getLocStart(), "TODO support UTF16 string literals"); return nullptr; @@ -3085,6 +3163,12 @@ static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const clang:: return trans_create_node(c, NodeTypeContinue); } +static AstNode *trans_predefined_expr(Context *c, ResultUsed result_used, TransScope *scope, + const clang::PredefinedExpr *expr) +{ + return trans_string_literal(c, result_used, scope, expr->getFunctionName()); +} + static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_scope, AstNode *result_node) { if (result_node == nullptr) return ErrorUnexpected; @@ -3109,7 +3193,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st trans_compound_stmt(c, scope, (const clang::CompoundStmt *)stmt, out_node_scope)); case clang::Stmt::IntegerLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_integer_literal(c, (const clang::IntegerLiteral *)stmt)); + trans_integer_literal(c, result_used, (const clang::IntegerLiteral *)stmt)); case clang::Stmt::ConditionalOperatorClass: return wrap_stmt(out_node, out_child_scope, scope, trans_conditional_operator(c, result_used, scope, (const clang::ConditionalOperator *)stmt)); @@ -3121,7 +3205,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st trans_compound_assign_operator(c, result_used, scope, (const clang::CompoundAssignOperator *)stmt)); case clang::Stmt::ImplicitCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_implicit_cast_expr(c, scope, (const clang::ImplicitCastExpr *)stmt)); + trans_implicit_cast_expr(c, result_used, scope, (const clang::ImplicitCastExpr *)stmt)); case clang::Stmt::DeclRefExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_decl_ref_expr(c, scope, (const clang::DeclRefExpr *)stmt, lrvalue)); @@ -3152,28 +3236,28 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st return wrap_stmt(out_node, out_child_scope, scope, trans_call_expr(c, result_used, scope, (const clang::CallExpr *)stmt)); case clang::Stmt::NullStmtClass: - *out_node = nullptr; + *out_node = trans_create_node(c, NodeTypeBlock); *out_child_scope = scope; return ErrorNone; case clang::Stmt::MemberExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_member_expr(c, scope, (const clang::MemberExpr *)stmt)); + trans_member_expr(c, result_used, scope, (const clang::MemberExpr *)stmt)); case clang::Stmt::ArraySubscriptExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_array_subscript_expr(c, scope, (const clang::ArraySubscriptExpr *)stmt)); + trans_array_subscript_expr(c, result_used, scope, (const clang::ArraySubscriptExpr *)stmt)); case clang::Stmt::CStyleCastExprClass: return wrap_stmt(out_node, out_child_scope, scope, trans_c_style_cast_expr(c, result_used, scope, (const clang::CStyleCastExpr *)stmt, lrvalue)); case clang::Stmt::UnaryExprOrTypeTraitExprClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_unary_expr_or_type_trait_expr(c, scope, (const clang::UnaryExprOrTypeTraitExpr *)stmt)); + trans_unary_expr_or_type_trait_expr(c, result_used, scope, (const clang::UnaryExprOrTypeTraitExpr *)stmt)); case clang::Stmt::ForStmtClass: { AstNode *node = trans_for_loop(c, scope, (const clang::ForStmt *)stmt); return wrap_stmt(out_node, out_child_scope, scope, node); } case clang::Stmt::StringLiteralClass: return wrap_stmt(out_node, out_child_scope, scope, - trans_string_literal(c, scope, (const clang::StringLiteral *)stmt)); + trans_string_literal(c, result_used, scope, (const clang::StringLiteral *)stmt)); case clang::Stmt::BreakStmtClass: return wrap_stmt(out_node, out_child_scope, scope, trans_break_stmt(c, scope, (const clang::BreakStmt *)stmt)); @@ -3479,8 +3563,8 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); return ErrorUnexpected; case clang::Stmt::PredefinedExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); - return ErrorUnexpected; + return wrap_stmt(out_node, out_child_scope, scope, + trans_predefined_expr(c, result_used, scope, (const clang::PredefinedExpr *)stmt)); case clang::Stmt::PseudoObjectExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); return ErrorUnexpected; @@ -3491,8 +3575,8 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *st emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); return ErrorUnexpected; case clang::Stmt::StmtExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); - return ErrorUnexpected; + return wrap_stmt(out_node, out_child_scope, scope, + trans_stmt_expr(c, result_used, scope, (const clang::StmtExpr *)stmt, out_node_scope)); case clang::Stmt::SubstNonTypeTemplateParmExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); return ErrorUnexpected; diff --git a/test/translate_c.zig b/test/translate_c.zig index 5ed57de2f4..cd8e7cb6d0 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -59,6 +59,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void { ); } + cases.add("predefined expressions", + \\void foo(void) { + \\ __func__; + \\ __FUNCTION__; + \\ __PRETTY_FUNCTION__; + \\} + , + \\pub fn foo() void { + \\ _ = c"foo"; + \\ _ = c"foo"; + \\ _ = c"void foo(void)"; + \\} + ); + + cases.add("ignore result", + \\void foo() { + \\ int a; + \\ 1; + \\ "hey"; + \\ 1 + 1; + \\ 1 - 1; + \\ a = 1; + \\} + , + \\pub fn foo() void { + \\ var a: c_int = undefined; + \\ _ = 1; + \\ _ = c"hey"; + \\ _ = (1 + 1); + \\ _ = (1 - 1); + \\ a = 1; + \\} + ); + cases.add("for loop with var init but empty body", \\void foo(void) { \\ for (int x = 0; x < 10; x++); @@ -79,6 +113,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , // TODO this should be if (1 != 0) break \\pub fn foo() void { \\ while (true) { + \\ {} \\ if (!1) break; \\ } \\} @@ -511,11 +546,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return b; \\ else \\ return a; + \\ + \\ if (a < b) ; else ; \\} , \\pub export fn max(a: c_int, b: c_int) c_int { \\ if (a < b) return b; \\ if (a < b) return b else return a; + \\ if (a < b) {} else {} \\} ); @@ -720,7 +758,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ ;;;;; \\} , - \\pub export fn foo() void {} + \\pub export fn foo() void { + \\ {} + \\ {} + \\ {} + \\ {} + \\ {} + \\} ); cases.add("undefined array global", @@ -751,6 +795,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); + cases.addC("void cast", + \\void foo(int a) { + \\ (void) a; + \\} + , + \\pub export fn foo(a: c_int) void { + \\ _ = a; + \\} + ); + cases.addC("implicit cast to void *", \\void *foo(unsigned short *x) { \\ return x; @@ -795,6 +849,32 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); + cases.addC("statement expression", + \\int foo(void) { + \\ return ({ + \\ int a = 1; + \\ a; + \\ }); + \\} + , + \\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; + \\} + , + \\pub export fn foo() c_int { + \\ return 1; + \\} + ); + cases.addC("bitshift", \\int foo(void) { \\ return (1 << 2) >> 1; @@ -1425,52 +1505,52 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn bar() void {} ); - cases.addC("u integer suffix after 0 (zero) in macro definition", - "#define ZERO 0U" - , - "pub const ZERO = c_uint(0);" + cases.addC( + "u integer suffix after 0 (zero) in macro definition", + "#define ZERO 0U", + "pub const ZERO = c_uint(0);", ); - cases.addC("l integer suffix after 0 (zero) in macro definition", - "#define ZERO 0L" - , - "pub const ZERO = c_long(0);" + cases.addC( + "l integer suffix after 0 (zero) in macro definition", + "#define ZERO 0L", + "pub const ZERO = c_long(0);", ); - cases.addC("ul integer suffix after 0 (zero) in macro definition", - "#define ZERO 0UL" - , - "pub const ZERO = c_ulong(0);" + cases.addC( + "ul integer suffix after 0 (zero) in macro definition", + "#define ZERO 0UL", + "pub const ZERO = c_ulong(0);", ); - cases.addC("lu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LU" - , - "pub const ZERO = c_ulong(0);" + cases.addC( + "lu integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LU", + "pub const ZERO = c_ulong(0);", ); - cases.addC("ll integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LL" - , - "pub const ZERO = c_longlong(0);" + cases.addC( + "ll integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LL", + "pub const ZERO = c_longlong(0);", ); - cases.addC("ull integer suffix after 0 (zero) in macro definition", - "#define ZERO 0ULL" - , - "pub const ZERO = c_ulonglong(0);" + cases.addC( + "ull integer suffix after 0 (zero) in macro definition", + "#define ZERO 0ULL", + "pub const ZERO = c_ulonglong(0);", ); - cases.addC("llu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LLU" - , - "pub const ZERO = c_ulonglong(0);" + cases.addC( + "llu integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LLU", + "pub const ZERO = c_ulonglong(0);", ); - cases.addC("bitwise not on u-suffixed 0 (zero) in macro definition", - "#define NOT_ZERO (~0U)" - , - "pub const NOT_ZERO = ~c_uint(0);" + cases.addC( + "bitwise not on u-suffixed 0 (zero) in macro definition", + "#define NOT_ZERO (~0U)", + "pub const NOT_ZERO = ~c_uint(0);", ); // cases.add("empty array with initializer",