| author | |
| committer | |
| log | a5cb19c0ac6b3eec8b0e246507a5feffd1daca59 |
| tree | 0be4697a96ba9eb4c7499191be2d7805b7393256 |
| parent | 2b1316954f169a88cfb694f4c1defc0d965455ea |
| parent | 692a974c3edd05944d33cd579bcb355cdd7199fc |
| signature |
Translate-c fixes5 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 | 812 | pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; |
| 813 | 813 | pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool; |
| 814 | 814 | pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool; |
| 815 | pub extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(self: ?*const struct_ZigClangType, *const ZigClangASTContext) bool; | |
| 815 | 816 | pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool; |
| 816 | 817 | pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool; |
| 817 | 818 | pub 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 | 793 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { |
| 794 | 794 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); |
| 795 | 795 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); |
| 796 | const field_qt = ZigClangFieldDecl_getType(field_decl); | |
| 796 | 797 | |
| 797 | 798 | if (ZigClangFieldDecl_isBitField(field_decl)) { |
| 798 | 799 | const opaque = try transCreateNodeOpaqueType(c); |
| ... | ... | @@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 801 | 802 | break :blk opaque; |
| 802 | 803 | } |
| 803 | 804 | |
| 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 | 812 | var is_anon = false; |
| 805 | 813 | var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); |
| 806 | 814 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { |
| ... | ... | @@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 809 | 817 | } |
| 810 | 818 | const field_name = try appendIdentifier(c, raw_name); |
| 811 | 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 | 821 | error.UnsupportedType => { |
| 814 | 822 | const opaque = try transCreateNodeOpaqueType(c); |
| 815 | 823 | semicolon = try appendToken(c, .Semicolon, ";"); |
| ... | ... | @@ -2237,6 +2245,7 @@ fn transWhileLoop( |
| 2237 | 2245 | .id = .Loop, |
| 2238 | 2246 | }; |
| 2239 | 2247 | while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value); |
| 2248 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2240 | 2249 | return &while_node.base; |
| 2241 | 2250 | } |
| 2242 | 2251 | |
| ... | ... | @@ -2346,8 +2355,10 @@ fn transForLoop( |
| 2346 | 2355 | try block_scope.?.block_node.statements.push(&while_node.base); |
| 2347 | 2356 | block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 2348 | 2357 | return &block_scope.?.block_node.base; |
| 2349 | } else | |
| 2358 | } else { | |
| 2359 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2350 | 2360 | return &while_node.base; |
| 2361 | } | |
| 2351 | 2362 | } |
| 2352 | 2363 | |
| 2353 | 2364 | fn transSwitch( |
| ... | ... | @@ -5431,6 +5442,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5431 | 5442 | //else |
| 5432 | 5443 | // @as(dest, x) |
| 5433 | 5444 | |
| 5445 | const lparen = try appendToken(c, .LParen, "("); | |
| 5446 | ||
| 5434 | 5447 | const if_1 = try transCreateNodeIf(c); |
| 5435 | 5448 | const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); |
| 5436 | 5449 | const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); |
| ... | ... | @@ -5492,7 +5505,13 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5492 | 5505 | as.rparen_token = try appendToken(c, .RParen, ")"); |
| 5493 | 5506 | else_2.body = &as.base; |
| 5494 | 5507 | |
| 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 | 5516 | else => { |
| 5498 | 5517 | const first_tok = it.list.at(0); |
| ... | ... | @@ -5545,14 +5564,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5545 | 5564 | ); |
| 5546 | 5565 | return error.ParseError; |
| 5547 | 5566 | } |
| 5548 | // deref is often used together with casts so we group the lhs expression | |
| 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); | |
| 5567 | const deref = try transCreateNodePtrDeref(c, node); | |
| 5556 | 5568 | node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]); |
| 5557 | 5569 | continue; |
| 5558 | 5570 | }, |
| ... | ... | @@ -5596,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5596 | 5608 | }, |
| 5597 | 5609 | .Ampersand => { |
| 5598 | 5610 | op_token = try appendToken(c, .Ampersand, "&"); |
| 5599 | op_id .BitAnd; | |
| 5611 | op_id = .BitAnd; | |
| 5600 | 5612 | }, |
| 5601 | 5613 | .Plus => { |
| 5602 | 5614 | op_token = try appendToken(c, .Plus, "+"); |
| ... | ... | @@ -5604,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5604 | 5616 | }, |
| 5605 | 5617 | .Minus => { |
| 5606 | 5618 | op_token = try appendToken(c, .Minus, "-"); |
| 5607 | op_id .Sub; | |
| 5619 | op_id = .Sub; | |
| 5608 | 5620 | }, |
| 5609 | 5621 | .AmpersandAmpersand => { |
| 5610 | 5622 | op_token = try appendToken(c, .Keyword_and, "and"); |
| ... | ... | @@ -5676,19 +5688,17 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5676 | 5688 | }, |
| 5677 | 5689 | .BangEqual => { |
| 5678 | 5690 | op_token = try appendToken(c, .BangEqual, "!="); |
| 5679 | op_id = .BangEqual; | |
| 5691 | op_id = .BangEqual; | |
| 5680 | 5692 | }, |
| 5681 | 5693 | .EqualEqual => { |
| 5682 | 5694 | op_token = try appendToken(c, .EqualEqual, "=="); |
| 5683 | 5695 | op_id = .EqualEqual; |
| 5684 | 5696 | }, |
| 5685 | 5697 | .Slash => { |
| 5686 | // unsigned/float division uses the operator | |
| 5687 | 5698 | op_id = .Div; |
| 5688 | 5699 | op_token = try appendToken(c, .Slash, "/"); |
| 5689 | 5700 | }, |
| 5690 | 5701 | .Percent => { |
| 5691 | // unsigned/float division uses the operator | |
| 5692 | 5702 | op_id = .Mod; |
| 5693 | 5703 | op_token = try appendToken(c, .Percent, "%"); |
| 5694 | 5704 | }, |
| ... | ... | @@ -5729,25 +5739,12 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5729 | 5739 | return &node.base; |
| 5730 | 5740 | }, |
| 5731 | 5741 | .Asterisk => { |
| 5732 | // deref is often used together with casts so we group the lhs expression | |
| 5733 | const group = try c.a().create(ast.Node.GroupedExpression); | |
| 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); | |
| 5742 | const node = try parseCPrefixOpExpr(c, it, source, source_loc, scope); | |
| 5743 | return try transCreateNodePtrDeref(c, node); | |
| 5740 | 5744 | }, |
| 5741 | 5745 | .Ampersand => { |
| 5742 | // address of is often used together with casts so we group the rhs expression | |
| 5743 | 5746 | const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&"); |
| 5744 | const group = try c.a().create(ast.Node.GroupedExpression); | |
| 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; | |
| 5747 | node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope); | |
| 5751 | 5748 | return &node.base; |
| 5752 | 5749 | }, |
| 5753 | 5750 | else => { |
src/zig_clang.cpp+20| ... | ... | @@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) { |
| 1881 | 1881 | return casted->isRecordType(); |
| 1882 | 1882 | } |
| 1883 | 1883 | |
| 1884 | bool 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 | ||
| 1884 | 1904 | bool ZigClangType_isConstantArrayType(const ZigClangType *self) { |
| 1885 | 1905 | auto casted = reinterpret_cast<const clang::Type *>(self); |
| 1886 | 1906 | return casted->isConstantArrayType(); |
src/zig_clang.h+1| ... | ... | @@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self); |
| 947 | 947 | ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self); |
| 948 | 948 | ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self); |
| 949 | 949 | ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self); |
| 950 | ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx); | |
| 950 | 951 | ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self); |
| 951 | 952 | ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self); |
| 952 | 953 | ZIG_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 | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | |
| 5 | 5 | pub 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 | 31 | cases.add("macro comma operator", |
| 7 | 32 | \\#define foo (foo, bar) |
| 8 | 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 | 39 | , |
| 15 | 40 | \\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) { |
| 16 | 41 | \\ return blk: { |
| 17 | \\ _ = &(x); | |
| 42 | \\ _ = &x; | |
| 18 | 43 | \\ _ = 3; |
| 19 | 44 | \\ _ = 4 == 4; |
| 20 | 45 | \\ _ = 5 * 6; |
| ... | ... | @@ -1404,7 +1429,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1404 | 1429 | cases.add("macro pointer cast", |
| 1405 | 1430 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) |
| 1406 | 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 | }); |
| 1409 | 1434 | |
| 1410 | 1435 | cases.add("basic macro function", |
| ... | ... | @@ -1993,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1993 | 2018 | , |
| 1994 | 2019 | \\pub const DOT = a.b; |
| 1995 | 2020 | , |
| 1996 | \\pub const ARROW = (a).*.b; | |
| 2021 | \\pub const ARROW = a.*.b; | |
| 1997 | 2022 | }); |
| 1998 | 2023 | |
| 1999 | 2024 | cases.add("array access", |
| ... | ... | @@ -2588,11 +2613,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2588 | 2613 | \\#define FOO(bar) baz((void *)(baz)) |
| 2589 | 2614 | \\#define BAR (void*) a |
| 2590 | 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))) { | |
| 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)); | |
| 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)))) { | |
| 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 | }); |
| 2597 | 2622 | |
| 2598 | 2623 | cases.add("macro conditional operator", |