diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig index 7adec6168f..f8914ead80 100644 --- a/test/behavior/alignof.zig +++ b/test/behavior/alignof.zig @@ -39,3 +39,8 @@ test "correct alignment for elements and slices of aligned array" { try expect(@alignOf(@TypeOf(&buf[start..end])) == @alignOf(*u8)); try expect(@alignOf(@TypeOf(&buf[start])) == @alignOf(*u8)); } + +test "@alignOf(anyerror!noreturn)" { + try expect(@alignOf(anyerror!noreturn) == @alignOf(anyerror)); + try expect(@alignOf(anyerror!anyerror!noreturn) == @alignOf(anyerror)); +} diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 4dd5ae08da..9ec1ed8c35 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1354,3 +1354,18 @@ test "empty enum passed as argument" { }; E.f(@as(E, undefined)); } + +test "enum int tag type uses declaration inside the enum" { + const static = struct { + const E = enum(E.IntTag) { + const IntTag = u8; + a, + b, + c, + }; + }; + try expect(@sizeOf(static.E) == @sizeOf(u8)); + const val: static.E = .b; + try expect(val == .b); + try expect(@intFromEnum(val) == 1); +} diff --git a/test/behavior/error.zig b/test/behavior/error.zig index d74a7668a9..0679736ac3 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -1109,3 +1109,36 @@ test "'if' ignores error via local while 'else' ignores error directly" { try S.testOne(false); try S.testOne(true); } + +test "@errorCast into own inferred error set" { + const static = struct { + fn foo(b: bool) !void { + if (b) { + return @errorCast(error.Bad); + } + } + }; + try static.foo(false); + if (static.foo(true)) { + return error.ExpectedError; + } else |err| { + try expect(err == error.Bad); + } + + const errors = @typeInfo(@typeInfo(@TypeOf(static.foo(false))).error_union.error_set).error_set.?; + comptime assert(errors.len == 1); + comptime assert(std.mem.eql(u8, errors[0].name, "Bad")); +} + +test "@errorCast into other inferred error set" { + const static = struct { + fn foo() !void { + return error.Bad; + } + }; + const Ies = @typeInfo(@TypeOf(static.foo())).error_union.error_set; + const err: Ies = @errorCast(error.Bad); + try expect(err == error.Bad); + const non_err: Ies!u32 = @errorCast(@as(error{}!u32, 123)); + try expect(try non_err == 123); +} diff --git a/test/behavior/packed-union.zig b/test/behavior/packed-union.zig index f625c8b073..330a4853b1 100644 --- a/test/behavior/packed-union.zig +++ b/test/behavior/packed-union.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; +const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; test "flags in packed union" { @@ -177,3 +178,24 @@ test "assigning to non-active field at comptime" { test_bits.bits = .{}; } } + +test "packed union with explicit backing integer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const U = packed union(i32) { + raw: i32, + unsigned_halves: packed struct { low: u16, high: u16 }, + + fn check(val: @This()) !void { + try expect(@as(i32, @bitCast(val)) == -2); + try expect(@as(u32, @bitCast(val)) == 0xFFFFFFFE); + try expect(val.raw == -2); + try expect(val.unsigned_halves.low == 0xFFFE); + try expect(val.unsigned_halves.high == 0xFFFF); + } + }; + try U.check(.{ .raw = -2 }); + try comptime U.check(.{ .raw = -2 }); +} diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index e6a3558646..3c2d01f6a4 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -2254,3 +2254,54 @@ test "runtime-known slice of comptime-only struct" { .{ .index = 15, .T = Mixed }, }); } + +test "struct contains aligned pointer to itself through type decl" { + const Slab = struct { + const Ptr = *align(64) const @This(); + next: Ptr, + }; + // We intentionally use `Slab.Ptr` before `Slab`. + var ptr: Slab.Ptr = undefined; + var slab: Slab align(64) = undefined; + ptr = &slab; + slab.next = ptr; + + try expect(ptr == &slab); + try expect(slab.next == &slab); + try expect(slab.next.next == &slab); + try expect(slab.next.next.next == &slab); +} + +test "struct contains underaligned field with overaligned pointer to itself" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + const S = struct { + ptr: *align(8) @This() align(1), + }; + var val: S align(8) = undefined; + val.ptr = &val; + try expect(val.ptr == &val); + try expect(val.ptr.ptr == &val); + try expect(val.ptr.ptr.ptr == &val); +} + +test "struct contains pointer to function accepting that struct" { + const S = struct { + const FnPtr = ?*const fn (@This()) void; + fn_ptr: FnPtr, + }; + const dummy_fn_ptr: S.FnPtr = @ptrFromInt(0x100000); + const dummy_s: S = .{ .fn_ptr = dummy_fn_ptr }; + try expect(dummy_s.fn_ptr == dummy_fn_ptr); + try expect(@TypeOf(dummy_s.fn_ptr.?) == *const fn (S) void); +} + +test "struct queries typeinfo of struct containing pointer back to first struct" { + const static = struct { + const A = struct { b: *B }; + const B = struct { a: T: { + _ = @typeInfo(A); + break :T u32; + } }; + }; + _ = @as(static.A, undefined); +} diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index a88a99171b..75cf4515a5 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -592,3 +592,14 @@ test "array of tuples that end with a zero-bit field followed by padding" { try expect(S.foo[1][1] == 4); try expect(S.foo[1][2] == {}); } + +test "call function at comptime through container-level const tuple" { + const static = struct { + const MyTuple = struct { (fn () u32) }; + const val: MyTuple = .{foo}; + fn foo() u32 { + return 1234; + } + }; + comptime assert(static.val[0]() == 1234); +} diff --git a/test/cases/compile_errors/enum_uses_own_typeinfo.zig b/test/cases/compile_errors/enum_uses_own_typeinfo.zig new file mode 100644 index 0000000000..5906ba6bcb --- /dev/null +++ b/test/cases/compile_errors/enum_uses_own_typeinfo.zig @@ -0,0 +1,15 @@ +const E = enum(u9) { + const a_val: @typeInfo(E).@"enum".tag_type = 0; + a = a_val, +}; +comptime { + _ = E.a; +} + +// error +// +// error: dependency loop with length 3 +// :3:9: note: type 'tmp.E' uses value of declaration 'tmp.E.a_val' here +// :2:50: note: value of declaration 'tmp.E.a_val' uses type of declaration 'tmp.E.a_val' here +// :2:18: note: type of declaration 'tmp.E.a_val' depends on type 'tmp.E' for type information query here +// note: eliminate any one of these dependencies to break the loop diff --git a/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig b/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig index 3ff9961de8..aa79ee1ad6 100644 --- a/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig +++ b/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig @@ -11,6 +11,6 @@ comptime { // // :3:5: error: unable to export type 'type' // :7:5: error: unable to export type 'tmp.E' -// :7:5: note: enum tag type 'u1' is not extern compatible -// :7:5: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible +// :1:11: note: integer tag type of enum is inferred +// :1:11: note: consider explicitly specifying the integer tag type // :1:11: note: enum declared here diff --git a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig deleted file mode 100644 index a0e476f087..0000000000 --- a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig +++ /dev/null @@ -1,45 +0,0 @@ -// zig fmt: off -pub const E = enum { -@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12", -@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23", -@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34", -@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45", -@"46",@"47",@"48",@"49",@"50",@"51",@"52",@"53",@"54",@"55",@"56", -@"57",@"58",@"59",@"60",@"61",@"62",@"63",@"64",@"65",@"66",@"67", -@"68",@"69",@"70",@"71",@"72",@"73",@"74",@"75",@"76",@"77",@"78", -@"79",@"80",@"81",@"82",@"83",@"84",@"85",@"86",@"87",@"88",@"89", -@"90",@"91",@"92",@"93",@"94",@"95",@"96",@"97",@"98",@"99",@"100", -@"101",@"102",@"103",@"104",@"105",@"106",@"107",@"108",@"109", -@"110",@"111",@"112",@"113",@"114",@"115",@"116",@"117",@"118", -@"119",@"120",@"121",@"122",@"123",@"124",@"125",@"126",@"127", -@"128",@"129",@"130",@"131",@"132",@"133",@"134",@"135",@"136", -@"137",@"138",@"139",@"140",@"141",@"142",@"143",@"144",@"145", -@"146",@"147",@"148",@"149",@"150",@"151",@"152",@"153",@"154", -@"155",@"156",@"157",@"158",@"159",@"160",@"161",@"162",@"163", -@"164",@"165",@"166",@"167",@"168",@"169",@"170",@"171",@"172", -@"173",@"174",@"175",@"176",@"177",@"178",@"179",@"180",@"181", -@"182",@"183",@"184",@"185",@"186",@"187",@"188",@"189",@"190", -@"191",@"192",@"193",@"194",@"195",@"196",@"197",@"198",@"199", -@"200",@"201",@"202",@"203",@"204",@"205",@"206",@"207",@"208", -@"209",@"210",@"211",@"212",@"213",@"214",@"215",@"216",@"217", -@"218",@"219",@"220",@"221",@"222",@"223",@"224",@"225",@"226", -@"227",@"228",@"229",@"230",@"231",@"232",@"233",@"234",@"235", -@"236",@"237",@"238",@"239",@"240",@"241",@"242",@"243",@"244", -@"245",@"246",@"247",@"248",@"249",@"250",@"251",@"252",@"253", -@"254",@"255", @"256" -}; -// zig fmt: on -pub const S = extern struct { - e: E, -}; -export fn entry() void { - const s: S = undefined; - _ = s; -} - -// error -// -// :33:8: error: extern structs cannot contain fields of type 'tmp.E' -// :33:8: note: enum tag type 'u9' is not extern compatible -// :33:8: note: only integers with 0 or power of two bits are extern compatible -// :2:15: note: enum declared here diff --git a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig index 373f10444d..fdf0f9aadd 100644 --- a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig +++ b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig @@ -10,6 +10,6 @@ export fn entry() void { // error // // :3:8: error: extern structs cannot contain fields of type 'tmp.E' -// :3:8: note: enum tag type 'u31' is not extern compatible -// :3:8: note: only integers with 0 or power of two bits are extern compatible +// :1:15: note: enum tag type 'u31' is not extern compatible +// :1:15: note: only integers with 0 or power of two bits are extern compatible // :1:15: note: enum declared here diff --git a/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig b/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig new file mode 100644 index 0000000000..4afacccc8d --- /dev/null +++ b/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig @@ -0,0 +1,8 @@ +const MyFn = fn () ?*const MyFn; +comptime { + _ = MyFn; +} + +// error +// +// :1:28: error: value of declaration 'tmp.MyFn' depends on itself here diff --git a/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig b/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig index 8122a89adc..ed9828c692 100644 --- a/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig +++ b/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig @@ -7,6 +7,6 @@ export fn entry(foo: Foo) void { // target=x86_64-linux // // :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'x86_64_sysv' -// :2:17: note: enum tag type 'u2' is not extern compatible -// :2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible +// :1:13: note: integer tag type of enum is inferred +// :1:13: note: consider explicitly specifying the integer tag type // :1:13: note: enum declared here diff --git a/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig b/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig new file mode 100644 index 0000000000..5d1b8e75ae --- /dev/null +++ b/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig @@ -0,0 +1,51 @@ +const PackedStruct = packed struct { x: u32 }; +const PackedUnion = packed union { x: u32 }; + +/// This enum has 256 fields, so `u8` will be its inferred tag type. +const Enum = enum { + // zig fmt: off + _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0a, _0b, _0c, _0d, _0e, _0f, + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1a, _1b, _1c, _1d, _1e, _1f, + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2a, _2b, _2c, _2d, _2e, _2f, + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3a, _3b, _3c, _3d, _3e, _3f, + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4a, _4b, _4c, _4d, _4e, _4f, + _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5a, _5b, _5c, _5d, _5e, _5f, + _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6a, _6b, _6c, _6d, _6e, _6f, + _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7a, _7b, _7c, _7d, _7e, _7f, + _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8a, _8b, _8c, _8d, _8e, _8f, + _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9a, _9b, _9c, _9d, _9e, _9f, + _a0, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _aa, _ab, _ac, _ad, _ae, _af, + _b0, _b1, _b2, _b3, _b4, _b5, _b6, _b7, _b8, _b9, _ba, _bb, _bc, _bd, _be, _bf, + _c0, _c1, _c2, _c3, _c4, _c5, _c6, _c7, _c8, _c9, _ca, _cb, _cc, _cd, _ce, _cf, + _d0, _d1, _d2, _d3, _d4, _d5, _d6, _d7, _d8, _d9, _da, _db, _dc, _dd, _de, _df, + _e0, _e1, _e2, _e3, _e4, _e5, _e6, _e7, _e8, _e9, _ea, _eb, _ec, _ed, _ee, _ef, + _f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _fa, _fb, _fc, _fd, _fe, _ff, + // zig fmt: on +}; + +const Extern0 = extern struct { val: PackedStruct }; +const Extern1 = extern struct { val: PackedUnion }; +const Extern2 = extern struct { val: Enum }; + +comptime { + _ = @as(Extern0, undefined); +} +comptime { + _ = @as(Extern1, undefined); +} +comptime { + _ = @as(Extern2, undefined); +} + +// error +// +// :26:38: error: extern structs cannot contain fields of type 'tmp.PackedStruct' +// :26:38: note: inferred backing integer of packed struct has unspecified signedness +// :1:29: note: struct declared here +// :27:38: error: extern structs cannot contain fields of type 'tmp.PackedUnion' +// :27:38: note: inferred backing integer of packed union has unspecified signedness +// :2:28: note: union declared here +// :28:38: error: extern structs cannot contain fields of type 'tmp.Enum' +// :5:14: note: integer tag type of enum is inferred +// :5:14: note: consider explicitly specifying the integer tag type +// :5:14: note: enum declared here diff --git a/test/cases/compile_errors/packed_struct_uses_own_size.zig b/test/cases/compile_errors/packed_struct_uses_own_size.zig new file mode 100644 index 0000000000..7d5a7613df --- /dev/null +++ b/test/cases/compile_errors/packed_struct_uses_own_size.zig @@ -0,0 +1,10 @@ +const S = packed struct { + x: @Int(.unsigned, @sizeOf(S)), +}; +comptime { + _ = @as(S, undefined); +} + +// error +// +// :2:32: error: type 'tmp.S' depends on itself for size query here diff --git a/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig b/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig new file mode 100644 index 0000000000..6a1fe41eb9 --- /dev/null +++ b/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig @@ -0,0 +1,13 @@ +const S = packed struct(u16) { + a: bool, + b: bool, + _padding: @Int(.unsigned, 17 - @typeInfo(S).Struct.fields.len) = 0, +}; + +comptime { + _ = @as(S, .{ .a = true, .b = true }); +} + +// error +// +// :4:36: error: type 'tmp.S' depends on itself for type information query here diff --git a/test/cases/compile_errors/simple_struct_loop.zig b/test/cases/compile_errors/simple_struct_loop.zig new file mode 100644 index 0000000000..3ae0b2ed82 --- /dev/null +++ b/test/cases/compile_errors/simple_struct_loop.zig @@ -0,0 +1,16 @@ +const A = struct { + b: B, +}; +const B = struct { + a: A, +}; +comptime { + _ = @as(A, undefined); +} + +// error +// +// error: dependency loop with length 2 +// :2:8: note: type 'tmp.A' depends on type 'tmp.B' for field declared here +// :5:8: note: type 'tmp.B' depends on type 'tmp.A' for field declared here +// note: eliminate any one of these dependencies to break the loop diff --git a/test/cases/compile_errors/sizeOf_bad_type.zig b/test/cases/compile_errors/sizeOf_bad_type.zig index 6d20251064..08ce7f4358 100644 --- a/test/cases/compile_errors/sizeOf_bad_type.zig +++ b/test/cases/compile_errors/sizeOf_bad_type.zig @@ -15,6 +15,9 @@ const S4 = struct { a: u32, b: noreturn }; export fn entry4() usize { return @sizeOf(S4); } +export fn entry5() usize { + return @sizeOf([1]fn () void); +} // error // @@ -25,3 +28,4 @@ export fn entry4() usize { // :10:12: note: struct declared here // :16:20: error: no size available for uninstantiable type 'tmp.S4' // :14:12: note: struct declared here +// :19:20: error: no size available for comptime-only type '[1]fn () void' diff --git a/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig b/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig new file mode 100644 index 0000000000..593b440149 --- /dev/null +++ b/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig @@ -0,0 +1,14 @@ +const Foo = packed struct { + bar: (T: { + _ = @hasField(Foo, "bar"); + break :T void; + }), +}; + +comptime { + _ = @as(Foo, undefined); +} + +// error +// +// :3:23: error: type 'tmp.Foo' depends on itself for field query here diff --git a/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig b/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig new file mode 100644 index 0000000000..f3f7361de7 --- /dev/null +++ b/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig @@ -0,0 +1,13 @@ +const A = struct { b: *B }; +const B = @Struct(.auto, null, &.{"x"}, &.{A}, &.{.{ .@"align" = @alignOf(A) }}); +comptime { + _ = @as(A, undefined); + _ = @as(B, undefined); +} + +// error +// +// error: dependency loop with length 2 +// :1:24: note: type 'tmp.A' uses value of declaration 'tmp.B' here +// :2:75: note: value of declaration 'tmp.B' depends on type 'tmp.A' for alignment query here +// note: eliminate any one of these dependencies to break the loop diff --git a/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig b/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig new file mode 100644 index 0000000000..a8e0183465 --- /dev/null +++ b/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig @@ -0,0 +1,10 @@ +const S = struct { + a: *[@sizeOf(S)]u8, +}; +comptime { + _ = @as(S, undefined); +} + +// error +// +// :2:18: error: type 'tmp.S' depends on itself for size query here