authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-14 15:27:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-14 22:50:00-04:00
log9a5a1013a833229e1d12588615c1a05644f76cc5
treec8a1cca2e5324891a4f748b3fd38c0f65ef78d03
parentc12a262503150d1b2251f7ba29e0f1ba4f649bf6

std.zig.ast: extract out Node.LabeledBlock from Node.Block

This is part of an ongoing effort to reduce size of in-memory AST. This enum flattening pattern is widespread throughout the self-hosted compiler. This is a API breaking change for consumers of the self-hosted parser.

6 files changed, 220 insertions(+), 109 deletions(-)

lib/std/zig/ast.zig+80-12
......@@ -526,6 +526,7 @@ pub const Node = struct {
526526 Comptime,
527527 Nosuspend,
528528 Block,
529 LabeledBlock,
529530
530531 // Misc
531532 DocComment,
......@@ -654,6 +655,7 @@ pub const Node = struct {
654655 .Comptime => Comptime,
655656 .Nosuspend => Nosuspend,
656657 .Block => Block,
658 .LabeledBlock => LabeledBlock,
657659 .DocComment => DocComment,
658660 .SwitchCase => SwitchCase,
659661 .SwitchElse => SwitchElse,
......@@ -666,6 +668,13 @@ pub const Node = struct {
666668 .FieldInitializer => FieldInitializer,
667669 };
668670 }
671
672 pub fn isBlock(tag: Tag) bool {
673 return switch (tag) {
674 .Block, .LabeledBlock => true,
675 else => false,
676 };
677 }
669678 };
670679
671680 /// Prefer `castTag` to this.
......@@ -729,6 +738,7 @@ pub const Node = struct {
729738 .Root,
730739 .ContainerField,
731740 .Block,
741 .LabeledBlock,
732742 .Payload,
733743 .PointerPayload,
734744 .PointerIndexPayload,
......@@ -739,6 +749,7 @@ pub const Node = struct {
739749 .DocComment,
740750 .TestDecl,
741751 => return false,
752
742753 .While => {
743754 const while_node = @fieldParentPtr(While, "base", n);
744755 if (while_node.@"else") |@"else"| {
......@@ -746,7 +757,7 @@ pub const Node = struct {
746757 continue;
747758 }
748759
749 return while_node.body.tag != .Block;
760 return !while_node.body.tag.isBlock();
750761 },
751762 .For => {
752763 const for_node = @fieldParentPtr(For, "base", n);
......@@ -755,7 +766,7 @@ pub const Node = struct {
755766 continue;
756767 }
757768
758 return for_node.body.tag != .Block;
769 return !for_node.body.tag.isBlock();
759770 },
760771 .If => {
761772 const if_node = @fieldParentPtr(If, "base", n);
......@@ -764,7 +775,7 @@ pub const Node = struct {
764775 continue;
765776 }
766777
767 return if_node.body.tag != .Block;
778 return !if_node.body.tag.isBlock();
768779 },
769780 .Else => {
770781 const else_node = @fieldParentPtr(Else, "base", n);
......@@ -773,29 +784,40 @@ pub const Node = struct {
773784 },
774785 .Defer => {
775786 const defer_node = @fieldParentPtr(Defer, "base", n);
776 return defer_node.expr.tag != .Block;
787 return !defer_node.expr.tag.isBlock();
777788 },
778789 .Comptime => {
779790 const comptime_node = @fieldParentPtr(Comptime, "base", n);
780 return comptime_node.expr.tag != .Block;
791 return !comptime_node.expr.tag.isBlock();
781792 },
782793 .Suspend => {
783794 const suspend_node = @fieldParentPtr(Suspend, "base", n);
784795 if (suspend_node.body) |body| {
785 return body.tag != .Block;
796 return !body.tag.isBlock();
786797 }
787798
788799 return true;
789800 },
790801 .Nosuspend => {
791802 const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);
792 return nosuspend_node.expr.tag != .Block;
803 return !nosuspend_node.expr.tag.isBlock();
793804 },
794805 else => return true,
795806 }
796807 }
797808 }
798809
810 /// Asserts the node is a Block or LabeledBlock and returns the statements slice.
811 pub fn blockStatements(base: *Node) []*Node {
812 if (base.castTag(.Block)) |block| {
813 return block.statements();
814 } else if (base.castTag(.LabeledBlock)) |labeled_block| {
815 return labeled_block.statements();
816 } else {
817 unreachable;
818 }
819 }
820
799821 pub fn dump(self: *Node, indent: usize) void {
800822 {
801823 var i: usize = 0;
......@@ -1460,7 +1482,6 @@ pub const Node = struct {
14601482 statements_len: NodeIndex,
14611483 lbrace: TokenIndex,
14621484 rbrace: TokenIndex,
1463 label: ?TokenIndex,
14641485
14651486 /// After this the caller must initialize the statements list.
14661487 pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*Block {
......@@ -1483,10 +1504,6 @@ pub const Node = struct {
14831504 }
14841505
14851506 pub fn firstToken(self: *const Block) TokenIndex {
1486 if (self.label) |label| {
1487 return label;
1488 }
1489
14901507 return self.lbrace;
14911508 }
14921509
......@@ -1509,6 +1526,57 @@ pub const Node = struct {
15091526 }
15101527 };
15111528
1529 /// The statements of the block follow LabeledBlock directly in memory.
1530 pub const LabeledBlock = struct {
1531 base: Node = Node{ .tag = .LabeledBlock },
1532 statements_len: NodeIndex,
1533 lbrace: TokenIndex,
1534 rbrace: TokenIndex,
1535 label: TokenIndex,
1536
1537 /// After this the caller must initialize the statements list.
1538 pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*LabeledBlock {
1539 const bytes = try allocator.alignedAlloc(u8, @alignOf(LabeledBlock), sizeInBytes(statements_len));
1540 return @ptrCast(*LabeledBlock, bytes.ptr);
1541 }
1542
1543 pub fn free(self: *LabeledBlock, allocator: *mem.Allocator) void {
1544 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.statements_len)];
1545 allocator.free(bytes);
1546 }
1547
1548 pub fn iterate(self: *const LabeledBlock, index: usize) ?*Node {
1549 var i = index;
1550
1551 if (i < self.statements_len) return self.statementsConst()[i];
1552 i -= self.statements_len;
1553
1554 return null;
1555 }
1556
1557 pub fn firstToken(self: *const LabeledBlock) TokenIndex {
1558 return self.label;
1559 }
1560
1561 pub fn lastToken(self: *const LabeledBlock) TokenIndex {
1562 return self.rbrace;
1563 }
1564
1565 pub fn statements(self: *LabeledBlock) []*Node {
1566 const decls_start = @ptrCast([*]u8, self) + @sizeOf(LabeledBlock);
1567 return @ptrCast([*]*Node, decls_start)[0..self.statements_len];
1568 }
1569
1570 pub fn statementsConst(self: *const LabeledBlock) []const *Node {
1571 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(LabeledBlock);
1572 return @ptrCast([*]const *Node, decls_start)[0..self.statements_len];
1573 }
1574
1575 fn sizeInBytes(statements_len: NodeIndex) usize {
1576 return @sizeOf(LabeledBlock) + @sizeOf(*Node) * @as(usize, statements_len);
1577 }
1578 };
1579
15121580 pub const Defer = struct {
15131581 base: Node = Node{ .tag = .Defer },
15141582 defer_token: TokenIndex,
lib/std/zig/parse.zig+37-29
......@@ -364,9 +364,10 @@ const Parser = struct {
364364 const name_node = try p.expectNode(parseStringLiteralSingle, .{
365365 .ExpectedStringLiteral = .{ .token = p.tok_i },
366366 });
367 const block_node = try p.expectNode(parseBlock, .{
368 .ExpectedLBrace = .{ .token = p.tok_i },
369 });
367 const block_node = (try p.parseBlock(null)) orelse {
368 try p.errors.append(p.gpa, .{ .ExpectedLBrace = .{ .token = p.tok_i } });
369 return error.ParseError;
370 };
370371
371372 const test_node = try p.arena.allocator.create(Node.TestDecl);
372373 test_node.* = .{
......@@ -540,12 +541,14 @@ const Parser = struct {
540541 if (p.eatToken(.Semicolon)) |_| {
541542 break :blk null;
542543 }
543 break :blk try p.expectNodeRecoverable(parseBlock, .{
544 const body_block = (try p.parseBlock(null)) orelse {
544545 // Since parseBlock only return error.ParseError on
545546 // a missing '}' we can assume this function was
546547 // supposed to end here.
547 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
548 });
548 try p.errors.append(p.gpa, .{ .ExpectedSemiOrLBrace = .{ .token = p.tok_i } });
549 break :blk null;
550 };
551 break :blk body_block;
549552 },
550553 .as_type => null,
551554 };
......@@ -823,10 +826,7 @@ const Parser = struct {
823826 var colon: TokenIndex = undefined;
824827 const label_token = p.parseBlockLabel(&colon);
825828
826 if (try p.parseBlock()) |node| {
827 node.cast(Node.Block).?.label = label_token;
828 return node;
829 }
829 if (try p.parseBlock(label_token)) |node| return node;
830830
831831 if (try p.parseLoopStatement()) |node| {
832832 if (node.cast(Node.For)) |for_node| {
......@@ -1003,14 +1003,13 @@ const Parser = struct {
10031003 fn parseBlockExpr(p: *Parser) Error!?*Node {
10041004 var colon: TokenIndex = undefined;
10051005 const label_token = p.parseBlockLabel(&colon);
1006 const block_node = (try p.parseBlock()) orelse {
1006 const block_node = (try p.parseBlock(label_token)) orelse {
10071007 if (label_token) |label| {
10081008 p.putBackToken(label + 1); // ":"
10091009 p.putBackToken(label); // IDENTIFIER
10101010 }
10111011 return null;
10121012 };
1013 block_node.cast(Node.Block).?.label = label_token;
10141013 return block_node;
10151014 }
10161015
......@@ -1177,7 +1176,7 @@ const Parser = struct {
11771176 p.putBackToken(token); // IDENTIFIER
11781177 }
11791178
1180 if (try p.parseBlock()) |node| return node;
1179 if (try p.parseBlock(null)) |node| return node;
11811180 if (try p.parseCurlySuffixExpr()) |node| return node;
11821181
11831182 return null;
......@@ -1189,7 +1188,7 @@ const Parser = struct {
11891188 }
11901189
11911190 /// Block <- LBRACE Statement* RBRACE
1192 fn parseBlock(p: *Parser) !?*Node {
1191 fn parseBlock(p: *Parser, label_token: ?TokenIndex) !?*Node {
11931192 const lbrace = p.eatToken(.LBrace) orelse return null;
11941193
11951194 var statements = std.ArrayList(*Node).init(p.gpa);
......@@ -1211,16 +1210,26 @@ const Parser = struct {
12111210
12121211 const statements_len = @intCast(NodeIndex, statements.items.len);
12131212
1214 const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
1215 block_node.* = .{
1216 .label = null,
1217 .lbrace = lbrace,
1218 .statements_len = statements_len,
1219 .rbrace = rbrace,
1220 };
1221 std.mem.copy(*Node, block_node.statements(), statements.items);
1222
1223 return &block_node.base;
1213 if (label_token) |label| {
1214 const block_node = try Node.LabeledBlock.alloc(&p.arena.allocator, statements_len);
1215 block_node.* = .{
1216 .label = label,
1217 .lbrace = lbrace,
1218 .statements_len = statements_len,
1219 .rbrace = rbrace,
1220 };
1221 std.mem.copy(*Node, block_node.statements(), statements.items);
1222 return &block_node.base;
1223 } else {
1224 const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len);
1225 block_node.* = .{
1226 .lbrace = lbrace,
1227 .statements_len = statements_len,
1228 .rbrace = rbrace,
1229 };
1230 std.mem.copy(*Node, block_node.statements(), statements.items);
1231 return &block_node.base;
1232 }
12241233 }
12251234
12261235 /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr)
......@@ -1658,11 +1667,8 @@ const Parser = struct {
16581667 var colon: TokenIndex = undefined;
16591668 const label = p.parseBlockLabel(&colon);
16601669
1661 if (label) |token| {
1662 if (try p.parseBlock()) |node| {
1663 node.cast(Node.Block).?.label = token;
1664 return node;
1665 }
1670 if (label) |label_token| {
1671 if (try p.parseBlock(label_token)) |node| return node;
16661672 }
16671673
16681674 if (try p.parseLoopTypeExpr()) |node| {
......@@ -3440,6 +3446,7 @@ const Parser = struct {
34403446 }
34413447 }
34423448
3449 /// TODO Delete this function. I don't like the inversion of control.
34433450 fn expectNode(
34443451 p: *Parser,
34453452 parseFn: NodeParseFn,
......@@ -3449,6 +3456,7 @@ const Parser = struct {
34493456 return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError;
34503457 }
34513458
3459 /// TODO Delete this function. I don't like the inversion of control.
34523460 fn expectNodeRecoverable(
34533461 p: *Parser,
34543462 parseFn: NodeParseFn,
lib/std/zig/render.zig+31-8
......@@ -392,28 +392,50 @@ fn renderExpression(
392392 return renderToken(tree, stream, any_type.token, indent, start_col, space);
393393 },
394394
395 .Block => {
396 const block = @fieldParentPtr(ast.Node.Block, "base", base);
395 .Block, .LabeledBlock => {
396 const block: struct {
397 label: ?ast.TokenIndex,
398 statements: []*ast.Node,
399 lbrace: ast.TokenIndex,
400 rbrace: ast.TokenIndex,
401 } = b: {
402 if (base.castTag(.Block)) |block| {
403 break :b .{
404 .label = null,
405 .statements = block.statements(),
406 .lbrace = block.lbrace,
407 .rbrace = block.rbrace,
408 };
409 } else if (base.castTag(.LabeledBlock)) |block| {
410 break :b .{
411 .label = block.label,
412 .statements = block.statements(),
413 .lbrace = block.lbrace,
414 .rbrace = block.rbrace,
415 };
416 } else {
417 unreachable;
418 }
419 };
397420
398421 if (block.label) |label| {
399422 try renderToken(tree, stream, label, indent, start_col, Space.None);
400423 try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space);
401424 }
402425
403 if (block.statements_len == 0) {
426 if (block.statements.len == 0) {
404427 try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None);
405428 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
406429 } else {
407430 const block_indent = indent + indent_delta;
408431 try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline);
409432
410 const block_statements = block.statements();
411 for (block_statements) |statement, i| {
433 for (block.statements) |statement, i| {
412434 try stream.writeByteNTimes(' ', block_indent);
413435 try renderStatement(allocator, stream, tree, block_indent, start_col, statement);
414436
415 if (i + 1 < block_statements.len) {
416 try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]);
437 if (i + 1 < block.statements.len) {
438 try renderExtraNewline(tree, stream, start_col, block.statements[i + 1]);
417439 }
418440 }
419441
......@@ -1841,7 +1863,7 @@ fn renderExpression(
18411863
18421864 const rparen = tree.nextToken(for_node.array_expr.lastToken());
18431865
1844 const body_is_block = for_node.body.tag == .Block;
1866 const body_is_block = for_node.body.tag.isBlock();
18451867 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
18461868 const body_on_same_line = body_is_block or src_one_line_to_body;
18471869
......@@ -2578,6 +2600,7 @@ fn renderDocCommentsToken(
25782600fn nodeIsBlock(base: *const ast.Node) bool {
25792601 return switch (base.tag) {
25802602 .Block,
2603 .LabeledBlock,
25812604 .If,
25822605 .For,
25832606 .While,
src-self-hosted/Module.zig+1-1
......@@ -1343,7 +1343,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13431343
13441344 const body_block = body_node.cast(ast.Node.Block).?;
13451345
1346 _ = try astgen.blockExpr(self, params_scope, .none, body_block);
1346 try astgen.blockExpr(self, params_scope, body_block);
13471347
13481348 if (gen_scope.instructions.items.len == 0 or
13491349 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
src-self-hosted/astgen.zig+25-15
......@@ -107,31 +107,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
107107 .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)),
108108 .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)),
109109 .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?),
110 .Block => return blockExpr(mod, scope, rl, node.castTag(.Block).?),
110 .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),
111 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
111112 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
112113 }
113114}
114115
115pub fn blockExpr(
116pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block) InnerError!void {
117 const tracy = trace(@src());
118 defer tracy.end();
119
120 try blockExprStmts(mod, parent_scope, &block_node.base, block_node.statements());
121}
122
123fn labeledBlockExpr(
116124 mod: *Module,
117125 parent_scope: *Scope,
118126 rl: ResultLoc,
119 block_node: *ast.Node.Block,
127 block_node: *ast.Node.LabeledBlock,
120128) InnerError!*zir.Inst {
121129 const tracy = trace(@src());
122130 defer tracy.end();
123131
124 if (block_node.label) |label| {
125 return mod.failTok(parent_scope, label, "TODO implement labeled blocks", .{});
132 const statements = block_node.statements();
133
134 if (statements.len == 0) {
135 // Hot path for `{}`.
136 return rlWrapVoid(mod, parent_scope, rl, &block_node.base, {});
126137 }
127138
128 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
129 defer block_arena.deinit();
139 return mod.failNode(parent_scope, &block_node.base, "TODO implement labeled blocks", .{});
140}
130141
142fn blockExprStmts(mod: *Module, parent_scope: *Scope, node: *ast.Node, statements: []*ast.Node) !void {
131143 const tree = parent_scope.tree();
132144
145 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
146 defer block_arena.deinit();
147
133148 var scope = parent_scope;
134 for (block_node.statements()) |statement| {
149 for (statements) |statement| {
135150 const src = tree.token_locs[statement.firstToken()].start;
136151 _ = try addZIRNoOp(mod, scope, src, .dbg_stmt);
137152 switch (statement.tag) {
......@@ -162,12 +177,6 @@ pub fn blockExpr(
162177 },
163178 }
164179 }
165
166 const src = tree.token_locs[block_node.firstToken()].start;
167 return addZIRInstConst(mod, parent_scope, src, .{
168 .ty = Type.initTag(.void),
169 .val = Value.initTag(.void_value),
170 });
171180}
172181
173182fn varDecl(
......@@ -1184,6 +1193,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
11841193 .Slice,
11851194 .Deref,
11861195 .ArrayAccess,
1196 .Block,
11871197 => return false,
11881198
11891199 // Forward the question to a sub-expression.
......@@ -1210,11 +1220,11 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
12101220 .Switch,
12111221 .Call,
12121222 .BuiltinCall, // TODO some of these can return false
1223 .LabeledBlock,
12131224 => return true,
12141225
12151226 // Depending on AST properties, they may need memory locations.
12161227 .If => return node.castTag(.If).?.@"else" != null,
1217 .Block => return node.castTag(.Block).?.label != null,
12181228 }
12191229 }
12201230}
src-self-hosted/translate_c.zig+46-44
......@@ -118,19 +118,31 @@ const Scope = struct {
118118 self.* = undefined;
119119 }
120120
121 fn complete(self: *Block, c: *Context) !*ast.Node.Block {
121 fn complete(self: *Block, c: *Context) !*ast.Node {
122122 // We reserve 1 extra statement if the parent is a Loop. This is in case of
123123 // do while, we want to put `if (cond) break;` at the end.
124124 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
125 const node = try ast.Node.Block.alloc(c.arena, alloc_len);
126 node.* = .{
127 .statements_len = self.statements.items.len,
128 .lbrace = self.lbrace,
129 .rbrace = try appendToken(c, .RBrace, "}"),
130 .label = self.label,
131 };
132 mem.copy(*ast.Node, node.statements(), self.statements.items);
133 return node;
125 const rbrace = try appendToken(c, .RBrace, "}");
126 if (self.label) |label| {
127 const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len);
128 node.* = .{
129 .statements_len = self.statements.items.len,
130 .lbrace = self.lbrace,
131 .rbrace = rbrace,
132 .label = label,
133 };
134 mem.copy(*ast.Node, node.statements(), self.statements.items);
135 return &node.base;
136 } else {
137 const node = try ast.Node.Block.alloc(c.arena, alloc_len);
138 node.* = .{
139 .statements_len = self.statements.items.len,
140 .lbrace = self.lbrace,
141 .rbrace = rbrace,
142 };
143 mem.copy(*ast.Node, node.statements(), self.statements.items);
144 return &node.base;
145 }
134146 }
135147
136148 /// Given the desired name, return a name that does not shadow anything from outer scopes.
......@@ -320,15 +332,9 @@ pub const Context = struct {
320332 return node;
321333 }
322334
323 fn createBlock(c: *Context, label: ?[]const u8, statements_len: ast.NodeIndex) !*ast.Node.Block {
324 const label_node = if (label) |l| blk: {
325 const ll = try appendIdentifier(c, l);
326 _ = try appendToken(c, .Colon, ":");
327 break :blk ll;
328 } else null;
335 fn createBlock(c: *Context, statements_len: ast.NodeIndex) !*ast.Node.Block {
329336 const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
330337 block_node.* = .{
331 .label = label_node,
332338 .lbrace = try appendToken(c, .LBrace, "{"),
333339 .statements_len = statements_len,
334340 .rbrace = undefined,
......@@ -640,8 +646,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
640646 var last = block_scope.statements.items[block_scope.statements.items.len - 1];
641647 while (true) {
642648 switch (last.tag) {
643 .Block => {
644 const stmts = last.castTag(.Block).?.statements();
649 .Block, .LabeledBlock => {
650 const stmts = last.blockStatements();
645651 if (stmts.len == 0) break;
646652
647653 last = stmts[stmts.len - 1];
......@@ -669,7 +675,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
669675 }
670676
671677 const body_node = try block_scope.complete(rp.c);
672 proto_node.setTrailer("body_node", &body_node.base);
678 proto_node.setTrailer("body_node", body_node);
673679 return addTopLevelDecl(c, fn_name, &proto_node.base);
674680}
675681
......@@ -1275,7 +1281,7 @@ fn transStmt(
12751281 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
12761282 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
12771283 .NullStmtClass => {
1278 const block = try rp.c.createBlock(null, 0);
1284 const block = try rp.c.createBlock(0);
12791285 block.rbrace = try appendToken(rp.c, .RBrace, "}");
12801286 return &block.base;
12811287 },
......@@ -1356,7 +1362,7 @@ fn transBinaryOperator(
13561362 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
13571363 grouped_expr.* = .{
13581364 .lparen = lparen,
1359 .expr = &block_node.base,
1365 .expr = block_node,
13601366 .rparen = rparen,
13611367 };
13621368 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
......@@ -1521,8 +1527,7 @@ fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompo
15211527 var block_scope = try Scope.Block.init(rp.c, scope, false);
15221528 defer block_scope.deinit();
15231529 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
1524 const node = try block_scope.complete(rp.c);
1525 return &node.base;
1530 return try block_scope.complete(rp.c);
15261531}
15271532
15281533fn transCStyleCastExprClass(
......@@ -2589,7 +2594,7 @@ fn transDoWhileLoop(
25892594 // zig: if (!cond) break;
25902595 // zig: }
25912596 const node = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
2592 break :blk node.cast(ast.Node.Block).?;
2597 break :blk node.castTag(.Block).?;
25932598 } else blk: {
25942599 // the C statement is without a block, so we need to create a block to contain it.
25952600 // c: do
......@@ -2600,7 +2605,7 @@ fn transDoWhileLoop(
26002605 // zig: if (!cond) break;
26012606 // zig: }
26022607 new = true;
2603 const block = try rp.c.createBlock(null, 2);
2608 const block = try rp.c.createBlock(2);
26042609 block.statements_len = 1; // over-allocated so we can add another below
26052610 block.statements()[0] = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value);
26062611 break :blk block;
......@@ -2659,8 +2664,7 @@ fn transForLoop(
26592664 while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
26602665 if (block_scope) |*bs| {
26612666 try bs.statements.append(&while_node.base);
2662 const node = try bs.complete(rp.c);
2663 return &node.base;
2667 return try bs.complete(rp.c);
26642668 } else {
26652669 _ = try appendToken(rp.c, .Semicolon, ";");
26662670 return &while_node.base;
......@@ -2768,7 +2772,7 @@ fn transSwitch(
27682772
27692773 const result_node = try switch_scope.pending_block.complete(rp.c);
27702774 switch_scope.pending_block.deinit();
2771 return &result_node.base;
2775 return result_node;
27722776}
27732777
27742778fn transCase(
......@@ -2820,7 +2824,7 @@ fn transCase(
28202824 switch_scope.pending_block.deinit();
28212825 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
28222826
2823 try switch_scope.pending_block.statements.append(&pending_node.base);
2827 try switch_scope.pending_block.statements.append(pending_node);
28242828
28252829 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
28262830}
......@@ -2857,7 +2861,7 @@ fn transDefault(
28572861 const pending_node = try switch_scope.pending_block.complete(rp.c);
28582862 switch_scope.pending_block.deinit();
28592863 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
2860 try switch_scope.pending_block.statements.append(&pending_node.base);
2864 try switch_scope.pending_block.statements.append(pending_node);
28612865
28622866 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
28632867}
......@@ -2972,7 +2976,7 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
29722976 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
29732977 grouped_expr.* = .{
29742978 .lparen = lparen,
2975 .expr = &block_node.base,
2979 .expr = block_node,
29762980 .rparen = rparen,
29772981 };
29782982 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
......@@ -3304,7 +3308,7 @@ fn transCreatePreCrement(
33043308 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
33053309 grouped_expr.* = .{
33063310 .lparen = try appendToken(rp.c, .LParen, "("),
3307 .expr = &block_node.base,
3311 .expr = block_node,
33083312 .rparen = try appendToken(rp.c, .RParen, ")"),
33093313 };
33103314 return &grouped_expr.base;
......@@ -3398,7 +3402,7 @@ fn transCreatePostCrement(
33983402 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
33993403 grouped_expr.* = .{
34003404 .lparen = try appendToken(rp.c, .LParen, "("),
3401 .expr = &block_node.base,
3405 .expr = block_node,
34023406 .rparen = try appendToken(rp.c, .RParen, ")"),
34033407 };
34043408 return &grouped_expr.base;
......@@ -3589,7 +3593,7 @@ fn transCreateCompoundAssign(
35893593 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
35903594 grouped_expr.* = .{
35913595 .lparen = try appendToken(rp.c, .LParen, "("),
3592 .expr = &block_node.base,
3596 .expr = block_node,
35933597 .rparen = try appendToken(rp.c, .RParen, ")"),
35943598 };
35953599 return &grouped_expr.base;
......@@ -3748,7 +3752,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
37483752 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
37493753 grouped_expr.* = .{
37503754 .lparen = lparen,
3751 .expr = &block_node.base,
3755 .expr = block_node,
37523756 .rparen = try appendToken(rp.c, .RParen, ")"),
37533757 };
37543758 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
......@@ -4191,7 +4195,7 @@ fn transCreateNodeAssign(
41914195 const block_node = try block_scope.complete(rp.c);
41924196 // semicolon must immediately follow rbrace because it is the last token in a block
41934197 _ = try appendToken(rp.c, .Semicolon, ";");
4194 return &block_node.base;
4198 return block_node;
41954199}
41964200
41974201fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
......@@ -4484,7 +4488,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
44844488
44854489 const block = try ast.Node.Block.alloc(c.arena, 1);
44864490 block.* = .{
4487 .label = null,
44884491 .lbrace = block_lbrace,
44894492 .statements_len = 1,
44904493 .rbrace = try appendToken(c, .RBrace, "}"),
......@@ -5475,9 +5478,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
54755478 if (last != .Eof and last != .Nl)
54765479 return m.fail(c, "unable to translate C expr: unexpected token .{}", .{@tagName(last)});
54775480 _ = try appendToken(c, .Semicolon, ";");
5478 const type_of_arg = if (expr.tag != .Block) expr else blk: {
5479 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
5480 const blk_last = blk.statements()[blk.statements_len - 1];
5481 const type_of_arg = if (!expr.tag.isBlock()) expr else blk: {
5482 const stmts = expr.blockStatements();
5483 const blk_last = stmts[stmts.len - 1];
54815484 const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
54825485 break :blk br.getRHS().?;
54835486 };
......@@ -5500,7 +5503,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55005503 .visib_token = pub_tok,
55015504 .extern_export_inline_token = inline_tok,
55025505 .name_token = name_tok,
5503 .body_node = &block_node.base,
5506 .body_node = block_node,
55045507 });
55055508 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
55065509
......@@ -5555,8 +5558,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
55555558
55565559 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
55575560 try block_scope.statements.append(&break_node.base);
5558 const block_node = try block_scope.complete(c);
5559 return &block_node.base;
5561 return try block_scope.complete(c);
55605562 },
55615563 else => {
55625564 m.i -= 1;