authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-30 21:44:07-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-30 21:44:07-04:00
logd4f668b2416aed2cae1ae498ede418e6d5a5bce8
treeeb2f9308d19995bd0d2f9877ad32e8ffb06ce623
parent3e126102b7313026ff94f314053c3fa3f791ce75
parenta77d89afe3766b69476488601bf82744fc92d334
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13361 from jacobly0/while-cont-scope

AstGen: avoid access to capture defined in an inner scope from a continue expression

10 files changed, 42 insertions(+), 55 deletions(-)

src/AstGen.zig+37-33
......@@ -5910,8 +5910,8 @@ fn whileExpr(
59105910 defer loop_scope.unstack();
59115911 defer loop_scope.labeled_breaks.deinit(astgen.gpa);
59125912
5913 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
5914 defer continue_scope.unstack();
5913 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
5914 defer cond_scope.unstack();
59155915
59165916 const payload_is_ref = if (while_full.payload_token) |payload_token|
59175917 token_tags[payload_token] == .asterisk
......@@ -5925,22 +5925,22 @@ fn whileExpr(
59255925 } = c: {
59265926 if (while_full.error_token) |_| {
59275927 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
5928 const err_union = try expr(&continue_scope, &continue_scope.base, cond_ri, while_full.ast.cond_expr);
5928 const err_union = try expr(&cond_scope, &cond_scope.base, cond_ri, while_full.ast.cond_expr);
59295929 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
59305930 break :c .{
59315931 .inst = err_union,
5932 .bool_bit = try continue_scope.addUnNode(tag, err_union, while_full.ast.then_expr),
5932 .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.then_expr),
59335933 };
59345934 } else if (while_full.payload_token) |_| {
59355935 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
5936 const optional = try expr(&continue_scope, &continue_scope.base, cond_ri, while_full.ast.cond_expr);
5936 const optional = try expr(&cond_scope, &cond_scope.base, cond_ri, while_full.ast.cond_expr);
59375937 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null;
59385938 break :c .{
59395939 .inst = optional,
5940 .bool_bit = try continue_scope.addUnNode(tag, optional, while_full.ast.then_expr),
5940 .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.then_expr),
59415941 };
59425942 } else {
5943 const cond = try expr(&continue_scope, &continue_scope.base, bool_ri, while_full.ast.cond_expr);
5943 const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr);
59445944 break :c .{
59455945 .inst = cond,
59465946 .bool_bit = cond,
......@@ -5949,16 +5949,16 @@ fn whileExpr(
59495949 };
59505950
59515951 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
5952 const condbr = try continue_scope.addCondBr(condbr_tag, node);
5952 const condbr = try cond_scope.addCondBr(condbr_tag, node);
59535953 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
59545954 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
5955 try continue_scope.setBlockBody(cond_block);
5956 // continue_scope unstacked now, can add new instructions to loop_scope
5955 try cond_scope.setBlockBody(cond_block);
5956 // cond_scope unstacked now, can add new instructions to loop_scope
59575957 try loop_scope.instructions.append(astgen.gpa, cond_block);
59585958
59595959 // make scope now but don't stack on parent_gz until loop_scope
59605960 // gets unstacked after cont_expr is emitted and added below
5961 var then_scope = parent_gz.makeSubBlock(&continue_scope.base);
5961 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
59625962 then_scope.instructions_top = GenZir.unstacked_top;
59635963 defer then_scope.unstack();
59645964
......@@ -6026,24 +6026,17 @@ fn whileExpr(
60266026 }
60276027 };
60286028
6029 // This code could be improved to avoid emitting the continue expr when there
6030 // are no jumps to it. This happens when the last statement of a while body is noreturn
6031 // and there are no `continue` statements.
6032 // Tracking issue: https://github.com/ziglang/zig/issues/9185
6033 try then_scope.addDbgBlockBegin();
6034 if (dbg_var_name) |some| {
6035 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
6036 }
6037 if (while_full.ast.cont_expr != 0) {
6038 _ = try unusedResultExpr(&loop_scope, then_sub_scope, while_full.ast.cont_expr);
6039 }
6040 try then_scope.addDbgBlockEnd();
6029 var continue_scope = parent_gz.makeSubBlock(then_sub_scope);
6030 continue_scope.instructions_top = GenZir.unstacked_top;
6031 defer continue_scope.unstack();
6032 const continue_block = try then_scope.makeBlockInst(block_tag, node);
6033
60416034 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
60426035 _ = try loop_scope.addNode(repeat_tag, node);
60436036
60446037 try loop_scope.setBlockBody(loop_block);
60456038 loop_scope.break_block = loop_block;
6046 loop_scope.continue_block = cond_block;
6039 loop_scope.continue_block = continue_block;
60476040 if (while_full.label_token) |label_token| {
60486041 loop_scope.label = @as(?GenZir.Label, GenZir.Label{
60496042 .token = label_token,
......@@ -6054,18 +6047,30 @@ fn whileExpr(
60546047 // done adding instructions to loop_scope, can now stack then_scope
60556048 then_scope.instructions_top = then_scope.instructions.items.len;
60566049
6057 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst);
60586050 try then_scope.addDbgBlockBegin();
6059 if (dbg_var_name) |some| {
6060 try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
6051 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst);
6052 if (dbg_var_name) |name| try then_scope.addDbgVar(.dbg_var_val, name, dbg_var_inst);
6053 try then_scope.instructions.append(astgen.gpa, continue_block);
6054 // This code could be improved to avoid emitting the continue expr when there
6055 // are no jumps to it. This happens when the last statement of a while body is noreturn
6056 // and there are no `continue` statements.
6057 // Tracking issue: https://github.com/ziglang/zig/issues/9185
6058 if (while_full.ast.cont_expr != 0) {
6059 _ = try unusedResultExpr(&then_scope, then_sub_scope, while_full.ast.cont_expr);
60616060 }
6062 const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, while_full.ast.then_expr);
6063 _ = try addEnsureResult(&then_scope, then_result, while_full.ast.then_expr);
6061 try then_scope.addDbgBlockEnd();
60646062
6063 continue_scope.instructions_top = continue_scope.instructions.items.len;
6064 _ = try unusedResultExpr(&continue_scope, &continue_scope.base, while_full.ast.then_expr);
60656065 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
6066 try then_scope.addDbgBlockEnd();
6066 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
6067 if (!continue_scope.endsWithNoReturn()) {
6068 const break_inst = try continue_scope.makeBreak(break_tag, continue_block, .void_value);
6069 try then_scope.instructions.append(astgen.gpa, break_inst);
6070 }
6071 try continue_scope.setBlockBody(continue_block);
60676072
6068 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
6073 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
60696074 defer else_scope.unstack();
60706075
60716076 const else_node = while_full.ast.else_expr;
......@@ -6128,7 +6133,6 @@ fn whileExpr(
61286133 try astgen.appendErrorTok(some.token, "unused while loop label", .{});
61296134 }
61306135 }
6131 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
61326136 const result = try finishThenElseBlock(
61336137 parent_gz,
61346138 ri,
......@@ -6138,7 +6142,7 @@ fn whileExpr(
61386142 &else_scope,
61396143 condbr,
61406144 cond.bool_bit,
6141 then_result,
6145 .void_value,
61426146 else_info.result,
61436147 loop_block,
61446148 cond_block,
src/Sema.zig+5-6
......@@ -71,8 +71,8 @@ preallocated_new_func: ?*Module.Fn = null,
7171/// TODO: after upgrading to use InternPool change the key here to be an
7272/// InternPool value index.
7373types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
74/// These are lazily created runtime blocks from inline_block instructions.
75/// They are created when an inline_break passes through a runtime condition, because
74/// These are lazily created runtime blocks from block_inline instructions.
75/// They are created when an break_inline passes through a runtime condition, because
7676/// Sema must convert comptime control flow to runtime control flow, which means
7777/// breaking from a block.
7878post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
......@@ -147,7 +147,7 @@ pub const Block = struct {
147147 /// for the one that will be the same for all Block instances.
148148 src_decl: Decl.Index,
149149 /// Non zero if a non-inline loop or a runtime conditional have been encountered.
150 /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index.
150 /// Stores to comptime variables are only allowed when var.runtime_index <= runtime_index.
151151 runtime_index: Value.RuntimeIndex = .zero,
152152 inline_block: Zir.Inst.Index = 0,
153153
......@@ -1391,9 +1391,8 @@ fn analyzeBodyInner(
13911391 // If this block contains a function prototype, we need to reset the
13921392 // current list of parameters and restore it later.
13931393 // Note: this probably needs to be resolved in a more general manner.
1394 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) {
1395 child_block.inline_block = inline_body[0];
1396 } else child_block.inline_block = block.inline_block;
1394 child_block.inline_block =
1395 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) inline_body[0] else inst;
13971396
13981397 var label: Block.Label = .{
13991398 .zir_block = inst,
test/behavior/basic.zig-1
......@@ -646,7 +646,6 @@ test "multiline string literal is null terminated" {
646646}
647647
648648test "string escapes" {
649 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
650649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
651650 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
652651 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/bit_shifting.zig-1
......@@ -62,7 +62,6 @@ fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, compt
6262
6363test "sharded table" {
6464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6766 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6867 // realistic 16-way sharding
test/behavior/bugs/6456.zig-1
......@@ -11,7 +11,6 @@ const text =
1111;
1212
1313test "issue 6456" {
14 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/optional.zig-1
......@@ -429,7 +429,6 @@ test "alignment of wrapping an optional payload" {
429429
430430test "Optional slice size is optimized" {
431431 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
432 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
433432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
434433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
435434 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/pointers.zig-1
......@@ -483,7 +483,6 @@ test "pointer to constant decl preserves alignment" {
483483test "ptrCast comptime known slice to C pointer" {
484484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
485485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
487486 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
488487
489488 const s: [:0]const u8 = "foo";
test/behavior/slice.zig-1
......@@ -702,7 +702,6 @@ test "slice field ptr var" {
702702test "global slice field access" {
703703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
704704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
706705 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
707706
708707 const S = struct {
test/behavior/translate_c_macros.zig-2
......@@ -123,7 +123,6 @@ test "large integer macro" {
123123test "string literal macro with embedded tab character" {
124124 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
125125 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
127126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
128127 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
129128
......@@ -133,7 +132,6 @@ test "string literal macro with embedded tab character" {
133132test "string and char literals that are not UTF-8 encoded. Issue #12784" {
134133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
135134 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
137135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
139137
test/behavior/typename.zig-8
......@@ -18,7 +18,6 @@ test "anon fn param" {
1818 return error.SkipZigTest;
1919 }
2020
21 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -50,7 +49,6 @@ test "anon field init" {
5049 return error.SkipZigTest;
5150 }
5251
53 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -76,7 +74,6 @@ test "anon field init" {
7674}
7775
7876test "basic" {
79 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8077 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
8178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8279 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -92,7 +89,6 @@ test "top level decl" {
9289 return error.SkipZigTest;
9390 }
9491
95 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
9692 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9793 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9894 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -142,7 +138,6 @@ const B = struct {
142138};
143139
144140test "fn param" {
145 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
146141 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
148143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -218,7 +213,6 @@ test "local variable" {
218213 return error.SkipZigTest;
219214 }
220215
221 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
222216 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
223217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
224218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -238,7 +232,6 @@ test "local variable" {
238232
239233test "comptime parameters not converted to anytype in function type" {
240234 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
242235 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
243236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
244237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -254,7 +247,6 @@ test "anon name strategy used in sub expression" {
254247 return error.SkipZigTest;
255248 }
256249
257 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
258250 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
259251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
260252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO