Commit 9485043b3c
Changed files (7)
src
test
doc/langref.html.in
@@ -587,7 +587,7 @@ const c_string_literal =
;
{#code_end#}
<p>
- In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const char{#endsyntax#} and
+ In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and
has a terminating null byte.
</p>
{#see_also|@embedFile#}
src/ir.cpp
@@ -155,6 +155,8 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
ConstExprValue *out_val, ConstExprValue *ptr_val);
+static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
+ ZigType *dest_type, IrInstruction *dest_type_src);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -8573,17 +8575,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
return result;
}
- // *T and [*]T can always cast to *c_void
- if (wanted_type->id == ZigTypeIdPointer &&
- wanted_type->data.pointer.ptr_len == PtrLenSingle &&
- wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void &&
- actual_type->id == ZigTypeIdPointer &&
- (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
- (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
- {
- return result;
- }
-
// pointer const
if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
@@ -11156,6 +11147,33 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
+ // cast from *T and [*]T to *c_void and ?*c_void
+ // but don't do it if the actual type is a double pointer
+ if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.child_type->id != ZigTypeIdPointer) {
+ ZigType *dest_ptr_type = nullptr;
+ if (wanted_type->id == ZigTypeIdPointer &&
+ wanted_type->data.pointer.ptr_len == PtrLenSingle &&
+ wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
+ {
+ dest_ptr_type = wanted_type;
+ } else if (wanted_type->id == ZigTypeIdOptional &&
+ wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&
+ wanted_type->data.maybe.child_type->data.pointer.ptr_len == PtrLenSingle &&
+ wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
+ {
+ dest_ptr_type = wanted_type->data.maybe.child_type;
+ }
+ if (dest_ptr_type != nullptr &&
+ (!actual_type->data.pointer.is_const || dest_ptr_type->data.pointer.is_const) &&
+ (!actual_type->data.pointer.is_volatile || dest_ptr_type->data.pointer.is_volatile) &&
+ actual_type->data.pointer.bit_offset == dest_ptr_type->data.pointer.bit_offset &&
+ actual_type->data.pointer.unaligned_bit_count == dest_ptr_type->data.pointer.unaligned_bit_count &&
+ get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type))
+ {
+ return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr);
+ }
+ }
+
// cast from T to *T where T is zero bits
if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
@@ -20234,79 +20252,75 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
return result;
}
-static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
+ ZigType *dest_type, IrInstruction *dest_type_src)
+{
Error err;
- IrInstruction *dest_type_value = instruction->dest_type->other;
- ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
- if (type_is_invalid(dest_type))
- return ira->codegen->builtin_types.entry_invalid;
-
- IrInstruction *ptr = instruction->ptr->other;
ZigType *src_type = ptr->value.type;
- if (type_is_invalid(src_type))
- return ira->codegen->builtin_types.entry_invalid;
+ assert(!type_is_invalid(src_type));
// We have a check for zero bits later so we use get_src_ptr_type to
// validate src_type and dest_type.
if (get_src_ptr_type(src_type) == nullptr) {
ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
}
if (get_src_ptr_type(dest_type) == nullptr) {
- ir_add_error(ira, dest_type_value,
+ ir_add_error(ira, dest_type_src,
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
}
if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {
- ir_add_error(ira, &instruction->base, buf_sprintf("cast discards const qualifier"));
- return ira->codegen->builtin_types.entry_invalid;
+ ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
+ return ira->codegen->invalid_instruction;
}
if (instr_is_comptime(ptr)) {
ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
if (!val)
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
- ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- copy_const_val(out_val, val, false);
- out_val->type = dest_type;
- return dest_type;
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ dest_type);
+ copy_const_val(&result->value, val, false);
+ result->value.type = dest_type;
+ return result;
}
uint32_t src_align_bytes;
if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
uint32_t dest_align_bytes;
if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
if (dest_align_bytes > src_align_bytes) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment"));
+ ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
add_error_note(ira->codegen, msg, ptr->source_node,
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes));
- add_error_note(ira->codegen, msg, dest_type_value->source_node,
+ add_error_note(ira->codegen, msg, dest_type_src->source_node,
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes));
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, nullptr, ptr);
+ IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, nullptr, ptr);
casted_ptr->value.type = dest_type;
if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base,
+ ErrorMsg *msg = ir_add_error(ira, source_instr,
buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
add_error_note(ira->codegen, msg, ptr->source_node,
buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name)));
- add_error_note(ira->codegen, msg, dest_type_value->source_node,
+ add_error_note(ira->codegen, msg, dest_type_src->source_node,
buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name)));
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
}
// Keep the bigger alignment, it can only help-
@@ -20315,10 +20329,28 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr
if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {
result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);
if (type_is_invalid(result->value.type))
- return ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
} else {
result = casted_ptr;
}
+ return result;
+}
+
+static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+ IrInstruction *dest_type_value = instruction->dest_type->other;
+ ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *ptr = instruction->ptr->other;
+ ZigType *src_type = ptr->value.type;
+ if (type_is_invalid(src_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *result = ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value);
+ if (type_is_invalid(result->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
ir_link_new_instruction(result, &instruction->base);
return result->value.type;
}
std/event/tcp.zig
@@ -110,13 +110,61 @@ pub const Server = struct {
}
};
+pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
+ const sockfd = try std.os.posixSocket(
+ posix.AF_UNIX,
+ posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK,
+ 0,
+ );
+ errdefer std.os.close(sockfd);
+
+ var sock_addr = posix.sockaddr{
+ .un = posix.sockaddr_un{
+ .family = posix.AF_UNIX,
+ .path = undefined,
+ },
+ };
+
+ if (path.len > @typeOf(sock_addr.un.path).len) return error.NameTooLong;
+ mem.copy(u8, sock_addr.un.path[0..], path);
+ const size = @intCast(u32, @sizeOf(posix.sa_family_t) + path.len);
+ try std.os.posixConnectAsync(sockfd, &sock_addr, size);
+ try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
+ try std.os.posixGetSockOptConnectError(sockfd);
+
+ return sockfd;
+}
+
+pub async fn socketRead(loop: *std.event.Loop, fd: i32, buffer: []u8) !void {
+ while (true) {
+ return std.os.posixRead(fd, buffer) catch |err| switch (err) {
+ error.WouldBlock => {
+ try await try async loop.linuxWaitFd(fd, std.os.posix.EPOLLET | std.os.posix.EPOLLIN);
+ continue;
+ },
+ else => return err,
+ };
+ }
+}
+pub async fn socketWrite(loop: *std.event.Loop, fd: i32, buffer: []const u8) !void {
+ while (true) {
+ return std.os.posixWrite(fd, buffer) catch |err| switch (err) {
+ error.WouldBlock => {
+ try await try async loop.linuxWaitFd(fd, std.os.posix.EPOLLET | std.os.posix.EPOLLOUT);
+ continue;
+ },
+ else => return err,
+ };
+ }
+}
+
pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {
var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
errdefer std.os.close(sockfd);
- try std.os.posixConnectAsync(sockfd, &address.os_addr);
+ try std.os.posixConnectAsync(sockfd, &address.os_addr, @sizeOf(posix.sockaddr_in));
try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
try std.os.posixGetSockOptConnectError(sockfd);
std/os/linux/index.zig
@@ -1094,6 +1094,7 @@ pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const socklen_t = u32;
+/// This intentionally only has ip4 and ip6
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
@@ -1114,6 +1115,11 @@ pub const sockaddr_in6 = extern struct {
scope_id: u32,
};
+pub const sockaddr_un = extern struct {
+ family: sa_family_t,
+ path: [108]u8,
+};
+
pub const iovec = extern struct {
iov_base: [*]u8,
iov_len: usize,
@@ -1148,8 +1154,8 @@ pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
}
-pub fn connect(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
- return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
+pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
+ return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len);
}
pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
std/os/index.zig
@@ -2677,9 +2677,9 @@ pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectEr
/// Same as posixConnect except it is for blocking socket file descriptors.
/// It expects to receive EINPROGRESS.
-pub fn posixConnectAsync(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
+pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
while (true) {
- const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
+ const rc = posix.connect(sockfd, sockaddr, len);
const err = posix.getErrno(rc);
switch (err) {
0, posix.EINPROGRESS => return,
test/cases/cast.zig
@@ -537,3 +537,13 @@ pub const PFN_void = extern fn (*c_void) void;
fn foobar(func: PFN_void) void {
std.debug.assert(@ptrToInt(func) == @maxValue(usize));
}
+
+test "implicit ptr to *c_void" {
+ var a: u32 = 1;
+ var ptr: *c_void = &a;
+ var b: *u32 = @ptrCast(*u32, ptr);
+ assert(b.* == 1);
+ var ptr2: ?*c_void = &a;
+ var c: *u32 = @ptrCast(*u32, ptr2.?);
+ assert(c.* == 1);
+}
test/compile_errors.zig
@@ -1,6 +1,18 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.add(
+ "don't implicit cast double pointer to *c_void",
+ \\export fn entry() void {
+ \\ var a: u32 = 1;
+ \\ var ptr: *c_void = &a;
+ \\ var b: *u32 = @ptrCast(*u32, ptr);
+ \\ var ptr2: *c_void = &b;
+ \\}
+ ,
+ ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'",
+ );
+
cases.add(
"runtime index into comptime type slice",
\\const Struct = struct {