authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-11 19:04:44+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-11 19:04:44+02:00
loga72b584c765e0b714e40b55b43971d4b0d2ad8dd
tree22e671cd4bd71c358df0f57b4ee11fc49bf5823e
parentd086b371f0e21e5029e1b0d05838b87502eb63e6
parent85b105d4f9970e81fef130978cae0e0ef7268571
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13126 from tau-dev/master

translate-c: Fix function pointers, add cast to subscripts in macros

4 files changed, 116 insertions(+), 63 deletions(-)

src/translate_c.zig+10-14
......@@ -436,7 +436,7 @@ pub fn translate(
436436 }
437437 }
438438
439 return ast.render(gpa, context.global_scope.nodes.items);
439 return ast.render(gpa, zig_is_stage1, context.global_scope.nodes.items);
440440}
441441
442442/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
......@@ -2072,10 +2072,7 @@ fn transImplicitCastExpr(
20722072 },
20732073 .PointerToBoolean => {
20742074 // @ptrToInt(val) != 0
2075 var ptr_node = try transExpr(c, scope, sub_expr, .used);
2076 if (ptr_node.tag() == .fn_identifier) {
2077 ptr_node = try Tag.address_of.create(c.arena, ptr_node);
2078 }
2075 const ptr_node = try transExpr(c, scope, sub_expr, .used);
20792076 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);
20802077
20812078 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
......@@ -2524,10 +2521,7 @@ fn transCCast(
25242521 }
25252522 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
25262523 // @intCast(dest_type, @ptrToInt(val))
2527 const ptr_to_int = if (expr.tag() == .fn_identifier)
2528 try Tag.ptr_to_int.create(c.arena, try Tag.address_of.create(c.arena, expr))
2529 else
2530 try Tag.ptr_to_int.create(c.arena, expr);
2524 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
25312525 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
25322526 }
25332527 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
......@@ -3566,7 +3560,8 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
35663560
35673561 // Special case: actual pointer (not decayed array) and signed integer subscript
35683562 // See discussion at https://github.com/ziglang/zig/pull/8589
3569 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);
3563 if (is_signed and (base_stmt == unwrapped_base) and !is_vector and !is_nonnegative_int_literal)
3564 return transSignedArrayAccess(c, scope, base_stmt, subscr_expr, result_used);
35703565
35713566 const container_node = try transExpr(c, scope, unwrapped_base, .used);
35723567 const rhs = if (is_longlong or is_signed) blk: {
......@@ -3761,9 +3756,6 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
37613756 else
37623757 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
37633758 .AddrOf => {
3764 if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) {
3765 return transExpr(c, scope, op_expr, used);
3766 }
37673759 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
37683760 },
37693761 .Deref => {
......@@ -6504,7 +6496,11 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65046496 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
65056497 },
65066498 .LBracket => {
6507 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
6499 const index_val = try macroBoolToInt(c, try parseCExpr(c, m, scope));
6500 const index = try Tag.int_cast.create(c.arena, .{
6501 .lhs = try Tag.type.create(c.arena, "usize"),
6502 .rhs = index_val,
6503 });
65086504 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
65096505 try m.skip(c, .RBracket);
65106506 },
src/translate_c/ast.zig+68-8
......@@ -717,10 +717,11 @@ pub const Payload = struct {
717717
718718/// Converts the nodes into a Zig Ast.
719719/// Caller must free the source slice.
720pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast {
720pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig.Ast {
721721 var ctx = Context{
722722 .gpa = gpa,
723723 .buf = std.ArrayList(u8).init(gpa),
724 .zig_is_stage1 = zig_is_stage1,
724725 };
725726 defer ctx.buf.deinit();
726727 defer ctx.nodes.deinit(gpa);
......@@ -789,6 +790,11 @@ const Context = struct {
789790 extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{},
790791 tokens: std.zig.Ast.TokenList = .{},
791792
793 /// This is used to emit different code depending on whether
794 /// the output zig source code is intended to be compiled with stage1 or stage2.
795 /// Refer to the Context in translate_c.zig.
796 zig_is_stage1: bool,
797
792798 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {
793799 const start_index = c.buf.items.len;
794800 try c.buf.writer().print(format ++ " ", args);
......@@ -910,7 +916,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
910916 },
911917 .call => {
912918 const payload = node.castTag(.call).?.data;
913 const lhs = try renderNode(c, payload.lhs);
919 // Cosmetic: avoids an unnecesary address_of on most function calls.
920 const lhs = if (!c.zig_is_stage1 and payload.lhs.tag() == .fn_identifier)
921 try c.addNode(.{
922 .tag = .identifier,
923 .main_token = try c.addIdentifier(payload.lhs.castTag(.fn_identifier).?.data),
924 .data = undefined,
925 })
926 else
927 try renderNodeGrouped(c, payload.lhs);
914928 return renderCall(c, lhs, payload.args);
915929 },
916930 .null_literal => return c.addNode(.{
......@@ -1064,12 +1078,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
10641078 });
10651079 },
10661080 .fn_identifier => {
1081 // C semantics are that a function identifier has address
1082 // value (implicit in stage1, explicit in stage2), except in
1083 // the context of an address_of, which is handled there.
10671084 const payload = node.castTag(.fn_identifier).?.data;
1068 return c.addNode(.{
1069 .tag = .identifier,
1070 .main_token = try c.addIdentifier(payload),
1071 .data = undefined,
1072 });
1085 if (c.zig_is_stage1) {
1086 return try c.addNode(.{
1087 .tag = .identifier,
1088 .main_token = try c.addIdentifier(payload),
1089 .data = undefined,
1090 });
1091 } else {
1092 const tok = try c.addToken(.ampersand, "&");
1093 const arg = try c.addNode(.{
1094 .tag = .identifier,
1095 .main_token = try c.addIdentifier(payload),
1096 .data = undefined,
1097 });
1098 return c.addNode(.{
1099 .tag = .address_of,
1100 .main_token = tok,
1101 .data = .{
1102 .lhs = arg,
1103 .rhs = undefined,
1104 },
1105 });
1106 }
10731107 },
10741108 .float_literal => {
10751109 const payload = node.castTag(.float_literal).?.data;
......@@ -1391,7 +1425,33 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
13911425 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
13921426 .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"),
13931427 .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"),
1394 .address_of => return renderPrefixOp(c, node, .address_of, .ampersand, "&"),
1428 .address_of => {
1429 const payload = node.castTag(.address_of).?.data;
1430 if (c.zig_is_stage1 and payload.tag() == .fn_identifier)
1431 return try c.addNode(.{
1432 .tag = .identifier,
1433 .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data),
1434 .data = undefined,
1435 });
1436
1437 const ampersand = try c.addToken(.ampersand, "&");
1438 const base = if (payload.tag() == .fn_identifier)
1439 try c.addNode(.{
1440 .tag = .identifier,
1441 .main_token = try c.addIdentifier(payload.castTag(.fn_identifier).?.data),
1442 .data = undefined,
1443 })
1444 else
1445 try renderNodeGrouped(c, payload);
1446 return c.addNode(.{
1447 .tag = .address_of,
1448 .main_token = ampersand,
1449 .data = .{
1450 .lhs = base,
1451 .rhs = undefined,
1452 },
1453 });
1454 },
13951455 .deref => {
13961456 const payload = node.castTag(.deref).?.data;
13971457 const operand = try renderNodeGrouped(c, payload);
test/run_translated_c.zig+33-36
......@@ -891,42 +891,39 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
891891 \\}
892892 , "");
893893
894 if (@import("builtin").zig_backend == .stage1) {
895 // https://github.com/ziglang/zig/issues/12263
896 cases.add("Obscure ways of calling functions; issue #4124",
897 \\#include <stdlib.h>
898 \\static int add(int a, int b) {
899 \\ return a + b;
900 \\}
901 \\typedef int (*adder)(int, int);
902 \\typedef void (*funcptr)(void);
903 \\int main() {
904 \\ if ((add)(1, 2) != 3) abort();
905 \\ if ((&add)(1, 2) != 3) abort();
906 \\ if (add(3, 1) != 4) abort();
907 \\ if ((*add)(2, 3) != 5) abort();
908 \\ if ((**add)(7, -1) != 6) abort();
909 \\ if ((***add)(-2, 9) != 7) abort();
910 \\
911 \\ int (*ptr)(int a, int b);
912 \\ ptr = add;
913 \\
914 \\ if (ptr(1, 2) != 3) abort();
915 \\ if ((*ptr)(3, 1) != 4) abort();
916 \\ if ((**ptr)(2, 3) != 5) abort();
917 \\ if ((***ptr)(7, -1) != 6) abort();
918 \\ if ((****ptr)(-2, 9) != 7) abort();
919 \\
920 \\ funcptr addr1 = (funcptr)(add);
921 \\ funcptr addr2 = (funcptr)(&add);
922 \\
923 \\ if (addr1 != addr2) abort();
924 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort();
925 \\ if (((adder)addr2)(1, 2) != 3) abort();
926 \\ return 0;
927 \\}
928 , "");
929 }
894 cases.add("Obscure ways of calling functions; issue #4124",
895 \\#include <stdlib.h>
896 \\static int add(int a, int b) {
897 \\ return a + b;
898 \\}
899 \\typedef int (*adder)(int, int);
900 \\typedef void (*funcptr)(void);
901 \\int main() {
902 \\ if ((add)(1, 2) != 3) abort();
903 \\ if ((&add)(1, 2) != 3) abort();
904 \\ if (add(3, 1) != 4) abort();
905 \\ if ((*add)(2, 3) != 5) abort();
906 \\ if ((**add)(7, -1) != 6) abort();
907 \\ if ((***add)(-2, 9) != 7) abort();
908 \\
909 \\ int (*ptr)(int a, int b);
910 \\ ptr = add;
911 \\
912 \\ if (ptr(1, 2) != 3) abort();
913 \\ if ((*ptr)(3, 1) != 4) abort();
914 \\ if ((**ptr)(2, 3) != 5) abort();
915 \\ if ((***ptr)(7, -1) != 6) abort();
916 \\ if ((****ptr)(-2, 9) != 7) abort();
917 \\
918 \\ funcptr addr1 = (funcptr)(add);
919 \\ funcptr addr2 = (funcptr)(&add);
920 \\
921 \\ if (addr1 != addr2) abort();
922 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort();
923 \\ if (((adder)addr2)(1, 2) != 3) abort();
924 \\ return 0;
925 \\}
926 , "");
930927
931928 cases.add("Return boolean expression as int; issue #6215",
932929 \\#include <stdlib.h>
test/translate_c.zig+5-5
......@@ -907,7 +907,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
907907 , &[_][]const u8{
908908 \\pub extern fn foo() void;
909909 \\pub export fn bar() void {
910 \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, foo);
910 \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo);
911911 \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr)));
912912 \\ _ = @TypeOf(typed_func_ptr);
913913 \\}
......@@ -2726,7 +2726,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
27262726 \\ return array[@intCast(c_uint, index)];
27272727 \\}
27282728 ,
2729 \\pub const ACCESS = array[@as(c_int, 2)];
2729 \\pub const ACCESS = array[@intCast(usize, @as(c_int, 2))];
27302730 });
27312731
27322732 cases.add("cast signed array index to unsigned",
......@@ -2956,8 +2956,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29562956 \\ return 0;
29572957 \\}
29582958 \\pub export fn bar() void {
2959 \\ var f: ?*const fn () callconv(.C) void = foo;
2960 \\ var b: ?*const fn () callconv(.C) c_int = baz;
2959 \\ var f: ?*const fn () callconv(.C) void = &foo;
2960 \\ var b: ?*const fn () callconv(.C) c_int = &baz;
29612961 \\ f.?();
29622962 \\ f.?();
29632963 \\ foo();
......@@ -3780,7 +3780,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
37803780
37813781 cases.add("Demote function that dereference types that contain opaque type",
37823782 \\struct inner {
3783 \\ _Atomic int a;
3783 \\ _Atomic int a;
37843784 \\};
37853785 \\struct outer {
37863786 \\ int thing;