diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig index 044670e867..c6df2a66eb 100644 --- a/lib/std/array_list.zig +++ b/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); +} diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 08066edc73..b0e0670459 100644 --- a/test/behavior/cast.zig +++ b/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); +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 8c3962e3e4..86409c0231 100644 --- a/test/behavior/eval.zig +++ b/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); +} diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 5f13e660bd..f48000a871 100644 --- a/test/behavior/for.zig +++ b/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); + } +} diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 9821145658..3e91c6807c 100644 --- a/test/behavior/optional.zig +++ b/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()); +} diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 392ebc23c8..2290b1d1cc 100644 --- a/test/behavior/packed-struct.zig +++ b/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); + }, + } +} diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index 0a983f82c6..9336d58641 100644 --- a/test/behavior/ptrcast.zig +++ b/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; + } +} diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 416423e9cc..63c3178325 100644 --- a/test/behavior/slice.zig +++ b/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)); +} diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 041b8ddcd8..dfed7d276e 100644 --- a/test/behavior/struct.zig +++ b/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); +} diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index da51127412..c80318c144 100644 --- a/test/behavior/tuple.zig +++ b/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"); +} diff --git a/test/behavior/union.zig b/test/behavior/union.zig index dcd311392f..3a0fce30ff 100644 --- a/test/behavior/union.zig +++ b/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); +} diff --git a/test/cases/compile_errors/control_flow_uses_comptime_var_at_runtime.zig b/test/cases/compile_errors/control_flow_uses_comptime_var_at_runtime.zig index 43ef20873c..a8058e8c75 100644 --- a/test/cases/compile_errors/control_flow_uses_comptime_var_at_runtime.zig +++ b/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 diff --git a/test/cases/compile_errors/reference_to_const_data.zig b/test/cases/compile_errors/reference_to_const_data.zig index b7f2e93fbd..cbc0fe131c 100644 --- a/test/cases/compile_errors/reference_to_const_data.zig +++ b/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 diff --git a/test/cases/compile_errors/return_incompatible_generic_struct.zig b/test/cases/compile_errors/return_incompatible_generic_struct.zig new file mode 100644 index 0000000000..f46d44d53f --- /dev/null +++ b/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