| author | |
| committer | |
| log | a72b584c765e0b714e40b55b43971d4b0d2ad8dd |
| tree | 22e671cd4bd71c358df0f57b4ee11fc49bf5823e |
| parent | d086b371f0e21e5029e1b0d05838b87502eb63e6 |
| parent | 85b105d4f9970e81fef130978cae0e0ef7268571 |
| signature |
translate-c: Fix function pointers, add cast to subscripts in macros4 files changed, 116 insertions(+), 63 deletions(-)
src/translate_c.zig+10-14| ... | ... | @@ -436,7 +436,7 @@ pub fn translate( |
| 436 | 436 | } |
| 437 | 437 | } |
| 438 | 438 | |
| 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 | } |
| 441 | 441 | |
| 442 | 442 | /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) |
| ... | ... | @@ -2072,10 +2072,7 @@ fn transImplicitCastExpr( |
| 2072 | 2072 | }, |
| 2073 | 2073 | .PointerToBoolean => { |
| 2074 | 2074 | // @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); | |
| 2079 | 2076 | const ptr_to_int = try Tag.ptr_to_int.create(c.arena, ptr_node); |
| 2080 | 2077 | |
| 2081 | 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 | 2521 | } |
| 2525 | 2522 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { |
| 2526 | 2523 | // @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); | |
| 2531 | 2525 | return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); |
| 2532 | 2526 | } |
| 2533 | 2527 | if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { |
| ... | ... | @@ -3566,7 +3560,8 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip |
| 3566 | 3560 | |
| 3567 | 3561 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3568 | 3562 | // 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); | |
| 3570 | 3565 | |
| 3571 | 3566 | const container_node = try transExpr(c, scope, unwrapped_base, .used); |
| 3572 | 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 | 3756 | else |
| 3762 | 3757 | return transCreatePreCrement(c, scope, stmt, .sub_assign, used), |
| 3763 | 3758 | .AddrOf => { |
| 3764 | if (c.zig_is_stage1 and cIsFunctionDeclRef(op_expr)) { | |
| 3765 | return transExpr(c, scope, op_expr, used); | |
| 3766 | } | |
| 3767 | 3759 | return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used)); |
| 3768 | 3760 | }, |
| 3769 | 3761 | .Deref => { |
| ... | ... | @@ -6504,7 +6496,11 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6504 | 6496 | node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() }); |
| 6505 | 6497 | }, |
| 6506 | 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 | 6504 | node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index }); |
| 6509 | 6505 | try m.skip(c, .RBracket); |
| 6510 | 6506 | }, |
src/translate_c/ast.zig+68-8| ... | ... | @@ -717,10 +717,11 @@ pub const Payload = struct { |
| 717 | 717 | |
| 718 | 718 | /// Converts the nodes into a Zig Ast. |
| 719 | 719 | /// Caller must free the source slice. |
| 720 | pub fn render(gpa: Allocator, nodes: []const Node) !std.zig.Ast { | |
| 720 | pub fn render(gpa: Allocator, zig_is_stage1: bool, nodes: []const Node) !std.zig.Ast { | |
| 721 | 721 | var ctx = Context{ |
| 722 | 722 | .gpa = gpa, |
| 723 | 723 | .buf = std.ArrayList(u8).init(gpa), |
| 724 | .zig_is_stage1 = zig_is_stage1, | |
| 724 | 725 | }; |
| 725 | 726 | defer ctx.buf.deinit(); |
| 726 | 727 | defer ctx.nodes.deinit(gpa); |
| ... | ... | @@ -789,6 +790,11 @@ const Context = struct { |
| 789 | 790 | extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, |
| 790 | 791 | tokens: std.zig.Ast.TokenList = .{}, |
| 791 | 792 | |
| 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 | 798 | fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { |
| 793 | 799 | const start_index = c.buf.items.len; |
| 794 | 800 | try c.buf.writer().print(format ++ " ", args); |
| ... | ... | @@ -910,7 +916,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 910 | 916 | }, |
| 911 | 917 | .call => { |
| 912 | 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 | 928 | return renderCall(c, lhs, payload.args); |
| 915 | 929 | }, |
| 916 | 930 | .null_literal => return c.addNode(.{ |
| ... | ... | @@ -1064,12 +1078,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1064 | 1078 | }); |
| 1065 | 1079 | }, |
| 1066 | 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 | 1084 | 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 | } | |
| 1073 | 1107 | }, |
| 1074 | 1108 | .float_literal => { |
| 1075 | 1109 | const payload = node.castTag(.float_literal).?.data; |
| ... | ... | @@ -1391,7 +1425,33 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1391 | 1425 | .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"), |
| 1392 | 1426 | .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"), |
| 1393 | 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 | 1455 | .deref => { |
| 1396 | 1456 | const payload = node.castTag(.deref).?.data; |
| 1397 | 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 | 891 | \\} |
| 892 | 892 | , ""); |
| 893 | 893 | |
| 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 | , ""); | |
| 930 | 927 | |
| 931 | 928 | cases.add("Return boolean expression as int; issue #6215", |
| 932 | 929 | \\#include <stdlib.h> |
test/translate_c.zig+5-5| ... | ... | @@ -907,7 +907,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 907 | 907 | , &[_][]const u8{ |
| 908 | 908 | \\pub extern fn foo() void; |
| 909 | 909 | \\pub export fn bar() void { |
| 910 | \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, foo); | |
| 910 | \\ var func_ptr: ?*anyopaque = @ptrCast(?*anyopaque, &foo); | |
| 911 | 911 | \\ var typed_func_ptr: ?*const fn () callconv(.C) void = @intToPtr(?*const fn () callconv(.C) void, @intCast(c_ulong, @ptrToInt(func_ptr))); |
| 912 | 912 | \\ _ = @TypeOf(typed_func_ptr); |
| 913 | 913 | \\} |
| ... | ... | @@ -2726,7 +2726,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2726 | 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 | }); |
| 2731 | 2731 | |
| 2732 | 2732 | cases.add("cast signed array index to unsigned", |
| ... | ... | @@ -2956,8 +2956,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2956 | 2956 | \\ return 0; |
| 2957 | 2957 | \\} |
| 2958 | 2958 | \\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; | |
| 2961 | 2961 | \\ f.?(); |
| 2962 | 2962 | \\ f.?(); |
| 2963 | 2963 | \\ foo(); |
| ... | ... | @@ -3780,7 +3780,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3780 | 3780 | |
| 3781 | 3781 | cases.add("Demote function that dereference types that contain opaque type", |
| 3782 | 3782 | \\struct inner { |
| 3783 | \\ _Atomic int a; | |
| 3783 | \\ _Atomic int a; | |
| 3784 | 3784 | \\}; |
| 3785 | 3785 | \\struct outer { |
| 3786 | 3786 | \\ int thing; |