| ... | ... | @@ -280,6 +280,8 @@ pub const Context = struct { |
| 280 | 280 | opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{}, |
| 281 | 281 | /// Table of unnamed enums and records that are child types of typedefs. |
| 282 | 282 | unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{}, |
| 283 | /// Needed to decide if we are parsing a typename |
| 284 | typedefs: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 283 | 285 | |
| 284 | 286 | /// This one is different than the root scope's name table. This contains |
| 285 | 287 | /// a list of names that we found by visiting all the top level decls without |
| ... | ... | @@ -348,6 +350,7 @@ pub fn translate( |
| 348 | 350 | context.global_names.deinit(gpa); |
| 349 | 351 | context.opaque_demotes.deinit(gpa); |
| 350 | 352 | context.unnamed_typedefs.deinit(gpa); |
| 353 | context.typedefs.deinit(gpa); |
| 351 | 354 | context.global_scope.deinit(); |
| 352 | 355 | } |
| 353 | 356 | |
| ... | ... | @@ -461,6 +464,7 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 461 | 464 | result.value_ptr.* = name; |
| 462 | 465 | // Put this typedef in the decl_table to avoid redefinitions. |
| 463 | 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 | 796 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 793 | 797 | // TODO https://github.com/ziglang/zig/issues/1802 |
| 794 | 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 | 801 | if (builtin_typedef_map.get(name)) |builtin| { |
| 796 | 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 | 5309 | .IntegerLiteral, .FloatLiteral => { |
| 5304 | 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 | 5312 | .Identifier => { |
| 5357 | 5313 | const mangled_name = scope.getAlias(slice); |
| 5358 | 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 | 5325 | try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)}); |
| 5370 | 5326 | return error.ParseError; |
| 5371 | 5327 | } |
| 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; |
| 5401 | 5329 | }, |
| 5402 | 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 | 5337 | try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)}); |
| 5404 | 5338 | return error.ParseError; |
| 5405 | 5339 | }, |
| ... | ... | @@ -5605,7 +5539,7 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5605 | 5539 | } |
| 5606 | 5540 | |
| 5607 | 5541 | fn 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 | 5543 | while (true) { |
| 5610 | 5544 | switch (m.next().?) { |
| 5611 | 5545 | .Asterisk => { |
| ... | ... | @@ -5633,18 +5567,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5633 | 5567 | } else { |
| 5634 | 5568 | // expr * expr |
| 5635 | 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 | 5571 | node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 5638 | 5572 | } |
| 5639 | 5573 | }, |
| 5640 | 5574 | .Slash => { |
| 5641 | 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 | 5577 | node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 5644 | 5578 | }, |
| 5645 | 5579 | .Percent => { |
| 5646 | 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 | 5582 | node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 5649 | 5583 | }, |
| 5650 | 5584 | else => { |
| ... | ... | @@ -5655,8 +5589,209 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5655 | 5589 | } |
| 5656 | 5590 | } |
| 5657 | 5591 | |
| 5658 | | fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5659 | | var node = try parseCPrimaryExpr(c, m, scope); |
| 5592 | fn 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 | |
| 5614 | fn 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 | |
| 5622 | fn 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 | |
| 5664 | fn 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 | |
| 5765 | fn 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 | |
| 5793 | fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) ParseError!Node { |
| 5794 | var node = type_name orelse try parseCPrimaryExpr(c, m, scope); |
| 5660 | 5795 | while (true) { |
| 5661 | 5796 | switch (m.next().?) { |
| 5662 | 5797 | .Period => { |
| ... | ... | @@ -5776,24 +5911,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5776 | 5911 | fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5777 | 5912 | switch (m.next().?) { |
| 5778 | 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 | 5915 | return Tag.not.create(c.arena, operand); |
| 5781 | 5916 | }, |
| 5782 | 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 | 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 | 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 | 5924 | return Tag.bit_not.create(c.arena, operand); |
| 5790 | 5925 | }, |
| 5791 | 5926 | .Asterisk => { |
| 5792 | | const operand = try parseCUnaryExpr(c, m, scope); |
| 5927 | const operand = try parseCCastExpr(c, m, scope); |
| 5793 | 5928 | return Tag.deref.create(c.arena, operand); |
| 5794 | 5929 | }, |
| 5795 | 5930 | .Ampersand => { |
| 5796 | | const operand = try parseCUnaryExpr(c, m, scope); |
| 5931 | const operand = try parseCCastExpr(c, m, scope); |
| 5797 | 5932 | return Tag.address_of.create(c.arena, operand); |
| 5798 | 5933 | }, |
| 5799 | 5934 | .Keyword_sizeof => { |
| ... | ... | @@ -5834,7 +5969,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5834 | 5969 | }, |
| 5835 | 5970 | else => { |
| 5836 | 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 | } |