authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-10 17:09:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-10 17:52:18-07:00
log273da9efd9238e20da1299789537b00de2f0ebd8
tree54905594f55be9fd19a179ab1bcaeb1900d02bc1
parenta30d283981ae31ed0212ef153f086e07daeffe65

AstGen: structInitExpr and arrayInitExpr avoid crash

when an inferred alloc is passed as the result pointer of a block.

4 files changed, 69 insertions(+), 10 deletions(-)

src/AstGen.zig+30-1
...@@ -1360,6 +1360,12 @@ fn arrayInitExpr(...@@ -1360,6 +1360,12 @@ fn arrayInitExpr(
1360 }1360 }
1361 },1361 },
1362 .block_ptr => |block_gz| {1362 .block_ptr => |block_gz| {
1363 // This condition is here for the same reason as the above condition in `inferred_ptr`.
1364 // See corresponding logic in structInitExpr.
1365 if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) {
1366 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1367 return rvalue(gz, rl, result, node);
1368 }
1363 return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array);1369 return arrayInitExprRlPtr(gz, scope, rl, node, block_gz.rl_ptr, array_init.ast.elements, types.array);
1364 },1370 },
1365 }1371 }
...@@ -1604,7 +1610,16 @@ fn structInitExpr(...@@ -1604,7 +1610,16 @@ fn structInitExpr(
1604 return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst);1610 return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst);
1605 }1611 }
1606 },1612 },
1607 .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr),1613 .block_ptr => |block_gz| {
1614 // This condition is here for the same reason as the above condition in `inferred_ptr`.
1615 // See corresponding logic in arrayInitExpr.
1616 if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) {
1617 const result = try structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
1618 return rvalue(gz, rl, result, node);
1619 }
1620
1621 return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr);
1622 },
1608 }1623 }
1609}1624}
16101625
...@@ -10938,3 +10953,17 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -10938,3 +10953,17 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
10938 }10953 }
10939 return decl_count;10954 return decl_count;
10940}10955}
10956
10957fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {
10958 const inst = refToIndex(ref) orelse return false;
10959 const zir_tags = astgen.instructions.items(.tag);
10960 return switch (zir_tags[inst]) {
10961 .alloc_inferred,
10962 .alloc_inferred_mut,
10963 .alloc_inferred_comptime,
10964 .alloc_inferred_comptime_mut,
10965 => true,
10966
10967 else => false,
10968 };
10969}
src/Zir.zig+1-1
...@@ -516,7 +516,7 @@ pub const Inst = struct {...@@ -516,7 +516,7 @@ pub const Inst = struct {
516 /// Same as `store` except provides a source location.516 /// Same as `store` except provides a source location.
517 /// Uses the `pl_node` union field. Payload is `Bin`.517 /// Uses the `pl_node` union field. Payload is `Bin`.
518 store_node,518 store_node,
519 /// This instruction is not really supposed to be emitted from AstGen; nevetheless it519 /// This instruction is not really supposed to be emitted from AstGen; nevertheless it
520 /// is sometimes emitted due to deficiencies in AstGen. When Sema sees this instruction,520 /// is sometimes emitted due to deficiencies in AstGen. When Sema sees this instruction,
521 /// it must clean up after AstGen's mess by looking at various context clues and521 /// it must clean up after AstGen's mess by looking at various context clues and
522 /// then treating it as one of the following:522 /// then treating it as one of the following:
test/behavior/bugs/5474.zig+6-8
...@@ -49,19 +49,17 @@ fn constant() !void {...@@ -49,19 +49,17 @@ fn constant() !void {
49}49}
5050
51test "pointer-to-array constness for zero-size elements, var" {51test "pointer-to-array constness for zero-size elements, var" {
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;54
55 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
56 try mutable();55 try mutable();
57 comptime try mutable();56 comptime try mutable();
58}57}
5958
60test "pointer-to-array constness for zero-size elements, const" {59test "pointer-to-array constness for zero-size elements, const" {
61 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;61 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;62
64 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
65 try constant();63 try constant();
66 comptime try constant();64 comptime try constant();
67}65}
test/behavior/tuple.zig+32
...@@ -165,3 +165,35 @@ test "array-like initializer for tuple types" {...@@ -165,3 +165,35 @@ test "array-like initializer for tuple types" {
165 try S.doTheTest();165 try S.doTheTest();
166 comptime try S.doTheTest();166 comptime try S.doTheTest();
167}167}
168
169test "anon struct as the result from a labeled block" {
170 const S = struct {
171 fn doTheTest() !void {
172 const precomputed = comptime blk: {
173 var x: i32 = 1234;
174 break :blk .{
175 .x = x,
176 };
177 };
178 try expect(precomputed.x == 1234);
179 }
180 };
181
182 try S.doTheTest();
183 comptime try S.doTheTest();
184}
185
186test "tuple as the result from a labeled block" {
187 const S = struct {
188 fn doTheTest() !void {
189 const precomputed = comptime blk: {
190 var x: i32 = 1234;
191 break :blk .{x};
192 };
193 try expect(precomputed[0] == 1234);
194 }
195 };
196
197 try S.doTheTest();
198 comptime try S.doTheTest();
199}