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(...@@ -436,7 +436,7 @@ pub fn translate(
436 }436 }
437 }437 }
438438
439 return ast.render(gpa, context.global_scope.nodes.items);439 return ast.render(gpa, zig_is_stage1, context.global_scope.nodes.items);
440}440}
441441
442/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)442/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
...@@ -2072,10 +2072,7 @@ fn transImplicitCastExpr(...@@ -2072,10 +2072,7 @@ fn transImplicitCastExpr(
2072 },2072 },
2073 .PointerToBoolean => {2073 .PointerToBoolean => {
2074 // @ptrToInt(val) != 02074 // @ptrToInt(val) != 0
2075 var ptr_node = try transExpr(c, scope, sub_expr, .used);2075 const 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 }
2079 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);2076 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node);
20802077
2081 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });2078 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
...@@ -2524,10 +2521,7 @@ fn transCCast(...@@ -2524,10 +2521,7 @@ fn transCCast(
2524 }2521 }
2525 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {2522 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
2526 // @intCast(dest_type, @ptrToInt(val))2523 // @intCast(dest_type, @ptrToInt(val))
2527 const ptr_to_int = if (expr.tag() == .fn_identifier)2524 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
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);
2531 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });2525 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
2532 }2526 }
2533 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {2527 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
...@@ -3566,7 +3560,8 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip...@@ -3566,7 +3560,8 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip
35663560
3567 // Special case: actual pointer (not decayed array) and signed integer subscript3561 // Special case: actual pointer (not decayed array) and signed integer subscript
3568 // See discussion at https://github.com/ziglang/zig/pull/85893562 // 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
3571 const container_node = try transExpr(c, scope, unwrapped_base, .used);3566 const container_node = try transExpr(c, scope, unwrapped_base, .used);
3572 const rhs = if (is_longlong or is_signed) blk: {3567 const rhs = if (is_longlong or is_signed) blk: {
...@@ -3761,9 +3756,6 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat...@@ -3761,9 +3756,6 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
3761 else3756 else
3762 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),3757 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
3763 .AddrOf => {3758 .AddrOf => {
3764 if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) {
3765 return transExpr(c, scope, op_expr, used);
3766 }
3767 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));3759 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
3768 },3760 },
3769 .Deref => {3761 .Deref => {
...@@ -6504,7 +6496,11 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6504,7 +6496,11 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6504 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });6496 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
6505 },6497 },
6506 .LBracket => {6498 .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 });
6508 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });6504 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
6509 try m.skip(c, .RBracket);6505 try m.skip(c, .RBracket);
6510 },6506 },
src/translate_c/ast.zig+68-8
...@@ -717,10 +717,11 @@ pub const Payload = struct {...@@ -717,10 +717,11 @@ pub const Payload = struct {
717717
718/// Converts the nodes into a Zig Ast.718/// Converts the nodes into a Zig Ast.
719/// Caller must free the source slice.719/// 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 {
721 var ctx = Context{721 var ctx = Context{
722 .gpa = gpa,722 .gpa = gpa,
723 .buf = std.ArrayList(u8).init(gpa),723 .buf = std.ArrayList(u8).init(gpa),
724 .zig_is_stage1 = zig_is_stage1,
724 };725 };
725 defer ctx.buf.deinit();726 defer ctx.buf.deinit();
726 defer ctx.nodes.deinit(gpa);727 defer ctx.nodes.deinit(gpa);
...@@ -789,6 +790,11 @@ const Context = struct {...@@ -789,6 +790,11 @@ const Context = struct {
789 extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{},790 extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{},
790 tokens: std.zig.Ast.TokenList = .{},791 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
792 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {798 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {
793 const start_index = c.buf.items.len;799 const start_index = c.buf.items.len;
794 try c.buf.writer().print(format ++ " ", args);800 try c.buf.writer().print(format ++ " ", args);
...@@ -910,7 +916,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -910,7 +916,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
910 },916 },
911 .call => {917 .call => {
912 const payload = node.castTag(.call).?.data;918 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);
914 return renderCall(c, lhs, payload.args);928 return renderCall(c, lhs, payload.args);
915 },929 },
916 .null_literal => return c.addNode(.{930 .null_literal => return c.addNode(.{
...@@ -1064,12 +1078,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1064,12 +1078,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1064 });1078 });
1065 },1079 },
1066 .fn_identifier => {1080 .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.
1067 const payload = node.castTag(.fn_identifier).?.data;1084 const payload = node.castTag(.fn_identifier).?.data;
1068 return c.addNode(.{1085 if (c.zig_is_stage1) {
1069 .tag = .identifier,1086 return try c.addNode(.{
1070 .main_token = try c.addIdentifier(payload),1087 .tag = .identifier,
1071 .data = undefined,1088 .main_token = try c.addIdentifier(payload),
1072 });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 }
1073 },1107 },
1074 .float_literal => {1108 .float_literal => {
1075 const payload = node.castTag(.float_literal).?.data;1109 const payload = node.castTag(.float_literal).?.data;
...@@ -1391,7 +1425,33 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1391,7 +1425,33 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1391 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),1425 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
1392 .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"),1426 .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"),
1393 .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"),1427 .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 },
1395 .deref => {1455 .deref => {
1396 const payload = node.castTag(.deref).?.data;1456 const payload = node.castTag(.deref).?.data;
1397 const operand = try renderNodeGrouped(c, payload);1457 const operand = try renderNodeGrouped(c, payload);
test/run_translated_c.zig+33-36
...@@ -891,42 +891,39 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -891,42 +891,39 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
891 \\}891 \\}
892 , "");892 , "");
893893
894 if (@import("builtin").zig_backend == .stage1) {894 cases.add("Obscure ways of calling functions; issue #4124",
895 // https://github.com/ziglang/zig/issues/12263895 \\#include <stdlib.h>
896 cases.add("Obscure ways of calling functions; issue #4124",896 \\static int add(int a, int b) {
897 \\#include <stdlib.h>897 \\ return a + b;
898 \\static int add(int a, int b) {898 \\}
899 \\ return a + b;899 \\typedef int (*adder)(int, int);
900 \\}900 \\typedef void (*funcptr)(void);
901 \\typedef int (*adder)(int, int);901 \\int main() {
902 \\typedef void (*funcptr)(void);902 \\ if ((add)(1, 2) != 3) abort();
903 \\int main() {903 \\ if ((&add)(1, 2) != 3) abort();
904 \\ if ((add)(1, 2) != 3) abort();904 \\ if (add(3, 1) != 4) abort();
905 \\ if ((&add)(1, 2) != 3) abort();905 \\ if ((*add)(2, 3) != 5) abort();
906 \\ if (add(3, 1) != 4) abort();906 \\ if ((**add)(7, -1) != 6) abort();
907 \\ if ((*add)(2, 3) != 5) abort();907 \\ if ((***add)(-2, 9) != 7) abort();
908 \\ if ((**add)(7, -1) != 6) abort();908 \\
909 \\ if ((***add)(-2, 9) != 7) abort();909 \\ int (*ptr)(int a, int b);
910 \\910 \\ ptr = add;
911 \\ int (*ptr)(int a, int b);911 \\
912 \\ ptr = add;912 \\ if (ptr(1, 2) != 3) abort();
913 \\913 \\ if ((*ptr)(3, 1) != 4) abort();
914 \\ if (ptr(1, 2) != 3) abort();914 \\ if ((**ptr)(2, 3) != 5) abort();
915 \\ if ((*ptr)(3, 1) != 4) abort();915 \\ if ((***ptr)(7, -1) != 6) abort();
916 \\ if ((**ptr)(2, 3) != 5) abort();916 \\ if ((****ptr)(-2, 9) != 7) abort();
917 \\ if ((***ptr)(7, -1) != 6) abort();917 \\
918 \\ if ((****ptr)(-2, 9) != 7) abort();918 \\ funcptr addr1 = (funcptr)(add);
919 \\919 \\ funcptr addr2 = (funcptr)(&add);
920 \\ funcptr addr1 = (funcptr)(add);920 \\
921 \\ funcptr addr2 = (funcptr)(&add);921 \\ if (addr1 != addr2) abort();
922 \\922 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort();
923 \\ if (addr1 != addr2) abort();923 \\ if (((adder)addr2)(1, 2) != 3) abort();
924 \\ if (((int(*)(int, int))addr1)(1, 2) != 3) abort();924 \\ return 0;
925 \\ if (((adder)addr2)(1, 2) != 3) abort();925 \\}
926 \\ return 0;926 , "");
927 \\}
928 , "");
929 }
930927
931 cases.add("Return boolean expression as int; issue #6215",928 cases.add("Return boolean expression as int; issue #6215",
932 \\#include <stdlib.h>929 \\#include <stdlib.h>
test/translate_c.zig+5-5
...@@ -907,7 +907,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -907,7 +907,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
907 , &[_][]const u8{907 , &[_][]const u8{
908 \\pub extern fn foo() void;908 \\pub extern fn foo() void;
909 \\pub export fn bar() void {909 \\pub export fn bar() void {
910 \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, foo);910 \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo);
911 \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr)));911 \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr)));
912 \\ _ = @TypeOf(typed_func_ptr);912 \\ _ = @TypeOf(typed_func_ptr);
913 \\}913 \\}
...@@ -2726,7 +2726,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2726,7 +2726,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2726 \\ return array[@intCast(c_uint, index)];2726 \\ return array[@intCast(c_uint, index)];
2727 \\}2727 \\}
2728 ,2728 ,
2729 \\pub const ACCESS = array[@as(c_int, 2)];2729 \\pub const ACCESS = array[@intCast(usize, @as(c_int, 2))];
2730 });2730 });
27312731
2732 cases.add("cast signed array index to unsigned",2732 cases.add("cast signed array index to unsigned",
...@@ -2956,8 +2956,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2956,8 +2956,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2956 \\ return 0;2956 \\ return 0;
2957 \\}2957 \\}
2958 \\pub export fn bar() void {2958 \\pub export fn bar() void {
2959 \\ var f: ?*const fn () callconv(.C) void = foo;2959 \\ var f: ?*const fn () callconv(.C) void = &foo;
2960 \\ var b: ?*const fn () callconv(.C) c_int = baz;2960 \\ var b: ?*const fn () callconv(.C) c_int = &baz;
2961 \\ f.?();2961 \\ f.?();
2962 \\ f.?();2962 \\ f.?();
2963 \\ foo();2963 \\ foo();
...@@ -3780,7 +3780,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3780,7 +3780,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
37803780
3781 cases.add("Demote function that dereference types that contain opaque type",3781 cases.add("Demote function that dereference types that contain opaque type",
3782 \\struct inner {3782 \\struct inner {
3783 \\ _Atomic int a; 3783 \\ _Atomic int a;
3784 \\};3784 \\};
3785 \\struct outer {3785 \\struct outer {
3786 \\ int thing;3786 \\ int thing;