authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-13 19:51:22+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-13 19:51:22+03:00
log37f36da391570739e639f857bef3de1170eaac50
tree8881dd0b7151a8a18332096224868af5684189d2
parentf58fbb1004e26982ad83c61b3fecf5e575fb9210
parent029fe6c9abca1373ef0e379fa8e24fbf3a987800
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9092 from xackus/translate-c-type-parsing

translate-c: improve type parsing

5 files changed, 278 insertions(+), 123 deletions(-)

lib/std/meta.zig+32-30
......@@ -890,38 +890,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
890890 // this function should behave like transCCast in translate-c, except it's for macros and enums
891891 const SourceType = @TypeOf(target);
892892 switch (@typeInfo(DestType)) {
893 .Pointer => {
894 switch (@typeInfo(SourceType)) {
895 .Int, .ComptimeInt => {
896 return @intToPtr(DestType, target);
897 },
898 .Pointer => {
899 return castPtr(DestType, target);
900 },
901 .Optional => |opt| {
902 if (@typeInfo(opt.child) == .Pointer) {
903 return castPtr(DestType, target);
904 }
905 },
906 else => {},
907 }
908 },
893 .Pointer => return castToPtr(DestType, SourceType, target),
909894 .Optional => |dest_opt| {
910895 if (@typeInfo(dest_opt.child) == .Pointer) {
911 switch (@typeInfo(SourceType)) {
912 .Int, .ComptimeInt => {
913 return @intToPtr(DestType, target);
914 },
915 .Pointer => {
916 return castPtr(DestType, target);
917 },
918 .Optional => |target_opt| {
919 if (@typeInfo(target_opt.child) == .Pointer) {
920 return castPtr(DestType, target);
921 }
922 },
923 else => {},
924 }
896 return castToPtr(DestType, SourceType, target);
925897 }
926898 },
927899 .Enum => |enum_type| {
......@@ -977,6 +949,30 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
977949 return @ptrCast(DestType, @alignCast(dest.alignment, target));
978950}
979951
952fn castToPtr(comptime DestType: type, comptime SourceType: type, target: anytype) DestType {
953 switch (@typeInfo(SourceType)) {
954 .Int => {
955 return @intToPtr(DestType, castInt(usize, target));
956 },
957 .ComptimeInt => {
958 if (target < 0)
959 return @intToPtr(DestType, @bitCast(usize, @intCast(isize, target)))
960 else
961 return @intToPtr(DestType, @intCast(usize, target));
962 },
963 .Pointer => {
964 return castPtr(DestType, target);
965 },
966 .Optional => |target_opt| {
967 if (@typeInfo(target_opt.child) == .Pointer) {
968 return castPtr(DestType, target);
969 }
970 },
971 else => {},
972 }
973 return @as(DestType, target);
974}
975
980976fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
981977 return switch (@typeInfo(PtrType)) {
982978 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
......@@ -1026,6 +1022,12 @@ test "std.meta.cast" {
10261022 try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
10271023 try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
10281024 try testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));
1025
1026 var foo: c_int = -1;
1027 try testing.expect(cast(*c_void, -1) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
1028 try testing.expect(cast(*c_void, foo) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
1029 try testing.expect(cast(?*c_void, -1) == @intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))));
1030 try testing.expect(cast(?*c_void, foo) == @intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))));
10291031}
10301032
10311033/// Given a value returns its size as C's sizeof operator would.
src/translate_c.zig+227-92
......@@ -280,6 +280,8 @@ pub const Context = struct {
280280 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
281281 /// Table of unnamed enums and records that are child types of typedefs.
282282 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
283 /// Needed to decide if we are parsing a typename
284 typedefs: std.StringArrayHashMapUnmanaged(void) = .{},
283285
284286 /// This one is different than the root scope's name table. This contains
285287 /// a list of names that we found by visiting all the top level decls without
......@@ -348,6 +350,7 @@ pub fn translate(
348350 context.global_names.deinit(gpa);
349351 context.opaque_demotes.deinit(gpa);
350352 context.unnamed_typedefs.deinit(gpa);
353 context.typedefs.deinit(gpa);
351354 context.global_scope.deinit();
352355 }
353356
......@@ -461,6 +464,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
461464 result.value_ptr.* = name;
462465 // Put this typedef in the decl_table to avoid redefinitions.
463466 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
467 try c.typedefs.put(c.gpa, name, {});
464468 }
465469 }
466470}
......@@ -792,6 +796,8 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNa
792796 // TODO https://github.com/ziglang/zig/issues/3756
793797 // TODO https://github.com/ziglang/zig/issues/1802
794798 var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;
799 try c.typedefs.put(c.gpa, name, {});
800
795801 if (builtin_typedef_map.get(name)) |builtin| {
796802 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
797803 }
......@@ -5303,56 +5309,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
53035309 .IntegerLiteral, .FloatLiteral => {
53045310 return parseCNumLit(c, m);
53055311 },
5306 // eventually this will be replaced by std.c.parse which will handle these correctly
5307 .Keyword_void => return Tag.type.create(c.arena, "c_void"),
5308 .Keyword_bool => return Tag.type.create(c.arena, "bool"),
5309 .Keyword_double => return Tag.type.create(c.arena, "f64"),
5310 .Keyword_long => return Tag.type.create(c.arena, "c_long"),
5311 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
5312 .Keyword_float => return Tag.type.create(c.arena, "f32"),
5313 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
5314 .Keyword_char => return Tag.type.create(c.arena, "u8"),
5315 .Keyword_unsigned => if (m.next()) |t| switch (t) {
5316 .Keyword_char => return Tag.type.create(c.arena, "u8"),
5317 .Keyword_short => return Tag.type.create(c.arena, "c_ushort"),
5318 .Keyword_int => return Tag.type.create(c.arena, "c_uint"),
5319 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5320 _ = m.next();
5321 return Tag.type.create(c.arena, "c_ulonglong");
5322 } else return Tag.type.create(c.arena, "c_ulong"),
5323 else => {
5324 m.i -= 1;
5325 return Tag.type.create(c.arena, "c_uint");
5326 },
5327 } else {
5328 return Tag.type.create(c.arena, "c_uint");
5329 },
5330 .Keyword_signed => if (m.next()) |t| switch (t) {
5331 .Keyword_char => return Tag.type.create(c.arena, "i8"),
5332 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
5333 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
5334 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5335 _ = m.next();
5336 return Tag.type.create(c.arena, "c_longlong");
5337 } else return Tag.type.create(c.arena, "c_long"),
5338 else => {
5339 m.i -= 1;
5340 return Tag.type.create(c.arena, "c_int");
5341 },
5342 } else {
5343 return Tag.type.create(c.arena, "c_int");
5344 },
5345 .Keyword_enum, .Keyword_struct, .Keyword_union => {
5346 // struct Foo will be declared as struct_Foo by transRecordDecl
5347 const next_id = m.next().?;
5348 if (next_id != .Identifier) {
5349 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
5350 return error.ParseError;
5351 }
5352
5353 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
5354 return Tag.identifier.create(c.arena, name);
5355 },
53565312 .Identifier => {
53575313 const mangled_name = scope.getAlias(slice);
53585314 if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {
......@@ -5369,37 +5325,15 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
53695325 try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)});
53705326 return error.ParseError;
53715327 }
5372 var saw_l_paren = false;
5373 var saw_integer_literal = false;
5374 switch (m.peek().?) {
5375 // (type)(to_cast)
5376 .LParen => {
5377 saw_l_paren = true;
5378 _ = m.next();
5379 },
5380 // (type)sizeof(x)
5381 .Keyword_sizeof,
5382 // (type)alignof(x)
5383 .Keyword_alignof,
5384 // (type)identifier
5385 .Identifier,
5386 => {},
5387 // (type)integer
5388 .IntegerLiteral => {
5389 saw_integer_literal = true;
5390 },
5391 else => return inner_node,
5392 }
5393 const node_to_cast = try parseCExpr(c, m, scope);
5394
5395 if (saw_l_paren and m.next().? != .RParen) {
5396 try m.fail(c, "unable to translate C expr: expected ')'", .{});
5397 return error.ParseError;
5398 }
5399
5400 return Tag.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast });
5328 return inner_node;
54015329 },
54025330 else => {
5331 // for handling type macros (EVIL)
5332 // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
5333 m.i -= 1;
5334 if (try parseCTypeName(c, m, scope)) |type_name| {
5335 return type_name;
5336 }
54035337 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});
54045338 return error.ParseError;
54055339 },
......@@ -5605,7 +5539,7 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56055539}
56065540
56075541fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5608 var node = try parseCUnaryExpr(c, m, scope);
5542 var node = try parseCCastExpr(c, m, scope);
56095543 while (true) {
56105544 switch (m.next().?) {
56115545 .Asterisk => {
......@@ -5633,18 +5567,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56335567 } else {
56345568 // expr * expr
56355569 const lhs = try macroBoolToInt(c, node);
5636 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5570 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56375571 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56385572 }
56395573 },
56405574 .Slash => {
56415575 const lhs = try macroBoolToInt(c, node);
5642 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5576 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56435577 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56445578 },
56455579 .Percent => {
56465580 const lhs = try macroBoolToInt(c, node);
5647 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5581 const rhs = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
56485582 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
56495583 },
56505584 else => {
......@@ -5655,8 +5589,209 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56555589 }
56565590}
56575591
5658fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5659 var node = try parseCPrimaryExpr(c, m, scope);
5592fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5593 switch (m.next().?) {
5594 .LParen => {
5595 if (try parseCTypeName(c, m, scope)) |type_name| {
5596 if (m.next().? != .RParen) {
5597 try m.fail(c, "unable to translate C expr: expected ')'", .{});
5598 return error.ParseError;
5599 }
5600 if (m.peek().? == .LBrace) {
5601 // initializer list
5602 return parseCPostfixExpr(c, m, scope, type_name);
5603 }
5604 const node_to_cast = try parseCCastExpr(c, m, scope);
5605 return Tag.std_meta_cast.create(c.arena, .{ .lhs = type_name, .rhs = node_to_cast });
5606 }
5607 },
5608 else => {},
5609 }
5610 m.i -= 1;
5611 return parseCUnaryExpr(c, m, scope);
5612}
5613
5614fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!?Node {
5615 if (try parseCSpecifierQualifierList(c, m, scope)) |node| {
5616 return try parseCAbstractDeclarator(c, m, scope, node);
5617 } else {
5618 return null;
5619 }
5620}
5621
5622fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!?Node {
5623 switch (m.next().?) {
5624 .Identifier => {
5625 const mangled_name = scope.getAlias(m.slice());
5626 if (c.typedefs.contains(mangled_name)) {
5627 return try Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
5628 }
5629 },
5630 .Keyword_void => return try Tag.type.create(c.arena, "c_void"),
5631 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),
5632 .Keyword_char,
5633 .Keyword_int,
5634 .Keyword_short,
5635 .Keyword_long,
5636 .Keyword_float,
5637 .Keyword_double,
5638 .Keyword_signed,
5639 .Keyword_unsigned,
5640 .Keyword_complex,
5641 => {
5642 m.i -= 1;
5643 return try parseCNumericType(c, m, scope);
5644 },
5645 .Keyword_enum, .Keyword_struct, .Keyword_union => {
5646 // struct Foo will be declared as struct_Foo by transRecordDecl
5647 const slice = m.slice();
5648 const next_id = m.next().?;
5649 if (next_id != .Identifier) {
5650 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
5651 return error.ParseError;
5652 }
5653
5654 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
5655 return try Tag.identifier.create(c.arena, name);
5656 },
5657 else => {},
5658 }
5659
5660 m.i -= 1;
5661 return null;
5662}
5663
5664fn parseCNumericType(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5665 const KwCounter = struct {
5666 double: u8 = 0,
5667 long: u8 = 0,
5668 int: u8 = 0,
5669 float: u8 = 0,
5670 short: u8 = 0,
5671 char: u8 = 0,
5672 unsigned: u8 = 0,
5673 signed: u8 = 0,
5674 complex: u8 = 0,
5675
5676 fn eql(self: @This(), other: @This()) bool {
5677 return meta.eql(self, other);
5678 }
5679 };
5680
5681 // Yes, these can be in *any* order
5682 // This still doesn't cover cases where for example volatile is intermixed
5683
5684 var kw = KwCounter{};
5685 // prevent overflow
5686 var i: u8 = 0;
5687 while (i < math.maxInt(u8)) : (i += 1) {
5688 switch (m.next().?) {
5689 .Keyword_double => kw.double += 1,
5690 .Keyword_long => kw.long += 1,
5691 .Keyword_int => kw.int += 1,
5692 .Keyword_float => kw.float += 1,
5693 .Keyword_short => kw.short += 1,
5694 .Keyword_char => kw.char += 1,
5695 .Keyword_unsigned => kw.unsigned += 1,
5696 .Keyword_signed => kw.signed += 1,
5697 .Keyword_complex => kw.complex += 1,
5698 else => {
5699 m.i -= 1;
5700 break;
5701 },
5702 }
5703 }
5704
5705 if (kw.eql(.{ .int = 1 }) or kw.eql(.{ .signed = 1 }) or kw.eql(.{ .signed = 1, .int = 1 }))
5706 return Tag.type.create(c.arena, "c_int");
5707
5708 if (kw.eql(.{ .unsigned = 1 }) or kw.eql(.{ .unsigned = 1, .int = 1 }))
5709 return Tag.type.create(c.arena, "c_uint");
5710
5711 if (kw.eql(.{ .long = 1 }) or kw.eql(.{ .signed = 1, .long = 1 }) or kw.eql(.{ .long = 1, .int = 1 }) or kw.eql(.{ .signed = 1, .long = 1, .int = 1 }))
5712 return Tag.type.create(c.arena, "c_long");
5713
5714 if (kw.eql(.{ .unsigned = 1, .long = 1 }) or kw.eql(.{ .unsigned = 1, .long = 1, .int = 1 }))
5715 return Tag.type.create(c.arena, "c_ulong");
5716
5717 if (kw.eql(.{ .long = 2 }) or kw.eql(.{ .signed = 1, .long = 2 }) or kw.eql(.{ .long = 2, .int = 1 }) or kw.eql(.{ .signed = 1, .long = 2, .int = 1 }))
5718 return Tag.type.create(c.arena, "c_longlong");
5719
5720 if (kw.eql(.{ .unsigned = 1, .long = 2 }) or kw.eql(.{ .unsigned = 1, .long = 2, .int = 1 }))
5721 return Tag.type.create(c.arena, "c_ulonglong");
5722
5723 if (kw.eql(.{ .signed = 1, .char = 1 }))
5724 return Tag.type.create(c.arena, "i8");
5725
5726 if (kw.eql(.{ .char = 1 }) or kw.eql(.{ .unsigned = 1, .char = 1 }))
5727 return Tag.type.create(c.arena, "u8");
5728
5729 if (kw.eql(.{ .short = 1 }) or kw.eql(.{ .signed = 1, .short = 1 }) or kw.eql(.{ .short = 1, .int = 1 }) or kw.eql(.{ .signed = 1, .short = 1, .int = 1 }))
5730 return Tag.type.create(c.arena, "c_short");
5731
5732 if (kw.eql(.{ .unsigned = 1, .short = 1 }) or kw.eql(.{ .unsigned = 1, .short = 1, .int = 1 }))
5733 return Tag.type.create(c.arena, "c_ushort");
5734
5735 if (kw.eql(.{ .float = 1 }))
5736 return Tag.type.create(c.arena, "f32");
5737
5738 if (kw.eql(.{ .double = 1 }))
5739 return Tag.type.create(c.arena, "f64");
5740
5741 if (kw.eql(.{ .long = 1, .double = 1 })) {
5742 try m.fail(c, "unable to translate: TODO long double", .{});
5743 return error.ParseError;
5744 }
5745
5746 if (kw.eql(.{ .float = 1, .complex = 1 })) {
5747 try m.fail(c, "unable to translate: TODO _Complex", .{});
5748 return error.ParseError;
5749 }
5750
5751 if (kw.eql(.{ .double = 1, .complex = 1 })) {
5752 try m.fail(c, "unable to translate: TODO _Complex", .{});
5753 return error.ParseError;
5754 }
5755
5756 if (kw.eql(.{ .long = 1, .double = 1, .complex = 1 })) {
5757 try m.fail(c, "unable to translate: TODO _Complex", .{});
5758 return error.ParseError;
5759 }
5760
5761 try m.fail(c, "unable to translate: invalid numeric type", .{});
5762 return error.ParseError;
5763}
5764
5765fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, scope: *Scope, node: Node) ParseError!Node {
5766 switch (m.next().?) {
5767 .Asterisk => {
5768 // last token of `node`
5769 const prev_id = m.list[m.i - 1].id;
5770
5771 if (prev_id == .Keyword_void) {
5772 const ptr = try Tag.single_pointer.create(c.arena, .{
5773 .is_const = false,
5774 .is_volatile = false,
5775 .elem_type = node,
5776 });
5777 return Tag.optional_type.create(c.arena, ptr);
5778 } else {
5779 return Tag.c_pointer.create(c.arena, .{
5780 .is_const = false,
5781 .is_volatile = false,
5782 .elem_type = node,
5783 });
5784 }
5785 },
5786 else => {
5787 m.i -= 1;
5788 return node;
5789 },
5790 }
5791}
5792
5793fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) ParseError!Node {
5794 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
56605795 while (true) {
56615796 switch (m.next().?) {
56625797 .Period => {
......@@ -5776,24 +5911,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
57765911fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
57775912 switch (m.next().?) {
57785913 .Bang => {
5779 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
5914 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
57805915 return Tag.not.create(c.arena, operand);
57815916 },
57825917 .Minus => {
5783 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5918 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
57845919 return Tag.negate.create(c.arena, operand);
57855920 },
5786 .Plus => return try parseCUnaryExpr(c, m, scope),
5921 .Plus => return try parseCCastExpr(c, m, scope),
57875922 .Tilde => {
5788 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
5923 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
57895924 return Tag.bit_not.create(c.arena, operand);
57905925 },
57915926 .Asterisk => {
5792 const operand = try parseCUnaryExpr(c, m, scope);
5927 const operand = try parseCCastExpr(c, m, scope);
57935928 return Tag.deref.create(c.arena, operand);
57945929 },
57955930 .Ampersand => {
5796 const operand = try parseCUnaryExpr(c, m, scope);
5931 const operand = try parseCCastExpr(c, m, scope);
57975932 return Tag.address_of.create(c.arena, operand);
57985933 },
57995934 .Keyword_sizeof => {
......@@ -5834,7 +5969,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
58345969 },
58355970 else => {
58365971 m.i -= 1;
5837 return try parseCPostfixExpr(c, m, scope);
5972 return try parseCPostfixExpr(c, m, scope, null);
58385973 },
58395974 }
58405975}
test/behavior/translate_c_macros.h+2
......@@ -16,3 +16,5 @@ struct Foo {
1616};
1717
1818#define SIZE_OF_FOO sizeof(struct Foo)
19
20#define MAP_FAILED ((void *) -1)
test/behavior/translate_c_macros.zig+4
......@@ -20,3 +20,7 @@ test "sizeof in macros" {
2020test "reference to a struct type" {
2121 try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);
2222}
23
24test "cast negative integer to pointer" {
25 try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);
26}
test/translate_c.zig+13-1
......@@ -238,7 +238,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
238238 });
239239
240240 cases.add("use cast param as macro fn return type",
241 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED)
241 \\#include <stdint.h>
242 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((uint32_t)(x) + SYS_BASE_CACHED)
242243 , &[_][]const u8{
243244 \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*c_void {
244245 \\ return @import("std").meta.cast(?*c_void, @import("std").meta.cast(u32, x) + SYS_BASE_CACHED);
......@@ -1878,6 +1879,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18781879 });
18791880
18801881 cases.add("macro pointer cast",
1882 \\typedef struct { int dummy; } NRF_GPIO_Type;
18811883 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
18821884 , &[_][]const u8{
18831885 \\pub const NRF_GPIO = @import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
......@@ -3175,6 +3177,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
31753177 });
31763178
31773179 cases.add("macro cast",
3180 \\#include <stdint.h>
31783181 \\#define FOO(bar) baz((void *)(baz))
31793182 \\#define BAR (void*) a
31803183 \\#define BAZ (uint32_t)(2)
......@@ -3633,4 +3636,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
36333636 \\ return foo.static.x;
36343637 \\}
36353638 });
3639
3640 cases.add("macro with nontrivial cast",
3641 \\#define MAP_FAILED ((void *) -1)
3642 \\typedef long long LONG_PTR;
3643 \\#define INVALID_HANDLE_VALUE ((void *)(LONG_PTR)-1)
3644 , &[_][]const u8{
3645 \\pub const MAP_FAILED = @import("std").meta.cast(?*c_void, -@as(c_int, 1));
3646 \\pub const INVALID_HANDLE_VALUE = @import("std").meta.cast(?*c_void, @import("std").meta.cast(LONG_PTR, -@as(c_int, 1)));
3647 });
36363648}