AstGen: fix loop result locations
The main problem was that the loop body was treated as an expression that was one of the peer result values of a loop, when in reality the loop body is noreturn and only the `break` operands are the result values of loops. This was solved by introducing an override that prevents rvalue() from emitting a store to result location instruction for loop bodies. An orthogonal change also included in this commit is switching `elem_val` index expressions to using `coerced_ty` and doing the coercion to `usize` inside `Sema`, resulting in smaller ZIR (since the cast becomes implied). I also changed the break operand expression to use `reachableExpr`, introducing a new compile error for double break. This makes a few more behavior tests pass for `while` and `for` loops.
This commit is contained in:
@@ -145,7 +145,6 @@ test {
|
||||
_ = @import("behavior/bugs/7027.zig");
|
||||
_ = @import("behavior/bugs/7047.zig");
|
||||
_ = @import("behavior/bugs/9584.zig");
|
||||
_ = @import("behavior/bugs/9967.zig");
|
||||
_ = @import("behavior/bugs/10147.zig");
|
||||
_ = @import("behavior/byteswap.zig");
|
||||
_ = @import("behavior/call_stage1.zig");
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
test "nested breaks to same labeled block" {
|
||||
const a = blk: {
|
||||
break :blk break :blk @as(u32, 1);
|
||||
};
|
||||
try std.testing.expectEqual(a, 1);
|
||||
}
|
||||
@@ -116,3 +116,20 @@ test "for with null and T peer types and inferred result location type" {
|
||||
try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
comptime try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
}
|
||||
|
||||
test "2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
var buf: [10]u8 = undefined;
|
||||
var ok = false;
|
||||
ok = for (buf) |item| {
|
||||
_ = item;
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
@@ -26,23 +26,6 @@ fn mangleString(s: []u8) void {
|
||||
}
|
||||
}
|
||||
|
||||
test "2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
var buf: [10]u8 = undefined;
|
||||
var ok = false;
|
||||
ok = for (buf) |item| {
|
||||
_ = item;
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
test "for copies its payload" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
|
||||
@@ -236,3 +236,33 @@ test "while on error union with else result follow break prong" {
|
||||
} else |_| @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
test "while bool 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
var ok = false;
|
||||
ok = while (t) {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
test "while optional 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(opt_t: ?bool, f: bool) !void {
|
||||
var ok = false;
|
||||
ok = while (opt_t) |t| {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
@@ -1,36 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "while bool 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
var ok = false;
|
||||
ok = while (t) {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
test "while optional 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(opt_t: ?bool, f: bool) !void {
|
||||
var ok = false;
|
||||
ok = while (opt_t) |t| {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.entry(true, false);
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
test "while error 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(opt_t: anyerror!bool, f: bool) !void {
|
||||
|
||||
@@ -5042,6 +5042,17 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
"tmp.zig:2:12: note: control flow is diverted here",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("unreachable code - double break",
|
||||
\\export fn a() void {
|
||||
\\ const b = blk: {
|
||||
\\ break :blk break :blk @as(u32, 1);
|
||||
\\ };
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:9: error: unreachable code",
|
||||
"tmp.zig:3:20: note: control flow is diverted here",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("chained comparison operators",
|
||||
\\export fn a(value: u32) bool {
|
||||
\\ return 1 < value < 1000;
|
||||
|
||||
Reference in New Issue
Block a user