authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-14 14:39:00-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-14 14:39:00-05:00
log9e1afdc23469e1dece4aea318eb8ad2f6c100a94
tree359b448f6031edf558e639198ed41c3c60b2898b
parent058f38220afecb96d115143f8888496162029aed
parent1c8ac2a0c140ba2406f1dc164dc4eeb99a8b6b5b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4454 from LemonBoy/capture-reform

Payload captures no longer alias the original value

5 files changed, 114 insertions(+), 25 deletions(-)

src/ir.cpp+29-23
......@@ -8106,9 +8106,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81068106 if (var_symbol) {
81078107 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node,
81088108 err_val_ptr, false, false);
8109 IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
8110 ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
8111 ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr);
8109 IrInstSrc *var_value = node->data.while_expr.var_is_ptr ?
8110 payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr);
8111 build_decl_var_and_init(irb, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime);
81128112 }
81138113
81148114 ZigList<IrInstSrc *> incoming_values = {0};
......@@ -8156,7 +8156,8 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81568156 true, false, false, is_comptime);
81578157 Scope *err_scope = err_var->child_scope;
81588158 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, err_symbol_node, err_val_ptr);
8159 ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_ptr);
8159 IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, err_symbol_node, err_ptr);
8160 build_decl_var_and_init(irb, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime);
81608161
81618162 if (peer_parent->peers.length != 0) {
81628163 peer_parent->peers.last()->next_bb = else_block;
......@@ -8217,9 +8218,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82178218
82188219 ir_set_cursor_at_end_and_append_block(irb, body_block);
82198220 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false, false);
8220 IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?
8221 ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;
8222 ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr);
8221 IrInstSrc *var_value = node->data.while_expr.var_is_ptr ?
8222 payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr);
8223 build_decl_var_and_init(irb, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime);
82238224
82248225 ZigList<IrInstSrc *> incoming_values = {0};
82258226 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
......@@ -8458,9 +8459,9 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod
84588459 ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
84598460 Scope *child_scope = elem_var->child_scope;
84608461
8461 IrInstSrc *var_ptr = node->data.for_expr.elem_is_ptr ?
8462 ir_build_ref_src(irb, &spill_scope->base, elem_node, elem_ptr, true, false) : elem_ptr;
8463 ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr);
8462 IrInstSrc *elem_value = node->data.for_expr.elem_is_ptr ?
8463 elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr);
8464 build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime);
84648465
84658466 ZigList<IrInstSrc *> incoming_values = {0};
84668467 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
......@@ -8880,8 +8881,9 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo
88808881 var_symbol, is_const, is_const, is_shadowable, is_comptime);
88818882
88828883 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false);
8883 IrInstSrc *var_ptr = var_is_ptr ? ir_build_ref_src(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
8884 ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr);
8884 IrInstSrc *var_value = var_is_ptr ?
8885 payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, node, payload_ptr);
8886 build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime);
88858887 var_scope = var->child_scope;
88868888 } else {
88878889 var_scope = subexpr_scope;
......@@ -8962,9 +8964,9 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
89628964 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
89638965
89648966 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, subexpr_scope, node, err_val_ptr, false, false);
8965 IrInstSrc *var_ptr = var_is_ptr ?
8966 ir_build_ref_src(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;
8967 ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr);
8967 IrInstSrc *var_value = var_is_ptr ?
8968 payload_ptr : ir_build_load_ptr(irb, subexpr_scope, node, payload_ptr);
8969 build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime);
89688970 var_scope = var->child_scope;
89698971 } else {
89708972 var_scope = subexpr_scope;
......@@ -8989,7 +8991,8 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
89898991 err_symbol, is_const, is_const, is_shadowable, is_comptime);
89908992
89918993 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, subexpr_scope, node, err_val_ptr);
8992 ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, err_ptr);
8994 IrInstSrc *err_value = ir_build_load_ptr(irb, subexpr_scope, node, err_ptr);
8995 build_decl_var_and_init(irb, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime);
89938996 err_var_scope = var->child_scope;
89948997 } else {
89958998 err_var_scope = subexpr_scope;
......@@ -9039,22 +9042,24 @@ static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *s
90399042 ZigVar *var = ir_create_var(irb, var_symbol_node, scope,
90409043 var_name, is_const, is_const, is_shadowable, var_is_comptime);
90419044 child_scope = var->child_scope;
9042 IrInstSrc *var_ptr;
9045 IrInstSrc *var_value;
90439046 if (out_switch_else_var != nullptr) {
90449047 IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node,
90459048 target_value_ptr);
90469049 *out_switch_else_var = switch_else_var;
90479050 IrInstSrc *payload_ptr = &switch_else_var->base;
9048 var_ptr = var_is_ptr ? ir_build_ref_src(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr;
9051 var_value = var_is_ptr ?
9052 payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr);
90499053 } else if (prong_values != nullptr) {
90509054 IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr,
90519055 prong_values, prong_values_len);
9052 var_ptr = var_is_ptr ? ir_build_ref_src(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr;
9056 var_value = var_is_ptr ?
9057 payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr);
90539058 } else {
9054 var_ptr = var_is_ptr ?
9055 ir_build_ref_src(irb, scope, var_symbol_node, target_value_ptr, true, false) : target_value_ptr;
9059 var_value = var_is_ptr ?
9060 target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
90569061 }
9057 ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_ptr);
9062 build_decl_var_and_init(irb, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime);
90589063 } else {
90599064 child_scope = scope;
90609065 }
......@@ -9627,7 +9632,8 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
96279632 is_const, is_const, is_shadowable, is_comptime);
96289633 err_scope = var->child_scope;
96299634 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, node, err_union_ptr);
9630 ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_ptr);
9635 IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, var_node, err_ptr);
9636 build_decl_var_and_init(irb, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime);
96319637 } else {
96329638 err_scope = subexpr_scope;
96339639 }
test/stage1/behavior/for.zig+28
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
34const mem = std.mem;
45
56test "continue in for loop" {
......@@ -142,3 +143,30 @@ test "for with null and T peer types and inferred result location type" {
142143 S.doTheTest(&[_]u8{ 1, 2 });
143144 comptime S.doTheTest(&[_]u8{ 1, 2 });
144145}
146
147test "for copies its payload" {
148 const S = struct {
149 fn doTheTest() void {
150 var x = [_]usize{ 1, 2, 3 };
151 for (x) |value, i| {
152 // Modify the original array
153 x[i] += 99;
154 expectEqual(value, i + 1);
155 }
156 }
157 };
158 S.doTheTest();
159 comptime S.doTheTest();
160}
161
162test "for on slice with allowzero ptr" {
163 const S = struct {
164 fn doTheTest(slice: []u8) void {
165 var ptr = @ptrCast([*]allowzero u8, slice.ptr)[0..slice.len];
166 for (ptr) |x, i| expect(x == i + 1);
167 for (ptr) |*x, i| expect(x.* == i + 1);
168 }
169 };
170 S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
171 comptime S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
172}
test/stage1/behavior/if.zig+18-1
......@@ -1,4 +1,6 @@
1const expect = @import("std").testing.expect;
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
24
35test "if statements" {
46 shouldBeEqual(1, 1);
......@@ -90,3 +92,18 @@ test "if prongs cast to expected type instead of peer type resolution" {
9092 S.doTheTest(false);
9193 comptime S.doTheTest(false);
9294}
95
96test "while copies its payload" {
97 const S = struct {
98 fn doTheTest() void {
99 var tmp: ?i32 = 10;
100 if (tmp) |value| {
101 // Modify the original variable
102 tmp = null;
103 expectEqual(@as(i32, 10), value);
104 } else unreachable;
105 }
106 };
107 S.doTheTest();
108 comptime S.doTheTest();
109}
test/stage1/behavior/switch.zig+22
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const expect = std.testing.expect;
33const expectError = std.testing.expectError;
4const expectEqual = std.testing.expectEqual;
45
56test "switch with numbers" {
67 testSwitchWithNumbers(13);
......@@ -493,3 +494,24 @@ test "switch on error set with single else" {
493494 S.doTheTest();
494495 comptime S.doTheTest();
495496}
497
498test "while copies its payload" {
499 const S = struct {
500 fn doTheTest() void {
501 var tmp: union(enum) {
502 A: u8,
503 B: u32,
504 } = .{ .A = 42 };
505 switch (tmp) {
506 .A => |value| {
507 // Modify the original union
508 tmp = .{ .B = 0x10101010 };
509 expectEqual(@as(u8, 42), value);
510 },
511 else => unreachable,
512 }
513 }
514 };
515 S.doTheTest();
516 comptime S.doTheTest();
517}
test/stage1/behavior/while.zig+17-1
......@@ -1,4 +1,5 @@
1const expect = @import("std").testing.expect;
1const std = @import("std");
2const expect = std.testing.expect;
23
34test "while loop" {
45 var i: i32 = 0;
......@@ -271,3 +272,18 @@ test "while error 2 break statements and an else" {
271272 S.entry(true, false);
272273 comptime S.entry(true, false);
273274}
275
276test "while copies its payload" {
277 const S = struct {
278 fn doTheTest() void {
279 var tmp: ?i32 = 10;
280 while (tmp) |value| {
281 // Modify the original variable
282 tmp = null;
283 expect(value == 10);
284 }
285 }
286 };
287 S.doTheTest();
288 comptime S.doTheTest();
289}