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(...@@ -6487,8 +6487,7 @@ fn forExpr(
64876487
6488 {6488 {
6489 var capture_token = for_full.payload_token;6489 var capture_token = for_full.payload_token;
6490 for (for_full.ast.inputs, 0..) |input, i_usize| {6490 for (for_full.ast.inputs, indexables, lens) |input, *indexable_ref, *len_ref| {
6491 const i = @as(u32, @intCast(i_usize));
6492 const capture_is_ref = token_tags[capture_token] == .asterisk;6491 const capture_is_ref = token_tags[capture_token] == .asterisk;
6493 const ident_tok = capture_token + @intFromBool(capture_is_ref);6492 const ident_tok = capture_token + @intFromBool(capture_is_ref);
6494 const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");6493 const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");
...@@ -6527,14 +6526,14 @@ fn forExpr(...@@ -6527,14 +6526,14 @@ fn forExpr(
6527 });6526 });
65286527
6529 any_len_checks = any_len_checks or range_len != .none;6528 any_len_checks = any_len_checks or range_len != .none;
6530 indexables[i] = if (start_is_zero) .none else start_val;6529 indexable_ref.* = if (start_is_zero) .none else start_val;
6531 lens[i] = range_len;6530 len_ref.* = range_len;
6532 } else {6531 } else {
6533 const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input);6532 const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input);
65346533
6535 any_len_checks = true;6534 any_len_checks = true;
6536 indexables[i] = indexable;6535 indexable_ref.* = indexable;
6537 lens[i] = indexable;6536 len_ref.* = indexable;
6538 }6537 }
6539 }6538 }
6540 }6539 }
...@@ -6546,7 +6545,7 @@ fn forExpr(...@@ -6546,7 +6545,7 @@ fn forExpr(
6546 // We use a dedicated ZIR instruction to assert the lengths to assist with6545 // We use a dedicated ZIR instruction to assert the lengths to assist with
6547 // nicer error reporting as well as fewer ZIR bytes emitted.6546 // nicer error reporting as well as fewer ZIR bytes emitted.
6548 const len: Zir.Inst.Ref = len: {6547 const len: Zir.Inst.Ref = len: {
6549 const lens_len = @as(u32, @intCast(lens.len));6548 const lens_len: u32 = @intCast(lens.len);
6550 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.MultiOp).Struct.fields.len + lens_len);6549 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.MultiOp).Struct.fields.len + lens_len);
6551 const len = try parent_gz.addPlNode(.for_len, node, Zir.Inst.MultiOp{6550 const len = try parent_gz.addPlNode(.for_len, node, Zir.Inst.MultiOp{
6552 .operands_len = lens_len,6551 .operands_len = lens_len,
...@@ -6565,7 +6564,10 @@ fn forExpr(...@@ -6565,7 +6564,10 @@ fn forExpr(
6565 defer loop_scope.unstack();6564 defer loop_scope.unstack();
6566 defer loop_scope.labeled_breaks.deinit(gpa);6565 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.
6568 const index = try loop_scope.addUnNode(.load, index_ptr, node);6569 const index = try loop_scope.addUnNode(.load, index_ptr, node);
6570 _ = loop_scope.instructions.pop();
65696571
6570 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);6572 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
6571 defer cond_scope.unstack();6573 defer cond_scope.unstack();
...@@ -6581,26 +6583,14 @@ fn forExpr(...@@ -6581,26 +6583,14 @@ fn forExpr(
6581 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;6583 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
6582 const cond_block = try loop_scope.makeBlockInst(block_tag, node);6584 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
6583 try cond_scope.setBlockBody(cond_block);6585 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);
6597 loop_scope.break_block = loop_block;6587 loop_scope.break_block = loop_block;
6598 loop_scope.continue_block = cond_block;6588 loop_scope.continue_block = cond_block;
6599 if (for_full.label_token) |label_token| {6589 if (for_full.label_token) |label_token| {
6600 loop_scope.label = @as(?GenZir.Label, GenZir.Label{6590 loop_scope.label = .{
6601 .token = label_token,6591 .token = label_token,
6602 .block_inst = loop_block,6592 .block_inst = loop_block,
6603 });6593 };
6604 }6594 }
66056595
6606 var then_node = for_full.ast.then_expr;6596 var then_node = for_full.ast.then_expr;
...@@ -6615,8 +6605,7 @@ fn forExpr(...@@ -6615,8 +6605,7 @@ fn forExpr(
6615 const then_sub_scope = blk: {6605 const then_sub_scope = blk: {
6616 var capture_token = for_full.payload_token;6606 var capture_token = for_full.payload_token;
6617 var capture_sub_scope: *Scope = &then_scope.base;6607 var capture_sub_scope: *Scope = &then_scope.base;
6618 for (for_full.ast.inputs, 0..) |input, i_usize| {6608 for (for_full.ast.inputs, indexables, capture_scopes) |input, indexable_ref, *capture_scope| {
6619 const i = @as(u32, @intCast(i_usize));
6620 const capture_is_ref = token_tags[capture_token] == .asterisk;6609 const capture_is_ref = token_tags[capture_token] == .asterisk;
6621 const ident_tok = capture_token + @intFromBool(capture_is_ref);6610 const ident_tok = capture_token + @intFromBool(capture_is_ref);
6622 const capture_name = tree.tokenSlice(ident_tok);6611 const capture_name = tree.tokenSlice(ident_tok);
...@@ -6631,7 +6620,7 @@ fn forExpr(...@@ -6631,7 +6620,7 @@ fn forExpr(
6631 const capture_inst = inst: {6620 const capture_inst = inst: {
6632 const is_counter = node_tags[input] == .for_range;6621 const is_counter = node_tags[input] == .for_range;
66336622
6634 if (indexables[i] == .none) {6623 if (indexable_ref == .none) {
6635 // Special case: the main index can be used directly.6624 // Special case: the main index can be used directly.
6636 assert(is_counter);6625 assert(is_counter);
6637 assert(!capture_is_ref);6626 assert(!capture_is_ref);
...@@ -6650,12 +6639,12 @@ fn forExpr(...@@ -6650,12 +6639,12 @@ fn forExpr(
6650 0b11 => unreachable, // compile error emitted already6639 0b11 => unreachable, // compile error emitted already
6651 };6640 };
6652 break :inst try then_scope.addPlNode(tag, input, Zir.Inst.Bin{6641 break :inst try then_scope.addPlNode(tag, input, Zir.Inst.Bin{
6653 .lhs = indexables[i],6642 .lhs = indexable_ref,
6654 .rhs = index,6643 .rhs = index,
6655 });6644 });
6656 };6645 };
66576646
6658 capture_scopes[i] = .{6647 capture_scope.* = .{
6659 .parent = capture_sub_scope,6648 .parent = capture_sub_scope,
6660 .gen_zir = &then_scope,6649 .gen_zir = &then_scope,
6661 .name = name_str_index,6650 .name = name_str_index,
...@@ -6665,7 +6654,7 @@ fn forExpr(...@@ -6665,7 +6654,7 @@ fn forExpr(
6665 };6654 };
66666655
6667 try then_scope.addDbgVar(.dbg_var_val, name_str_index, capture_inst);6656 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;
6669 }6658 }
66706659
6671 break :blk capture_sub_scope;6660 break :blk capture_sub_scope;
...@@ -6730,6 +6719,24 @@ fn forExpr(...@@ -6730,6 +6719,24 @@ fn forExpr(
6730 cond_block,6719 cond_block,
6731 break_tag,6720 break_tag,
6732 );6721 );
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
6733 if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) {6740 if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) {
6734 _ = try rvalue(parent_gz, ri, .void_value, node);6741 _ = try rvalue(parent_gz, ri, .void_value, node);
6735 }6742 }
test/behavior/for.zig+38
...@@ -479,3 +479,41 @@ test "inline for on tuple pointer" {...@@ -479,3 +479,41 @@ test "inline for on tuple pointer" {
479479
480 try expectEqual(S{ 0, 1, 2 }, s);480 try expectEqual(S{ 0, 1, 2 }, s);
481}481}
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}