From 6be16eeae92120fab81c51dbeaf9960375dc0ab1 Mon Sep 17 00:00:00 2001 From: Tau Date: Mon, 10 Oct 2022 22:30:33 +0200 Subject: [PATCH] translate-c: fix the remaining function pointer issues --- src/translate_c.zig | 18 +++------- src/translate_c/ast.zig | 76 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index e24c78f052..aaf288934e 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -436,7 +436,7 @@ pub fn translate( } } - return ast.render(gpa, context.global_scope.nodes.items); + return ast.render(gpa, zig_is_stage1, context.global_scope.nodes.items); } /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) @@ -2072,10 +2072,7 @@ fn transImplicitCastExpr( }, .PointerToBoolean => { // @ptrToInt(val) != 0 - var ptr_node = try transExpr(c, scope, sub_expr, .used); - if (ptr_node.tag() == .fn_identifier) { - ptr_node = try Tag.address_of.create(c.arena, ptr_node); - } + const ptr_node = try transExpr(c, scope, sub_expr, .used); const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node); const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() }); @@ -2524,10 +2521,7 @@ fn transCCast( } if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { // @intCast(dest_type, @ptrToInt(val)) - const ptr_to_int = if (expr.tag() == .fn_identifier) - try Tag.ptr_to_int.create(c.arena, try Tag.address_of.create(c.arena, expr)) - else - try Tag.ptr_to_int.create(c.arena, expr); + const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr); return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); } if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { @@ -3566,7 +3560,8 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip // Special case: actual pointer (not decayed array) and signed integer subscript // See discussion at https://github.com/ziglang/zig/pull/8589 - if (is_signed and (base_stmt == unwrapped_base) and !is_vector and !is_nonnegative_int_literal) return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); + if (is_signed and (base_stmt == unwrapped_base) and !is_vector and !is_nonnegative_int_literal) + return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used); const container_node = try transExpr(c, scope, unwrapped_base, .used); const rhs = if (is_longlong or is_signed) blk: { @@ -3761,9 +3756,6 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat else return transCreatePreCrement(c, scope, stmt, .sub_assign, used), .AddrOf => { - if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) { - return transExpr(c, scope, op_expr, used); - } return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used)); }, .Deref => { diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index fb71e1c325..4dcdbc4250 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -717,10 +717,11 @@ pub const Payload = struct { /// Converts the nodes into a Zig Ast. /// Caller must free the source slice. -pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast { +pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig.Ast { var ctx = Context{ .gpa = gpa, .buf = std.ArrayList(u8).init(gpa), + .zig_is_stage1 = zig_is_stage1, }; defer ctx.buf.deinit(); defer ctx.nodes.deinit(gpa); @@ -789,6 +790,11 @@ const Context = struct { extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, tokens: std.zig.Ast.TokenList = .{}, + /// This is used to emit different code depending on whether + /// the output zig source code is intended to be compiled with stage1 or stage2. + /// Refer to the Context in translate_c.zig. + zig_is_stage1: bool, + fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { const start_index = c.buf.items.len; try c.buf.writer().print(format ++ " ", args); @@ -910,7 +916,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }, .call => { const payload = node.castTag(.call).?.data; - const lhs = try renderNodeGrouped(c, payload.lhs); + // Cosmetic: avoids an unnecesary address_of on most function calls. + const lhs = if (!c.zig_is_stage1 and payload.lhs.tag() == .fn_identifier) + try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload.lhs.castTag(.fn_identifier).?.data), + .data = undefined, + }) + else + try renderNodeGrouped(c, payload.lhs); return renderCall(c, lhs, payload.args); }, .null_literal => return c.addNode(.{ @@ -1064,12 +1078,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }); }, .fn_identifier => { + // C semantics are that a function identifier has address + // value (implicit in stage1, explicit in stage2), except in + // the context of an address_of, which is handled there. const payload = node.castTag(.fn_identifier).?.data; - return c.addNode(.{ - .tag = .identifier, - .main_token = try c.addIdentifier(payload), - .data = undefined, - }); + if (c.zig_is_stage1) { + return try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload), + .data = undefined, + }); + } else { + const tok = try c.addToken(.ampersand, "&"); + const arg = try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload), + .data = undefined, + }); + return c.addNode(.{ + .tag = .address_of, + .main_token = tok, + .data = .{ + .lhs = arg, + .rhs = undefined, + }, + }); + } }, .float_literal => { const payload = node.castTag(.float_literal).?.data; @@ -1391,7 +1425,33 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"), .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"), .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"), - .address_of => return renderPrefixOp(c, node, .address_of, .ampersand, "&"), + .address_of => { + const payload = node.castTag(.address_of).?.data; + if (c.zig_is_stage1 and payload.tag() == .fn_identifier) + return try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), + .data = undefined, + }); + + const ampersand = try c.addToken(.ampersand, "&"); + const base = if (payload.tag() == .fn_identifier) + try c.addNode(.{ + .tag = .identifier, + .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data), + .data = undefined, + }) + else + try renderNodeGrouped(c, payload); + return c.addNode(.{ + .tag = .address_of, + .main_token = ampersand, + .data = .{ + .lhs = base, + .rhs = undefined, + }, + }); + }, .deref => { const payload = node.castTag(.deref).?.data; const operand = try renderNodeGrouped(c, payload);