fix implicit casting to *c_void
closes #1588 also some small std lib changes regarding posix sockets and one doc typo fix
This commit is contained in:
parent
7b204649e3
commit
9485043b3c
|
@ -587,7 +587,7 @@ const c_string_literal =
|
||||||
;
|
;
|
||||||
{#code_end#}
|
{#code_end#}
|
||||||
<p>
|
<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.
|
has a terminating null byte.
|
||||||
</p>
|
</p>
|
||||||
{#see_also|@embedFile#}
|
{#see_also|@embedFile#}
|
||||||
|
|
196
src/ir.cpp
196
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 void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
|
||||||
static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
|
static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
|
||||||
ConstExprValue *out_val, ConstExprValue *ptr_val);
|
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) {
|
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
|
||||||
assert(get_src_ptr_type(const_val->type) != nullptr);
|
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;
|
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
|
// pointer const
|
||||||
if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
|
if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
|
||||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
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
|
// cast from T to *T where T is zero bits
|
||||||
if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
|
if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||||
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||||
|
@ -20234,9 +20252,91 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
|
||||||
return result;
|
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;
|
Error err;
|
||||||
|
|
||||||
|
ZigType *src_type = ptr->value.type;
|
||||||
|
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->invalid_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_src_ptr_type(dest_type) == nullptr) {
|
||||||
|
ir_add_error(ira, dest_type_src,
|
||||||
|
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {
|
||||||
|
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->invalid_instruction;
|
||||||
|
|
||||||
|
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->invalid_instruction;
|
||||||
|
|
||||||
|
uint32_t dest_align_bytes;
|
||||||
|
if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
|
if (dest_align_bytes > src_align_bytes) {
|
||||||
|
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_src->source_node,
|
||||||
|
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes));
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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_src->source_node,
|
||||||
|
buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name)));
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the bigger alignment, it can only help-
|
||||||
|
// unless the target is zero bits.
|
||||||
|
IrInstruction *result;
|
||||||
|
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->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;
|
IrInstruction *dest_type_value = instruction->dest_type->other;
|
||||||
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
|
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
|
||||||
if (type_is_invalid(dest_type))
|
if (type_is_invalid(dest_type))
|
||||||
|
@ -20247,78 +20347,10 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr
|
||||||
if (type_is_invalid(src_type))
|
if (type_is_invalid(src_type))
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
// We have a check for zero bits later so we use get_src_ptr_type to
|
IrInstruction *result = ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value);
|
||||||
// validate src_type and dest_type.
|
if (type_is_invalid(result->value.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_src_ptr_type(dest_type) == nullptr) {
|
|
||||||
ir_add_error(ira, dest_type_value,
|
|
||||||
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instr_is_comptime(ptr)) {
|
|
||||||
ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
|
|
||||||
if (!val)
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->builtin_types.entry_invalid;
|
||||||
|
|
||||||
uint32_t dest_align_bytes;
|
|
||||||
if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
|
|
||||||
if (dest_align_bytes > src_align_bytes) {
|
|
||||||
ErrorMsg *msg = ir_add_error(ira, &instruction->base, 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,
|
|
||||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes));
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,
|
|
||||||
instruction->base.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,
|
|
||||||
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,
|
|
||||||
buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name)));
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the bigger alignment, it can only help-
|
|
||||||
// unless the target is zero bits.
|
|
||||||
IrInstruction *result;
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
result = casted_ptr;
|
|
||||||
}
|
|
||||||
ir_link_new_instruction(result, &instruction->base);
|
ir_link_new_instruction(result, &instruction->base);
|
||||||
return result->value.type;
|
return result->value.type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
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
|
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);
|
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);
|
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 await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
|
||||||
try std.os.posixGetSockOptConnectError(sockfd);
|
try std.os.posixGetSockOptConnectError(sockfd);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
/// Same as posixConnect except it is for blocking socket file descriptors.
|
||||||
/// It expects to receive EINPROGRESS.
|
/// 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) {
|
while (true) {
|
||||||
const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
|
const rc = posix.connect(sockfd, sockaddr, len);
|
||||||
const err = posix.getErrno(rc);
|
const err = posix.getErrno(rc);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
0, posix.EINPROGRESS => return,
|
0, posix.EINPROGRESS => return,
|
||||||
|
|
|
@ -1094,6 +1094,7 @@ pub const in_port_t = u16;
|
||||||
pub const sa_family_t = u16;
|
pub const sa_family_t = u16;
|
||||||
pub const socklen_t = u32;
|
pub const socklen_t = u32;
|
||||||
|
|
||||||
|
/// This intentionally only has ip4 and ip6
|
||||||
pub const sockaddr = extern union {
|
pub const sockaddr = extern union {
|
||||||
in: sockaddr_in,
|
in: sockaddr_in,
|
||||||
in6: sockaddr_in6,
|
in6: sockaddr_in6,
|
||||||
|
@ -1114,6 +1115,11 @@ pub const sockaddr_in6 = extern struct {
|
||||||
scope_id: u32,
|
scope_id: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const sockaddr_un = extern struct {
|
||||||
|
family: sa_family_t,
|
||||||
|
path: [108]u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const iovec = extern struct {
|
pub const iovec = extern struct {
|
||||||
iov_base: [*]u8,
|
iov_base: [*]u8,
|
||||||
iov_len: usize,
|
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);
|
return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
|
pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
|
||||||
return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
|
return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
|
pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
|
||||||
|
|
|
@ -537,3 +537,13 @@ pub const PFN_void = extern fn (*c_void) void;
|
||||||
fn foobar(func: PFN_void) void {
|
fn foobar(func: PFN_void) void {
|
||||||
std.debug.assert(@ptrToInt(func) == @maxValue(usize));
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
const tests = @import("tests.zig");
|
const tests = @import("tests.zig");
|
||||||
|
|
||||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
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(
|
cases.add(
|
||||||
"runtime index into comptime type slice",
|
"runtime index into comptime type slice",
|
||||||
\\const Struct = struct {
|
\\const Struct = struct {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user