Commit d54c288bd3
Changed files (3)
src-self-hosted
test
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;
+
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;
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 <stddef.h>
\\size_t size_of(void) {