| ... | ... | @@ -61,7 +61,8 @@ const Scope = struct { |
| 61 | 61 | pending_block: Block, |
| 62 | 62 | cases: []*ast.Node, |
| 63 | 63 | case_index: usize, |
| 64 | | has_default: bool = false, |
| 64 | switch_label: ?[]const u8, |
| 65 | default_label: ?[]const u8, |
| 65 | 66 | }; |
| 66 | 67 | |
| 67 | 68 | /// Used for the scope of condition expressions, for example `if (cond)`. |
| ... | ... | @@ -73,7 +74,7 @@ const Scope = struct { |
| 73 | 74 | |
| 74 | 75 | fn getBlockScope(self: *Condition, c: *Context) !*Block { |
| 75 | 76 | if (self.block) |*b| return b; |
| 76 | | self.block = try Block.init(c, &self.base, "blk"); |
| 77 | self.block = try Block.init(c, &self.base, true); |
| 77 | 78 | return &self.block.?; |
| 78 | 79 | } |
| 79 | 80 | |
| ... | ... | @@ -93,21 +94,22 @@ const Scope = struct { |
| 93 | 94 | mangle_count: u32 = 0, |
| 94 | 95 | lbrace: ast.TokenIndex, |
| 95 | 96 | |
| 96 | | fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block { |
| 97 | | return Block{ |
| 97 | fn init(c: *Context, parent: *Scope, labeled: bool) !Block { |
| 98 | var blk = Block{ |
| 98 | 99 | .base = .{ |
| 99 | 100 | .id = .Block, |
| 100 | 101 | .parent = parent, |
| 101 | 102 | }, |
| 102 | 103 | .statements = std.ArrayList(*ast.Node).init(c.gpa), |
| 103 | 104 | .variables = AliasList.init(c.gpa), |
| 104 | | .label = if (label) |l| blk: { |
| 105 | | const ll = try appendIdentifier(c, l); |
| 106 | | _ = try appendToken(c, .Colon, ":"); |
| 107 | | break :blk ll; |
| 108 | | } else null, |
| 105 | .label = null, |
| 109 | 106 | .lbrace = try appendToken(c, .LBrace, "{"), |
| 110 | 107 | }; |
| 108 | if (labeled) { |
| 109 | blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk")); |
| 110 | _ = try appendToken(c, .Colon, ":"); |
| 111 | } |
| 112 | return blk; |
| 111 | 113 | } |
| 112 | 114 | |
| 113 | 115 | fn deinit(self: *Block) void { |
| ... | ... | @@ -577,7 +579,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 577 | 579 | |
| 578 | 580 | // actual function definition with body |
| 579 | 581 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); |
| 580 | | var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); |
| 582 | var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false); |
| 581 | 583 | defer block_scope.deinit(); |
| 582 | 584 | var scope = &block_scope.base; |
| 583 | 585 | |
| ... | ... | @@ -1307,7 +1309,7 @@ fn transBinaryOperator( |
| 1307 | 1309 | const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 1308 | 1310 | if (expr) { |
| 1309 | 1311 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1310 | | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, rhs); |
| 1312 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs); |
| 1311 | 1313 | try block_scope.statements.append(&break_node.base); |
| 1312 | 1314 | const block_node = try block_scope.complete(rp.c); |
| 1313 | 1315 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| ... | ... | @@ -1476,7 +1478,7 @@ fn transCompoundStmtInline( |
| 1476 | 1478 | } |
| 1477 | 1479 | |
| 1478 | 1480 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { |
| 1479 | | var block_scope = try Scope.Block.init(rp.c, scope, null); |
| 1481 | var block_scope = try Scope.Block.init(rp.c, scope, false); |
| 1480 | 1482 | defer block_scope.deinit(); |
| 1481 | 1483 | try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope); |
| 1482 | 1484 | const node = try block_scope.complete(rp.c); |
| ... | ... | @@ -2587,7 +2589,7 @@ fn transForLoop( |
| 2587 | 2589 | defer if (block_scope) |*bs| bs.deinit(); |
| 2588 | 2590 | |
| 2589 | 2591 | if (ZigClangForStmt_getInit(stmt)) |init| { |
| 2590 | | block_scope = try Scope.Block.init(rp.c, scope, null); |
| 2592 | block_scope = try Scope.Block.init(rp.c, scope, false); |
| 2591 | 2593 | loop_scope.parent = &block_scope.?.base; |
| 2592 | 2594 | const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value); |
| 2593 | 2595 | try block_scope.?.statements.append(init_node); |
| ... | ... | @@ -2673,17 +2675,19 @@ fn transSwitch( |
| 2673 | 2675 | .cases = switch_node.cases(), |
| 2674 | 2676 | .case_index = 0, |
| 2675 | 2677 | .pending_block = undefined, |
| 2678 | .default_label = null, |
| 2679 | .switch_label = null, |
| 2676 | 2680 | }; |
| 2677 | 2681 | |
| 2678 | 2682 | // tmp block that all statements will go before being picked up by a case or default |
| 2679 | | var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); |
| 2683 | var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false); |
| 2680 | 2684 | defer block_scope.deinit(); |
| 2681 | 2685 | |
| 2682 | 2686 | // Note that we do not defer a deinit here; the switch_scope.pending_block field |
| 2683 | 2687 | // has its own memory management. This resource is freed inside `transCase` and |
| 2684 | 2688 | // then the final pending_block is freed at the bottom of this function with |
| 2685 | 2689 | // pending_block.deinit(). |
| 2686 | | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); |
| 2690 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); |
| 2687 | 2691 | try switch_scope.pending_block.statements.append(&switch_node.base); |
| 2688 | 2692 | |
| 2689 | 2693 | const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); |
| ... | ... | @@ -2698,11 +2702,19 @@ fn transSwitch( |
| 2698 | 2702 | switch_scope.pending_block.statements.appendAssumeCapacity(n); |
| 2699 | 2703 | } |
| 2700 | 2704 | |
| 2701 | | switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); |
| 2702 | | _ = try appendToken(rp.c, .Colon, ":"); |
| 2703 | | if (!switch_scope.has_default) { |
| 2705 | if (switch_scope.default_label == null) { |
| 2706 | switch_scope.switch_label = try block_scope.makeMangledName(rp.c, "switch"); |
| 2707 | } |
| 2708 | if (switch_scope.switch_label) |l| { |
| 2709 | switch_scope.pending_block.label = try appendIdentifier(rp.c, l); |
| 2710 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2711 | } |
| 2712 | if (switch_scope.default_label == null) { |
| 2704 | 2713 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); |
| 2705 | | else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch", null)).base; |
| 2714 | else_prong.expr = blk: { |
| 2715 | var br = try CtrlFlow.init(rp.c, .Break, switch_scope.switch_label.?); |
| 2716 | break :blk &(try br.finish(null)).base; |
| 2717 | }; |
| 2706 | 2718 | _ = try appendToken(rp.c, .Comma, ","); |
| 2707 | 2719 | |
| 2708 | 2720 | if (switch_scope.case_index >= switch_scope.cases.len) |
| ... | ... | @@ -2726,7 +2738,7 @@ fn transCase( |
| 2726 | 2738 | ) TransError!*ast.Node { |
| 2727 | 2739 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; |
| 2728 | 2740 | const switch_scope = scope.getSwitch(); |
| 2729 | | const label = try std.fmt.allocPrint(rp.c.arena, "__case_{}", .{switch_scope.case_index - @boolToInt(switch_scope.has_default)}); |
| 2741 | const label = try block_scope.makeMangledName(rp.c, "case"); |
| 2730 | 2742 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2731 | 2743 | |
| 2732 | 2744 | const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: { |
| ... | ... | @@ -2746,7 +2758,10 @@ fn transCase( |
| 2746 | 2758 | try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value); |
| 2747 | 2759 | |
| 2748 | 2760 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); |
| 2749 | | switch_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base; |
| 2761 | switch_prong.expr = blk: { |
| 2762 | var br = try CtrlFlow.init(rp.c, .Break, label); |
| 2763 | break :blk &(try br.finish(null)).base; |
| 2764 | }; |
| 2750 | 2765 | _ = try appendToken(rp.c, .Comma, ","); |
| 2751 | 2766 | |
| 2752 | 2767 | if (switch_scope.case_index >= switch_scope.cases.len) |
| ... | ... | @@ -2763,7 +2778,7 @@ fn transCase( |
| 2763 | 2778 | |
| 2764 | 2779 | const pending_node = try switch_scope.pending_block.complete(rp.c); |
| 2765 | 2780 | switch_scope.pending_block.deinit(); |
| 2766 | | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); |
| 2781 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); |
| 2767 | 2782 | |
| 2768 | 2783 | try switch_scope.pending_block.statements.append(&pending_node.base); |
| 2769 | 2784 | |
| ... | ... | @@ -2777,12 +2792,14 @@ fn transDefault( |
| 2777 | 2792 | ) TransError!*ast.Node { |
| 2778 | 2793 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; |
| 2779 | 2794 | const switch_scope = scope.getSwitch(); |
| 2780 | | const label = "__default"; |
| 2781 | | switch_scope.has_default = true; |
| 2795 | switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default"); |
| 2782 | 2796 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2783 | 2797 | |
| 2784 | 2798 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); |
| 2785 | | else_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base; |
| 2799 | else_prong.expr = blk: { |
| 2800 | var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?); |
| 2801 | break :blk &(try br.finish(null)).base; |
| 2802 | }; |
| 2786 | 2803 | _ = try appendToken(rp.c, .Comma, ","); |
| 2787 | 2804 | |
| 2788 | 2805 | if (switch_scope.case_index >= switch_scope.cases.len) |
| ... | ... | @@ -2790,7 +2807,7 @@ fn transDefault( |
| 2790 | 2807 | switch_scope.cases[switch_scope.case_index] = &else_prong.base; |
| 2791 | 2808 | switch_scope.case_index += 1; |
| 2792 | 2809 | |
| 2793 | | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); |
| 2810 | switch_scope.pending_block.label = try appendIdentifier(rp.c, switch_scope.default_label.?); |
| 2794 | 2811 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2795 | 2812 | |
| 2796 | 2813 | // take all pending statements |
| ... | ... | @@ -2799,7 +2816,7 @@ fn transDefault( |
| 2799 | 2816 | |
| 2800 | 2817 | const pending_node = try switch_scope.pending_block.complete(rp.c); |
| 2801 | 2818 | switch_scope.pending_block.deinit(); |
| 2802 | | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); |
| 2819 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); |
| 2803 | 2820 | try switch_scope.pending_block.statements.append(&pending_node.base); |
| 2804 | 2821 | |
| 2805 | 2822 | return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value); |
| ... | ... | @@ -2894,7 +2911,7 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, |
| 2894 | 2911 | return transCompoundStmt(rp, scope, comp); |
| 2895 | 2912 | } |
| 2896 | 2913 | const lparen = try appendToken(rp.c, .LParen, "("); |
| 2897 | | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 2914 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 2898 | 2915 | defer block_scope.deinit(); |
| 2899 | 2916 | |
| 2900 | 2917 | var it = ZigClangCompoundStmt_body_begin(comp); |
| ... | ... | @@ -3209,7 +3226,7 @@ fn transCreatePreCrement( |
| 3209 | 3226 | // zig: _ref.* += 1; |
| 3210 | 3227 | // zig: break :blk _ref.* |
| 3211 | 3228 | // zig: }) |
| 3212 | | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3229 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 3213 | 3230 | defer block_scope.deinit(); |
| 3214 | 3231 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3215 | 3232 | |
| ... | ... | @@ -3239,7 +3256,7 @@ fn transCreatePreCrement( |
| 3239 | 3256 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); |
| 3240 | 3257 | try block_scope.statements.append(assign); |
| 3241 | 3258 | |
| 3242 | | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node); |
| 3259 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node); |
| 3243 | 3260 | try block_scope.statements.append(&break_node.base); |
| 3244 | 3261 | const block_node = try block_scope.complete(rp.c); |
| 3245 | 3262 | // semicolon must immediately follow rbrace because it is the last token in a block |
| ... | ... | @@ -3283,7 +3300,7 @@ fn transCreatePostCrement( |
| 3283 | 3300 | // zig: _ref.* += 1; |
| 3284 | 3301 | // zig: break :blk _tmp |
| 3285 | 3302 | // zig: }) |
| 3286 | | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3303 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 3287 | 3304 | defer block_scope.deinit(); |
| 3288 | 3305 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3289 | 3306 | |
| ... | ... | @@ -3458,7 +3475,7 @@ fn transCreateCompoundAssign( |
| 3458 | 3475 | // zig: _ref.* = _ref.* + rhs; |
| 3459 | 3476 | // zig: break :blk _ref.* |
| 3460 | 3477 | // zig: }) |
| 3461 | | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3478 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 3462 | 3479 | defer block_scope.deinit(); |
| 3463 | 3480 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3464 | 3481 | |
| ... | ... | @@ -3526,7 +3543,7 @@ fn transCreateCompoundAssign( |
| 3526 | 3543 | try block_scope.statements.append(assign); |
| 3527 | 3544 | } |
| 3528 | 3545 | |
| 3529 | | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node); |
| 3546 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node); |
| 3530 | 3547 | try block_scope.statements.append(&break_node.base); |
| 3531 | 3548 | const block_node = try block_scope.complete(rp.c); |
| 3532 | 3549 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| ... | ... | @@ -3602,8 +3619,16 @@ fn transCPtrCast( |
| 3602 | 3619 | |
| 3603 | 3620 | fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { |
| 3604 | 3621 | const break_scope = scope.getBreakableScope(); |
| 3605 | | const label_text: ?[]const u8 = if (break_scope.id == .Switch) "__switch" else null; |
| 3606 | | const br = try transCreateNodeBreak(rp.c, label_text, null); |
| 3622 | const label_text: ?[]const u8 = if (break_scope.id == .Switch) blk: { |
| 3623 | const swtch = @fieldParentPtr(Scope.Switch, "base", break_scope); |
| 3624 | const block_scope = try scope.findBlockScope(rp.c); |
| 3625 | swtch.switch_label = try block_scope.makeMangledName(rp.c, "switch"); |
| 3626 | break :blk swtch.switch_label; |
| 3627 | } else |
| 3628 | null; |
| 3629 | |
| 3630 | var cf = try CtrlFlow.init(rp.c, .Break, label_text); |
| 3631 | const br = try cf.finish(null); |
| 3607 | 3632 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3608 | 3633 | return &br.base; |
| 3609 | 3634 | } |
| ... | ... | @@ -3634,7 +3659,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const |
| 3634 | 3659 | // }) |
| 3635 | 3660 | const lparen = try appendToken(rp.c, .LParen, "("); |
| 3636 | 3661 | |
| 3637 | | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3662 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 3638 | 3663 | defer block_scope.deinit(); |
| 3639 | 3664 | |
| 3640 | 3665 | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); |
| ... | ... | @@ -4082,8 +4107,7 @@ fn transCreateNodeAssign( |
| 4082 | 4107 | // zig: lhs = _tmp; |
| 4083 | 4108 | // zig: break :blk _tmp |
| 4084 | 4109 | // zig: }) |
| 4085 | | const label_name = "blk"; |
| 4086 | | var block_scope = try Scope.Block.init(rp.c, scope, label_name); |
| 4110 | var block_scope = try Scope.Block.init(rp.c, scope, true); |
| 4087 | 4111 | defer block_scope.deinit(); |
| 4088 | 4112 | |
| 4089 | 4113 | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); |
| ... | ... | @@ -4118,7 +4142,7 @@ fn transCreateNodeAssign( |
| 4118 | 4142 | try block_scope.statements.append(assign); |
| 4119 | 4143 | |
| 4120 | 4144 | const break_node = blk: { |
| 4121 | | var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, label_name); |
| 4145 | var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, tokenSlice(rp.c, block_scope.label.?)); |
| 4122 | 4146 | const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp); |
| 4123 | 4147 | break :blk try tmp_ctrl_flow.finish(rhs_expr); |
| 4124 | 4148 | }; |
| ... | ... | @@ -4495,23 +4519,12 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { |
| 4495 | 4519 | return node; |
| 4496 | 4520 | } |
| 4497 | 4521 | |
| 4498 | | fn transCreateNodeBreakToken( |
| 4499 | | c: *Context, |
| 4500 | | label: ?ast.TokenIndex, |
| 4501 | | rhs: ?*ast.Node, |
| 4502 | | ) !*ast.Node.ControlFlowExpression { |
| 4503 | | const other_token = label orelse return transCreateNodeBreak(c, null, rhs); |
| 4504 | | const loc = c.token_locs.items[other_token]; |
| 4505 | | const label_name = c.source_buffer.items[loc.start..loc.end]; |
| 4506 | | return transCreateNodeBreak(c, label_name, rhs); |
| 4507 | | } |
| 4508 | | |
| 4509 | 4522 | fn transCreateNodeBreak( |
| 4510 | 4523 | c: *Context, |
| 4511 | | label: ?[]const u8, |
| 4524 | label: ?ast.TokenIndex, |
| 4512 | 4525 | rhs: ?*ast.Node, |
| 4513 | 4526 | ) !*ast.Node.ControlFlowExpression { |
| 4514 | | var ctrl_flow = try CtrlFlow.init(c, .Break, label); |
| 4527 | var ctrl_flow = try CtrlFlow.init(c, .Break, if (label) |l| tokenSlice(c, l) else null); |
| 4515 | 4528 | return ctrl_flow.finish(rhs); |
| 4516 | 4529 | } |
| 4517 | 4530 | |
| ... | ... | @@ -5362,7 +5375,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5362 | 5375 | } |
| 5363 | 5376 | |
| 5364 | 5377 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5365 | | var block_scope = try Scope.Block.init(c, &c.global_scope.base, null); |
| 5378 | var block_scope = try Scope.Block.init(c, &c.global_scope.base, false); |
| 5366 | 5379 | defer block_scope.deinit(); |
| 5367 | 5380 | const scope = &block_scope.base; |
| 5368 | 5381 | |
| ... | ... | @@ -5475,8 +5488,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node { |
| 5475 | 5488 | }, |
| 5476 | 5489 | .Comma => { |
| 5477 | 5490 | _ = try appendToken(c, .Semicolon, ";"); |
| 5478 | | const label_name = "blk"; |
| 5479 | | var block_scope = try Scope.Block.init(c, scope, label_name); |
| 5491 | var block_scope = try Scope.Block.init(c, scope, true); |
| 5480 | 5492 | defer block_scope.deinit(); |
| 5481 | 5493 | |
| 5482 | 5494 | var last = node; |
| ... | ... | @@ -5501,7 +5513,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node { |
| 5501 | 5513 | } |
| 5502 | 5514 | } |
| 5503 | 5515 | |
| 5504 | | const break_node = try transCreateNodeBreak(c, label_name, last); |
| 5516 | const break_node = try transCreateNodeBreak(c, block_scope.label, last); |
| 5505 | 5517 | try block_scope.statements.append(&break_node.base); |
| 5506 | 5518 | const block_node = try block_scope.complete(c); |
| 5507 | 5519 | return &block_node.base; |