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
signature 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...@@ -8106,9 +8106,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
8106 if (var_symbol) {8106 if (var_symbol) {
8107 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node,8107 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node,
8108 err_val_ptr, false, false);8108 err_val_ptr, false, false);
8109 IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ?8109 IrInstSrc *var_value = node->data.while_expr.var_is_ptr ?
8110 ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr;8110 payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr);
8111 ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr);8111 build_decl_var_and_init(irb, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime);
8112 }8112 }
81138113
8114 ZigList<IrInstSrc *> incoming_values = {0};8114 ZigList<IrInstSrc *> incoming_values = {0};
...@@ -8156,7 +8156,8 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no...@@ -8156,7 +8156,8 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
8156 true, false, false, is_comptime);8156 true, false, false, is_comptime);
8157 Scope *err_scope = err_var->child_scope;8157 Scope *err_scope = err_var->child_scope;
8158 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, err_symbol_node, err_val_ptr);8158 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
8161 if (peer_parent->peers.length != 0) {8162 if (peer_parent->peers.length != 0) {
8162 peer_parent->peers.last()->next_bb = else_block;8163 peer_parent->peers.last()->next_bb = else_block;
...@@ -8217,9 +8218,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no...@@ -8217,9 +8218,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82178218
8218 ir_set_cursor_at_end_and_append_block(irb, body_block);8219 ir_set_cursor_at_end_and_append_block(irb, body_block);
8219 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false, false);8220 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 IrInstSrc *var_value = 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 payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr);
8222 ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr);8223 build_decl_var_and_init(irb, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime);
82238224
8224 ZigList<IrInstSrc *> incoming_values = {0};8225 ZigList<IrInstSrc *> incoming_values = {0};
8225 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};8226 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
...@@ -8458,9 +8459,9 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod...@@ -8458,9 +8459,9 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod
8458 ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);8459 ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
8459 Scope *child_scope = elem_var->child_scope;8460 Scope *child_scope = elem_var->child_scope;
84608461
8461 IrInstSrc *var_ptr = node->data.for_expr.elem_is_ptr ?8462 IrInstSrc *elem_value = 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 elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr);
8463 ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr);8464 build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime);
84648465
8465 ZigList<IrInstSrc *> incoming_values = {0};8466 ZigList<IrInstSrc *> incoming_values = {0};
8466 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};8467 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
...@@ -8880,8 +8881,9 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo...@@ -8880,8 +8881,9 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo
8880 var_symbol, is_const, is_const, is_shadowable, is_comptime);8881 var_symbol, is_const, is_const, is_shadowable, is_comptime);
88818882
8882 IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false);8883 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 IrInstSrc *var_value = var_is_ptr ?
8884 ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_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);
8885 var_scope = var->child_scope;8887 var_scope = var->child_scope;
8886 } else {8888 } else {
8887 var_scope = subexpr_scope;8889 var_scope = subexpr_scope;
...@@ -8962,9 +8964,9 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n...@@ -8962,9 +8964,9 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
8962 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);8964 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
89638965
8964 IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, subexpr_scope, node, err_val_ptr, false, false);8966 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 ?8967 IrInstSrc *var_value = var_is_ptr ?
8966 ir_build_ref_src(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr;8968 payload_ptr : ir_build_load_ptr(irb, subexpr_scope, node, payload_ptr);
8967 ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr);8969 build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime);
8968 var_scope = var->child_scope;8970 var_scope = var->child_scope;
8969 } else {8971 } else {
8970 var_scope = subexpr_scope;8972 var_scope = subexpr_scope;
...@@ -8989,7 +8991,8 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n...@@ -8989,7 +8991,8 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
8989 err_symbol, is_const, is_const, is_shadowable, is_comptime);8991 err_symbol, is_const, is_const, is_shadowable, is_comptime);
89908992
8991 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, subexpr_scope, node, err_val_ptr);8993 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);
8993 err_var_scope = var->child_scope;8996 err_var_scope = var->child_scope;
8994 } else {8997 } else {
8995 err_var_scope = subexpr_scope;8998 err_var_scope = subexpr_scope;
...@@ -9039,22 +9042,24 @@ static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *s...@@ -9039,22 +9042,24 @@ static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *s
9039 ZigVar *var = ir_create_var(irb, var_symbol_node, scope,9042 ZigVar *var = ir_create_var(irb, var_symbol_node, scope,
9040 var_name, is_const, is_const, is_shadowable, var_is_comptime);9043 var_name, is_const, is_const, is_shadowable, var_is_comptime);
9041 child_scope = var->child_scope;9044 child_scope = var->child_scope;
9042 IrInstSrc *var_ptr;9045 IrInstSrc *var_value;
9043 if (out_switch_else_var != nullptr) {9046 if (out_switch_else_var != nullptr) {
9044 IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node,9047 IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node,
9045 target_value_ptr);9048 target_value_ptr);
9046 *out_switch_else_var = switch_else_var;9049 *out_switch_else_var = switch_else_var;
9047 IrInstSrc *payload_ptr = &switch_else_var->base;9050 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);
9049 } else if (prong_values != nullptr) {9053 } else if (prong_values != nullptr) {
9050 IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr,9054 IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr,
9051 prong_values, prong_values_len);9055 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);
9053 } else {9058 } else {
9054 var_ptr = var_is_ptr ?9059 var_value = var_is_ptr ?
9055 ir_build_ref_src(irb, scope, var_symbol_node, target_value_ptr, true, false) : target_value_ptr;9060 target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
9056 }9061 }
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);
9058 } else {9063 } else {
9059 child_scope = scope;9064 child_scope = scope;
9060 }9065 }
...@@ -9627,7 +9632,8 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *...@@ -9627,7 +9632,8 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
9627 is_const, is_const, is_shadowable, is_comptime);9632 is_const, is_const, is_shadowable, is_comptime);
9628 err_scope = var->child_scope;9633 err_scope = var->child_scope;
9629 IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, node, err_union_ptr);9634 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);
9631 } else {9637 } else {
9632 err_scope = subexpr_scope;9638 err_scope = subexpr_scope;
9633 }9639 }
test/stage1/behavior/for.zig+28
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
3const mem = std.mem;4const mem = std.mem;
45
5test "continue in for loop" {6test "continue in for loop" {
...@@ -142,3 +143,30 @@ test "for with null and T peer types and inferred result location type" {...@@ -142,3 +143,30 @@ test "for with null and T peer types and inferred result location type" {
142 S.doTheTest(&[_]u8{ 1, 2 });143 S.doTheTest(&[_]u8{ 1, 2 });
143 comptime S.doTheTest(&[_]u8{ 1, 2 });144 comptime S.doTheTest(&[_]u8{ 1, 2 });
144}145}
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 @@...@@ -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
3test "if statements" {5test "if statements" {
4 shouldBeEqual(1, 1);6 shouldBeEqual(1, 1);
...@@ -90,3 +92,18 @@ test "if prongs cast to expected type instead of peer type resolution" {...@@ -90,3 +92,18 @@ test "if prongs cast to expected type instead of peer type resolution" {
90 S.doTheTest(false);92 S.doTheTest(false);
91 comptime S.doTheTest(false);93 comptime S.doTheTest(false);
92}94}
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 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectError = std.testing.expectError;3const expectError = std.testing.expectError;
4const expectEqual = std.testing.expectEqual;
45
5test "switch with numbers" {6test "switch with numbers" {
6 testSwitchWithNumbers(13);7 testSwitchWithNumbers(13);
...@@ -493,3 +494,24 @@ test "switch on error set with single else" {...@@ -493,3 +494,24 @@ test "switch on error set with single else" {
493 S.doTheTest();494 S.doTheTest();
494 comptime S.doTheTest();495 comptime S.doTheTest();
495}496}
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 @@...@@ -1,4 +1,5 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const expect = std.testing.expect;
23
3test "while loop" {4test "while loop" {
4 var i: i32 = 0;5 var i: i32 = 0;
...@@ -271,3 +272,18 @@ test "while error 2 break statements and an else" {...@@ -271,3 +272,18 @@ test "while error 2 break statements and an else" {
271 S.entry(true, false);272 S.entry(true, false);
272 comptime S.entry(true, false);273 comptime S.entry(true, false);
273}274}
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}