| author | |
| committer | |
| log | 5d8fec3d4cdfa58b54756c4368bdb3e76d21380f |
| tree | bf300a4a12b43ca4f9487193cc3fb6b0b15e4b90 |
| parent | 6acd903a9510d0e145b7bba3a9d42d4b9c07cc34 |
| parent | 5e39ab460073b0068d30a74488abf83333761c8d |
19 files changed, 651 insertions(+), 169 deletions(-)
.builds/freebsd.yml+2-2| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | image: freebsd/latest | 1 | image: freebsd/latest |
| 2 | secrets: | 2 | secrets: |
| 3 | - 6c60aaee-92e7-4e7d-812c-114817689b4d | 3 | - 51bfddf5-86a6-4e01-8576-358c72a4a0a4 |
| 4 | - dd0bd962-7664-4d3e-b0f3-41c9ee96b8b8 | 4 | - 5cfede76-914e-4071-893e-e5e2e6ae3cea |
| 5 | sources: | 5 | sources: |
| 6 | - https://github.com/ziglang/zig | 6 | - https://github.com/ziglang/zig |
| 7 | tasks: | 7 | tasks: |
ci/srht/freebsd_script+4-6| ... | @@ -28,11 +28,8 @@ make $JOBS install | ... | @@ -28,11 +28,8 @@ make $JOBS install |
| 28 | 28 | ||
| 29 | release/bin/zig build test-fmt | 29 | release/bin/zig build test-fmt |
| 30 | release/bin/zig build test-behavior | 30 | release/bin/zig build test-behavior |
| 31 | 31 | # TODO get these tests passing on freebsd and re-enable | |
| 32 | # This test is disabled because it triggers "out of memory" on the sr.ht CI service. | 32 | #release/bin/zig build test-std |
| 33 | # See https://github.com/ziglang/zig/issues/3210 | ||
| 34 | # release/bin/zig build test-std | ||
| 35 | |||
| 36 | release/bin/zig build test-compiler-rt | 33 | release/bin/zig build test-compiler-rt |
| 37 | release/bin/zig build test-compare-output | 34 | release/bin/zig build test-compare-output |
| 38 | release/bin/zig build test-standalone | 35 | release/bin/zig build test-standalone |
| ... | @@ -44,7 +41,8 @@ release/bin/zig build test-translate-c | ... | @@ -44,7 +41,8 @@ release/bin/zig build test-translate-c |
| 44 | release/bin/zig build test-run-translated-c | 41 | release/bin/zig build test-run-translated-c |
| 45 | # TODO disabled until we are shipping self-hosted | 42 | # TODO disabled until we are shipping self-hosted |
| 46 | #release/bin/zig build test-gen-h | 43 | #release/bin/zig build test-gen-h |
| 47 | release/bin/zig build test-compile-errors | 44 | # TODO disabled to save time and hit that 45 minute limit |
| 45 | #release/bin/zig build test-compile-errors | ||
| 48 | release/bin/zig build docs | 46 | release/bin/zig build docs |
| 49 | 47 | ||
| 50 | if [ -f ~/.s3cfg ]; then | 48 | if [ -f ~/.s3cfg ]; then |
ci/srht/on_master_success+1-1| ... | @@ -36,4 +36,4 @@ jq <$YML_FILE -sR '{ | ... | @@ -36,4 +36,4 @@ jq <$YML_FILE -sR '{ |
| 36 | -H Authorization:"token $OAUTH_TOKEN" \ | 36 | -H Authorization:"token $OAUTH_TOKEN" \ |
| 37 | -H Content-Type:application/json \ | 37 | -H Content-Type:application/json \ |
| 38 | -X POST \ | 38 | -X POST \ |
| 39 | -d @- "https://builds.sr.ht/api/jobs" | 39 | -d @- "https://builds.hut.lavatech.top/api/jobs" |
lib/std/builtin.zig-1| ... | @@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) { | ... | @@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) { |
| 317 | /// therefore must be kept in sync with the compiler implementation. | 317 | /// therefore must be kept in sync with the compiler implementation. |
| 318 | pub const UnionField = struct { | 318 | pub const UnionField = struct { |
| 319 | name: []const u8, | 319 | name: []const u8, |
| 320 | enum_field: ?EnumField, | ||
| 321 | field_type: type, | 320 | field_type: type, |
| 322 | }; | 321 | }; |
| 323 | 322 |
lib/std/fmt.zig+1-1| ... | @@ -399,7 +399,7 @@ pub fn formatType( | ... | @@ -399,7 +399,7 @@ pub fn formatType( |
| 399 | try writer.writeAll(@tagName(@as(UnionTagType, value))); | 399 | try writer.writeAll(@tagName(@as(UnionTagType, value))); |
| 400 | try writer.writeAll(" = "); | 400 | try writer.writeAll(" = "); |
| 401 | inline for (info.fields) |u_field| { | 401 | inline for (info.fields) |u_field| { |
| 402 | if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { | 402 | if (value == @field(UnionTagType, u_field.name)) { |
| 403 | try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); | 403 | try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); |
| 404 | } | 404 | } |
| 405 | } | 405 | } |
lib/std/hash/auto_hash.zig+2-3| ... | @@ -139,9 +139,8 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -139,9 +139,8 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 139 | const tag = meta.activeTag(key); | 139 | const tag = meta.activeTag(key); |
| 140 | const s = hash(hasher, tag, strat); | 140 | const s = hash(hasher, tag, strat); |
| 141 | inline for (info.fields) |field| { | 141 | inline for (info.fields) |field| { |
| 142 | const enum_field = field.enum_field.?; | 142 | if (@field(tag_type, field.name) == tag) { |
| 143 | if (enum_field.value == @enumToInt(tag)) { | 143 | hash(hasher, @field(key, field.name), strat); |
| 144 | hash(hasher, @field(key, enum_field.name), strat); | ||
| 145 | // TODO use a labelled break when it does not crash the compiler. cf #2908 | 144 | // TODO use a labelled break when it does not crash the compiler. cf #2908 |
| 146 | // break :blk; | 145 | // break :blk; |
| 147 | return; | 146 | return; |
lib/std/hash/crc.zig+1-4| ... | @@ -71,10 +71,7 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type { | ... | @@ -71,10 +71,7 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type { |
| 71 | const p = input[i .. i + 8]; | 71 | const p = input[i .. i + 8]; |
| 72 | 72 | ||
| 73 | // Unrolling this way gives ~50Mb/s increase | 73 | // Unrolling this way gives ~50Mb/s increase |
| 74 | self.crc ^= (@as(u32, p[0]) << 0); | 74 | self.crc ^= std.mem.readIntLittle(u32, p[0..4]); |
| 75 | self.crc ^= (@as(u32, p[1]) << 8); | ||
| 76 | self.crc ^= (@as(u32, p[2]) << 16); | ||
| 77 | self.crc ^= (@as(u32, p[3]) << 24); | ||
| 78 | 75 | ||
| 79 | self.crc = | 76 | self.crc = |
| 80 | lookup_tables[0][p[7]] ^ | 77 | lookup_tables[0][p[7]] ^ |
lib/std/io/serialization.zig+2-2| ... | @@ -156,7 +156,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, | ... | @@ -156,7 +156,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, |
| 156 | const tag = try self.deserializeInt(TagInt); | 156 | const tag = try self.deserializeInt(TagInt); |
| 157 | 157 | ||
| 158 | inline for (info.fields) |field_info| { | 158 | inline for (info.fields) |field_info| { |
| 159 | if (field_info.enum_field.?.value == tag) { | 159 | if (@enumToInt(@field(TagType, field_info.name)) == tag) { |
| 160 | const name = field_info.name; | 160 | const name = field_info.name; |
| 161 | const FieldType = field_info.field_type; | 161 | const FieldType = field_info.field_type; |
| 162 | ptr.* = @unionInit(C, name, undefined); | 162 | ptr.* = @unionInit(C, name, undefined); |
| ... | @@ -320,7 +320,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co | ... | @@ -320,7 +320,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co |
| 320 | // value, but @field requires a comptime value. Our alternative | 320 | // value, but @field requires a comptime value. Our alternative |
| 321 | // is to check each field for a match | 321 | // is to check each field for a match |
| 322 | inline for (info.fields) |field_info| { | 322 | inline for (info.fields) |field_info| { |
| 323 | if (field_info.enum_field.?.value == @enumToInt(active_tag)) { | 323 | if (@field(TagType, field_info.name) == active_tag) { |
| 324 | const name = field_info.name; | 324 | const name = field_info.name; |
| 325 | const FieldType = field_info.field_type; | 325 | const FieldType = field_info.field_type; |
| 326 | try self.serialize(@field(value, name)); | 326 | try self.serialize(@field(value, name)); |
lib/std/json.zig+2-2| ... | @@ -1613,7 +1613,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { | ... | @@ -1613,7 +1613,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { |
| 1613 | .Union => |unionInfo| { | 1613 | .Union => |unionInfo| { |
| 1614 | if (unionInfo.tag_type) |UnionTagType| { | 1614 | if (unionInfo.tag_type) |UnionTagType| { |
| 1615 | inline for (unionInfo.fields) |u_field| { | 1615 | inline for (unionInfo.fields) |u_field| { |
| 1616 | if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { | 1616 | if (value == @field(UnionTagType, u_field.name)) { |
| 1617 | parseFree(u_field.field_type, @field(value, u_field.name), options); | 1617 | parseFree(u_field.field_type, @field(value, u_field.name), options); |
| 1618 | break; | 1618 | break; |
| 1619 | } | 1619 | } |
| ... | @@ -2458,7 +2458,7 @@ pub fn stringify( | ... | @@ -2458,7 +2458,7 @@ pub fn stringify( |
| 2458 | const info = @typeInfo(T).Union; | 2458 | const info = @typeInfo(T).Union; |
| 2459 | if (info.tag_type) |UnionTagType| { | 2459 | if (info.tag_type) |UnionTagType| { |
| 2460 | inline for (info.fields) |u_field| { | 2460 | inline for (info.fields) |u_field| { |
| 2461 | if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { | 2461 | if (value == @field(UnionTagType, u_field.name)) { |
| 2462 | return try stringify(@field(value, u_field.name), options, out_stream); | 2462 | return try stringify(@field(value, u_field.name), options, out_stream); |
| 2463 | } | 2463 | } |
| 2464 | } | 2464 | } |
lib/std/meta.zig+7-5| ... | @@ -465,10 +465,13 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type { | ... | @@ -465,10 +465,13 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type { |
| 465 | testing.expect(trait.is(.Union)(U)); | 465 | testing.expect(trait.is(.Union)(U)); |
| 466 | 466 | ||
| 467 | const info = @typeInfo(U).Union; | 467 | const info = @typeInfo(U).Union; |
| 468 | const tag_info = @typeInfo(@TagType(U)).Enum; | ||
| 468 | 469 | ||
| 469 | inline for (info.fields) |field_info| { | 470 | inline for (info.fields) |field_info| { |
| 470 | if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type; | 471 | if (comptime mem.eql(u8, field_info.name, @tagName(tag))) |
| 472 | return field_info.field_type; | ||
| 471 | } | 473 | } |
| 474 | |||
| 472 | unreachable; | 475 | unreachable; |
| 473 | } | 476 | } |
| 474 | 477 | ||
| ... | @@ -504,15 +507,14 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { | ... | @@ -504,15 +507,14 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { |
| 504 | } | 507 | } |
| 505 | }, | 508 | }, |
| 506 | .Union => |info| { | 509 | .Union => |info| { |
| 507 | if (info.tag_type) |_| { | 510 | if (info.tag_type) |Tag| { |
| 508 | const tag_a = activeTag(a); | 511 | const tag_a = activeTag(a); |
| 509 | const tag_b = activeTag(b); | 512 | const tag_b = activeTag(b); |
| 510 | if (tag_a != tag_b) return false; | 513 | if (tag_a != tag_b) return false; |
| 511 | 514 | ||
| 512 | inline for (info.fields) |field_info| { | 515 | inline for (info.fields) |field_info| { |
| 513 | const enum_field = field_info.enum_field.?; | 516 | if (@field(Tag, field_info.name) == tag_a) { |
| 514 | if (enum_field.value == @enumToInt(tag_a)) { | 517 | return eql(@field(a, field_info.name), @field(b, field_info.name)); |
| 515 | return eql(@field(a, enum_field.name), @field(b, enum_field.name)); | ||
| 516 | } | 518 | } |
| 517 | } | 519 | } |
| 518 | return false; | 520 | return false; |
lib/std/os.zig+9-1| ... | @@ -320,6 +320,7 @@ pub const ReadError = error{ | ... | @@ -320,6 +320,7 @@ pub const ReadError = error{ |
| 320 | /// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000` | 320 | /// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000` |
| 321 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as | 321 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as |
| 322 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page. | 322 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page. |
| 323 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. | ||
| 323 | /// For POSIX the limit is `math.maxInt(isize)`. | 324 | /// For POSIX the limit is `math.maxInt(isize)`. |
| 324 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | 325 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 325 | if (builtin.os.tag == .windows) { | 326 | if (builtin.os.tag == .windows) { |
| ... | @@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 353 | // Prevents EINVAL. | 354 | // Prevents EINVAL. |
| 354 | const max_count = switch (std.Target.current.os.tag) { | 355 | const max_count = switch (std.Target.current.os.tag) { |
| 355 | .linux => 0x7ffff000, | 356 | .linux => 0x7ffff000, |
| 357 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | ||
| 356 | else => math.maxInt(isize), | 358 | else => math.maxInt(isize), |
| 357 | }; | 359 | }; |
| 358 | const adjusted_len = math.min(max_count, buf.len); | 360 | const adjusted_len = math.min(max_count, buf.len); |
| ... | @@ -693,6 +695,7 @@ pub const WriteError = error{ | ... | @@ -693,6 +695,7 @@ pub const WriteError = error{ |
| 693 | /// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000` | 695 | /// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000` |
| 694 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as | 696 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as |
| 695 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. | 697 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. |
| 698 | /// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. | ||
| 696 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 699 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 697 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { | 700 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 698 | if (builtin.os.tag == .windows) { | 701 | if (builtin.os.tag == .windows) { |
| ... | @@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { | ... | @@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 726 | 729 | ||
| 727 | const max_count = switch (std.Target.current.os.tag) { | 730 | const max_count = switch (std.Target.current.os.tag) { |
| 728 | .linux => 0x7ffff000, | 731 | .linux => 0x7ffff000, |
| 732 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | ||
| 729 | else => math.maxInt(isize), | 733 | else => math.maxInt(isize), |
| 730 | }; | 734 | }; |
| 731 | const adjusted_len = math.min(max_count, bytes.len); | 735 | const adjusted_len = math.min(max_count, bytes.len); |
| ... | @@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable}; | ... | @@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable}; |
| 851 | /// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000` | 855 | /// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000` |
| 852 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as | 856 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as |
| 853 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. | 857 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. |
| 858 | /// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. | ||
| 854 | /// The corresponding POSIX limit is `math.maxInt(isize)`. | 859 | /// The corresponding POSIX limit is `math.maxInt(isize)`. |
| 855 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { | 860 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 856 | if (std.Target.current.os.tag == .windows) { | 861 | if (std.Target.current.os.tag == .windows) { |
| ... | @@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { | ... | @@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 888 | // Prevent EINVAL. | 893 | // Prevent EINVAL. |
| 889 | const max_count = switch (std.Target.current.os.tag) { | 894 | const max_count = switch (std.Target.current.os.tag) { |
| 890 | .linux => 0x7ffff000, | 895 | .linux => 0x7ffff000, |
| 896 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | ||
| 891 | else => math.maxInt(isize), | 897 | else => math.maxInt(isize), |
| 892 | }; | 898 | }; |
| 893 | const adjusted_len = math.min(max_count, bytes.len); | 899 | const adjusted_len = math.min(max_count, bytes.len); |
| ... | @@ -3084,7 +3090,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con | ... | @@ -3084,7 +3090,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con |
| 3084 | .WSAECONNREFUSED => return error.ConnectionRefused, | 3090 | .WSAECONNREFUSED => return error.ConnectionRefused, |
| 3085 | .WSAETIMEDOUT => return error.ConnectionTimedOut, | 3091 | .WSAETIMEDOUT => return error.ConnectionTimedOut, |
| 3086 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? | 3092 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? |
| 3087 | , .WSAENETUNREACH => return error.NetworkUnreachable, | 3093 | , .WSAENETUNREACH => return error.NetworkUnreachable, |
| 3088 | .WSAEFAULT => unreachable, | 3094 | .WSAEFAULT => unreachable, |
| 3089 | .WSAEINVAL => unreachable, | 3095 | .WSAEINVAL => unreachable, |
| 3090 | .WSAEISCONN => unreachable, | 3096 | .WSAEISCONN => unreachable, |
| ... | @@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize { | ... | @@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize { |
| 4711 | /// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000` | 4717 | /// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000` |
| 4712 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as | 4718 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as |
| 4713 | /// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page. | 4719 | /// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page. |
| 4720 | /// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. | ||
| 4714 | /// The corresponding POSIX limit on this is `math.maxInt(isize)`. | 4721 | /// The corresponding POSIX limit on this is `math.maxInt(isize)`. |
| 4715 | pub fn sendfile( | 4722 | pub fn sendfile( |
| 4716 | out_fd: fd_t, | 4723 | out_fd: fd_t, |
| ... | @@ -4733,6 +4740,7 @@ pub fn sendfile( | ... | @@ -4733,6 +4740,7 @@ pub fn sendfile( |
| 4733 | }); | 4740 | }); |
| 4734 | const max_count = switch (std.Target.current.os.tag) { | 4741 | const max_count = switch (std.Target.current.os.tag) { |
| 4735 | .linux => 0x7ffff000, | 4742 | .linux => 0x7ffff000, |
| 4743 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | ||
| 4736 | else => math.maxInt(size_t), | 4744 | else => math.maxInt(size_t), |
| 4737 | }; | 4745 | }; |
| 4738 | 4746 |
lib/std/os/linux/bpf.zig+1| ... | @@ -12,6 +12,7 @@ const expectError = std.testing.expectError; | ... | @@ -12,6 +12,7 @@ const expectError = std.testing.expectError; |
| 12 | const expect = std.testing.expect; | 12 | const expect = std.testing.expect; |
| 13 | 13 | ||
| 14 | pub const btf = @import("bpf/btf.zig"); | 14 | pub const btf = @import("bpf/btf.zig"); |
| 15 | pub const kern = @import("bpf/kern.zig"); | ||
| 15 | 16 | ||
| 16 | // instruction classes | 17 | // instruction classes |
| 17 | pub const LD = 0x00; | 18 | pub const LD = 0x00; |
lib/std/os/linux/bpf/helpers.zig created+157| ... | @@ -0,0 +1,157 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | const kern = @import("kern.zig"); | ||
| 7 | |||
| 8 | // in BPF, all the helper calls | ||
| 9 | // TODO: when https://github.com/ziglang/zig/issues/1717 is here, make a nice | ||
| 10 | // function that uses the Helper enum | ||
| 11 | // | ||
| 12 | // Note, these function signatures were created from documentation found in | ||
| 13 | // '/usr/include/linux/bpf.h' | ||
| 14 | pub const map_lookup_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) ?*c_void, 1); | ||
| 15 | pub const map_update_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void, value: ?*const c_void, flags: u64) c_long, 2); | ||
| 16 | pub const map_delete_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) c_long, 3); | ||
| 17 | pub const probe_read = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 4); | ||
| 18 | pub const ktime_get_ns = @intToPtr(fn () u64, 5); | ||
| 19 | pub const trace_printk = @intToPtr(fn (fmt: [*:0]const u8, fmt_size: u32, arg1: u64, arg2: u64, arg3: u64) c_long, 6); | ||
| 20 | pub const get_prandom_u32 = @intToPtr(fn () u32, 7); | ||
| 21 | pub const get_smp_processor_id = @intToPtr(fn () u32, 8); | ||
| 22 | pub const skb_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32, flags: u64) c_long, 9); | ||
| 23 | pub const l3_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, size: u64) c_long, 10); | ||
| 24 | pub const l4_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, flags: u64) c_long, 11); | ||
| 25 | pub const tail_call = @intToPtr(fn (ctx: ?*c_void, prog_array_map: *const kern.MapDef, index: u32) c_long, 12); | ||
| 26 | pub const clone_redirect = @intToPtr(fn (skb: *kern.SkBuff, ifindex: u32, flags: u64) c_long, 13); | ||
| 27 | pub const get_current_pid_tgid = @intToPtr(fn () u64, 14); | ||
| 28 | pub const get_current_uid_gid = @intToPtr(fn () u64, 15); | ||
| 29 | pub const get_current_comm = @intToPtr(fn (buf: ?*c_void, size_of_buf: u32) c_long, 16); | ||
| 30 | pub const get_cgroup_classid = @intToPtr(fn (skb: *kern.SkBuff) u32, 17); | ||
| 31 | // Note vlan_proto is big endian | ||
| 32 | pub const skb_vlan_push = @intToPtr(fn (skb: *kern.SkBuff, vlan_proto: u16, vlan_tci: u16) c_long, 18); | ||
| 33 | pub const skb_vlan_pop = @intToPtr(fn (skb: *kern.SkBuff) c_long, 19); | ||
| 34 | pub const skb_get_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 20); | ||
| 35 | pub const skb_set_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 21); | ||
| 36 | pub const perf_event_read = @intToPtr(fn (map: *const kern.MapDef, flags: u64) u64, 22); | ||
| 37 | pub const redirect = @intToPtr(fn (ifindex: u32, flags: u64) c_long, 23); | ||
| 38 | pub const get_route_realm = @intToPtr(fn (skb: *kern.SkBuff) u32, 24); | ||
| 39 | pub const perf_event_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 25); | ||
| 40 | pub const skb_load_bytes = @intToPtr(fn (skb: ?*c_void, offset: u32, to: ?*c_void, len: u32) c_long, 26); | ||
| 41 | pub const get_stackid = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64) c_long, 27); | ||
| 42 | // from and to point to __be32 | ||
| 43 | pub const csum_diff = @intToPtr(fn (from: *u32, from_size: u32, to: *u32, to_size: u32, seed: u32) i64, 28); | ||
| 44 | pub const skb_get_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 29); | ||
| 45 | pub const skb_set_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 30); | ||
| 46 | // proto is __be16 | ||
| 47 | pub const skb_change_proto = @intToPtr(fn (skb: *kern.SkBuff, proto: u16, flags: u64) c_long, 31); | ||
| 48 | pub const skb_change_type = @intToPtr(fn (skb: *kern.SkBuff, skb_type: u32) c_long, 32); | ||
| 49 | pub const skb_under_cgroup = @intToPtr(fn (skb: *kern.SkBuff, map: ?*const c_void, index: u32) c_long, 33); | ||
| 50 | pub const get_hash_recalc = @intToPtr(fn (skb: *kern.SkBuff) u32, 34); | ||
| 51 | pub const get_current_task = @intToPtr(fn () u64, 35); | ||
| 52 | pub const probe_write_user = @intToPtr(fn (dst: ?*c_void, src: ?*const c_void, len: u32) c_long, 36); | ||
| 53 | pub const current_task_under_cgroup = @intToPtr(fn (map: *const kern.MapDef, index: u32) c_long, 37); | ||
| 54 | pub const skb_change_tail = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 38); | ||
| 55 | pub const skb_pull_data = @intToPtr(fn (skb: *kern.SkBuff, len: u32) c_long, 39); | ||
| 56 | pub const csum_update = @intToPtr(fn (skb: *kern.SkBuff, csum: u32) i64, 40); | ||
| 57 | pub const set_hash_invalid = @intToPtr(fn (skb: *kern.SkBuff) void, 41); | ||
| 58 | pub const get_numa_node_id = @intToPtr(fn () c_long, 42); | ||
| 59 | pub const skb_change_head = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 43); | ||
| 60 | pub const xdp_adjust_head = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 44); | ||
| 61 | pub const probe_read_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 45); | ||
| 62 | pub const get_socket_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 46); | ||
| 63 | pub const get_socket_uid = @intToPtr(fn (skb: *kern.SkBuff) u32, 47); | ||
| 64 | pub const set_hash = @intToPtr(fn (skb: *kern.SkBuff, hash: u32) c_long, 48); | ||
| 65 | pub const setsockopt = @intToPtr(fn (bpf_socket: *kern.SockOps, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 49); | ||
| 66 | pub const skb_adjust_room = @intToPtr(fn (skb: *kern.SkBuff, len_diff: i32, mode: u32, flags: u64) c_long, 50); | ||
| 67 | pub const redirect_map = @intToPtr(fn (map: *const kern.MapDef, key: u32, flags: u64) c_long, 51); | ||
| 68 | pub const sk_redirect_map = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: u32, flags: u64) c_long, 52); | ||
| 69 | pub const sock_map_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 53); | ||
| 70 | pub const xdp_adjust_meta = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 54); | ||
| 71 | pub const perf_event_read_value = @intToPtr(fn (map: *const kern.MapDef, flags: u64, buf: *kern.PerfEventValue, buf_size: u32) c_long, 55); | ||
| 72 | pub const perf_prog_read_value = @intToPtr(fn (ctx: *kern.PerfEventData, buf: *kern.PerfEventValue, buf_size: u32) c_long, 56); | ||
| 73 | pub const getsockopt = @intToPtr(fn (bpf_socket: ?*c_void, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 57); | ||
| 74 | pub const override_return = @intToPtr(fn (regs: *PtRegs, rc: u64) c_long, 58); | ||
| 75 | pub const sock_ops_cb_flags_set = @intToPtr(fn (bpf_sock: *kern.SockOps, argval: c_int) c_long, 59); | ||
| 76 | pub const msg_redirect_map = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: u32, flags: u64) c_long, 60); | ||
| 77 | pub const msg_apply_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 61); | ||
| 78 | pub const msg_cork_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 62); | ||
| 79 | pub const msg_pull_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, end: u32, flags: u64) c_long, 63); | ||
| 80 | pub const bind = @intToPtr(fn (ctx: *kern.BpfSockAddr, addr: *kern.SockAddr, addr_len: c_int) c_long, 64); | ||
| 81 | pub const xdp_adjust_tail = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 65); | ||
| 82 | pub const skb_get_xfrm_state = @intToPtr(fn (skb: *kern.SkBuff, index: u32, xfrm_state: *kern.XfrmState, size: u32, flags: u64) c_long, 66); | ||
| 83 | pub const get_stack = @intToPtr(fn (ctx: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 67); | ||
| 84 | pub const skb_load_bytes_relative = @intToPtr(fn (skb: ?*const c_void, offset: u32, to: ?*c_void, len: u32, start_header: u32) c_long, 68); | ||
| 85 | pub const fib_lookup = @intToPtr(fn (ctx: ?*c_void, params: *kern.FibLookup, plen: c_int, flags: u32) c_long, 69); | ||
| 86 | pub const sock_hash_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 70); | ||
| 87 | pub const msg_redirect_hash = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 71); | ||
| 88 | pub const sk_redirect_hash = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 72); | ||
| 89 | pub const lwt_push_encap = @intToPtr(fn (skb: *kern.SkBuff, typ: u32, hdr: ?*c_void, len: u32) c_long, 73); | ||
| 90 | pub const lwt_seg6_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32) c_long, 74); | ||
| 91 | pub const lwt_seg6_adjust_srh = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, delta: i32) c_long, 75); | ||
| 92 | pub const lwt_seg6_action = @intToPtr(fn (skb: *kern.SkBuff, action: u32, param: ?*c_void, param_len: u32) c_long, 76); | ||
| 93 | pub const rc_repeat = @intToPtr(fn (ctx: ?*c_void) c_long, 77); | ||
| 94 | pub const rc_keydown = @intToPtr(fn (ctx: ?*c_void, protocol: u32, scancode: u64, toggle: u32) c_long, 78); | ||
| 95 | pub const skb_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff) u64, 79); | ||
| 96 | pub const get_current_cgroup_id = @intToPtr(fn () u64, 80); | ||
| 97 | pub const get_local_storage = @intToPtr(fn (map: ?*c_void, flags: u64) ?*c_void, 81); | ||
| 98 | pub const sk_select_reuseport = @intToPtr(fn (reuse: *kern.SkReusePortMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 82); | ||
| 99 | pub const skb_ancestor_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff, ancestor_level: c_int) u64, 83); | ||
| 100 | pub const sk_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 84); | ||
| 101 | pub const sk_lookup_udp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 85); | ||
| 102 | pub const sk_release = @intToPtr(fn (sock: *kern.Sock) c_long, 86); | ||
| 103 | pub const map_push_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*const c_void, flags: u64) c_long, 87); | ||
| 104 | pub const map_pop_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 88); | ||
| 105 | pub const map_peek_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 89); | ||
| 106 | pub const msg_push_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 90); | ||
| 107 | pub const msg_pop_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 91); | ||
| 108 | pub const rc_pointer_rel = @intToPtr(fn (ctx: ?*c_void, rel_x: i32, rel_y: i32) c_long, 92); | ||
| 109 | pub const spin_lock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 93); | ||
| 110 | pub const spin_unlock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 94); | ||
| 111 | pub const sk_fullsock = @intToPtr(fn (sk: *kern.Sock) ?*SkFullSock, 95); | ||
| 112 | pub const tcp_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.TcpSock, 96); | ||
| 113 | pub const skb_ecn_set_ce = @intToPtr(fn (skb: *kern.SkBuff) c_long, 97); | ||
| 114 | pub const get_listener_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.Sock, 98); | ||
| 115 | pub const skc_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 99); | ||
| 116 | pub const tcp_check_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) c_long, 100); | ||
| 117 | pub const sysctl_get_name = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong, flags: u64) c_long, 101); | ||
| 118 | pub const sysctl_get_current_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 102); | ||
| 119 | pub const sysctl_get_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 103); | ||
| 120 | pub const sysctl_set_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*const u8, buf_len: c_ulong) c_long, 104); | ||
| 121 | pub const strtol = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_long) c_long, 105); | ||
| 122 | pub const strtoul = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_ulong) c_long, 106); | ||
| 123 | pub const sk_storage_get = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock, value: ?*c_void, flags: u64) ?*c_void, 107); | ||
| 124 | pub const sk_storage_delete = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock) c_long, 108); | ||
| 125 | pub const send_signal = @intToPtr(fn (sig: u32) c_long, 109); | ||
| 126 | pub const tcp_gen_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) i64, 110); | ||
| 127 | pub const skb_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 111); | ||
| 128 | pub const probe_read_user = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 112); | ||
| 129 | pub const probe_read_kernel = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 113); | ||
| 130 | pub const probe_read_user_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 114); | ||
| 131 | pub const probe_read_kernel_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 115); | ||
| 132 | pub const tcp_send_ack = @intToPtr(fn (tp: ?*c_void, rcv_nxt: u32) c_long, 116); | ||
| 133 | pub const send_signal_thread = @intToPtr(fn (sig: u32) c_long, 117); | ||
| 134 | pub const jiffies64 = @intToPtr(fn () u64, 118); | ||
| 135 | pub const read_branch_records = @intToPtr(fn (ctx: *kern.PerfEventData, buf: ?*c_void, size: u32, flags: u64) c_long, 119); | ||
| 136 | pub const get_ns_current_pid_tgid = @intToPtr(fn (dev: u64, ino: u64, nsdata: *kern.PidNsInfo, size: u32) c_long, 120); | ||
| 137 | pub const xdp_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 121); | ||
| 138 | pub const get_netns_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 122); | ||
| 139 | pub const get_current_ancestor_cgroup_id = @intToPtr(fn (ancestor_level: c_int) u64, 123); | ||
| 140 | pub const sk_assign = @intToPtr(fn (skb: *kern.SkBuff, sk: *kern.Sock, flags: u64) c_long, 124); | ||
| 141 | pub const ktime_get_boot_ns = @intToPtr(fn () u64, 125); | ||
| 142 | pub const seq_printf = @intToPtr(fn (m: *kern.SeqFile, fmt: ?*const u8, fmt_size: u32, data: ?*const c_void, data_len: u32) c_long, 126); | ||
| 143 | pub const seq_write = @intToPtr(fn (m: *kern.SeqFile, data: ?*const u8, len: u32) c_long, 127); | ||
| 144 | pub const sk_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock) u64, 128); | ||
| 145 | pub const sk_ancestor_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock, ancestor_level: c_long) u64, 129); | ||
| 146 | pub const ringbuf_output = @intToPtr(fn (ringbuf: ?*c_void, data: ?*c_void, size: u64, flags: u64) ?*c_void, 130); | ||
| 147 | pub const ringbuf_reserve = @intToPtr(fn (ringbuf: ?*c_void, size: u64, flags: u64) ?*c_void, 131); | ||
| 148 | pub const ringbuf_submit = @intToPtr(fn (data: ?*c_void, flags: u64) void, 132); | ||
| 149 | pub const ringbuf_discard = @intToPtr(fn (data: ?*c_void, flags: u64) void, 133); | ||
| 150 | pub const ringbuf_query = @intToPtr(fn (ringbuf: ?*c_void, flags: u64) u64, 134); | ||
| 151 | pub const csum_level = @intToPtr(fn (skb: *kern.SkBuff, level: u64) c_long, 134); | ||
| 152 | pub const skc_to_tcp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Tcp6Sock, 135); | ||
| 153 | pub const skc_to_tcp_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpSock, 136); | ||
| 154 | pub const skc_to_tcp_timewait_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpTimewaitSock, 137); | ||
| 155 | pub const skc_to_tcp_request_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpRequestSock, 138); | ||
| 156 | pub const skc_to_udp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Udp6Sock, 139); | ||
| 157 | pub const get_task_stack = @intToPtr(fn (task: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 140); | ||
lib/std/os/linux/bpf/kern.zig created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2020 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | const std = @import("../../../std.zig"); | ||
| 7 | |||
| 8 | const in_bpf_program = switch (std.builtin.arch) { | ||
| 9 | .bpfel, .bpfeb => true, | ||
| 10 | else => false, | ||
| 11 | }; | ||
| 12 | |||
| 13 | pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {}; | ||
| 14 | |||
| 15 | pub const BpfSock = @Type(.Opaque); | ||
| 16 | pub const BpfSockAddr = @Type(.Opaque); | ||
| 17 | pub const FibLookup = @Type(.Opaque); | ||
| 18 | pub const MapDef = @Type(.Opaque); | ||
| 19 | pub const PerfEventData = @Type(.Opaque); | ||
| 20 | pub const PerfEventValue = @Type(.Opaque); | ||
| 21 | pub const PidNsInfo = @Type(.Opaque); | ||
| 22 | pub const SeqFile = @Type(.Opaque); | ||
| 23 | pub const SkBuff = @Type(.Opaque); | ||
| 24 | pub const SkMsgMd = @Type(.Opaque); | ||
| 25 | pub const SkReusePortMd = @Type(.Opaque); | ||
| 26 | pub const Sock = @Type(.Opaque); | ||
| 27 | pub const SockAddr = @Type(.Opaque); | ||
| 28 | pub const SockOps = @Type(.Opaque); | ||
| 29 | pub const SockTuple = @Type(.Opaque); | ||
| 30 | pub const SpinLock = @Type(.Opaque); | ||
| 31 | pub const SysCtl = @Type(.Opaque); | ||
| 32 | pub const Tcp6Sock = @Type(.Opaque); | ||
| 33 | pub const TcpRequestSock = @Type(.Opaque); | ||
| 34 | pub const TcpSock = @Type(.Opaque); | ||
| 35 | pub const TcpTimewaitSock = @Type(.Opaque); | ||
| 36 | pub const TunnelKey = @Type(.Opaque); | ||
| 37 | pub const Udp6Sock = @Type(.Opaque); | ||
| 38 | pub const XdpMd = @Type(.Opaque); | ||
| 39 | pub const XfrmState = @Type(.Opaque); | ||
src/analyze.cpp+147-116| ... | @@ -2379,7 +2379,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { | ... | @@ -2379,7 +2379,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 2379 | if (field->gen_index == UINT32_MAX) | 2379 | if (field->gen_index == UINT32_MAX) |
| 2380 | continue; | 2380 | continue; |
| 2381 | 2381 | ||
| 2382 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; | 2382 | AstNode *align_expr = nullptr; |
| 2383 | if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) { | ||
| 2384 | align_expr = field->decl_node->data.struct_field.align_expr; | ||
| 2385 | } | ||
| 2383 | if (align_expr != nullptr) { | 2386 | if (align_expr != nullptr) { |
| 2384 | if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, | 2387 | if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, |
| 2385 | &field->align)) | 2388 | &field->align)) |
| ... | @@ -2475,9 +2478,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { | ... | @@ -2475,9 +2478,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 2475 | 2478 | ||
| 2476 | AstNode *decl_node = union_type->data.unionation.decl_node; | 2479 | AstNode *decl_node = union_type->data.unionation.decl_node; |
| 2477 | 2480 | ||
| 2478 | |||
| 2479 | assert(decl_node->type == NodeTypeContainerDecl); | ||
| 2480 | |||
| 2481 | uint32_t field_count = union_type->data.unionation.src_field_count; | 2481 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 2482 | TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; | 2482 | TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; |
| 2483 | 2483 | ||
| ... | @@ -2610,16 +2610,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -2610,16 +2610,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2610 | if (decl_node->type == NodeTypeContainerDecl) { | 2610 | if (decl_node->type == NodeTypeContainerDecl) { |
| 2611 | assert(!enum_type->data.enumeration.fields); | 2611 | assert(!enum_type->data.enumeration.fields); |
| 2612 | field_count = (uint32_t)decl_node->data.container_decl.fields.length; | 2612 | field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| 2613 | if (field_count == 0) { | ||
| 2614 | add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); | ||
| 2615 | |||
| 2616 | enum_type->data.enumeration.src_field_count = field_count; | ||
| 2617 | enum_type->data.enumeration.fields = nullptr; | ||
| 2618 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | ||
| 2619 | return ErrorSemanticAnalyzeFail; | ||
| 2620 | } | ||
| 2621 | } else { | 2613 | } else { |
| 2622 | field_count = enum_type->data.enumeration.src_field_count; | 2614 | field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive; |
| 2615 | } | ||
| 2616 | |||
| 2617 | if (field_count == 0) { | ||
| 2618 | add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); | ||
| 2619 | enum_type->data.enumeration.src_field_count = field_count; | ||
| 2620 | enum_type->data.enumeration.fields = nullptr; | ||
| 2621 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | ||
| 2622 | return ErrorSemanticAnalyzeFail; | ||
| 2623 | } | 2623 | } |
| 2624 | 2624 | ||
| 2625 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; | 2625 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; |
| ... | @@ -3062,7 +3062,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3062,7 +3062,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3062 | return ErrorNone; | 3062 | return ErrorNone; |
| 3063 | 3063 | ||
| 3064 | AstNode *decl_node = union_type->data.unionation.decl_node; | 3064 | AstNode *decl_node = union_type->data.unionation.decl_node; |
| 3065 | assert(decl_node->type == NodeTypeContainerDecl); | ||
| 3066 | 3065 | ||
| 3067 | if (union_type->data.unionation.resolve_loop_flag_zero_bits) { | 3066 | if (union_type->data.unionation.resolve_loop_flag_zero_bits) { |
| 3068 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { | 3067 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { |
| ... | @@ -3076,30 +3075,51 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3076,30 +3075,51 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3076 | 3075 | ||
| 3077 | union_type->data.unionation.resolve_loop_flag_zero_bits = true; | 3076 | union_type->data.unionation.resolve_loop_flag_zero_bits = true; |
| 3078 | 3077 | ||
| 3079 | assert(union_type->data.unionation.fields == nullptr); | 3078 | uint32_t field_count; |
| 3080 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | 3079 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3080 | assert(union_type->data.unionation.fields == nullptr); | ||
| 3081 | field_count = (uint32_t)decl_node->data.container_decl.fields.length; | ||
| 3082 | union_type->data.unionation.src_field_count = field_count; | ||
| 3083 | union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count); | ||
| 3084 | union_type->data.unionation.fields_by_name.init(field_count); | ||
| 3085 | } else { | ||
| 3086 | field_count = union_type->data.unionation.src_field_count; | ||
| 3087 | assert(field_count == 0 || union_type->data.unionation.fields != nullptr); | ||
| 3088 | } | ||
| 3089 | |||
| 3081 | if (field_count == 0) { | 3090 | if (field_count == 0) { |
| 3082 | add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); | 3091 | add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); |
| 3083 | union_type->data.unionation.src_field_count = field_count; | 3092 | union_type->data.unionation.src_field_count = field_count; |
| 3084 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3093 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3085 | return ErrorSemanticAnalyzeFail; | 3094 | return ErrorSemanticAnalyzeFail; |
| 3086 | } | 3095 | } |
| 3087 | union_type->data.unionation.src_field_count = field_count; | ||
| 3088 | union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count); | ||
| 3089 | union_type->data.unionation.fields_by_name.init(field_count); | ||
| 3090 | 3096 | ||
| 3091 | Scope *scope = &union_type->data.unionation.decls_scope->base; | 3097 | Scope *scope = &union_type->data.unionation.decls_scope->base; |
| 3092 | 3098 | ||
| 3093 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {}; | 3099 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {}; |
| 3094 | 3100 | ||
| 3095 | AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr; | 3101 | bool is_auto_enum; // union(enum) or union(enum(expr)) |
| 3096 | union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum || | 3102 | bool is_explicit_enum; // union(expr) |
| 3097 | enum_type_node != nullptr; | 3103 | AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr) |
| 3098 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | 3104 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3099 | bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); | 3105 | is_auto_enum = decl_node->data.container_decl.auto_enum; |
| 3106 | is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr; | ||
| 3107 | enum_type_node = decl_node->data.container_decl.init_arg_expr; | ||
| 3108 | } else { | ||
| 3109 | is_auto_enum = false; | ||
| 3110 | is_explicit_enum = union_type->data.unionation.tag_type != nullptr; | ||
| 3111 | enum_type_node = nullptr; | ||
| 3112 | } | ||
| 3113 | union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum; | ||
| 3114 | |||
| 3115 | bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto; | ||
| 3116 | bool want_safety = (field_count >= 2) | ||
| 3117 | && (is_auto_layout || is_explicit_enum) | ||
| 3118 | && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); | ||
| 3100 | ZigType *tag_type; | 3119 | ZigType *tag_type; |
| 3101 | bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); | 3120 | bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety); |
| 3102 | bool *covered_enum_fields; | 3121 | bool *covered_enum_fields; |
| 3122 | bool *is_zero_bits = heap::c_allocator.allocate<bool>(field_count); | ||
| 3103 | ZigLLVMDIEnumerator **di_enumerators; | 3123 | ZigLLVMDIEnumerator **di_enumerators; |
| 3104 | if (create_enum_type) { | 3124 | if (create_enum_type) { |
| 3105 | occupied_tag_values.init(field_count); | 3125 | occupied_tag_values.init(field_count); |
| ... | @@ -3157,71 +3177,81 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3157,71 +3177,81 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3157 | return err; | 3177 | return err; |
| 3158 | } | 3178 | } |
| 3159 | tag_type = enum_type; | 3179 | tag_type = enum_type; |
| 3160 | covered_enum_fields = heap::c_allocator.allocate<bool>(enum_type->data.enumeration.src_field_count); | ||
| 3161 | } else { | 3180 | } else { |
| 3162 | tag_type = nullptr; | 3181 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3182 | tag_type = nullptr; | ||
| 3183 | } else { | ||
| 3184 | tag_type = union_type->data.unionation.tag_type; | ||
| 3185 | } | ||
| 3186 | } | ||
| 3187 | if (tag_type != nullptr) { | ||
| 3188 | covered_enum_fields = heap::c_allocator.allocate<bool>(tag_type->data.enumeration.src_field_count); | ||
| 3163 | } | 3189 | } |
| 3164 | union_type->data.unionation.tag_type = tag_type; | 3190 | union_type->data.unionation.tag_type = tag_type; |
| 3165 | 3191 | ||
| 3166 | uint32_t gen_field_index = 0; | ||
| 3167 | for (uint32_t i = 0; i < field_count; i += 1) { | 3192 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 3168 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | ||
| 3169 | Buf *field_name = field_node->data.struct_field.name; | ||
| 3170 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | 3193 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; |
| 3171 | union_field->name = field_node->data.struct_field.name; | 3194 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3172 | union_field->decl_node = field_node; | 3195 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); |
| 3173 | union_field->gen_index = UINT32_MAX; | 3196 | union_field->name = field_node->data.struct_field.name; |
| 3174 | 3197 | union_field->decl_node = field_node; | |
| 3175 | auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); | 3198 | union_field->gen_index = UINT32_MAX; |
| 3176 | if (field_entry != nullptr) { | 3199 | is_zero_bits[i] = false; |
| 3177 | ErrorMsg *msg = add_node_error(g, field_node, | ||
| 3178 | buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); | ||
| 3179 | add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); | ||
| 3180 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | ||
| 3181 | return ErrorSemanticAnalyzeFail; | ||
| 3182 | } | ||
| 3183 | 3200 | ||
| 3184 | bool field_is_zero_bits; | 3201 | auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); |
| 3185 | if (field_node->data.struct_field.type == nullptr) { | 3202 | if (field_entry != nullptr) { |
| 3186 | if (decl_node->data.container_decl.auto_enum || | 3203 | ErrorMsg *msg = add_node_error(g, union_field->decl_node, |
| 3187 | decl_node->data.container_decl.init_arg_expr != nullptr) | 3204 | buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); |
| 3188 | { | 3205 | add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); |
| 3189 | union_field->type_entry = g->builtin_types.entry_void; | ||
| 3190 | field_is_zero_bits = true; | ||
| 3191 | } else { | ||
| 3192 | add_node_error(g, field_node, buf_sprintf("union field missing type")); | ||
| 3193 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3206 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3194 | return ErrorSemanticAnalyzeFail; | 3207 | return ErrorSemanticAnalyzeFail; |
| 3195 | } | 3208 | } |
| 3196 | } else { | 3209 | |
| 3197 | ZigValue *field_type_val = analyze_const_value(g, scope, | 3210 | if (field_node->data.struct_field.type == nullptr) { |
| 3198 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | 3211 | if (is_auto_enum || is_explicit_enum) { |
| 3199 | if (type_is_invalid(field_type_val->type)) { | 3212 | union_field->type_entry = g->builtin_types.entry_void; |
| 3200 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3213 | is_zero_bits[i] = true; |
| 3201 | return ErrorSemanticAnalyzeFail; | 3214 | } else { |
| 3215 | add_node_error(g, field_node, buf_sprintf("union field missing type")); | ||
| 3216 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | ||
| 3217 | return ErrorSemanticAnalyzeFail; | ||
| 3218 | } | ||
| 3219 | } else { | ||
| 3220 | ZigValue *field_type_val = analyze_const_value(g, scope, | ||
| 3221 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | ||
| 3222 | if (type_is_invalid(field_type_val->type)) { | ||
| 3223 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | ||
| 3224 | return ErrorSemanticAnalyzeFail; | ||
| 3225 | } | ||
| 3226 | assert(field_type_val->special != ConstValSpecialRuntime); | ||
| 3227 | union_field->type_val = field_type_val; | ||
| 3202 | } | 3228 | } |
| 3203 | assert(field_type_val->special != ConstValSpecialRuntime); | ||
| 3204 | union_field->type_val = field_type_val; | ||
| 3205 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) | ||
| 3206 | return ErrorSemanticAnalyzeFail; | ||
| 3207 | 3229 | ||
| 3230 | if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { | ||
| 3231 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, | ||
| 3232 | buf_create_from_str("untagged union field assignment")); | ||
| 3233 | add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); | ||
| 3234 | } | ||
| 3235 | } | ||
| 3236 | |||
| 3237 | if (union_field->type_val != nullptr) { | ||
| 3208 | bool field_is_opaque_type; | 3238 | bool field_is_opaque_type; |
| 3209 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { | 3239 | if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) { |
| 3210 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3240 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3211 | return ErrorSemanticAnalyzeFail; | 3241 | return ErrorSemanticAnalyzeFail; |
| 3212 | } | 3242 | } |
| 3213 | if (field_is_opaque_type) { | 3243 | if (field_is_opaque_type) { |
| 3214 | add_node_error(g, field_node, | 3244 | add_node_error(g, union_field->decl_node, |
| 3215 | buf_create_from_str( | 3245 | buf_create_from_str( |
| 3216 | "opaque types have unknown size and therefore cannot be directly embedded in unions")); | 3246 | "opaque types have unknown size and therefore cannot be directly embedded in unions")); |
| 3217 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3247 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3218 | return ErrorSemanticAnalyzeFail; | 3248 | return ErrorSemanticAnalyzeFail; |
| 3219 | } | 3249 | } |
| 3220 | 3250 | ||
| 3221 | switch (type_val_resolve_requires_comptime(g, field_type_val)) { | 3251 | switch (type_val_resolve_requires_comptime(g, union_field->type_val)) { |
| 3222 | case ReqCompTimeInvalid: | 3252 | case ReqCompTimeInvalid: |
| 3223 | if (g->trace_err != nullptr) { | 3253 | if (g->trace_err != nullptr) { |
| 3224 | g->trace_err = add_error_note(g, g->trace_err, field_node, | 3254 | g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node, |
| 3225 | buf_create_from_str("while checking this field")); | 3255 | buf_create_from_str("while checking this field")); |
| 3226 | } | 3256 | } |
| 3227 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3257 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| ... | @@ -3233,29 +3263,25 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3233,29 +3263,25 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3233 | break; | 3263 | break; |
| 3234 | } | 3264 | } |
| 3235 | 3265 | ||
| 3236 | if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) { | 3266 | if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) { |
| 3237 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3267 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3238 | return ErrorSemanticAnalyzeFail; | 3268 | return ErrorSemanticAnalyzeFail; |
| 3239 | } | 3269 | } |
| 3240 | } | 3270 | } |
| 3241 | 3271 | ||
| 3242 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { | ||
| 3243 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, | ||
| 3244 | buf_create_from_str("untagged union field assignment")); | ||
| 3245 | add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); | ||
| 3246 | } | ||
| 3247 | |||
| 3248 | if (create_enum_type) { | 3272 | if (create_enum_type) { |
| 3249 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i); | 3273 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i); |
| 3250 | union_field->enum_field = &tag_type->data.enumeration.fields[i]; | 3274 | union_field->enum_field = &tag_type->data.enumeration.fields[i]; |
| 3251 | union_field->enum_field->name = field_name; | 3275 | union_field->enum_field->name = union_field->name; |
| 3252 | union_field->enum_field->decl_index = i; | 3276 | union_field->enum_field->decl_index = i; |
| 3253 | union_field->enum_field->decl_node = field_node; | 3277 | union_field->enum_field->decl_node = union_field->decl_node; |
| 3254 | 3278 | ||
| 3255 | auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field); | 3279 | auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field); |
| 3256 | assert(prev_entry == nullptr); // caught by union de-duplicator above | 3280 | assert(prev_entry == nullptr); // caught by union de-duplicator above |
| 3257 | 3281 | ||
| 3258 | AstNode *tag_value = field_node->data.struct_field.value; | 3282 | AstNode *tag_value = decl_node->type == NodeTypeContainerDecl |
| 3283 | ? union_field->decl_node->data.struct_field.value : nullptr; | ||
| 3284 | |||
| 3259 | // In this first pass we resolve explicit tag values. | 3285 | // In this first pass we resolve explicit tag values. |
| 3260 | // In a second pass we will fill in the unspecified ones. | 3286 | // In a second pass we will fill in the unspecified ones. |
| 3261 | if (tag_value != nullptr) { | 3287 | if (tag_value != nullptr) { |
| ... | @@ -3283,11 +3309,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3283,11 +3309,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3283 | return ErrorSemanticAnalyzeFail; | 3309 | return ErrorSemanticAnalyzeFail; |
| 3284 | } | 3310 | } |
| 3285 | } | 3311 | } |
| 3286 | } else if (enum_type_node != nullptr) { | 3312 | } else if (tag_type != nullptr) { |
| 3287 | union_field->enum_field = find_enum_type_field(tag_type, field_name); | 3313 | union_field->enum_field = find_enum_type_field(tag_type, union_field->name); |
| 3288 | if (union_field->enum_field == nullptr) { | 3314 | if (union_field->enum_field == nullptr) { |
| 3289 | ErrorMsg *msg = add_node_error(g, field_node, | 3315 | ErrorMsg *msg = add_node_error(g, union_field->decl_node, |
| 3290 | buf_sprintf("enum field not found: '%s'", buf_ptr(field_name))); | 3316 | buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name))); |
| 3291 | add_error_note(g, msg, tag_type->data.enumeration.decl_node, | 3317 | add_error_note(g, msg, tag_type->data.enumeration.decl_node, |
| 3292 | buf_sprintf("enum declared here")); | 3318 | buf_sprintf("enum declared here")); |
| 3293 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3319 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| ... | @@ -3296,21 +3322,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3296,21 +3322,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3296 | covered_enum_fields[union_field->enum_field->decl_index] = true; | 3322 | covered_enum_fields[union_field->enum_field->decl_index] = true; |
| 3297 | } else { | 3323 | } else { |
| 3298 | union_field->enum_field = heap::c_allocator.create<TypeEnumField>(); | 3324 | union_field->enum_field = heap::c_allocator.create<TypeEnumField>(); |
| 3299 | union_field->enum_field->name = field_name; | 3325 | union_field->enum_field->name = union_field->name; |
| 3300 | union_field->enum_field->decl_index = i; | 3326 | union_field->enum_field->decl_index = i; |
| 3301 | bigint_init_unsigned(&union_field->enum_field->value, i); | 3327 | bigint_init_unsigned(&union_field->enum_field->value, i); |
| 3302 | } | 3328 | } |
| 3303 | assert(union_field->enum_field != nullptr); | 3329 | assert(union_field->enum_field != nullptr); |
| 3330 | } | ||
| 3304 | 3331 | ||
| 3305 | if (field_is_zero_bits) | 3332 | uint32_t gen_field_index = 0; |
| 3306 | continue; | 3333 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 3307 | 3334 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | |
| 3308 | union_field->gen_index = gen_field_index; | 3335 | if (!is_zero_bits[i]) { |
| 3309 | gen_field_index += 1; | 3336 | union_field->gen_index = gen_field_index; |
| 3337 | gen_field_index += 1; | ||
| 3338 | } | ||
| 3310 | } | 3339 | } |
| 3311 | 3340 | ||
| 3312 | bool src_have_tag = decl_node->data.container_decl.auto_enum || | 3341 | bool src_have_tag = is_auto_enum || is_explicit_enum; |
| 3313 | decl_node->data.container_decl.init_arg_expr != nullptr; | ||
| 3314 | 3342 | ||
| 3315 | if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { | 3343 | if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { |
| 3316 | const char *qual_str; | 3344 | const char *qual_str; |
| ... | @@ -3324,8 +3352,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3324,8 +3352,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3324 | qual_str = "extern"; | 3352 | qual_str = "extern"; |
| 3325 | break; | 3353 | break; |
| 3326 | } | 3354 | } |
| 3327 | AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ? | 3355 | AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node; |
| 3328 | decl_node->data.container_decl.init_arg_expr : decl_node; | ||
| 3329 | add_node_error(g, source_node, | 3356 | add_node_error(g, source_node, |
| 3330 | buf_sprintf("%s union does not support enum tag type", qual_str)); | 3357 | buf_sprintf("%s union does not support enum tag type", qual_str)); |
| 3331 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3358 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| ... | @@ -3333,43 +3360,47 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -3333,43 +3360,47 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 3333 | } | 3360 | } |
| 3334 | 3361 | ||
| 3335 | if (create_enum_type) { | 3362 | if (create_enum_type) { |
| 3336 | // Now iterate again and populate the unspecified tag values | 3363 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3337 | uint32_t next_maybe_unoccupied_index = 0; | 3364 | // Now iterate again and populate the unspecified tag values |
| 3365 | uint32_t next_maybe_unoccupied_index = 0; | ||
| 3338 | 3366 | ||
| 3339 | for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { | 3367 | for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { |
| 3340 | AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); | 3368 | AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); |
| 3341 | TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; | 3369 | TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; |
| 3342 | AstNode *tag_value = field_node->data.struct_field.value; | 3370 | AstNode *tag_value = field_node->data.struct_field.value; |
| 3343 | 3371 | ||
| 3344 | if (tag_value == nullptr) { | 3372 | if (tag_value == nullptr) { |
| 3345 | if (occupied_tag_values.size() == 0) { | 3373 | if (occupied_tag_values.size() == 0) { |
| 3346 | bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); | 3374 | bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); |
| 3347 | next_maybe_unoccupied_index += 1; | ||
| 3348 | } else { | ||
| 3349 | BigInt proposed_value; | ||
| 3350 | for (;;) { | ||
| 3351 | bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); | ||
| 3352 | next_maybe_unoccupied_index += 1; | 3375 | next_maybe_unoccupied_index += 1; |
| 3353 | auto entry = occupied_tag_values.put_unique(proposed_value, field_node); | 3376 | } else { |
| 3354 | if (entry != nullptr) { | 3377 | BigInt proposed_value; |
| 3355 | continue; | 3378 | for (;;) { |
| 3379 | bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); | ||
| 3380 | next_maybe_unoccupied_index += 1; | ||
| 3381 | auto entry = occupied_tag_values.put_unique(proposed_value, field_node); | ||
| 3382 | if (entry != nullptr) { | ||
| 3383 | continue; | ||
| 3384 | } | ||
| 3385 | break; | ||
| 3356 | } | 3386 | } |
| 3357 | break; | 3387 | bigint_init_bigint(&union_field->enum_field->value, &proposed_value); |
| 3358 | } | 3388 | } |
| 3359 | bigint_init_bigint(&union_field->enum_field->value, &proposed_value); | ||
| 3360 | } | 3389 | } |
| 3361 | } | 3390 | } |
| 3362 | } | 3391 | } |
| 3363 | } else if (enum_type_node != nullptr) { | 3392 | } else if (tag_type != nullptr) { |
| 3364 | for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { | 3393 | for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { |
| 3365 | TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; | 3394 | TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; |
| 3366 | if (!covered_enum_fields[i]) { | 3395 | if (!covered_enum_fields[i]) { |
| 3367 | AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; | ||
| 3368 | AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); | ||
| 3369 | ErrorMsg *msg = add_node_error(g, decl_node, | 3396 | ErrorMsg *msg = add_node_error(g, decl_node, |
| 3370 | buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); | 3397 | buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); |
| 3371 | add_error_note(g, msg, field_node, | 3398 | if (decl_node->type == NodeTypeContainerDecl) { |
| 3372 | buf_sprintf("declared here")); | 3399 | AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; |
| 3400 | AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); | ||
| 3401 | add_error_note(g, msg, field_node, | ||
| 3402 | buf_sprintf("declared here")); | ||
| 3403 | } | ||
| 3373 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 3404 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 3374 | } | 3405 | } |
| 3375 | } | 3406 | } |
| ... | @@ -8357,7 +8388,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS | ... | @@ -8357,7 +8388,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 8357 | ZigLLVMDIFile *di_file; | 8388 | ZigLLVMDIFile *di_file; |
| 8358 | ZigLLVMDIScope *di_scope; | 8389 | ZigLLVMDIScope *di_scope; |
| 8359 | unsigned line; | 8390 | unsigned line; |
| 8360 | if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) { | 8391 | if (decl_node != nullptr) { |
| 8361 | Scope *scope = &struct_type->data.structure.decls_scope->base; | 8392 | Scope *scope = &struct_type->data.structure.decls_scope->base; |
| 8362 | ZigType *import = get_scope_import(scope); | 8393 | ZigType *import = get_scope_import(scope); |
| 8363 | di_file = import->data.structure.root_struct->di_file; | 8394 | di_file = import->data.structure.root_struct->di_file; |
| ... | @@ -8720,7 +8751,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta | ... | @@ -8720,7 +8751,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 8720 | 8751 | ||
| 8721 | uint64_t store_size_in_bits = union_field->type_entry->size_in_bits; | 8752 | uint64_t store_size_in_bits = union_field->type_entry->size_in_bits; |
| 8722 | uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align; | 8753 | uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align; |
| 8723 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | 8754 | AstNode *field_node = union_field->decl_node; |
| 8724 | union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | 8755 | union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 8725 | ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), | 8756 | ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), |
| 8726 | import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1), | 8757 | import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1), |
src/ir.cpp+85-20| ... | @@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy | ... | @@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy |
| 25424 | 25424 | ||
| 25425 | init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false); | 25425 | init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false); |
| 25426 | 25426 | ||
| 25427 | ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); | ||
| 25428 | |||
| 25429 | for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { | 25427 | for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { |
| 25430 | TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; | 25428 | TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; |
| 25431 | ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index]; | 25429 | ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index]; |
| ... | @@ -25433,20 +25431,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy | ... | @@ -25433,20 +25431,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy |
| 25433 | union_field_val->special = ConstValSpecialStatic; | 25431 | union_field_val->special = ConstValSpecialStatic; |
| 25434 | union_field_val->type = type_info_union_field_type; | 25432 | union_field_val->type = type_info_union_field_type; |
| 25435 | 25433 | ||
| 25436 | ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3); | 25434 | ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); |
| 25437 | inner_fields[1]->special = ConstValSpecialStatic; | 25435 | inner_fields[1]->special = ConstValSpecialStatic; |
| 25438 | inner_fields[1]->type = get_optional_type(ira->codegen, type_info_enum_field_type); | 25436 | inner_fields[1]->type = ira->codegen->builtin_types.entry_type; |
| 25439 | 25437 | inner_fields[1]->data.x_type = union_field->type_entry; | |
| 25440 | if (fields[1]->data.x_optional == nullptr) { | ||
| 25441 | inner_fields[1]->data.x_optional = nullptr; | ||
| 25442 | } else { | ||
| 25443 | inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>(); | ||
| 25444 | make_enum_field_val(ira, inner_fields[1]->data.x_optional, union_field->enum_field, type_info_enum_field_type); | ||
| 25445 | } | ||
| 25446 | |||
| 25447 | inner_fields[2]->special = ConstValSpecialStatic; | ||
| 25448 | inner_fields[2]->type = ira->codegen->builtin_types.entry_type; | ||
| 25449 | inner_fields[2]->data.x_type = union_field->type_entry; | ||
| 25450 | 25438 | ||
| 25451 | ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; | 25439 | ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; |
| 25452 | init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true); | 25440 | init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true); |
| ... | @@ -26102,7 +26090,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI | ... | @@ -26102,7 +26090,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI |
| 26102 | entry->data.structure.layout = layout; | 26090 | entry->data.structure.layout = layout; |
| 26103 | entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; | 26091 | entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; |
| 26104 | entry->data.structure.created_by_at_type = true; | 26092 | entry->data.structure.created_by_at_type = true; |
| 26105 | entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name); | 26093 | entry->data.structure.decls_scope = create_decls_scope( |
| 26094 | ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name); | ||
| 26106 | 26095 | ||
| 26107 | assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | 26096 | assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); |
| 26108 | assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); | 26097 | assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); |
| ... | @@ -26226,13 +26215,89 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI | ... | @@ -26226,13 +26215,89 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI |
| 26226 | return ira->codegen->invalid_inst_gen->value->type; | 26215 | return ira->codegen->invalid_inst_gen->value->type; |
| 26227 | field->value = *field_int_value; | 26216 | field->value = *field_int_value; |
| 26228 | } | 26217 | } |
| 26218 | return entry; | ||
| 26219 | } | ||
| 26220 | case ZigTypeIdUnion: { | ||
| 26221 | assert(payload->special == ConstValSpecialStatic); | ||
| 26222 | assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); | ||
| 26229 | 26223 | ||
| 26224 | ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); | ||
| 26225 | if (layout_value == nullptr) | ||
| 26226 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26227 | assert(layout_value->special == ConstValSpecialStatic); | ||
| 26228 | assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); | ||
| 26229 | ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); | ||
| 26230 | |||
| 26231 | ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1); | ||
| 26232 | if (tag_type != nullptr && type_is_invalid(tag_type)) { | ||
| 26233 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26234 | } | ||
| 26235 | if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { | ||
| 26236 | ir_add_error(ira, source_instr, buf_sprintf( | ||
| 26237 | "expected enum type, found '%s'", type_id_name(tag_type->id))); | ||
| 26238 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26239 | } | ||
| 26240 | |||
| 26241 | ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2); | ||
| 26242 | if (fields_value == nullptr) | ||
| 26243 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26244 | |||
| 26245 | assert(fields_value->special == ConstValSpecialStatic); | ||
| 26246 | assert(is_slice(fields_value->type)); | ||
| 26247 | ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; | ||
| 26248 | ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; | ||
| 26249 | size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); | ||
| 26250 | |||
| 26251 | ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 3); | ||
| 26252 | if (decls_value == nullptr) | ||
| 26253 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26254 | |||
| 26255 | assert(decls_value->special == ConstValSpecialStatic); | ||
| 26256 | assert(is_slice(decls_value->type)); | ||
| 26257 | ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; | ||
| 26258 | size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); | ||
| 26259 | if (decls_len != 0) { | ||
| 26260 | ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Union.decls must be empty for @Type")); | ||
| 26261 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26262 | } | ||
| 26263 | |||
| 26264 | ZigType *entry = new_type_table_entry(ZigTypeIdUnion); | ||
| 26265 | buf_init_from_buf(&entry->name, | ||
| 26266 | get_anon_type_name(ira->codegen, ira->old_irb.exec, "union", source_instr->scope, source_instr->source_node, &entry->name)); | ||
| 26267 | entry->data.unionation.decl_node = source_instr->source_node; | ||
| 26268 | entry->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(fields_len); | ||
| 26269 | entry->data.unionation.fields_by_name.init(fields_len); | ||
| 26270 | entry->data.unionation.decls_scope = create_decls_scope( | ||
| 26271 | ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name); | ||
| 26272 | entry->data.unionation.tag_type = tag_type; | ||
| 26273 | entry->data.unionation.src_field_count = fields_len; | ||
| 26274 | entry->data.unionation.layout = layout; | ||
| 26275 | |||
| 26276 | assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); | ||
| 26277 | assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); | ||
| 26278 | ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; | ||
| 26279 | assert(fields_arr->special == ConstValSpecialStatic); | ||
| 26280 | assert(fields_arr->data.x_array.special == ConstArraySpecialNone); | ||
| 26281 | for (size_t i = 0; i < fields_len; i++) { | ||
| 26282 | ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; | ||
| 26283 | assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr)); | ||
| 26284 | TypeUnionField *field = &entry->data.unionation.fields[i]; | ||
| 26285 | field->name = buf_alloc(); | ||
| 26286 | if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name))) | ||
| 26287 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26288 | if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) { | ||
| 26289 | ir_add_error(ira, source_instr, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name))); | ||
| 26290 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26291 | } | ||
| 26292 | field->decl_node = source_instr->source_node; | ||
| 26293 | ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1); | ||
| 26294 | if (type_value == nullptr) | ||
| 26295 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26296 | field->type_val = type_value; | ||
| 26297 | field->type_entry = type_value->data.x_type; | ||
| 26298 | } | ||
| 26230 | return entry; | 26299 | return entry; |
| 26231 | } | 26300 | } |
| 26232 | case ZigTypeIdUnion: | ||
| 26233 | ir_add_error(ira, source_instr, buf_sprintf( | ||
| 26234 | "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); | ||
| 26235 | return ira->codegen->invalid_inst_gen->value->type; | ||
| 26236 | case ZigTypeIdFn: | 26301 | case ZigTypeIdFn: |
| 26237 | case ZigTypeIdBoundFn: | 26302 | case ZigTypeIdBoundFn: |
| 26238 | ir_add_error(ira, source_instr, buf_sprintf( | 26303 | ir_add_error(ira, source_instr, buf_sprintf( |
test/compile_errors.zig+130-1| ... | @@ -10,6 +10,135 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -10,6 +10,135 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 10 | "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", | 10 | "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", |
| 11 | }); | 11 | }); |
| 12 | 12 | ||
| 13 | cases.add("@Type for union with opaque field", | ||
| 14 | \\const TypeInfo = @import("builtin").TypeInfo; | ||
| 15 | \\const Untagged = @Type(.{ | ||
| 16 | \\ .Union = .{ | ||
| 17 | \\ .layout = .Auto, | ||
| 18 | \\ .tag_type = null, | ||
| 19 | \\ .fields = &[_]TypeInfo.UnionField{ | ||
| 20 | \\ .{ .name = "foo", .field_type = @Type(.Opaque) }, | ||
| 21 | \\ }, | ||
| 22 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 23 | \\ }, | ||
| 24 | \\}); | ||
| 25 | \\export fn entry() void { | ||
| 26 | \\ _ = Untagged{}; | ||
| 27 | \\} | ||
| 28 | , &[_][]const u8{ | ||
| 29 | "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", | ||
| 30 | "tmp.zig:13:17: note: referenced here", | ||
| 31 | }); | ||
| 32 | |||
| 33 | cases.add("@Type for union with zero fields", | ||
| 34 | \\const TypeInfo = @import("builtin").TypeInfo; | ||
| 35 | \\const Untagged = @Type(.{ | ||
| 36 | \\ .Union = .{ | ||
| 37 | \\ .layout = .Auto, | ||
| 38 | \\ .tag_type = null, | ||
| 39 | \\ .fields = &[_]TypeInfo.UnionField{}, | ||
| 40 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 41 | \\ }, | ||
| 42 | \\}); | ||
| 43 | \\export fn entry() void { | ||
| 44 | \\ _ = Untagged{}; | ||
| 45 | \\} | ||
| 46 | , &[_][]const u8{ | ||
| 47 | "tmp.zig:2:25: error: unions must have 1 or more fields", | ||
| 48 | "tmp.zig:11:17: note: referenced here", | ||
| 49 | }); | ||
| 50 | |||
| 51 | cases.add("@Type for exhaustive enum with zero fields", | ||
| 52 | \\const TypeInfo = @import("builtin").TypeInfo; | ||
| 53 | \\const Tag = @Type(.{ | ||
| 54 | \\ .Enum = .{ | ||
| 55 | \\ .layout = .Auto, | ||
| 56 | \\ .tag_type = u1, | ||
| 57 | \\ .fields = &[_]TypeInfo.EnumField{}, | ||
| 58 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 59 | \\ .is_exhaustive = true, | ||
| 60 | \\ }, | ||
| 61 | \\}); | ||
| 62 | \\export fn entry() void { | ||
| 63 | \\ _ = @intToEnum(Tag, 0); | ||
| 64 | \\} | ||
| 65 | , &[_][]const u8{ | ||
| 66 | "tmp.zig:2:20: error: enums must have 1 or more fields", | ||
| 67 | "tmp.zig:12:9: note: referenced here", | ||
| 68 | }); | ||
| 69 | |||
| 70 | cases.add("@Type for tagged union with extra union field", | ||
| 71 | \\const TypeInfo = @import("builtin").TypeInfo; | ||
| 72 | \\const Tag = @Type(.{ | ||
| 73 | \\ .Enum = .{ | ||
| 74 | \\ .layout = .Auto, | ||
| 75 | \\ .tag_type = u1, | ||
| 76 | \\ .fields = &[_]TypeInfo.EnumField{ | ||
| 77 | \\ .{ .name = "signed", .value = 0 }, | ||
| 78 | \\ .{ .name = "unsigned", .value = 1 }, | ||
| 79 | \\ }, | ||
| 80 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 81 | \\ .is_exhaustive = true, | ||
| 82 | \\ }, | ||
| 83 | \\}); | ||
| 84 | \\const Tagged = @Type(.{ | ||
| 85 | \\ .Union = .{ | ||
| 86 | \\ .layout = .Auto, | ||
| 87 | \\ .tag_type = Tag, | ||
| 88 | \\ .fields = &[_]TypeInfo.UnionField{ | ||
| 89 | \\ .{ .name = "signed", .field_type = i32 }, | ||
| 90 | \\ .{ .name = "unsigned", .field_type = u32 }, | ||
| 91 | \\ .{ .name = "arst", .field_type = f32 }, | ||
| 92 | \\ }, | ||
| 93 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 94 | \\ }, | ||
| 95 | \\}); | ||
| 96 | \\export fn entry() void { | ||
| 97 | \\ var tagged = Tagged{ .signed = -1 }; | ||
| 98 | \\ tagged = .{ .unsigned = 1 }; | ||
| 99 | \\} | ||
| 100 | , &[_][]const u8{ | ||
| 101 | "tmp.zig:14:23: error: enum field not found: 'arst'", | ||
| 102 | "tmp.zig:2:20: note: enum declared here", | ||
| 103 | "tmp.zig:27:24: note: referenced here", | ||
| 104 | }); | ||
| 105 | |||
| 106 | cases.add("@Type for tagged union with extra enum field", | ||
| 107 | \\const TypeInfo = @import("builtin").TypeInfo; | ||
| 108 | \\const Tag = @Type(.{ | ||
| 109 | \\ .Enum = .{ | ||
| 110 | \\ .layout = .Auto, | ||
| 111 | \\ .tag_type = u2, | ||
| 112 | \\ .fields = &[_]TypeInfo.EnumField{ | ||
| 113 | \\ .{ .name = "signed", .value = 0 }, | ||
| 114 | \\ .{ .name = "unsigned", .value = 1 }, | ||
| 115 | \\ .{ .name = "arst", .field_type = 2 }, | ||
| 116 | \\ }, | ||
| 117 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 118 | \\ .is_exhaustive = true, | ||
| 119 | \\ }, | ||
| 120 | \\}); | ||
| 121 | \\const Tagged = @Type(.{ | ||
| 122 | \\ .Union = .{ | ||
| 123 | \\ .layout = .Auto, | ||
| 124 | \\ .tag_type = Tag, | ||
| 125 | \\ .fields = &[_]TypeInfo.UnionField{ | ||
| 126 | \\ .{ .name = "signed", .field_type = i32 }, | ||
| 127 | \\ .{ .name = "unsigned", .field_type = u32 }, | ||
| 128 | \\ }, | ||
| 129 | \\ .decls = &[_]TypeInfo.Declaration{}, | ||
| 130 | \\ }, | ||
| 131 | \\}); | ||
| 132 | \\export fn entry() void { | ||
| 133 | \\ var tagged = Tagged{ .signed = -1 }; | ||
| 134 | \\ tagged = .{ .unsigned = 1 }; | ||
| 135 | \\} | ||
| 136 | , &[_][]const u8{ | ||
| 137 | "tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'", | ||
| 138 | "tmp.zig:18:21: note: referenced here", | ||
| 139 | "tmp.zig:27:18: note: referenced here", | ||
| 140 | }); | ||
| 141 | |||
| 13 | cases.add("@Type with undefined", | 142 | cases.add("@Type with undefined", |
| 14 | \\comptime { | 143 | \\comptime { |
| 15 | \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); | 144 | \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); |
| ... | @@ -7419,7 +7548,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7419,7 +7548,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7419 | }); | 7548 | }); |
| 7420 | 7549 | ||
| 7421 | cases.add( // fixed bug #2032 | 7550 | cases.add( // fixed bug #2032 |
| 7422 | "compile diagnostic string for top level decl type", | 7551 | "compile diagnostic string for top level decl type", |
| 7423 | \\export fn entry() void { | 7552 | \\export fn entry() void { |
| 7424 | \\ var foo: u32 = @This(){}; | 7553 | \\ var foo: u32 = @This(){}; |
| 7425 | \\} | 7554 | \\} |
test/stage1/behavior/type.zig+61| ... | @@ -313,3 +313,64 @@ test "Type.Enum" { | ... | @@ -313,3 +313,64 @@ test "Type.Enum" { |
| 313 | testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); | 313 | testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); |
| 314 | testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); | 314 | testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); |
| 315 | } | 315 | } |
| 316 | |||
| 317 | test "Type.Union" { | ||
| 318 | const Untagged = @Type(.{ | ||
| 319 | .Union = .{ | ||
| 320 | .layout = .Auto, | ||
| 321 | .tag_type = null, | ||
| 322 | .fields = &[_]TypeInfo.UnionField{ | ||
| 323 | .{ .name = "int", .field_type = i32 }, | ||
| 324 | .{ .name = "float", .field_type = f32 }, | ||
| 325 | }, | ||
| 326 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 327 | }, | ||
| 328 | }); | ||
| 329 | var untagged = Untagged{ .int = 1 }; | ||
| 330 | untagged.float = 2.0; | ||
| 331 | untagged.int = 3; | ||
| 332 | testing.expectEqual(@as(i32, 3), untagged.int); | ||
| 333 | |||
| 334 | const PackedUntagged = @Type(.{ | ||
| 335 | .Union = .{ | ||
| 336 | .layout = .Packed, | ||
| 337 | .tag_type = null, | ||
| 338 | .fields = &[_]TypeInfo.UnionField{ | ||
| 339 | .{ .name = "signed", .field_type = i32 }, | ||
| 340 | .{ .name = "unsigned", .field_type = u32 }, | ||
| 341 | }, | ||
| 342 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 343 | }, | ||
| 344 | }); | ||
| 345 | var packed_untagged = PackedUntagged{ .signed = -1 }; | ||
| 346 | testing.expectEqual(@as(i32, -1), packed_untagged.signed); | ||
| 347 | testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned); | ||
| 348 | |||
| 349 | const Tag = @Type(.{ | ||
| 350 | .Enum = .{ | ||
| 351 | .layout = .Auto, | ||
| 352 | .tag_type = u1, | ||
| 353 | .fields = &[_]TypeInfo.EnumField{ | ||
| 354 | .{ .name = "signed", .value = 0 }, | ||
| 355 | .{ .name = "unsigned", .value = 1 }, | ||
| 356 | }, | ||
| 357 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 358 | .is_exhaustive = true, | ||
| 359 | }, | ||
| 360 | }); | ||
| 361 | const Tagged = @Type(.{ | ||
| 362 | .Union = .{ | ||
| 363 | .layout = .Auto, | ||
| 364 | .tag_type = Tag, | ||
| 365 | .fields = &[_]TypeInfo.UnionField{ | ||
| 366 | .{ .name = "signed", .field_type = i32 }, | ||
| 367 | .{ .name = "unsigned", .field_type = u32 }, | ||
| 368 | }, | ||
| 369 | .decls = &[_]TypeInfo.Declaration{}, | ||
| 370 | }, | ||
| 371 | }); | ||
| 372 | var tagged = Tagged{ .signed = -1 }; | ||
| 373 | testing.expectEqual(Tag.signed, tagged); | ||
| 374 | tagged = .{ .unsigned = 1 }; | ||
| 375 | testing.expectEqual(Tag.unsigned, tagged); | ||
| 376 | } |
test/stage1/behavior/type_info.zig-4| ... | @@ -198,8 +198,6 @@ fn testUnion() void { | ... | @@ -198,8 +198,6 @@ fn testUnion() void { |
| 198 | expect(typeinfo_info.Union.layout == .Auto); | 198 | expect(typeinfo_info.Union.layout == .Auto); |
| 199 | expect(typeinfo_info.Union.tag_type.? == TypeId); | 199 | expect(typeinfo_info.Union.tag_type.? == TypeId); |
| 200 | expect(typeinfo_info.Union.fields.len == 25); | 200 | expect(typeinfo_info.Union.fields.len == 25); |
| 201 | expect(typeinfo_info.Union.fields[4].enum_field != null); | ||
| 202 | expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); | ||
| 203 | expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); | 201 | expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); |
| 204 | expect(typeinfo_info.Union.decls.len == 21); | 202 | expect(typeinfo_info.Union.decls.len == 21); |
| 205 | 203 | ||
| ... | @@ -213,7 +211,6 @@ fn testUnion() void { | ... | @@ -213,7 +211,6 @@ fn testUnion() void { |
| 213 | expect(notag_union_info.Union.tag_type == null); | 211 | expect(notag_union_info.Union.tag_type == null); |
| 214 | expect(notag_union_info.Union.layout == .Auto); | 212 | expect(notag_union_info.Union.layout == .Auto); |
| 215 | expect(notag_union_info.Union.fields.len == 2); | 213 | expect(notag_union_info.Union.fields.len == 2); |
| 216 | expect(notag_union_info.Union.fields[0].enum_field == null); | ||
| 217 | expect(notag_union_info.Union.fields[1].field_type == u32); | 214 | expect(notag_union_info.Union.fields[1].field_type == u32); |
| 218 | 215 | ||
| 219 | const TestExternUnion = extern union { | 216 | const TestExternUnion = extern union { |
| ... | @@ -223,7 +220,6 @@ fn testUnion() void { | ... | @@ -223,7 +220,6 @@ fn testUnion() void { |
| 223 | const extern_union_info = @typeInfo(TestExternUnion); | 220 | const extern_union_info = @typeInfo(TestExternUnion); |
| 224 | expect(extern_union_info.Union.layout == .Extern); | 221 | expect(extern_union_info.Union.layout == .Extern); |
| 225 | expect(extern_union_info.Union.tag_type == null); | 222 | expect(extern_union_info.Union.tag_type == null); |
| 226 | expect(extern_union_info.Union.fields[0].enum_field == null); | ||
| 227 | expect(extern_union_info.Union.fields[0].field_type == *c_void); | 223 | expect(extern_union_info.Union.fields[0].field_type == *c_void); |
| 228 | } | 224 | } |
| 229 | 225 |