authorgravatar for 14938807+xackus@users.noreply.github.comxackus <14938807+xackus@users.noreply.github.com> 2021-06-12 15:54:39+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-13 16:47:42+03:00
logaa83cbb69737fbf8567c100340e476b5e38f0c84
tree5a96e2a519f1a1dd4fc55d980ed4d7cbccdf3a8d
parent46b9e061e07700ad1372ed2e9d2af9a29f24d76c

translate-c: better typename parsing


2 files changed, 164 insertions(+), 93 deletions(-)

src/translate_c.zig+151-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,133 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5655,8 +5589,133 @@ 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 // eventually this will be replaced by std.c.parse which will handle these correctly
5631 .Keyword_void => return try Tag.type.create(c.arena, "c_void"),
5632 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),
5633 .Keyword_double => return try Tag.type.create(c.arena, "f64"),
5634 .Keyword_long => return try Tag.type.create(c.arena, "c_long"),
5635 .Keyword_int => return try Tag.type.create(c.arena, "c_int"),
5636 .Keyword_float => return try Tag.type.create(c.arena, "f32"),
5637 .Keyword_short => return try Tag.type.create(c.arena, "c_short"),
5638 .Keyword_char => return try Tag.type.create(c.arena, "u8"),
5639 .Keyword_unsigned => if (m.next()) |t| switch (t) {
5640 .Keyword_char => return try Tag.type.create(c.arena, "u8"),
5641 .Keyword_short => return try Tag.type.create(c.arena, "c_ushort"),
5642 .Keyword_int => return try Tag.type.create(c.arena, "c_uint"),
5643 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5644 _ = m.next();
5645 return try Tag.type.create(c.arena, "c_ulonglong");
5646 } else return try Tag.type.create(c.arena, "c_ulong"),
5647 else => {
5648 m.i -= 1;
5649 return try Tag.type.create(c.arena, "c_uint");
5650 },
5651 } else {
5652 return try Tag.type.create(c.arena, "c_uint");
5653 },
5654 .Keyword_signed => if (m.next()) |t| switch (t) {
5655 .Keyword_char => return try Tag.type.create(c.arena, "i8"),
5656 .Keyword_short => return try Tag.type.create(c.arena, "c_short"),
5657 .Keyword_int => return try Tag.type.create(c.arena, "c_int"),
5658 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
5659 _ = m.next();
5660 return try Tag.type.create(c.arena, "c_longlong");
5661 } else return try Tag.type.create(c.arena, "c_long"),
5662 else => {
5663 m.i -= 1;
5664 return try Tag.type.create(c.arena, "c_int");
5665 },
5666 } else {
5667 return try Tag.type.create(c.arena, "c_int");
5668 },
5669 .Keyword_enum, .Keyword_struct, .Keyword_union => {
5670 // struct Foo will be declared as struct_Foo by transRecordDecl
5671 const slice = m.slice();
5672 const next_id = m.next().?;
5673 if (next_id != .Identifier) {
5674 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
5675 return error.ParseError;
5676 }
5677
5678 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
5679 return try Tag.identifier.create(c.arena, name);
5680 },
5681 .Keyword_complex => {}, // TODO
5682 else => {},
5683 }
5684
5685 m.i -= 1;
5686 return null;
5687}
5688
5689fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, scope: *Scope, node: Node) ParseError!Node {
5690 switch (m.next().?) {
5691 .Asterisk => {
5692 // last token of `node`
5693 const prev_id = m.list[m.i - 1].id;
5694
5695 if (prev_id == .Keyword_void) {
5696 const ptr = try Tag.single_pointer.create(c.arena, .{
5697 .is_const = false,
5698 .is_volatile = false,
5699 .elem_type = node,
5700 });
5701 return Tag.optional_type.create(c.arena, ptr);
5702 } else {
5703 return Tag.c_pointer.create(c.arena, .{
5704 .is_const = false,
5705 .is_volatile = false,
5706 .elem_type = node,
5707 });
5708 }
5709 },
5710 else => {
5711 m.i -= 1;
5712 return node;
5713 },
5714 }
5715}
5716
5717fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) ParseError!Node {
5718 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
5660 while (true) {5719 while (true) {
5661 switch (m.next().?) {5720 switch (m.next().?) {
5662 .Period => {5721 .Period => {
...@@ -5776,24 +5835,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5776,24 +5835,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5776fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {5835fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5777 switch (m.next().?) {5836 switch (m.next().?) {
5778 .Bang => {5837 .Bang => {
5779 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));5838 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
5780 return Tag.not.create(c.arena, operand);5839 return Tag.not.create(c.arena, operand);
5781 },5840 },
5782 .Minus => {5841 .Minus => {
5783 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));5842 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
5784 return Tag.negate.create(c.arena, operand);5843 return Tag.negate.create(c.arena, operand);
5785 },5844 },
5786 .Plus => return try parseCUnaryExpr(c, m, scope),5845 .Plus => return try parseCCastExpr(c, m, scope),
5787 .Tilde => {5846 .Tilde => {
5788 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));5847 const operand = try macroBoolToInt(c, try parseCCastExpr(c, m, scope));
5789 return Tag.bit_not.create(c.arena, operand);5848 return Tag.bit_not.create(c.arena, operand);
5790 },5849 },
5791 .Asterisk => {5850 .Asterisk => {
5792 const operand = try parseCUnaryExpr(c, m, scope);5851 const operand = try parseCCastExpr(c, m, scope);
5793 return Tag.deref.create(c.arena, operand);5852 return Tag.deref.create(c.arena, operand);
5794 },5853 },
5795 .Ampersand => {5854 .Ampersand => {
5796 const operand = try parseCUnaryExpr(c, m, scope);5855 const operand = try parseCCastExpr(c, m, scope);
5797 return Tag.address_of.create(c.arena, operand);5856 return Tag.address_of.create(c.arena, operand);
5798 },5857 },
5799 .Keyword_sizeof => {5858 .Keyword_sizeof => {
...@@ -5834,7 +5893,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5834,7 +5893,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5834 },5893 },
5835 else => {5894 else => {
5836 m.i -= 1;5895 m.i -= 1;
5837 return try parseCPostfixExpr(c, m, scope);5896 return try parseCPostfixExpr(c, m, scope, null);
5838 },5897 },
5839 }5898 }
5840}5899}
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}