authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-24 20:10:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-26 22:19:30-07:00
log7201e694542aae29afd2c6d0963af759a186638e
treedf792de32ccdafabb4074bc60599df041fc8dc20
parent1aacfa7186187ed467a5e3189a877493d5c620a1

AstGen: fix missing deferred ref

Closes #16524

2 files changed, 72 insertions(+), 27 deletions(-)

src/AstGen.zig+34-27
......@@ -6487,8 +6487,7 @@ fn forExpr(
64876487
64886488 {
64896489 var capture_token = for_full.payload_token;
6490 for (for_full.ast.inputs, 0..) |input, i_usize| {
6491 const i = @as(u32, @intCast(i_usize));
6490 for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_ref| {
64926491 const capture_is_ref = token_tags[capture_token] == .asterisk;
64936492 const ident_tok = capture_token + @intFromBool(capture_is_ref);
64946493 const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");
......@@ -6527,14 +6526,14 @@ fn forExpr(
65276526 });
65286527
65296528 any_len_checks = any_len_checks or range_len != .none;
6530 indexables[i] = if (start_is_zero) .none else start_val;
6531 lens[i] = range_len;
6529 indexable_ref.* = if (start_is_zero) .none else start_val;
6530 len_ref.* = range_len;
65326531 } else {
65336532 const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input);
65346533
65356534 any_len_checks = true;
6536 indexables[i] = indexable;
6537 lens[i] = indexable;
6535 indexable_ref.* = indexable;
6536 len_ref.* = indexable;
65386537 }
65396538 }
65406539 }
......@@ -6546,7 +6545,7 @@ fn forExpr(
65466545 // We use a dedicated ZIR instruction to assert the lengths to assist with
65476546 // nicer error reporting as well as fewer ZIR bytes emitted.
65486547 const len: Zir.Inst.Ref = len: {
6549 const lens_len = @as(u32, @intCast(lens.len));
6548 const lens_len: u32 = @intCast(lens.len);
65506549 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.MultiOp).Struct.fields.len + lens_len);
65516550 const len = try parent_gz.addPlNode(.for_len, node, Zir.Inst.MultiOp{
65526551 .operands_len = lens_len,
......@@ -6565,7 +6564,10 @@ fn forExpr(
65656564 defer loop_scope.unstack();
65666565 defer loop_scope.labeled_breaks.deinit(gpa);
65676566
6567 // We need to finish loop_scope later once we have the deferred refs from then_scope. However, the
6568 // load must be removed from instructions in the meantime or it appears to be part of parent_gz.
65686569 const index = try loop_scope.addUnNode(.load, index_ptr, node);
6570 _ = loop_scope.instructions.pop();
65696571
65706572 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
65716573 defer cond_scope.unstack();
......@@ -6581,26 +6583,14 @@ fn forExpr(
65816583 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
65826584 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
65836585 try cond_scope.setBlockBody(cond_block);
6584 // cond_block unstacked now, can add new instructions to loop_scope
6585 try loop_scope.instructions.append(gpa, cond_block);
65866586
6587 // Increment the index variable.
6588 const index_plus_one = try loop_scope.addPlNode(.add_unsafe, node, Zir.Inst.Bin{
6589 .lhs = index,
6590 .rhs = .one_usize,
6591 });
6592 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
6593 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
6594 _ = try loop_scope.addNode(repeat_tag, node);
6595
6596 try loop_scope.setBlockBody(loop_block);
65976587 loop_scope.break_block = loop_block;
65986588 loop_scope.continue_block = cond_block;
65996589 if (for_full.label_token) |label_token| {
6600 loop_scope.label = @as(?GenZir.Label, GenZir.Label{
6590 loop_scope.label = .{
66016591 .token = label_token,
66026592 .block_inst = loop_block,
6603 });
6593 };
66046594 }
66056595
66066596 var then_node = for_full.ast.then_expr;
......@@ -6615,8 +6605,7 @@ fn forExpr(
66156605 const then_sub_scope = blk: {
66166606 var capture_token = for_full.payload_token;
66176607 var capture_sub_scope: *Scope = &then_scope.base;
6618 for (for_full.ast.inputs, 0..) |input, i_usize| {
6619 const i = @as(u32, @intCast(i_usize));
6608 for (for_full.ast.inputs, indexables, capture_scopes) |input, indexable_ref, *capture_scope| {
66206609 const capture_is_ref = token_tags[capture_token] == .asterisk;
66216610 const ident_tok = capture_token + @intFromBool(capture_is_ref);
66226611 const capture_name = tree.tokenSlice(ident_tok);
......@@ -6631,7 +6620,7 @@ fn forExpr(
66316620 const capture_inst = inst: {
66326621 const is_counter = node_tags[input] == .for_range;
66336622
6634 if (indexables[i] == .none) {
6623 if (indexable_ref == .none) {
66356624 // Special case: the main index can be used directly.
66366625 assert(is_counter);
66376626 assert(!capture_is_ref);
......@@ -6650,12 +6639,12 @@ fn forExpr(
66506639 0b11 => unreachable, // compile error emitted already
66516640 };
66526641 break :inst try then_scope.addPlNode(tag, input, Zir.Inst.Bin{
6653 .lhs = indexables[i],
6642 .lhs = indexable_ref,
66546643 .rhs = index,
66556644 });
66566645 };
66576646
6658 capture_scopes[i] = .{
6647 capture_scope.* = .{
66596648 .parent = capture_sub_scope,
66606649 .gen_zir = &then_scope,
66616650 .name = name_str_index,
......@@ -6665,7 +6654,7 @@ fn forExpr(
66656654 };
66666655
66676656 try then_scope.addDbgVar(.dbg_var_val, name_str_index, capture_inst);
6668 capture_sub_scope = &capture_scopes[i].base;
6657 capture_sub_scope = &capture_scope.base;
66696658 }
66706659
66716660 break :blk capture_sub_scope;
......@@ -6730,6 +6719,24 @@ fn forExpr(
67306719 cond_block,
67316720 break_tag,
67326721 );
6722
6723 // then_block and else_block unstacked now, can resurrect loop_scope to finally finish it
6724 {
6725 loop_scope.instructions_top = loop_scope.instructions.items.len;
6726 try loop_scope.instructions.appendSlice(gpa, &.{ Zir.refToIndex(index).?, cond_block });
6727
6728 // Increment the index variable.
6729 const index_plus_one = try loop_scope.addPlNode(.add_unsafe, node, Zir.Inst.Bin{
6730 .lhs = index,
6731 .rhs = .one_usize,
6732 });
6733 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
6734 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
6735 _ = try loop_scope.addNode(repeat_tag, node);
6736
6737 try loop_scope.setBlockBody(loop_block);
6738 }
6739
67336740 if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) {
67346741 _ = try rvalue(parent_gz, ri, .void_value, node);
67356742 }
test/behavior/for.zig+38
......@@ -479,3 +479,41 @@ test "inline for on tuple pointer" {
479479
480480 try expectEqual(S{ 0, 1, 2 }, s);
481481}
482
483test "ref counter that starts at zero" {
484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
487 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
488
489 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
490 try expectEqual(i, j);
491 try expectEqual((&i).*, (&j).*);
492 }
493 inline for (.{ 0, 1, 2 }, 0..) |i, j| {
494 try expectEqual(i, j);
495 try expectEqual((&i).*, (&j).*);
496 }
497}
498
499test "inferred alloc ptr of for loop" {
500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
502 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
503 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
504
505 {
506 var cond = false;
507 var opt = for (0..1) |_| {
508 if (cond) break cond;
509 } else null;
510 try expectEqual(@as(?bool, null), opt);
511 }
512 {
513 var cond = true;
514 var opt = for (0..1) |_| {
515 if (cond) break cond;
516 } else null;
517 try expectEqual(@as(?bool, true), opt);
518 }
519}