diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index a3ad42225a57b22fd94c0c288aaffacdbee36f22..bf7adce1e0df1fea548248fbf21411a3ce8de59b 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -839,6 +839,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool; pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint; pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType; +pub extern fn ZigClangFunctionProtoType_getReturnType(self: *const ZigClangFunctionProtoType) ZigClangQualType; pub const ZigClangSourceLocation = struct_ZigClangSourceLocation; pub const ZigClangQualType = struct_ZigClangQualType; @@ -993,6 +994,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType; pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt; pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl; +pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl; pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; @@ -1105,3 +1107,7 @@ pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const pub extern fn ZigClangArraySubscriptExpr_getBase(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; pub extern fn ZigClangArraySubscriptExpr_getIdx(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; +pub extern fn ZigClangCallExpr_getCallee(*const ZigClangCallExpr) *const ZigClangExpr; +pub extern fn ZigClangCallExpr_getNumArgs(*const ZigClangCallExpr) c_uint; +pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const ZigClangExpr; + diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index e13e28608bb02b197886aae2a0c500257fcfab55..2247c4dc916a7971cd2e4e3769091c0b2a195fe5 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -851,6 +851,7 @@ fn transStmt( .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used), + .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used), else => { return revertAndWarn( rp, @@ -2004,6 +2005,73 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS return maybeSuppressResult(rp, scope, result_used, &node.base); } +fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, result_used: ResultUsed) TransError!*ast.Node { + const callee = ZigClangCallExpr_getCallee(stmt); + var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value); + + var is_ptr = false; + const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(callee), &is_ptr); + + const fn_expr = if (is_ptr and fn_ty != null) blk: { + if (ZigClangExpr_getStmtClass(callee) == .ImplicitCastExprClass) { + const implicit_cast = @ptrCast(*const ZigClangImplicitCastExpr, callee); + + if (ZigClangImplicitCastExpr_getCastKind(implicit_cast) == .FunctionToPointerDecay) { + const subexpr = ZigClangImplicitCastExpr_getSubExpr(implicit_cast); + if (ZigClangExpr_getStmtClass(subexpr) == .DeclRefExprClass) { + const decl_ref = @ptrCast(*const ZigClangDeclRefExpr, subexpr); + const named_decl = ZigClangDeclRefExpr_getFoundDecl(decl_ref); + if (ZigClangDecl_getKind(@ptrCast(*const ZigClangDecl, named_decl)) == .Function) { + break :blk raw_fn_expr; + } + } + } + } + break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); + } else + raw_fn_expr; + const node = try transCreateNodeFnCall(rp.c, fn_expr); + + const num_args = ZigClangCallExpr_getNumArgs(stmt); + const args = ZigClangCallExpr_getArgs(stmt); + var i: usize = 0; + while (i < num_args) : (i+=1) { + if (i != 0) { + _ = try appendToken(rp.c, .Comma, ","); + } + const arg = try transExpr(rp, scope, args[i], .used, .r_value); + try node.op.Call.params.push(arg); + } + node.rtoken = try appendToken(rp.c, .RParen, ")"); + + if (fn_ty) |ty| { + const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty)); + const ret_ty = ZigClangQualType_getTypePtr(canon); + if (ZigClangType_isVoidType(ret_ty)) { + _ = try appendToken(rp.c, .Semicolon, ";"); + return &node.base; + } + } + + return maybeSuppressResult(rp, scope, result_used, &node.base); +} + +fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType { + const canon = ZigClangQualType_getCanonicalType(qt); + var ty = ZigClangQualType_getTypePtr(canon); + is_ptr.* = false; + + if (ZigClangType_getTypeClass(ty) == .Pointer) { + is_ptr.* = true; + const child_qt = ZigClangType_getPointeeType(ty); + ty = ZigClangQualType_getTypePtr(child_qt); + } + if (ZigClangType_getTypeClass(ty) == .FunctionProto) { + return @ptrCast(*const ZigClangFunctionProtoType, ty); + } + return null; +} + fn transCPtrCast( rp: RestorePoint, loc: ZigClangSourceLocation, @@ -3947,6 +4015,22 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc if (it.next().?.id != .RBrace) return error.ParseError; }, + .LParen => { + const call_node = try transCreateNodeFnCall(rp.c, node); + while (true) { + const arg = try parseCExpr(rp, it, source_loc, scope); + try call_node.op.Call.params.push(arg); + const next = it.next().?; + if (next.id == .Comma) + _ = try appendToken(rp.c, .Comma, ",") + else if (next.id == .RParen) + break + else + return error.ParseError; + } + call_node.rtoken = try appendToken(rp.c, .RParen, ")"); + node = &call_node.base; + }, else => { _ = it.prev(); return node; diff --git a/test/translate_c.zig b/test/translate_c.zig index d34bfd9e8aedf6f37d37ae523bbe5fbb2d73d3b3..7f349c54c4d94924ec58de3b9b4669f34317c530 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -702,6 +702,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.addC_both("function call", + \\static void bar(void) { } + \\void foo(int *(baz)(void)) { + \\ bar(); + \\ baz(); + \\} + , &[_][]const u8{ + \\pub fn bar() void {} + \\pub export fn foo(baz: ?extern fn () [*c]c_int) void { + \\ bar(); + \\ _ = baz.?(); + \\} + }); + /////////////// Cases that pass for only stage2 //////////////// cases.add_2("Parameterless function prototypes", @@ -1538,6 +1552,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const ACCESS = array[2]; }); + cases.add_2("macro call", + \\#define CALL(arg) bar(arg) + , &[_][]const u8{ + \\pub inline fn CALL(arg: var) @TypeOf(bar(arg)) { + \\ return bar(arg); + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.addAllowWarnings("simple data types", @@ -1728,24 +1750,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("function call", - \\static void bar(void) { } - \\static int baz(void) { return 0; } - \\void foo(void) { - \\ bar(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub fn bar() void {} - \\pub fn baz() c_int { - \\ return 0; - \\} - \\pub export fn foo() void { - \\ bar(); - \\ _ = baz(); - \\} - }); - cases.addC("sizeof", \\#include \\size_t size_of(void) {