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 {...@@ -890,38 +890,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
890 // this function should behave like transCCast in translate-c, except it's for macros and enums890 // this function should behave like transCCast in translate-c, except it's for macros and enums
891 const SourceType = @TypeOf(target);891 const SourceType = @TypeOf(target);
892 switch (@typeInfo(DestType)) {892 switch (@typeInfo(DestType)) {
893 .Pointer => {893 .Pointer => return castToPtr(DestType, SourceType, target),
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 },
909 .Optional => |dest_opt| {894 .Optional => |dest_opt| {
910 if (@typeInfo(dest_opt.child) == .Pointer) {895 if (@typeInfo(dest_opt.child) == .Pointer) {
911 switch (@typeInfo(SourceType)) {896 return castToPtr(DestType, SourceType, target);
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 }
925 }897 }
926 },898 },
927 .Enum => |enum_type| {899 .Enum => |enum_type| {
...@@ -977,6 +949,30 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {...@@ -977,6 +949,30 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
977 return @ptrCast(DestType, @alignCast(dest.alignment, target));949 return @ptrCast(DestType, @alignCast(dest.alignment, target));
978}950}
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
980fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {976fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
981 return switch (@typeInfo(PtrType)) {977 return switch (@typeInfo(PtrType)) {
982 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,978 .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
...@@ -1026,6 +1022,12 @@ test "std.meta.cast" {...@@ -1026,6 +1022,12 @@ test "std.meta.cast" {
1026 try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);1022 try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
1027 try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);1023 try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
1028 try testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));1024 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))));
1029}1031}
10301032
1031/// Given a value returns its size as C's sizeof operator would.1033/// 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 {...@@ -280,6 +280,8 @@ pub const Context = struct {
280 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},280 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
281 /// Table of unnamed enums and records that are child types of typedefs.281 /// Table of unnamed enums and records that are child types of typedefs.
282 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},282 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
283 /// Needed to decide if we are parsing a typename
284 typedefs: std.StringArrayHashMapUnmanaged(void) = .{},
283285
284 /// This one is different than the root scope's name table. This contains286 /// This one is different than the root scope's name table. This contains
285 /// a list of names that we found by visiting all the top level decls without287 /// a list of names that we found by visiting all the top level decls without
...@@ -348,6 +350,7 @@ pub fn translate(...@@ -348,6 +350,7 @@ pub fn translate(
348 context.global_names.deinit(gpa);350 context.global_names.deinit(gpa);
349 context.opaque_demotes.deinit(gpa);351 context.opaque_demotes.deinit(gpa);
350 context.unnamed_typedefs.deinit(gpa);352 context.unnamed_typedefs.deinit(gpa);
353 context.typedefs.deinit(gpa);
351 context.global_scope.deinit();354 context.global_scope.deinit();
352 }355 }
353356
...@@ -461,6 +464,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {...@@ -461,6 +464,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
461 result.value_ptr.* = name;464 result.value_ptr.* = name;
462 // Put this typedef in the decl_table to avoid redefinitions.465 // Put this typedef in the decl_table to avoid redefinitions.
463 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);466 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
467 try c.typedefs.put(c.gpa, name, {});
464 }468 }
465 }469 }
466}470}
...@@ -792,6 +796,8 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNa...@@ -792,6 +796,8 @@ fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNa
792 // TODO https://github.com/ziglang/zig/issues/3756796 // TODO https://github.com/ziglang/zig/issues/3756
793 // TODO https://github.com/ziglang/zig/issues/1802797 // TODO https://github.com/ziglang/zig/issues/1802
794 var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;798 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
795 if (builtin_typedef_map.get(name)) |builtin| {801 if (builtin_typedef_map.get(name)) |builtin| {
796 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);802 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
797 }803 }
...@@ -5303,56 +5309,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5303,56 +5309,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5303 .IntegerLiteral, .FloatLiteral => {5309 .IntegerLiteral, .FloatLiteral => {
5304 return parseCNumLit(c, m);5310 return parseCNumLit(c, m);
5305 },5311 },
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 },
5356 .Identifier => {5312 .Identifier => {
5357 const mangled_name = scope.getAlias(slice);5313 const mangled_name = scope.getAlias(slice);
5358 if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {5314 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...@@ -5369,37 +5325,15 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5369 try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)});5325 try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)});
5370 return error.ParseError;5326 return error.ParseError;
5371 }5327 }
5372 var saw_l_paren = false;5328 return inner_node;
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 });
5401 },5329 },
5402 else => {5330 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 }
5403 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});5337 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});
5404 return error.ParseError;5338 return error.ParseError;
5405 },5339 },
...@@ -5605,7 +5539,7 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5605,7 +5539,7 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5605}5539}
56065540
5607fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5541fn 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);
5609 while (true) {5543 while (true) {
5610 switch (m.next().?) {5544 switch (m.next().?) {
5611 .Asterisk => {5545 .Asterisk => {
...@@ -5633,18 +5567,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5633,18 +5567,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5633 } else {5567 } else {
5634 // expr * expr5568 // expr * expr
5635 const lhs = try macroBoolToInt(c, node);5569 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));
5637 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });5571 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
5638 }5572 }
5639 },5573 },
5640 .Slash => {5574 .Slash => {
5641 const lhs = try macroBoolToInt(c, node);5575 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));
5643 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });5577 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
5644 },5578 },
5645 .Percent => {5579 .Percent => {
5646 const lhs = try macroBoolToInt(c, node);5580 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));
5648 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });5582 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
5649 },5583 },
5650 else => {5584 else => {
...@@ -5655,8 +5589,209 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5655,8 +5589,209 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5655 }5589 }
5656}5590}
56575591
5658fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5592fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5659 var node = try parseCPrimaryExpr(c, m, scope);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);
5660 while (true) {5795 while (true) {
5661 switch (m.next().?) {5796 switch (m.next().?) {
5662 .Period => {5797 .Period => {
...@@ -5776,24 +5911,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5776,24 +5911,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5776fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5911fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5777 switch (m.next().?) {5912 switch (m.next().?) {
5778 .Bang => {5913 .Bang => {
5779 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));5914 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
5780 return Tag.not.create(c.arena, operand);5915 return Tag.not.create(c.arena, operand);
5781 },5916 },
5782 .Minus => {5917 .Minus => {
5783 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));5918 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
5784 return Tag.negate.create(c.arena, operand);5919 return Tag.negate.create(c.arena, operand);
5785 },5920 },
5786 .Plus => return try parseCUnaryExpr(c, m, scope),5921 .Plus => return try parseCCastExpr(c, m, scope),
5787 .Tilde => {5922 .Tilde => {
5788 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));5923 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
5789 return Tag.bit_not.create(c.arena, operand);5924 return Tag.bit_not.create(c.arena, operand);
5790 },5925 },
5791 .Asterisk => {5926 .Asterisk => {
5792 const operand = try parseCUnaryExpr(c, m, scope);5927 const operand = try parseCCastExpr(c, m, scope);
5793 return Tag.deref.create(c.arena, operand);5928 return Tag.deref.create(c.arena, operand);
5794 },5929 },
5795 .Ampersand => {5930 .Ampersand => {
5796 const operand = try parseCUnaryExpr(c, m, scope);5931 const operand = try parseCCastExpr(c, m, scope);
5797 return Tag.address_of.create(c.arena, operand);5932 return Tag.address_of.create(c.arena, operand);
5798 },5933 },
5799 .Keyword_sizeof => {5934 .Keyword_sizeof => {
...@@ -5834,7 +5969,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5834,7 +5969,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5834 },5969 },
5835 else => {5970 else => {
5836 m.i -= 1;5971 m.i -= 1;
5837 return try parseCPostfixExpr(c, m, scope);5972 return try parseCPostfixExpr(c, m, scope, null);
5838 },5973 },
5839 }5974 }
5840}5975}
test/behavior/translate_c_macros.h+2
...@@ -16,3 +16,5 @@ struct Foo {...@@ -16,3 +16,5 @@ struct Foo {
16};16};
1717
18#define SIZE_OF_FOO sizeof(struct Foo)18#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" {...@@ -20,3 +20,7 @@ test "sizeof in macros" {
20test "reference to a struct type" {20test "reference to a struct type" {
21 try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);21 try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);
22}22}
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 {...@@ -238,7 +238,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
238 });238 });
239239
240 cases.add("use cast param as macro fn return type",240 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)
242 , &[_][]const u8{243 , &[_][]const u8{
243 \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*c_void {244 \\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*c_void {
244 \\ return @import("std").meta.cast(?*c_void, @import("std").meta.cast(u32, x) + SYS_BASE_CACHED);245 \\ 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 {...@@ -1878,6 +1879,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1878 });1879 });
18791880
1880 cases.add("macro pointer cast",1881 cases.add("macro pointer cast",
1882 \\typedef struct { int dummy; } NRF_GPIO_Type;
1881 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)1883 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1882 , &[_][]const u8{1884 , &[_][]const u8{
1883 \\pub const NRF_GPIO = @import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);1885 \\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 {...@@ -3175,6 +3177,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3175 });3177 });
31763178
3177 cases.add("macro cast",3179 cases.add("macro cast",
3180 \\#include <stdint.h>
3178 \\#define FOO(bar) baz((void *)(baz))3181 \\#define FOO(bar) baz((void *)(baz))
3179 \\#define BAR (void*) a3182 \\#define BAR (void*) a
3180 \\#define BAZ (uint32_t)(2)3183 \\#define BAZ (uint32_t)(2)
...@@ -3633,4 +3636,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3633,4 +3636,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3633 \\ return foo.static.x;3636 \\ return foo.static.x;
3634 \\}3637 \\}
3635 });3638 });
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 });
3636}3648}