authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-08 12:43:49-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-03-08 12:43:49-04:00
loga5cb19c0ac6b3eec8b0e246507a5feffd1daca59
tree0be4697a96ba9eb4c7499191be2d7805b7393256
parent2b1316954f169a88cfb694f4c1defc0d965455ea
parent692a974c3edd05944d33cd579bcb355cdd7199fc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4690 from Vexu/translate-c

Translate-c fixes

5 files changed, 82 insertions(+), 38 deletions(-)

src-self-hosted/clang.zig+1
...@@ -812,6 +812,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str...@@ -812,6 +812,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str
812pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;812pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
813pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool;813pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool;
814pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;814pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;
815pub extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(self: ?*const struct_ZigClangType, *const ZigClangASTContext) bool;
815pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;816pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;
816pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;817pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;
817pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;818pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
src-self-hosted/translate_c.zig+29-32
...@@ -793,6 +793,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -793,6 +793,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
793 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {793 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
794 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);794 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
795 const field_loc = ZigClangFieldDecl_getLocation(field_decl);795 const field_loc = ZigClangFieldDecl_getLocation(field_decl);
796 const field_qt = ZigClangFieldDecl_getType(field_decl);
796797
797 if (ZigClangFieldDecl_isBitField(field_decl)) {798 if (ZigClangFieldDecl_isBitField(field_decl)) {
798 const opaque = try transCreateNodeOpaqueType(c);799 const opaque = try transCreateNodeOpaqueType(c);
...@@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
801 break :blk opaque;802 break :blk opaque;
802 }803 }
803804
805 if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
806 const opaque = try transCreateNodeOpaqueType(c);
807 semicolon = try appendToken(c, .Semicolon, ";");
808 try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
809 break :blk opaque;
810 }
811
804 var is_anon = false;812 var is_anon = false;
805 var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));813 var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
806 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {814 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
...@@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
809 }817 }
810 const field_name = try appendIdentifier(c, raw_name);818 const field_name = try appendIdentifier(c, raw_name);
811 _ = try appendToken(c, .Colon, ":");819 _ = try appendToken(c, .Colon, ":");
812 const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {820 const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
813 error.UnsupportedType => {821 error.UnsupportedType => {
814 const opaque = try transCreateNodeOpaqueType(c);822 const opaque = try transCreateNodeOpaqueType(c);
815 semicolon = try appendToken(c, .Semicolon, ";");823 semicolon = try appendToken(c, .Semicolon, ";");
...@@ -2237,6 +2245,7 @@ fn transWhileLoop(...@@ -2237,6 +2245,7 @@ fn transWhileLoop(
2237 .id = .Loop,2245 .id = .Loop,
2238 };2246 };
2239 while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);2247 while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
2248 _ = try appendToken(rp.c, .Semicolon, ";");
2240 return &while_node.base;2249 return &while_node.base;
2241}2250}
22422251
...@@ -2346,8 +2355,10 @@ fn transForLoop(...@@ -2346,8 +2355,10 @@ fn transForLoop(
2346 try block_scope.?.block_node.statements.push(&while_node.base);2355 try block_scope.?.block_node.statements.push(&while_node.base);
2347 block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");2356 block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2348 return &block_scope.?.block_node.base;2357 return &block_scope.?.block_node.base;
2349 } else2358 } else {
2359 _ = try appendToken(rp.c, .Semicolon, ";");
2350 return &while_node.base;2360 return &while_node.base;
2361 }
2351}2362}
23522363
2353fn transSwitch(2364fn transSwitch(
...@@ -5431,6 +5442,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5431,6 +5442,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5431 //else5442 //else
5432 // @as(dest, x)5443 // @as(dest, x)
54335444
5445 const lparen = try appendToken(c, .LParen, "(");
5446
5434 const if_1 = try transCreateNodeIf(c);5447 const if_1 = try transCreateNodeIf(c);
5435 const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");5448 const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
5436 const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");5449 const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
...@@ -5492,7 +5505,13 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5492,7 +5505,13 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5492 as.rparen_token = try appendToken(c, .RParen, ")");5505 as.rparen_token = try appendToken(c, .RParen, ")");
5493 else_2.body = &as.base;5506 else_2.body = &as.base;
54945507
5495 return &if_1.base;5508 const group_node = try c.a().create(ast.Node.GroupedExpression);
5509 group_node.* = .{
5510 .lparen = lparen,
5511 .expr = &if_1.base,
5512 .rparen = try appendToken(c, .RParen, ")"),
5513 };
5514 return &group_node.base;
5496 },5515 },
5497 else => {5516 else => {
5498 const first_tok = it.list.at(0);5517 const first_tok = it.list.at(0);
...@@ -5545,14 +5564,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5545,14 +5564,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5545 );5564 );
5546 return error.ParseError;5565 return error.ParseError;
5547 }5566 }
5548 // deref is often used together with casts so we group the lhs expression5567 const deref = try transCreateNodePtrDeref(c, node);
5549 const group = try c.a().create(ast.Node.GroupedExpression);
5550 group.* = .{
5551 .lparen = try appendToken(c, .LParen, "("),
5552 .expr = node,
5553 .rparen = try appendToken(c, .RParen, ")"),
5554 };
5555 const deref = try transCreateNodePtrDeref(c, &group.base);
5556 node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]);5568 node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]);
5557 continue;5569 continue;
5558 },5570 },
...@@ -5596,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5596,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5596 },5608 },
5597 .Ampersand => {5609 .Ampersand => {
5598 op_token = try appendToken(c, .Ampersand, "&");5610 op_token = try appendToken(c, .Ampersand, "&");
5599 op_id .BitAnd;5611 op_id = .BitAnd;
5600 },5612 },
5601 .Plus => {5613 .Plus => {
5602 op_token = try appendToken(c, .Plus, "+");5614 op_token = try appendToken(c, .Plus, "+");
...@@ -5604,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5604,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5604 },5616 },
5605 .Minus => {5617 .Minus => {
5606 op_token = try appendToken(c, .Minus, "-");5618 op_token = try appendToken(c, .Minus, "-");
5607 op_id .Sub;5619 op_id = .Sub;
5608 },5620 },
5609 .AmpersandAmpersand => {5621 .AmpersandAmpersand => {
5610 op_token = try appendToken(c, .Keyword_and, "and");5622 op_token = try appendToken(c, .Keyword_and, "and");
...@@ -5676,19 +5688,17 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5676,19 +5688,17 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5676 },5688 },
5677 .BangEqual => {5689 .BangEqual => {
5678 op_token = try appendToken(c, .BangEqual, "!=");5690 op_token = try appendToken(c, .BangEqual, "!=");
5679 op_id = .BangEqual;5691 op_id = .BangEqual;
5680 },5692 },
5681 .EqualEqual => {5693 .EqualEqual => {
5682 op_token = try appendToken(c, .EqualEqual, "==");5694 op_token = try appendToken(c, .EqualEqual, "==");
5683 op_id = .EqualEqual;5695 op_id = .EqualEqual;
5684 },5696 },
5685 .Slash => {5697 .Slash => {
5686 // unsigned/float division uses the operator
5687 op_id = .Div;5698 op_id = .Div;
5688 op_token = try appendToken(c, .Slash, "/");5699 op_token = try appendToken(c, .Slash, "/");
5689 },5700 },
5690 .Percent => {5701 .Percent => {
5691 // unsigned/float division uses the operator
5692 op_id = .Mod;5702 op_id = .Mod;
5693 op_token = try appendToken(c, .Percent, "%");5703 op_token = try appendToken(c, .Percent, "%");
5694 },5704 },
...@@ -5729,25 +5739,12 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5729,25 +5739,12 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5729 return &node.base;5739 return &node.base;
5730 },5740 },
5731 .Asterisk => {5741 .Asterisk => {
5732 // deref is often used together with casts so we group the lhs expression5742 const node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5733 const group = try c.a().create(ast.Node.GroupedExpression);5743 return try transCreateNodePtrDeref(c, node);
5734 group.* = .{
5735 .lparen = try appendToken(c, .LParen, "("),
5736 .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
5737 .rparen = try appendToken(c, .RParen, ")"),
5738 };
5739 return try transCreateNodePtrDeref(c, &group.base);
5740 },5744 },
5741 .Ampersand => {5745 .Ampersand => {
5742 // address of is often used together with casts so we group the rhs expression
5743 const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");5746 const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
5744 const group = try c.a().create(ast.Node.GroupedExpression);5747 node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
5745 group.* = .{
5746 .lparen = try appendToken(c, .LParen, "("),
5747 .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
5748 .rparen = try appendToken(c, .RParen, ")"),
5749 };
5750 node.rhs = &group.base;
5751 return &node.base;5748 return &node.base;
5752 },5749 },
5753 else => {5750 else => {
src/zig_clang.cpp+20
...@@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {...@@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
1881 return casted->isRecordType();1881 return casted->isRecordType();
1882}1882}
18831883
1884bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
1885 const struct ZigClangASTContext *ctx)
1886{
1887 auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
1888 auto casted = reinterpret_cast<const clang::QualType *>(self);
1889 auto casted_type = reinterpret_cast<const clang::Type *>(self);
1890 if (casted_type->isIncompleteArrayType())
1891 return true;
1892
1893 clang::QualType elem_type = *casted;
1894 while (const clang::ConstantArrayType *ArrayT = casted_ctx->getAsConstantArrayType(elem_type)) {
1895 if (ArrayT->getSize() == 0)
1896 return true;
1897
1898 elem_type = ArrayT->getElementType();
1899 }
1900
1901 return false;
1902}
1903
1884bool ZigClangType_isConstantArrayType(const ZigClangType *self) {1904bool ZigClangType_isConstantArrayType(const ZigClangType *self) {
1885 auto casted = reinterpret_cast<const clang::Type *>(self);1905 auto casted = reinterpret_cast<const clang::Type *>(self);
1886 return casted->isConstantArrayType();1906 return casted->isConstantArrayType();
src/zig_clang.h+1
...@@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);...@@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
947ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);947ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
948ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);948ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
949ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);949ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
950ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
950ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);951ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
951ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);952ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
952ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self);953ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self);
test/translate_c.zig+31-6
...@@ -3,6 +3,31 @@ const std = @import("std");...@@ -3,6 +3,31 @@ const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("structs with VLAs are rejected",
7 \\struct foo { int x; int y[]; };
8 \\struct bar { int x; int y[0]; };
9 , &[_][]const u8{
10 \\pub const struct_foo = @OpaqueType();
11 ,
12 \\pub const struct_bar = @OpaqueType();
13 });
14
15 cases.add("nested loops without blocks",
16 \\void foo() {
17 \\ while (0) while (0) {}
18 \\ for (;;) while (0);
19 \\ for (;;) do {} while (0);
20 \\}
21 , &[_][]const u8{
22 \\pub export fn foo() void {
23 \\ while (@as(c_int, 0) != 0) while (@as(c_int, 0) != 0) {};
24 \\ while (true) while (@as(c_int, 0) != 0) {};
25 \\ while (true) while (true) {
26 \\ if (!(@as(c_int, 0) != 0)) break;
27 \\ };
28 \\}
29 });
30
6 cases.add("macro comma operator",31 cases.add("macro comma operator",
7 \\#define foo (foo, bar)32 \\#define foo (foo, bar)
8 \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))33 \\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
...@@ -14,7 +39,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -14,7 +39,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14 ,39 ,
15 \\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) {40 \\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) {
16 \\ return blk: {41 \\ return blk: {
17 \\ _ = &(x);42 \\ _ = &x;
18 \\ _ = 3;43 \\ _ = 3;
19 \\ _ = 4 == 4;44 \\ _ = 4 == 4;
20 \\ _ = 5 * 6;45 \\ _ = 5 * 6;
...@@ -1404,7 +1429,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1404,7 +1429,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1404 cases.add("macro pointer cast",1429 cases.add("macro pointer cast",
1405 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)1430 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1406 , &[_][]const u8{1431 , &[_][]const u8{
1407 \\pub const NRF_GPIO = if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);1432 \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
1408 });1433 });
14091434
1410 cases.add("basic macro function",1435 cases.add("basic macro function",
...@@ -1993,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1993,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1993 ,2018 ,
1994 \\pub const DOT = a.b;2019 \\pub const DOT = a.b;
1995 ,2020 ,
1996 \\pub const ARROW = (a).*.b;2021 \\pub const ARROW = a.*.b;
1997 });2022 });
19982023
1999 cases.add("array access",2024 cases.add("array access",
...@@ -2588,11 +2613,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2588,11 +2613,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2588 \\#define FOO(bar) baz((void *)(baz))2613 \\#define FOO(bar) baz((void *)(baz))
2589 \\#define BAR (void*) a2614 \\#define BAR (void*) a
2590 , &[_][]const u8{2615 , &[_][]const u8{
2591 \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) {2616 \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
2592 \\ return baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz));2617 \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
2593 \\}2618 \\}
2594 ,2619 ,
2595 \\pub const BAR = if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a);2620 \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a));
2596 });2621 });
25972622
2598 cases.add("macro conditional operator",2623 cases.add("macro conditional operator",