Commit 6be16eeae9

Tau <jonathan.haehne@hotmail.com>
2022-10-10 22:30:33
translate-c: fix the remaining function pointer issues
1 parent 2ca503e
Changed files (2)
src
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);
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 => {