diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 2a0a31af16..c6a25271b8 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -500,15 +500,31 @@ static bool qual_type_is_ptr(QualType qt) { return ty->getTypeClass() == Type::Pointer; } -static bool qual_type_is_fn_ptr(Context *c, QualType qt) { +static const FunctionProtoType *qual_type_get_fn_proto(QualType qt, bool *is_ptr) { const Type *ty = qual_type_canon(qt); - if (ty->getTypeClass() != Type::Pointer) { - return false; + *is_ptr = false; + + if (ty->getTypeClass() == Type::Pointer) { + *is_ptr = true; + const PointerType *pointer_ty = static_cast(ty); + QualType child_qt = pointer_ty->getPointeeType(); + ty = child_qt.getTypePtr(); } - const PointerType *pointer_ty = static_cast(ty); - QualType child_qt = pointer_ty->getPointeeType(); - const Type *child_ty = child_qt.getTypePtr(); - return child_ty->getTypeClass() == Type::FunctionProto; + + if (ty->getTypeClass() == Type::FunctionProto) { + return static_cast(ty); + } + + return nullptr; +} + +static bool qual_type_is_fn_ptr(QualType qt) { + bool is_ptr; + if (qual_type_get_fn_proto(qt, &is_ptr)) { + return is_ptr; + } + + return false; } static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { @@ -1871,7 +1887,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue); if (value_node == nullptr) return nullptr; - bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); + bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType()); if (is_fn_ptr) return value_node; AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); @@ -2327,8 +2343,10 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * if (callee_raw_node == nullptr) return nullptr; + bool is_ptr = false; + const FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr); AstNode *callee_node = nullptr; - if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { + if (is_ptr && fn_ty) { if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) { const ImplicitCastExpr *implicit_cast = static_cast(stmt->getCallee()); if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) { @@ -2360,6 +2378,10 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * node->data.fn_call_expr.params.append(arg_node); } + if (result_used == ResultUsedNo && fn_ty && !qual_type_canon(fn_ty->getReturnType())->isVoidType()) { + node = trans_create_node_bin_op(c, trans_create_node_symbol_str(c, "_"), BinOpTypeAssign, node); + } + return node; } diff --git a/test/translate_c.zig b/test/translate_c.zig index 74bf5a1cb5..0cfefe79ab 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -515,11 +515,19 @@ pub fn addCases(cases: &tests.TranslateCContext) void { cases.addC("function call", \\static void bar(void) { } - \\void foo(void) { bar(); } + \\static int baz(void) { return 0; } + \\void foo(void) { + \\ bar(); + \\ baz(); + \\} , \\pub fn bar() void {} + \\pub fn baz() c_int { + \\ return 0; + \\} \\pub export fn foo() void { \\ bar(); + \\ _ = baz(); \\} ); @@ -878,21 +886,31 @@ pub fn addCases(cases: &tests.TranslateCContext) void { cases.addC("deref function pointer", \\void foo(void) {} - \\void baz(void) {} + \\int baz(void) { return 0; } \\void bar(void) { \\ void(*f)(void) = foo; + \\ int(*b)(void) = baz; \\ f(); \\ (*(f))(); + \\ foo(); + \\ b(); + \\ (*(b))(); \\ baz(); \\} , \\pub export fn foo() void {} - \\pub export fn baz() void {} + \\pub export fn baz() c_int { + \\ return 0; + \\} \\pub export fn bar() void { \\ var f: ?extern fn() void = foo; + \\ var b: ?extern fn() c_int = baz; \\ (??f)(); \\ (??f)(); - \\ baz(); + \\ foo(); + \\ _ = (??b)(); + \\ _ = (??b)(); + \\ _ = baz(); \\} );