Merge remote-tracking branch 'origin/master' into stage2-zig-cc

This commit is contained in:
Andrew Kelley 2020-09-14 21:57:01 -07:00
commit 5d8fec3d4c
19 changed files with 656 additions and 174 deletions

View File

@ -1,7 +1,7 @@
image: freebsd/latest
secrets:
- 6c60aaee-92e7-4e7d-812c-114817689b4d
- dd0bd962-7664-4d3e-b0f3-41c9ee96b8b8
- 51bfddf5-86a6-4e01-8576-358c72a4a0a4
- 5cfede76-914e-4071-893e-e5e2e6ae3cea
sources:
- https://github.com/ziglang/zig
tasks:

View File

@ -28,11 +28,8 @@ make $JOBS install
release/bin/zig build test-fmt
release/bin/zig build test-behavior
# This test is disabled because it triggers "out of memory" on the sr.ht CI service.
# See https://github.com/ziglang/zig/issues/3210
# release/bin/zig build test-std
# TODO get these tests passing on freebsd and re-enable
#release/bin/zig build test-std
release/bin/zig build test-compiler-rt
release/bin/zig build test-compare-output
release/bin/zig build test-standalone
@ -44,7 +41,8 @@ release/bin/zig build test-translate-c
release/bin/zig build test-run-translated-c
# TODO disabled until we are shipping self-hosted
#release/bin/zig build test-gen-h
release/bin/zig build test-compile-errors
# TODO disabled to save time and hit that 45 minute limit
#release/bin/zig build test-compile-errors
release/bin/zig build docs
if [ -f ~/.s3cfg ]; then

View File

@ -36,4 +36,4 @@ jq <$YML_FILE -sR '{
-H Authorization:"token $OAUTH_TOKEN" \
-H Content-Type:application/json \
-X POST \
-d @- "https://builds.sr.ht/api/jobs"
-d @- "https://builds.hut.lavatech.top/api/jobs"

View File

@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) {
/// therefore must be kept in sync with the compiler implementation.
pub const UnionField = struct {
name: []const u8,
enum_field: ?EnumField,
field_type: type,
};

View File

@ -399,7 +399,7 @@ pub fn formatType(
try writer.writeAll(@tagName(@as(UnionTagType, value)));
try writer.writeAll(" = ");
inline for (info.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
if (value == @field(UnionTagType, u_field.name)) {
try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
}
}

View File

@ -139,9 +139,8 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
const tag = meta.activeTag(key);
const s = hash(hasher, tag, strat);
inline for (info.fields) |field| {
const enum_field = field.enum_field.?;
if (enum_field.value == @enumToInt(tag)) {
hash(hasher, @field(key, enum_field.name), strat);
if (@field(tag_type, field.name) == tag) {
hash(hasher, @field(key, field.name), strat);
// TODO use a labelled break when it does not crash the compiler. cf #2908
// break :blk;
return;

View File

@ -71,10 +71,7 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type {
const p = input[i .. i + 8];
// Unrolling this way gives ~50Mb/s increase
self.crc ^= (@as(u32, p[0]) << 0);
self.crc ^= (@as(u32, p[1]) << 8);
self.crc ^= (@as(u32, p[2]) << 16);
self.crc ^= (@as(u32, p[3]) << 24);
self.crc ^= std.mem.readIntLittle(u32, p[0..4]);
self.crc =
lookup_tables[0][p[7]] ^

View File

@ -156,7 +156,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,
const tag = try self.deserializeInt(TagInt);
inline for (info.fields) |field_info| {
if (field_info.enum_field.?.value == tag) {
if (@enumToInt(@field(TagType, field_info.name)) == tag) {
const name = field_info.name;
const FieldType = field_info.field_type;
ptr.* = @unionInit(C, name, undefined);
@ -320,7 +320,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co
// value, but @field requires a comptime value. Our alternative
// is to check each field for a match
inline for (info.fields) |field_info| {
if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
if (@field(TagType, field_info.name) == active_tag) {
const name = field_info.name;
const FieldType = field_info.field_type;
try self.serialize(@field(value, name));

View File

@ -1613,7 +1613,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
.Union => |unionInfo| {
if (unionInfo.tag_type) |UnionTagType| {
inline for (unionInfo.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
if (value == @field(UnionTagType, u_field.name)) {
parseFree(u_field.field_type, @field(value, u_field.name), options);
break;
}
@ -2458,7 +2458,7 @@ pub fn stringify(
const info = @typeInfo(T).Union;
if (info.tag_type) |UnionTagType| {
inline for (info.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
if (value == @field(UnionTagType, u_field.name)) {
return try stringify(@field(value, u_field.name), options, out_stream);
}
}

View File

@ -465,10 +465,13 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type {
testing.expect(trait.is(.Union)(U));
const info = @typeInfo(U).Union;
const tag_info = @typeInfo(@TagType(U)).Enum;
inline for (info.fields) |field_info| {
if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
if (comptime mem.eql(u8, field_info.name, @tagName(tag)))
return field_info.field_type;
}
unreachable;
}
@ -504,15 +507,14 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool {
}
},
.Union => |info| {
if (info.tag_type) |_| {
if (info.tag_type) |Tag| {
const tag_a = activeTag(a);
const tag_b = activeTag(b);
if (tag_a != tag_b) return false;
inline for (info.fields) |field_info| {
const enum_field = field_info.enum_field.?;
if (enum_field.value == @enumToInt(tag_a)) {
return eql(@field(a, enum_field.name), @field(b, enum_field.name));
if (@field(Tag, field_info.name) == tag_a) {
return eql(@field(a, field_info.name), @field(b, field_info.name));
}
}
return false;

View File

@ -320,6 +320,7 @@ pub const ReadError = error{
/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
/// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page.
/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
/// For POSIX the limit is `math.maxInt(isize)`.
pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
if (builtin.os.tag == .windows) {
@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
// Prevents EINVAL.
const max_count = switch (std.Target.current.os.tag) {
.linux => 0x7ffff000,
.macosx, .ios, .watchos, .tvos => math.maxInt(i32),
else => math.maxInt(isize),
};
const adjusted_len = math.min(max_count, buf.len);
@ -693,6 +695,7 @@ pub const WriteError = error{
/// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000`
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL.
/// The corresponding POSIX limit is `math.maxInt(isize)`.
pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
if (builtin.os.tag == .windows) {
@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
const max_count = switch (std.Target.current.os.tag) {
.linux => 0x7ffff000,
.macosx, .ios, .watchos, .tvos => math.maxInt(i32),
else => math.maxInt(isize),
};
const adjusted_len = math.min(max_count, bytes.len);
@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable};
/// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000`
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
/// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page.
/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
/// The corresponding POSIX limit is `math.maxInt(isize)`.
pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
if (std.Target.current.os.tag == .windows) {
@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
// Prevent EINVAL.
const max_count = switch (std.Target.current.os.tag) {
.linux => 0x7ffff000,
.macosx, .ios, .watchos, .tvos => math.maxInt(i32),
else => math.maxInt(isize),
};
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
.WSAECONNREFUSED => return error.ConnectionRefused,
.WSAETIMEDOUT => return error.ConnectionTimedOut,
.WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well?
, .WSAENETUNREACH => return error.NetworkUnreachable,
, .WSAENETUNREACH => return error.NetworkUnreachable,
.WSAEFAULT => unreachable,
.WSAEINVAL => unreachable,
.WSAEISCONN => unreachable,
@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize {
/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`
/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
/// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page.
/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
/// The corresponding POSIX limit on this is `math.maxInt(isize)`.
pub fn sendfile(
out_fd: fd_t,
@ -4733,6 +4740,7 @@ pub fn sendfile(
});
const max_count = switch (std.Target.current.os.tag) {
.linux => 0x7ffff000,
.macosx, .ios, .watchos, .tvos => math.maxInt(i32),
else => math.maxInt(size_t),
};

View File

@ -12,6 +12,7 @@ const expectError = std.testing.expectError;
const expect = std.testing.expect;
pub const btf = @import("bpf/btf.zig");
pub const kern = @import("bpf/kern.zig");
// instruction classes
pub const LD = 0x00;

View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const kern = @import("kern.zig");
// in BPF, all the helper calls
// TODO: when https://github.com/ziglang/zig/issues/1717 is here, make a nice
// function that uses the Helper enum
//
// Note, these function signatures were created from documentation found in
// '/usr/include/linux/bpf.h'
pub const map_lookup_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) ?*c_void, 1);
pub const map_update_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void, value: ?*const c_void, flags: u64) c_long, 2);
pub const map_delete_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) c_long, 3);
pub const probe_read = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 4);
pub const ktime_get_ns = @intToPtr(fn () u64, 5);
pub const trace_printk = @intToPtr(fn (fmt: [*:0]const u8, fmt_size: u32, arg1: u64, arg2: u64, arg3: u64) c_long, 6);
pub const get_prandom_u32 = @intToPtr(fn () u32, 7);
pub const get_smp_processor_id = @intToPtr(fn () u32, 8);
pub const skb_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32, flags: u64) c_long, 9);
pub const l3_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, size: u64) c_long, 10);
pub const l4_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, flags: u64) c_long, 11);
pub const tail_call = @intToPtr(fn (ctx: ?*c_void, prog_array_map: *const kern.MapDef, index: u32) c_long, 12);
pub const clone_redirect = @intToPtr(fn (skb: *kern.SkBuff, ifindex: u32, flags: u64) c_long, 13);
pub const get_current_pid_tgid = @intToPtr(fn () u64, 14);
pub const get_current_uid_gid = @intToPtr(fn () u64, 15);
pub const get_current_comm = @intToPtr(fn (buf: ?*c_void, size_of_buf: u32) c_long, 16);
pub const get_cgroup_classid = @intToPtr(fn (skb: *kern.SkBuff) u32, 17);
// Note vlan_proto is big endian
pub const skb_vlan_push = @intToPtr(fn (skb: *kern.SkBuff, vlan_proto: u16, vlan_tci: u16) c_long, 18);
pub const skb_vlan_pop = @intToPtr(fn (skb: *kern.SkBuff) c_long, 19);
pub const skb_get_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 20);
pub const skb_set_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 21);
pub const perf_event_read = @intToPtr(fn (map: *const kern.MapDef, flags: u64) u64, 22);
pub const redirect = @intToPtr(fn (ifindex: u32, flags: u64) c_long, 23);
pub const get_route_realm = @intToPtr(fn (skb: *kern.SkBuff) u32, 24);
pub const perf_event_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 25);
pub const skb_load_bytes = @intToPtr(fn (skb: ?*c_void, offset: u32, to: ?*c_void, len: u32) c_long, 26);
pub const get_stackid = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64) c_long, 27);
// from and to point to __be32
pub const csum_diff = @intToPtr(fn (from: *u32, from_size: u32, to: *u32, to_size: u32, seed: u32) i64, 28);
pub const skb_get_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 29);
pub const skb_set_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 30);
// proto is __be16
pub const skb_change_proto = @intToPtr(fn (skb: *kern.SkBuff, proto: u16, flags: u64) c_long, 31);
pub const skb_change_type = @intToPtr(fn (skb: *kern.SkBuff, skb_type: u32) c_long, 32);
pub const skb_under_cgroup = @intToPtr(fn (skb: *kern.SkBuff, map: ?*const c_void, index: u32) c_long, 33);
pub const get_hash_recalc = @intToPtr(fn (skb: *kern.SkBuff) u32, 34);
pub const get_current_task = @intToPtr(fn () u64, 35);
pub const probe_write_user = @intToPtr(fn (dst: ?*c_void, src: ?*const c_void, len: u32) c_long, 36);
pub const current_task_under_cgroup = @intToPtr(fn (map: *const kern.MapDef, index: u32) c_long, 37);
pub const skb_change_tail = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 38);
pub const skb_pull_data = @intToPtr(fn (skb: *kern.SkBuff, len: u32) c_long, 39);
pub const csum_update = @intToPtr(fn (skb: *kern.SkBuff, csum: u32) i64, 40);
pub const set_hash_invalid = @intToPtr(fn (skb: *kern.SkBuff) void, 41);
pub const get_numa_node_id = @intToPtr(fn () c_long, 42);
pub const skb_change_head = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 43);
pub const xdp_adjust_head = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 44);
pub const probe_read_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 45);
pub const get_socket_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 46);
pub const get_socket_uid = @intToPtr(fn (skb: *kern.SkBuff) u32, 47);
pub const set_hash = @intToPtr(fn (skb: *kern.SkBuff, hash: u32) c_long, 48);
pub const setsockopt = @intToPtr(fn (bpf_socket: *kern.SockOps, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 49);
pub const skb_adjust_room = @intToPtr(fn (skb: *kern.SkBuff, len_diff: i32, mode: u32, flags: u64) c_long, 50);
pub const redirect_map = @intToPtr(fn (map: *const kern.MapDef, key: u32, flags: u64) c_long, 51);
pub const sk_redirect_map = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: u32, flags: u64) c_long, 52);
pub const sock_map_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 53);
pub const xdp_adjust_meta = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 54);
pub const perf_event_read_value = @intToPtr(fn (map: *const kern.MapDef, flags: u64, buf: *kern.PerfEventValue, buf_size: u32) c_long, 55);
pub const perf_prog_read_value = @intToPtr(fn (ctx: *kern.PerfEventData, buf: *kern.PerfEventValue, buf_size: u32) c_long, 56);
pub const getsockopt = @intToPtr(fn (bpf_socket: ?*c_void, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 57);
pub const override_return = @intToPtr(fn (regs: *PtRegs, rc: u64) c_long, 58);
pub const sock_ops_cb_flags_set = @intToPtr(fn (bpf_sock: *kern.SockOps, argval: c_int) c_long, 59);
pub const msg_redirect_map = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: u32, flags: u64) c_long, 60);
pub const msg_apply_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 61);
pub const msg_cork_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 62);
pub const msg_pull_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, end: u32, flags: u64) c_long, 63);
pub const bind = @intToPtr(fn (ctx: *kern.BpfSockAddr, addr: *kern.SockAddr, addr_len: c_int) c_long, 64);
pub const xdp_adjust_tail = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 65);
pub const skb_get_xfrm_state = @intToPtr(fn (skb: *kern.SkBuff, index: u32, xfrm_state: *kern.XfrmState, size: u32, flags: u64) c_long, 66);
pub const get_stack = @intToPtr(fn (ctx: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 67);
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);
pub const fib_lookup = @intToPtr(fn (ctx: ?*c_void, params: *kern.FibLookup, plen: c_int, flags: u32) c_long, 69);
pub const sock_hash_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 70);
pub const msg_redirect_hash = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 71);
pub const sk_redirect_hash = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 72);
pub const lwt_push_encap = @intToPtr(fn (skb: *kern.SkBuff, typ: u32, hdr: ?*c_void, len: u32) c_long, 73);
pub const lwt_seg6_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32) c_long, 74);
pub const lwt_seg6_adjust_srh = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, delta: i32) c_long, 75);
pub const lwt_seg6_action = @intToPtr(fn (skb: *kern.SkBuff, action: u32, param: ?*c_void, param_len: u32) c_long, 76);
pub const rc_repeat = @intToPtr(fn (ctx: ?*c_void) c_long, 77);
pub const rc_keydown = @intToPtr(fn (ctx: ?*c_void, protocol: u32, scancode: u64, toggle: u32) c_long, 78);
pub const skb_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff) u64, 79);
pub const get_current_cgroup_id = @intToPtr(fn () u64, 80);
pub const get_local_storage = @intToPtr(fn (map: ?*c_void, flags: u64) ?*c_void, 81);
pub const sk_select_reuseport = @intToPtr(fn (reuse: *kern.SkReusePortMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 82);
pub const skb_ancestor_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff, ancestor_level: c_int) u64, 83);
pub const sk_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 84);
pub const sk_lookup_udp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 85);
pub const sk_release = @intToPtr(fn (sock: *kern.Sock) c_long, 86);
pub const map_push_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*const c_void, flags: u64) c_long, 87);
pub const map_pop_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 88);
pub const map_peek_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 89);
pub const msg_push_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 90);
pub const msg_pop_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 91);
pub const rc_pointer_rel = @intToPtr(fn (ctx: ?*c_void, rel_x: i32, rel_y: i32) c_long, 92);
pub const spin_lock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 93);
pub const spin_unlock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 94);
pub const sk_fullsock = @intToPtr(fn (sk: *kern.Sock) ?*SkFullSock, 95);
pub const tcp_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.TcpSock, 96);
pub const skb_ecn_set_ce = @intToPtr(fn (skb: *kern.SkBuff) c_long, 97);
pub const get_listener_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.Sock, 98);
pub const skc_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 99);
pub const tcp_check_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) c_long, 100);
pub const sysctl_get_name = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong, flags: u64) c_long, 101);
pub const sysctl_get_current_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 102);
pub const sysctl_get_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 103);
pub const sysctl_set_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*const u8, buf_len: c_ulong) c_long, 104);
pub const strtol = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_long) c_long, 105);
pub const strtoul = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_ulong) c_long, 106);
pub const sk_storage_get = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock, value: ?*c_void, flags: u64) ?*c_void, 107);
pub const sk_storage_delete = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock) c_long, 108);
pub const send_signal = @intToPtr(fn (sig: u32) c_long, 109);
pub const tcp_gen_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) i64, 110);
pub const skb_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 111);
pub const probe_read_user = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 112);
pub const probe_read_kernel = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 113);
pub const probe_read_user_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 114);
pub const probe_read_kernel_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 115);
pub const tcp_send_ack = @intToPtr(fn (tp: ?*c_void, rcv_nxt: u32) c_long, 116);
pub const send_signal_thread = @intToPtr(fn (sig: u32) c_long, 117);
pub const jiffies64 = @intToPtr(fn () u64, 118);
pub const read_branch_records = @intToPtr(fn (ctx: *kern.PerfEventData, buf: ?*c_void, size: u32, flags: u64) c_long, 119);
pub const get_ns_current_pid_tgid = @intToPtr(fn (dev: u64, ino: u64, nsdata: *kern.PidNsInfo, size: u32) c_long, 120);
pub const xdp_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 121);
pub const get_netns_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 122);
pub const get_current_ancestor_cgroup_id = @intToPtr(fn (ancestor_level: c_int) u64, 123);
pub const sk_assign = @intToPtr(fn (skb: *kern.SkBuff, sk: *kern.Sock, flags: u64) c_long, 124);
pub const ktime_get_boot_ns = @intToPtr(fn () u64, 125);
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);
pub const seq_write = @intToPtr(fn (m: *kern.SeqFile, data: ?*const u8, len: u32) c_long, 127);
pub const sk_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock) u64, 128);
pub const sk_ancestor_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock, ancestor_level: c_long) u64, 129);
pub const ringbuf_output = @intToPtr(fn (ringbuf: ?*c_void, data: ?*c_void, size: u64, flags: u64) ?*c_void, 130);
pub const ringbuf_reserve = @intToPtr(fn (ringbuf: ?*c_void, size: u64, flags: u64) ?*c_void, 131);
pub const ringbuf_submit = @intToPtr(fn (data: ?*c_void, flags: u64) void, 132);
pub const ringbuf_discard = @intToPtr(fn (data: ?*c_void, flags: u64) void, 133);
pub const ringbuf_query = @intToPtr(fn (ringbuf: ?*c_void, flags: u64) u64, 134);
pub const csum_level = @intToPtr(fn (skb: *kern.SkBuff, level: u64) c_long, 134);
pub const skc_to_tcp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Tcp6Sock, 135);
pub const skc_to_tcp_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpSock, 136);
pub const skc_to_tcp_timewait_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpTimewaitSock, 137);
pub const skc_to_tcp_request_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpRequestSock, 138);
pub const skc_to_udp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Udp6Sock, 139);
pub const get_task_stack = @intToPtr(fn (task: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 140);

View File

@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("../../../std.zig");
const in_bpf_program = switch (std.builtin.arch) {
.bpfel, .bpfeb => true,
else => false,
};
pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};
pub const BpfSock = @Type(.Opaque);
pub const BpfSockAddr = @Type(.Opaque);
pub const FibLookup = @Type(.Opaque);
pub const MapDef = @Type(.Opaque);
pub const PerfEventData = @Type(.Opaque);
pub const PerfEventValue = @Type(.Opaque);
pub const PidNsInfo = @Type(.Opaque);
pub const SeqFile = @Type(.Opaque);
pub const SkBuff = @Type(.Opaque);
pub const SkMsgMd = @Type(.Opaque);
pub const SkReusePortMd = @Type(.Opaque);
pub const Sock = @Type(.Opaque);
pub const SockAddr = @Type(.Opaque);
pub const SockOps = @Type(.Opaque);
pub const SockTuple = @Type(.Opaque);
pub const SpinLock = @Type(.Opaque);
pub const SysCtl = @Type(.Opaque);
pub const Tcp6Sock = @Type(.Opaque);
pub const TcpRequestSock = @Type(.Opaque);
pub const TcpSock = @Type(.Opaque);
pub const TcpTimewaitSock = @Type(.Opaque);
pub const TunnelKey = @Type(.Opaque);
pub const Udp6Sock = @Type(.Opaque);
pub const XdpMd = @Type(.Opaque);
pub const XfrmState = @Type(.Opaque);

View File

@ -2379,7 +2379,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
if (field->gen_index == UINT32_MAX)
continue;
AstNode *align_expr = field->decl_node->data.struct_field.align_expr;
AstNode *align_expr = nullptr;
if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) {
align_expr = field->decl_node->data.struct_field.align_expr;
}
if (align_expr != nullptr) {
if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr,
&field->align))
@ -2475,9 +2478,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
AstNode *decl_node = union_type->data.unionation.decl_node;
assert(decl_node->type == NodeTypeContainerDecl);
uint32_t field_count = union_type->data.unionation.src_field_count;
TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
@ -2610,16 +2610,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
if (decl_node->type == NodeTypeContainerDecl) {
assert(!enum_type->data.enumeration.fields);
field_count = (uint32_t)decl_node->data.container_decl.fields.length;
if (field_count == 0) {
add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = nullptr;
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
} else {
field_count = enum_type->data.enumeration.src_field_count;
field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive;
}
if (field_count == 0) {
add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = nullptr;
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
@ -3062,7 +3062,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorNone;
AstNode *decl_node = union_type->data.unionation.decl_node;
assert(decl_node->type == NodeTypeContainerDecl);
if (union_type->data.unionation.resolve_loop_flag_zero_bits) {
if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
@ -3076,30 +3075,51 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
union_type->data.unionation.resolve_loop_flag_zero_bits = true;
assert(union_type->data.unionation.fields == nullptr);
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
uint32_t field_count;
if (decl_node->type == NodeTypeContainerDecl) {
assert(union_type->data.unionation.fields == nullptr);
field_count = (uint32_t)decl_node->data.container_decl.fields.length;
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
union_type->data.unionation.fields_by_name.init(field_count);
} else {
field_count = union_type->data.unionation.src_field_count;
assert(field_count == 0 || union_type->data.unionation.fields != nullptr);
}
if (field_count == 0) {
add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
union_type->data.unionation.fields_by_name.init(field_count);
Scope *scope = &union_type->data.unionation.decls_scope->base;
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
enum_type_node != nullptr;
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
bool is_auto_enum; // union(enum) or union(enum(expr))
bool is_explicit_enum; // union(expr)
AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr)
if (decl_node->type == NodeTypeContainerDecl) {
is_auto_enum = decl_node->data.container_decl.auto_enum;
is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr;
enum_type_node = decl_node->data.container_decl.init_arg_expr;
} else {
is_auto_enum = false;
is_explicit_enum = union_type->data.unionation.tag_type != nullptr;
enum_type_node = nullptr;
}
union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum;
bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto;
bool want_safety = (field_count >= 2)
&& (is_auto_layout || is_explicit_enum)
&& !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
ZigType *tag_type;
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety);
bool *covered_enum_fields;
bool *is_zero_bits = heap::c_allocator.allocate<bool>(field_count);
ZigLLVMDIEnumerator **di_enumerators;
if (create_enum_type) {
occupied_tag_values.init(field_count);
@ -3157,71 +3177,81 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return err;
}
tag_type = enum_type;
covered_enum_fields = heap::c_allocator.allocate<bool>(enum_type->data.enumeration.src_field_count);
} else {
tag_type = nullptr;
if (decl_node->type == NodeTypeContainerDecl) {
tag_type = nullptr;
} else {
tag_type = union_type->data.unionation.tag_type;
}
}
if (tag_type != nullptr) {
covered_enum_fields = heap::c_allocator.allocate<bool>(tag_type->data.enumeration.src_field_count);
}
union_type->data.unionation.tag_type = tag_type;
uint32_t gen_field_index = 0;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
Buf *field_name = field_node->data.struct_field.name;
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
union_field->name = field_node->data.struct_field.name;
union_field->decl_node = field_node;
union_field->gen_index = UINT32_MAX;
if (decl_node->type == NodeTypeContainerDecl) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
union_field->name = field_node->data.struct_field.name;
union_field->decl_node = field_node;
union_field->gen_index = UINT32_MAX;
is_zero_bits[i] = false;
auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, union_field->decl_node,
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
if (field_node->data.struct_field.type == nullptr) {
if (is_auto_enum || is_explicit_enum) {
union_field->type_entry = g->builtin_types.entry_void;
is_zero_bits[i] = true;
} else {
add_node_error(g, field_node, buf_sprintf("union field missing type"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
} else {
ZigValue *field_type_val = analyze_const_value(g, scope,
field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef);
if (type_is_invalid(field_type_val->type)) {
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
assert(field_type_val->special != ConstValSpecialRuntime);
union_field->type_val = field_type_val;
}
if (field_node->data.struct_field.value != nullptr && !is_auto_enum) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
buf_create_from_str("untagged union field assignment"));
add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
}
}
bool field_is_zero_bits;
if (field_node->data.struct_field.type == nullptr) {
if (decl_node->data.container_decl.auto_enum ||
decl_node->data.container_decl.init_arg_expr != nullptr)
{
union_field->type_entry = g->builtin_types.entry_void;
field_is_zero_bits = true;
} else {
add_node_error(g, field_node, buf_sprintf("union field missing type"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
} else {
ZigValue *field_type_val = analyze_const_value(g, scope,
field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef);
if (type_is_invalid(field_type_val->type)) {
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
assert(field_type_val->special != ConstValSpecialRuntime);
union_field->type_val = field_type_val;
if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
return ErrorSemanticAnalyzeFail;
if (union_field->type_val != nullptr) {
bool field_is_opaque_type;
if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) {
if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) {
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
if (field_is_opaque_type) {
add_node_error(g, field_node,
add_node_error(g, union_field->decl_node,
buf_create_from_str(
"opaque types have unknown size and therefore cannot be directly embedded in unions"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
switch (type_val_resolve_requires_comptime(g, field_type_val)) {
switch (type_val_resolve_requires_comptime(g, union_field->type_val)) {
case ReqCompTimeInvalid:
if (g->trace_err != nullptr) {
g->trace_err = add_error_note(g, g->trace_err, field_node,
g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node,
buf_create_from_str("while checking this field"));
}
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
@ -3233,29 +3263,25 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
break;
}
if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) {
if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) {
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
}
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
buf_create_from_str("untagged union field assignment"));
add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
}
if (create_enum_type) {
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i);
union_field->enum_field = &tag_type->data.enumeration.fields[i];
union_field->enum_field->name = field_name;
union_field->enum_field->name = union_field->name;
union_field->enum_field->decl_index = i;
union_field->enum_field->decl_node = field_node;
union_field->enum_field->decl_node = union_field->decl_node;
auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
assert(prev_entry == nullptr); // caught by union de-duplicator above
AstNode *tag_value = field_node->data.struct_field.value;
AstNode *tag_value = decl_node->type == NodeTypeContainerDecl
? union_field->decl_node->data.struct_field.value : nullptr;
// In this first pass we resolve explicit tag values.
// In a second pass we will fill in the unspecified ones.
if (tag_value != nullptr) {
@ -3283,11 +3309,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorSemanticAnalyzeFail;
}
}
} else if (enum_type_node != nullptr) {
union_field->enum_field = find_enum_type_field(tag_type, field_name);
} else if (tag_type != nullptr) {
union_field->enum_field = find_enum_type_field(tag_type, union_field->name);
if (union_field->enum_field == nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
ErrorMsg *msg = add_node_error(g, union_field->decl_node,
buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name)));
add_error_note(g, msg, tag_type->data.enumeration.decl_node,
buf_sprintf("enum declared here"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
@ -3296,21 +3322,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
covered_enum_fields[union_field->enum_field->decl_index] = true;
} else {
union_field->enum_field = heap::c_allocator.create<TypeEnumField>();
union_field->enum_field->name = field_name;
union_field->enum_field->name = union_field->name;
union_field->enum_field->decl_index = i;
bigint_init_unsigned(&union_field->enum_field->value, i);
}
assert(union_field->enum_field != nullptr);
if (field_is_zero_bits)
continue;
union_field->gen_index = gen_field_index;
gen_field_index += 1;
}
bool src_have_tag = decl_node->data.container_decl.auto_enum ||
decl_node->data.container_decl.init_arg_expr != nullptr;
uint32_t gen_field_index = 0;
for (uint32_t i = 0; i < field_count; i += 1) {
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
if (!is_zero_bits[i]) {
union_field->gen_index = gen_field_index;
gen_field_index += 1;
}
}
bool src_have_tag = is_auto_enum || is_explicit_enum;
if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
const char *qual_str;
@ -3324,8 +3352,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
qual_str = "extern";
break;
}
AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ?
decl_node->data.container_decl.init_arg_expr : decl_node;
AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node;
add_node_error(g, source_node,
buf_sprintf("%s union does not support enum tag type", qual_str));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
@ -3333,43 +3360,47 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
if (create_enum_type) {
// Now iterate again and populate the unspecified tag values
uint32_t next_maybe_unoccupied_index = 0;
if (decl_node->type == NodeTypeContainerDecl) {
// Now iterate again and populate the unspecified tag values
uint32_t next_maybe_unoccupied_index = 0;
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
AstNode *tag_value = field_node->data.struct_field.value;
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
AstNode *tag_value = field_node->data.struct_field.value;
if (tag_value == nullptr) {
if (occupied_tag_values.size() == 0) {
bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
next_maybe_unoccupied_index += 1;
} else {
BigInt proposed_value;
for (;;) {
bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
if (tag_value == nullptr) {
if (occupied_tag_values.size() == 0) {
bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
next_maybe_unoccupied_index += 1;
auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
if (entry != nullptr) {
continue;
} else {
BigInt proposed_value;
for (;;) {
bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
next_maybe_unoccupied_index += 1;
auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
if (entry != nullptr) {
continue;
}
break;
}
break;
bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
}
bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
}
}
}
} else if (enum_type_node != nullptr) {
} else if (tag_type != nullptr) {
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
if (!covered_enum_fields[i]) {
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
ErrorMsg *msg = add_node_error(g, decl_node,
buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
add_error_note(g, msg, field_node,
buf_sprintf("declared here"));
if (decl_node->type == NodeTypeContainerDecl) {
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
add_error_note(g, msg, field_node,
buf_sprintf("declared here"));
}
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
}
}
@ -8357,7 +8388,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
ZigLLVMDIFile *di_file;
ZigLLVMDIScope *di_scope;
unsigned line;
if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) {
if (decl_node != nullptr) {
Scope *scope = &struct_type->data.structure.decls_scope->base;
ZigType *import = get_scope_import(scope);
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
uint64_t store_size_in_bits = union_field->type_entry->size_in_bits;
uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align;
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
AstNode *field_node = union_field->decl_node;
union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name),
import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),

View File

@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false);
ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr);
for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
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
union_field_val->special = ConstValSpecialStatic;
union_field_val->type = type_info_union_field_type;
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = get_optional_type(ira->codegen, type_info_enum_field_type);
if (fields[1]->data.x_optional == nullptr) {
inner_fields[1]->data.x_optional = nullptr;
} else {
inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>();
make_enum_field_val(ira, inner_fields[1]->data.x_optional, union_field->enum_field, type_info_enum_field_type);
}
inner_fields[2]->special = ConstValSpecialStatic;
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = union_field->type_entry;
inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
inner_fields[1]->data.x_type = union_field->type_entry;
ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
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
entry->data.structure.layout = layout;
entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone;
entry->data.structure.created_by_at_type = true;
entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name);
entry->data.structure.decls_scope = create_decls_scope(
ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
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
return ira->codegen->invalid_inst_gen->value->type;
field->value = *field_int_value;
}
return entry;
}
case ZigTypeIdUnion:
ir_add_error(ira, source_instr, buf_sprintf(
"TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
return ira->codegen->invalid_inst_gen->value->type;
case ZigTypeIdUnion: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr));
ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0);
if (layout_value == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
assert(layout_value->special == ConstValSpecialStatic);
assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1);
if (tag_type != nullptr && type_is_invalid(tag_type)) {
return ira->codegen->invalid_inst_gen->value->type;
}
if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) {
ir_add_error(ira, source_instr, buf_sprintf(
"expected enum type, found '%s'", type_id_name(tag_type->id)));
return ira->codegen->invalid_inst_gen->value->type;
}
ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2);
if (fields_value == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
assert(fields_value->special == ConstValSpecialStatic);
assert(is_slice(fields_value->type));
ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index];
ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 3);
if (decls_value == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
assert(decls_value->special == ConstValSpecialStatic);
assert(is_slice(decls_value->type));
ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
if (decls_len != 0) {
ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Union.decls must be empty for @Type"));
return ira->codegen->invalid_inst_gen->value->type;
}
ZigType *entry = new_type_table_entry(ZigTypeIdUnion);
buf_init_from_buf(&entry->name,
get_anon_type_name(ira->codegen, ira->old_irb.exec, "union", source_instr->scope, source_instr->source_node, &entry->name));
entry->data.unionation.decl_node = source_instr->source_node;
entry->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(fields_len);
entry->data.unionation.fields_by_name.init(fields_len);
entry->data.unionation.decls_scope = create_decls_scope(
ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
entry->data.unionation.tag_type = tag_type;
entry->data.unionation.src_field_count = fields_len;
entry->data.unionation.layout = layout;
assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val;
assert(fields_arr->special == ConstValSpecialStatic);
assert(fields_arr->data.x_array.special == ConstArraySpecialNone);
for (size_t i = 0; i < fields_len; i++) {
ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i];
assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr));
TypeUnionField *field = &entry->data.unionation.fields[i];
field->name = buf_alloc();
if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name)))
return ira->codegen->invalid_inst_gen->value->type;
if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) {
ir_add_error(ira, source_instr, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name)));
return ira->codegen->invalid_inst_gen->value->type;
}
field->decl_node = source_instr->source_node;
ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1);
if (type_value == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
field->type_val = type_value;
field->type_entry = type_value->data.x_type;
}
return entry;
}
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
ir_add_error(ira, source_instr, buf_sprintf(

View File

@ -10,6 +10,135 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
});
cases.add("@Type for union with opaque field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "foo", .field_type = @Type(.Opaque) },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ _ = Untagged{};
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
"tmp.zig:13:17: note: referenced here",
});
cases.add("@Type for union with zero fields",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{},
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ _ = Untagged{};
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: unions must have 1 or more fields",
"tmp.zig:11:17: note: referenced here",
});
cases.add("@Type for exhaustive enum with zero fields",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
\\ .layout = .Auto,
\\ .tag_type = u1,
\\ .fields = &[_]TypeInfo.EnumField{},
\\ .decls = &[_]TypeInfo.Declaration{},
\\ .is_exhaustive = true,
\\ },
\\});
\\export fn entry() void {
\\ _ = @intToEnum(Tag, 0);
\\}
, &[_][]const u8{
"tmp.zig:2:20: error: enums must have 1 or more fields",
"tmp.zig:12:9: note: referenced here",
});
cases.add("@Type for tagged union with extra union field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
\\ .layout = .Auto,
\\ .tag_type = u1,
\\ .fields = &[_]TypeInfo.EnumField{
\\ .{ .name = "signed", .value = 0 },
\\ .{ .name = "unsigned", .value = 1 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ .is_exhaustive = true,
\\ },
\\});
\\const Tagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = Tag,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "signed", .field_type = i32 },
\\ .{ .name = "unsigned", .field_type = u32 },
\\ .{ .name = "arst", .field_type = f32 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ var tagged = Tagged{ .signed = -1 };
\\ tagged = .{ .unsigned = 1 };
\\}
, &[_][]const u8{
"tmp.zig:14:23: error: enum field not found: 'arst'",
"tmp.zig:2:20: note: enum declared here",
"tmp.zig:27:24: note: referenced here",
});
cases.add("@Type for tagged union with extra enum field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
\\ .layout = .Auto,
\\ .tag_type = u2,
\\ .fields = &[_]TypeInfo.EnumField{
\\ .{ .name = "signed", .value = 0 },
\\ .{ .name = "unsigned", .value = 1 },
\\ .{ .name = "arst", .field_type = 2 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ .is_exhaustive = true,
\\ },
\\});
\\const Tagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = Tag,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "signed", .field_type = i32 },
\\ .{ .name = "unsigned", .field_type = u32 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ var tagged = Tagged{ .signed = -1 };
\\ tagged = .{ .unsigned = 1 };
\\}
, &[_][]const u8{
"tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'",
"tmp.zig:18:21: note: referenced here",
"tmp.zig:27:18: note: referenced here",
});
cases.add("@Type with undefined",
\\comptime {
\\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
@ -7419,7 +7548,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add( // fixed bug #2032
"compile diagnostic string for top level decl type",
"compile diagnostic string for top level decl type",
\\export fn entry() void {
\\ var foo: u32 = @This(){};
\\}

View File

@ -313,3 +313,64 @@ test "Type.Enum" {
testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6)));
}
test "Type.Union" {
const Untagged = @Type(.{
.Union = .{
.layout = .Auto,
.tag_type = null,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "int", .field_type = i32 },
.{ .name = "float", .field_type = f32 },
},
.decls = &[_]TypeInfo.Declaration{},
},
});
var untagged = Untagged{ .int = 1 };
untagged.float = 2.0;
untagged.int = 3;
testing.expectEqual(@as(i32, 3), untagged.int);
const PackedUntagged = @Type(.{
.Union = .{
.layout = .Packed,
.tag_type = null,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "signed", .field_type = i32 },
.{ .name = "unsigned", .field_type = u32 },
},
.decls = &[_]TypeInfo.Declaration{},
},
});
var packed_untagged = PackedUntagged{ .signed = -1 };
testing.expectEqual(@as(i32, -1), packed_untagged.signed);
testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
const Tag = @Type(.{
.Enum = .{
.layout = .Auto,
.tag_type = u1,
.fields = &[_]TypeInfo.EnumField{
.{ .name = "signed", .value = 0 },
.{ .name = "unsigned", .value = 1 },
},
.decls = &[_]TypeInfo.Declaration{},
.is_exhaustive = true,
},
});
const Tagged = @Type(.{
.Union = .{
.layout = .Auto,
.tag_type = Tag,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "signed", .field_type = i32 },
.{ .name = "unsigned", .field_type = u32 },
},
.decls = &[_]TypeInfo.Declaration{},
},
});
var tagged = Tagged{ .signed = -1 };
testing.expectEqual(Tag.signed, tagged);
tagged = .{ .unsigned = 1 };
testing.expectEqual(Tag.unsigned, tagged);
}

View File

@ -198,8 +198,6 @@ fn testUnion() void {
expect(typeinfo_info.Union.layout == .Auto);
expect(typeinfo_info.Union.tag_type.? == TypeId);
expect(typeinfo_info.Union.fields.len == 25);
expect(typeinfo_info.Union.fields[4].enum_field != null);
expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
expect(typeinfo_info.Union.decls.len == 21);
@ -213,7 +211,6 @@ fn testUnion() void {
expect(notag_union_info.Union.tag_type == null);
expect(notag_union_info.Union.layout == .Auto);
expect(notag_union_info.Union.fields.len == 2);
expect(notag_union_info.Union.fields[0].enum_field == null);
expect(notag_union_info.Union.fields[1].field_type == u32);
const TestExternUnion = extern union {
@ -223,7 +220,6 @@ fn testUnion() void {
const extern_union_info = @typeInfo(TestExternUnion);
expect(extern_union_info.Union.layout == .Extern);
expect(extern_union_info.Union.tag_type == null);
expect(extern_union_info.Union.fields[0].enum_field == null);
expect(extern_union_info.Union.fields[0].field_type == *c_void);
}