| 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,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 | /// 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) != 0 | 2074 | // @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); |
| 2080 | 2077 | ||
| 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 |
| 3566 | 3560 | ||
| 3567 | // Special case: actual pointer (not decayed array) and signed integer subscript | 3561 | // Special case: actual pointer (not decayed array) and signed integer subscript |
| 3568 | // See discussion at https://github.com/ziglang/zig/pull/8589 | 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 | 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 | else | 3756 | 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 { |
| 717 | 717 | ||
| 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. |
| 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 | 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 = .{}, |
| 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 | 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 | , ""); |
| 893 | 893 | ||
| 894 | if (@import("builtin").zig_backend == .stage1) { | 894 | cases.add("Obscure ways of calling functions; issue #4124", |
| 895 | // https://github.com/ziglang/zig/issues/12263 | 895 | \\#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 | } | ||
| 930 | 927 | ||
| 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 | }); |
| 2731 | 2731 | ||
| 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 { |
| 3780 | 3780 | ||
| 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; |