Commit 9a0c593a54

Veikka Tuominen <git@vexu.eu>
2022-12-28 14:10:12
add tests for fixed stage1 bugs
Closes #1957 Closes #1994 Closes #2140 Closes #2746 Closes #2802 Closes #2855 Closes #2895 Closes #2981 Closes #3054 Closes #3158 Closes #3234 Closes #3259 Closes #3371 Closes #3376 Closes #3387 Closes #3529 Closes #3653 Closes #3750 Closes #3778 Closes #3882 Closes #3915 Closes #3929 Closes #3961 Closes #3988 Closes #4123 Closes #7448
1 parent 7350f0d
lib/std/array_list.zig
@@ -1604,3 +1604,20 @@ test "std.ArrayList(u0)" {
     }
     try testing.expectEqual(count, 3);
 }
+
+test "std.ArrayList(?u32).popOrNull()" {
+    const a = testing.allocator;
+
+    var list = ArrayList(?u32).init(a);
+    defer list.deinit();
+
+    try list.append(null);
+    try list.append(1);
+    try list.append(2);
+    try testing.expectEqual(list.items.len, 3);
+
+    try testing.expect(list.popOrNull().? == @as(u32, 2));
+    try testing.expect(list.popOrNull().? == @as(u32, 1));
+    try testing.expect(list.popOrNull().? == null);
+    try testing.expect(list.popOrNull() == null);
+}
test/behavior/cast.zig
@@ -1518,3 +1518,13 @@ test "bitcast packed struct with u0" {
     const i = @bitCast(u2, s);
     try expect(i == 2);
 }
+
+test "optional pointer coerced to optional allowzero pointer" {
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+    var p: ?*u32 = undefined;
+    var q: ?*allowzero u32 = undefined;
+    p = @intToPtr(*u32, 4);
+    q = p;
+    try expect(@ptrToInt(q.?) == 4);
+}
test/behavior/eval.zig
@@ -1547,3 +1547,77 @@ test "comptime function turns function value to function pointer" {
     };
     comptime try expect(S.foo[0] == &S.Nil);
 }
+
+test "container level const and var have unique addresses" {
+    const S = struct {
+        x: i32,
+        y: i32,
+        const c = @This(){ .x = 1, .y = 1 };
+        var v: @This() = c;
+    };
+    var p = &S.c;
+    try std.testing.expect(p.x == S.c.x);
+    S.v.x = 2;
+    try std.testing.expect(p.x == S.c.x);
+}
+
+test "break from block results in type" {
+    const S = struct {
+        fn NewType(comptime T: type) type {
+            const Padded = blk: {
+                if (@sizeOf(T) <= @sizeOf(usize)) break :blk void;
+                break :blk T;
+            };
+
+            return Padded;
+        }
+    };
+    const T = S.NewType(usize);
+    try expect(T == void);
+}
+
+test "struct in comptime false branch is not evaluated" {
+    const S = struct {
+        const comptime_const = 2;
+        fn some(comptime V: type) type {
+            return switch (comptime_const) {
+                3 => struct { a: V.foo },
+                2 => V,
+                else => unreachable,
+            };
+        }
+    };
+    try expect(S.some(u32) == u32);
+}
+
+test "result of nested switch assigned to variable" {
+    var zds: u32 = 0;
+    zds = switch (zds) {
+        0 => switch (zds) {
+            0...0 => 1234,
+            1...1 => zds,
+            2 => zds,
+            else => return,
+        },
+        else => zds,
+    };
+    try expect(zds == 1234);
+}
+
+test "inline for loop of functions returning error unions" {
+    const T1 = struct {
+        fn v() error{}!usize {
+            return 1;
+        }
+    };
+    const T2 = struct {
+        fn v() error{Error}!usize {
+            return 2;
+        }
+    };
+    var a: usize = 0;
+    inline for (.{ T1, T2 }) |T| {
+        a += try T.v();
+    }
+    try expect(a == 3);
+}
test/behavior/for.zig
@@ -227,3 +227,25 @@ test "else continue outer for" {
         } else continue;
     }
 }
+
+test "for loop with else branch" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+    {
+        var x = [_]u32{ 1, 2 };
+        const q = for (x) |y| {
+            if ((y & 1) != 0) continue;
+            break y * 2;
+        } else @as(u32, 1);
+        try expect(q == 4);
+    }
+    {
+        var x = [_]u32{ 1, 2 };
+        const q = for (x) |y| {
+            if ((y & 1) != 0) continue;
+            break y * 2;
+        } else @panic("");
+        try expect(q == 4);
+    }
+}
test/behavior/optional.zig
@@ -448,3 +448,46 @@ test "Optional slice size is optimized" {
     a = "hello";
     try expectEqualStrings(a.?, "hello");
 }
+
+test "peer type resolution in nested if expressions" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+    const Thing = struct { n: i32 };
+    var a = false;
+    var b = false;
+
+    var result1 = if (a)
+        Thing{ .n = 1 }
+    else
+        null;
+    try expect(result1 == null);
+    try expect(@TypeOf(result1) == ?Thing);
+
+    var result2 = if (a)
+        Thing{ .n = 0 }
+    else if (b)
+        Thing{ .n = 1 }
+    else
+        null;
+    try expect(result2 == null);
+    try expect(@TypeOf(result2) == ?Thing);
+}
+
+test "cast slice to const slice nested in error union and optional" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+    const S = struct {
+        fn inner() !?[]u8 {
+            return error.Foo;
+        }
+        fn outer() !?[]const u8 {
+            return inner();
+        }
+    };
+    try std.testing.expectError(error.Foo, S.outer());
+}
test/behavior/packed-struct.zig
@@ -567,3 +567,24 @@ test "packed struct passed to callconv(.C) function" {
     }, 5, 4, 3, 2, 1);
     try expect(result);
 }
+
+test "overaligned pointer to packed struct" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+    const S = packed struct { a: u32, b: u32 };
+    var foo: S align(4) = .{ .a = 123, .b = 456 };
+    const ptr: *align(4) S = &foo;
+    switch (comptime builtin.cpu.arch.endian()) {
+        .Little => {
+            const ptr_to_b: *u32 = &ptr.b;
+            try expect(ptr_to_b.* == 456);
+        },
+        .Big => {
+            // Byte aligned packed struct field pointers have not been implemented yet.
+            const ptr_to_a: *align(4:0:8) u32 = &ptr.a;
+            try expect(ptr_to_a.* == 123);
+        },
+    }
+}
test/behavior/ptrcast.zig
@@ -270,3 +270,15 @@ test "comptime @ptrCast a subset of an array, then write through it" {
         std.mem.copy(u8, buff[4..], "abcdef");
     }
 }
+
+test "@ptrCast undefined value at comptime" {
+    const S = struct {
+        fn transmute(comptime T: type, comptime U: type, value: T) U {
+            return @ptrCast(*const U, &value).*;
+        }
+    };
+    comptime {
+        var x = S.transmute([]u8, i32, undefined);
+        _ = x;
+    }
+}
test/behavior/slice.zig
@@ -706,3 +706,34 @@ test "global slice field access" {
     S.slice.len -= 2;
     try expectEqualStrings("trin", S.slice);
 }
+
+test "slice of void" {
+    var n: usize = 10;
+    var arr: [12]void = undefined;
+    const slice = @as([]void, &arr)[0..n];
+    try expect(slice.len == n);
+}
+
+test "slice with dereferenced value" {
+    var a: usize = 0;
+    var idx: *usize = &a;
+    _ = blk: {
+        var array = [_]u8{};
+        break :blk array[idx.*..];
+    };
+    const res = blk: {
+        var array = [_]u8{};
+        break :blk array[idx.*..];
+    };
+    try expect(res.len == 0);
+}
+
+test "empty slice ptr is non null" {
+    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64 and (builtin.os.tag == .macos or builtin.os.tag == .windows)) return error.SkipZigTest; // TODO
+
+    const empty_slice: []u8 = &[_]u8{};
+    const p: [*]u8 = empty_slice.ptr + 0;
+    const t = @ptrCast([*]i8, p);
+    try expect(@ptrToInt(t) == @ptrToInt(empty_slice.ptr));
+}
test/behavior/struct.zig
@@ -1458,3 +1458,40 @@ test "struct has only one reference" {
     try expectEqual(@sizeOf(struct { x: u16 }), S.optionalComptimeIntParam(@sizeOf(struct { x: u16 })));
     try expectEqual(@sizeOf(struct { x: u32 }), S.errorUnionComptimeIntParam(@sizeOf(struct { x: u32 })));
 }
+
+test "no dependency loop on pointer to optional struct" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+    const S = struct {
+        const A = struct { b: B };
+        const B = struct { a: *?A };
+    };
+    var a1: ?S.A = null;
+    var a2: ?S.A = .{ .b = .{ .a = &a1 } };
+    a1 = .{ .b = .{ .a = &a2 } };
+
+    try expect(a1.?.b.a == &a2);
+    try expect(a2.?.b.a == &a1);
+}
+
+test "discarded struct initialization works as expected" {
+    const S = struct { a: u32 };
+    _ = S{ .a = 1 };
+}
+
+test "function pointer in struct returns the struct" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+    const A = struct {
+        const A = @This();
+        f: *const fn () A,
+
+        fn f() A {
+            return .{ .f = f };
+        }
+    };
+    var a = A.f();
+    try expect(a.f == A.f);
+}
test/behavior/tuple.zig
@@ -2,6 +2,7 @@ const builtin = @import("builtin");
 const std = @import("std");
 const testing = std.testing;
 const expect = testing.expect;
+const expectEqualStrings = std.testing.expectEqualStrings;
 
 test "tuple concatenation" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@@ -340,3 +341,28 @@ test "tuple type with void field and a runtime field" {
     var t: T = .{ 5, {} };
     try expect(t[0] == 5);
 }
+
+test "branching inside tuple literal" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+    const S = struct {
+        fn foo(a: anytype) !void {
+            try expect(a[0] == 1234);
+        }
+    };
+    var a = false;
+    try S.foo(.{if (a) @as(u32, 5678) else @as(u32, 1234)});
+}
+
+test "tuple initialized with a runtime known value" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
+
+    const E = union(enum) { e: []const u8 };
+    const W = union(enum) { w: E };
+    var e = E{ .e = "test" };
+    const w = .{W{ .w = e }};
+    try expectEqualStrings(w[0].w.e, "test");
+}
test/behavior/union.zig
@@ -1471,3 +1471,34 @@ test "union int tag type is properly managed" {
     };
     try expect(@sizeOf(Bar) + 1 == 3);
 }
+
+test "no dependency loop when function pointer in union returns the union" {
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+    const U = union(enum) {
+        const U = @This();
+        a: u8,
+        b: *const fn (x: U) void,
+        c: *const fn (x: U) U,
+        d: *const fn (x: u8) U,
+        fn foo(x: u8) U {
+            return .{ .a = x };
+        }
+    };
+    var b: U = .{ .d = U.foo };
+    try expect(b.d(2).a == 2);
+}
+
+test "union reassignment can use previous value" {
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+    const U = union {
+        a: u32,
+        b: u32,
+    };
+    var a = U{ .a = 32 };
+    a = U{ .b = a.a };
+    try expect(a.b == 32);
+}
test/cases/compile_errors/control_flow_uses_comptime_var_at_runtime.zig
@@ -6,6 +6,27 @@ export fn foo() void {
 }
 
 fn bar() void { }
+export fn baz() void {
+    comptime var idx: u32 = 0;
+    while (idx < 1) {
+        const not_null: ?u32 = 1;
+        _ = not_null orelse return;
+        idx += 1;
+    }
+}
+
+export fn qux() void {
+    comptime var i = 0;
+    while (i < 3) : (i += 1) {
+        const T = switch (i) {
+            0 => f32,
+            1 => i8,
+            2 => bool,
+            else => unreachable,
+        };
+        _ = T;
+    }
+}
 
 // error
 // backend=stage2
@@ -13,3 +34,7 @@ fn bar() void { }
 //
 // :3:24: error: cannot store to comptime variable in non-inline loop
 // :3:5: note: non-inline loop here
+// :14:13: error: cannot store to comptime variable in non-inline loop
+// :11:5: note: non-inline loop here
+// :20:24: error: cannot store to comptime variable in non-inline loop
+// :20:5: note: non-inline loop here
test/cases/compile_errors/reference_to_const_data.zig
@@ -18,6 +18,10 @@ export fn qux() void {
     var ptr = &S{.x=1,.y=2};
     ptr.x = 2;
 }
+export fn quux() void {
+    var x = &@returnAddress();
+    x.* = 6;
+}
 
 // error
 // backend=stage2
@@ -27,3 +31,4 @@ export fn qux() void {
 // :7:8: error: cannot assign to constant
 // :11:8: error: cannot assign to constant
 // :19:8: error: cannot assign to constant
+// :23:6: error: cannot assign to constant
test/cases/compile_errors/return_incompatible_generic_struct.zig
@@ -0,0 +1,20 @@
+fn A(comptime T: type) type {
+    return struct { a: T };
+}
+fn B(comptime T: type) type {
+    return struct { b: T };
+}
+fn foo() A(u32) {
+    return B(u32){ .b = 1 };
+}
+export fn entry() void {
+    _ = foo();
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
+// :5:12: note: struct declared here
+// :2:12: note: struct declared here