authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-02 20:16:47+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-12-03 00:09:23+02:00
loge2509ddbe69a56bb1f4a56b46946b2a706d5aabe
tree109fc0748d4e735b8a0624907bfb0610c06d8301
parent0e38cc16d51178525e89774ce9151651b6a0e99a

AstGen: add error for invalid string comparisons

These operations are allowed because the string literals are just pointers but they produce unexpected results. These errors prevent beginners from shooting themselves in the foot while still allowing advanced users to circumvent them if they desire to do so. Closes #8290

3 files changed, 43 insertions(+), 1 deletions(-)

src/AstGen.zig+13
...@@ -5628,6 +5628,14 @@ fn simpleBinOp(...@@ -5628,6 +5628,14 @@ fn simpleBinOp(
5628 const tree = astgen.tree;5628 const tree = astgen.tree;
5629 const node_datas = tree.nodes.items(.data);5629 const node_datas = tree.nodes.items(.data);
56305630
5631 if (op_inst_tag == .cmp_neq or op_inst_tag == .cmp_eq) {
5632 const node_tags = tree.nodes.items(.tag);
5633 const str = if (op_inst_tag == .cmp_eq) "==" else "!=";
5634 if (node_tags[node_datas[node].lhs] == .string_literal or
5635 node_tags[node_datas[node].rhs] == .string_literal)
5636 return astgen.failNode(node, "cannot compare strings with {s}", .{str});
5637 }
5638
5631 const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node);5639 const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node);
5632 var line: u32 = undefined;5640 var line: u32 = undefined;
5633 var column: u32 = undefined;5641 var column: u32 = undefined;
...@@ -6625,6 +6633,11 @@ fn switchExpr(...@@ -6625,6 +6633,11 @@ fn switchExpr(
6625 continue;6633 continue;
6626 }6634 }
66276635
6636 for (case.ast.values) |val| {
6637 if (node_tags[val] == .string_literal)
6638 return astgen.failNode(val, "cannot switch on strings", .{});
6639 }
6640
6628 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) {6641 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) {
6629 scalar_cases_len += 1;6642 scalar_cases_len += 1;
6630 } else {6643 } else {
test/cases/compile_errors/invalid_compare_string.zig created+29
...@@ -0,0 +1,29 @@
1comptime {
2 var a = "foo";
3 if (a == "foo") unreachable;
4}
5comptime {
6 var a = "foo";
7 if (a == ("foo")) unreachable; // intentionally allow
8}
9comptime {
10 var a = "foo";
11 switch (a) {
12 "foo" => unreachable,
13 else => {},
14 }
15}
16comptime {
17 var a = "foo";
18 switch (a) {
19 ("foo") => unreachable, // intentionally allow
20 else => {},
21 }
22}
23
24// error
25// backend=stage2
26// target=native
27//
28// :3:11: error: cannot compare strings with ==
29// :12:9: error: cannot switch on strings
test/cases/compile_errors/switch_on_slice.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1pub export fn entry() void {1pub export fn entry() void {
2 var a: [:0]const u8 = "foo";2 var a: [:0]const u8 = "foo";
3 switch (a) {3 switch (a) {
4 "--version", "version" => unreachable,4 ("--version"), ("version") => unreachable,
5 else => {},5 else => {},
6 }6 }
7}7}