authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-26 11:06:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-26 11:06:09-04:00
log9485043b3c445a3153e61c0bbc908486134d564a
tree9a8d9f36bd6b445e49e166aaf716d9559d4538c8
parent7b204649e3af348a7831837d5a36219733b505ca
signaturelock-open Commit is signed but in an unrecognized format.

fix implicit casting to *c_void

closes #1588 also some small std lib changes regarding posix sockets and one doc typo fix

7 files changed, 155 insertions(+), 47 deletions(-)

doc/langref.html.in+1-1
...@@ -587,7 +587,7 @@ const c_string_literal =...@@ -587,7 +587,7 @@ const c_string_literal =
587;587;
588 {#code_end#}588 {#code_end#}
589 <p>589 <p>
590 In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const char{#endsyntax#} and590 In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and
591 has a terminating null byte.591 has a terminating null byte.
592 </p>592 </p>
593 {#see_also|@embedFile#}593 {#see_also|@embedFile#}
src/ir.cpp+73-41
...@@ -155,6 +155,8 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -155,6 +155,8 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
155static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);155static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
156static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,156static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
157 ConstExprValue *out_val, ConstExprValue *ptr_val);157 ConstExprValue *out_val, ConstExprValue *ptr_val);
158static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
159 ZigType *dest_type, IrInstruction *dest_type_src);
158160
159static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {161static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
160 assert(get_src_ptr_type(const_val->type) != nullptr);162 assert(get_src_ptr_type(const_val->type) != nullptr);
...@@ -8573,17 +8575,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -8573,17 +8575,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
8573 return result;8575 return result;
8574 }8576 }
85758577
8576 // *T and [*]T can always cast to *c_void
8577 if (wanted_type->id == ZigTypeIdPointer &&
8578 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8579 wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void &&
8580 actual_type->id == ZigTypeIdPointer &&
8581 (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
8582 (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
8583 {
8584 return result;
8585 }
8586
8587 // pointer const8578 // pointer const
8588 if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {8579 if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
8589 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,8580 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...@@ -11156,6 +11147,33 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
11156 }11147 }
11157 }11148 }
1115811149
11150 // cast from *T and [*]T to *c_void and ?*c_void
11151 // but don't do it if the actual type is a double pointer
11152 if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.child_type->id != ZigTypeIdPointer) {
11153 ZigType *dest_ptr_type = nullptr;
11154 if (wanted_type->id == ZigTypeIdPointer &&
11155 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
11156 wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
11157 {
11158 dest_ptr_type = wanted_type;
11159 } else if (wanted_type->id == ZigTypeIdOptional &&
11160 wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&
11161 wanted_type->data.maybe.child_type->data.pointer.ptr_len == PtrLenSingle &&
11162 wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
11163 {
11164 dest_ptr_type = wanted_type->data.maybe.child_type;
11165 }
11166 if (dest_ptr_type != nullptr &&
11167 (!actual_type->data.pointer.is_const || dest_ptr_type->data.pointer.is_const) &&
11168 (!actual_type->data.pointer.is_volatile || dest_ptr_type->data.pointer.is_volatile) &&
11169 actual_type->data.pointer.bit_offset == dest_ptr_type->data.pointer.bit_offset &&
11170 actual_type->data.pointer.unaligned_bit_count == dest_ptr_type->data.pointer.unaligned_bit_count &&
11171 get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type))
11172 {
11173 return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr);
11174 }
11175 }
11176
11159 // cast from T to *T where T is zero bits11177 // cast from T to *T where T is zero bits
11160 if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&11178 if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
11161 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,11179 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...@@ -20234,79 +20252,75 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
20234 return result;20252 return result;
20235}20253}
2023620254
20237static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {20255static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
20256 ZigType *dest_type, IrInstruction *dest_type_src)
20257{
20238 Error err;20258 Error err;
2023920259
20240 IrInstruction *dest_type_value = instruction->dest_type->other;
20241 ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
20242 if (type_is_invalid(dest_type))
20243 return ira->codegen->builtin_types.entry_invalid;
20244
20245 IrInstruction *ptr = instruction->ptr->other;
20246 ZigType *src_type = ptr->value.type;20260 ZigType *src_type = ptr->value.type;
20247 if (type_is_invalid(src_type))20261 assert(!type_is_invalid(src_type));
20248 return ira->codegen->builtin_types.entry_invalid;
2024920262
20250 // We have a check for zero bits later so we use get_src_ptr_type to20263 // We have a check for zero bits later so we use get_src_ptr_type to
20251 // validate src_type and dest_type.20264 // validate src_type and dest_type.
2025220265
20253 if (get_src_ptr_type(src_type) == nullptr) {20266 if (get_src_ptr_type(src_type) == nullptr) {
20254 ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));20267 ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
20255 return ira->codegen->builtin_types.entry_invalid;20268 return ira->codegen->invalid_instruction;
20256 }20269 }
2025720270
20258 if (get_src_ptr_type(dest_type) == nullptr) {20271 if (get_src_ptr_type(dest_type) == nullptr) {
20259 ir_add_error(ira, dest_type_value,20272 ir_add_error(ira, dest_type_src,
20260 buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));20273 buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
20261 return ira->codegen->builtin_types.entry_invalid;20274 return ira->codegen->invalid_instruction;
20262 }20275 }
2026320276
20264 if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {20277 if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {
20265 ir_add_error(ira, &instruction->base, buf_sprintf("cast discards const qualifier"));20278 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
20266 return ira->codegen->builtin_types.entry_invalid;20279 return ira->codegen->invalid_instruction;
20267 }20280 }
2026820281
20269 if (instr_is_comptime(ptr)) {20282 if (instr_is_comptime(ptr)) {
20270 ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);20283 ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
20271 if (!val)20284 if (!val)
20272 return ira->codegen->builtin_types.entry_invalid;20285 return ira->codegen->invalid_instruction;
2027320286
20274 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);20287 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
20275 copy_const_val(out_val, val, false);20288 dest_type);
20276 out_val->type = dest_type;20289 copy_const_val(&result->value, val, false);
20277 return dest_type;20290 result->value.type = dest_type;
20291 return result;
20278 }20292 }
2027920293
20280 uint32_t src_align_bytes;20294 uint32_t src_align_bytes;
20281 if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))20295 if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
20282 return ira->codegen->builtin_types.entry_invalid;20296 return ira->codegen->invalid_instruction;
2028320297
20284 uint32_t dest_align_bytes;20298 uint32_t dest_align_bytes;
20285 if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))20299 if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
20286 return ira->codegen->builtin_types.entry_invalid;20300 return ira->codegen->invalid_instruction;
2028720301
20288 if (dest_align_bytes > src_align_bytes) {20302 if (dest_align_bytes > src_align_bytes) {
20289 ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment"));20303 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
20290 add_error_note(ira->codegen, msg, ptr->source_node,20304 add_error_note(ira->codegen, msg, ptr->source_node,
20291 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes));20305 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes));
20292 add_error_note(ira->codegen, msg, dest_type_value->source_node,20306 add_error_note(ira->codegen, msg, dest_type_src->source_node,
20293 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes));20307 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes));
20294 return ira->codegen->builtin_types.entry_invalid;20308 return ira->codegen->invalid_instruction;
20295 }20309 }
2029620310
20297 IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope,20311 IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
20298 instruction->base.source_node, nullptr, ptr);20312 source_instr->source_node, nullptr, ptr);
20299 casted_ptr->value.type = dest_type;20313 casted_ptr->value.type = dest_type;
2030020314
20301 if (type_has_bits(dest_type) && !type_has_bits(src_type)) {20315 if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
20302 ErrorMsg *msg = ir_add_error(ira, &instruction->base,20316 ErrorMsg *msg = ir_add_error(ira, source_instr,
20303 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",20317 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
20304 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));20318 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
20305 add_error_note(ira->codegen, msg, ptr->source_node,20319 add_error_note(ira->codegen, msg, ptr->source_node,
20306 buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name)));20320 buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name)));
20307 add_error_note(ira->codegen, msg, dest_type_value->source_node,20321 add_error_note(ira->codegen, msg, dest_type_src->source_node,
20308 buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name)));20322 buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name)));
20309 return ira->codegen->builtin_types.entry_invalid;20323 return ira->codegen->invalid_instruction;
20310 }20324 }
2031120325
20312 // Keep the bigger alignment, it can only help-20326 // Keep the bigger alignment, it can only help-
...@@ -20315,10 +20329,28 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr...@@ -20315,10 +20329,28 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr
20315 if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {20329 if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {
20316 result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);20330 result = ir_align_cast(ira, casted_ptr, src_align_bytes, false);
20317 if (type_is_invalid(result->value.type))20331 if (type_is_invalid(result->value.type))
20318 return ira->codegen->builtin_types.entry_invalid;20332 return ira->codegen->invalid_instruction;
20319 } else {20333 } else {
20320 result = casted_ptr;20334 result = casted_ptr;
20321 }20335 }
20336 return result;
20337}
20338
20339static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
20340 IrInstruction *dest_type_value = instruction->dest_type->other;
20341 ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
20342 if (type_is_invalid(dest_type))
20343 return ira->codegen->builtin_types.entry_invalid;
20344
20345 IrInstruction *ptr = instruction->ptr->other;
20346 ZigType *src_type = ptr->value.type;
20347 if (type_is_invalid(src_type))
20348 return ira->codegen->builtin_types.entry_invalid;
20349
20350 IrInstruction *result = ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value);
20351 if (type_is_invalid(result->value.type))
20352 return ira->codegen->builtin_types.entry_invalid;
20353
20322 ir_link_new_instruction(result, &instruction->base);20354 ir_link_new_instruction(result, &instruction->base);
20323 return result->value.type;20355 return result->value.type;
20324}20356}
std/event/tcp.zig+49-1
...@@ -110,13 +110,61 @@ pub const Server = struct {...@@ -110,13 +110,61 @@ pub const Server = struct {
110 }110 }
111};111};
112112
113pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
114 const sockfd = try std.os.posixSocket(
115 posix.AF_UNIX,
116 posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK,
117 0,
118 );
119 errdefer std.os.close(sockfd);
120
121 var sock_addr = posix.sockaddr{
122 .un = posix.sockaddr_un{
123 .family = posix.AF_UNIX,
124 .path = undefined,
125 },
126 };
127
128 if (path.len > @typeOf(sock_addr.un.path).len) return error.NameTooLong;
129 mem.copy(u8, sock_addr.un.path[0..], path);
130 const size = @intCast(u32, @sizeOf(posix.sa_family_t) + path.len);
131 try std.os.posixConnectAsync(sockfd, &sock_addr, size);
132 try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
133 try std.os.posixGetSockOptConnectError(sockfd);
134
135 return sockfd;
136}
137
138pub async fn socketRead(loop: *std.event.Loop, fd: i32, buffer: []u8) !void {
139 while (true) {
140 return std.os.posixRead(fd, buffer) catch |err| switch (err) {
141 error.WouldBlock => {
142 try await try async loop.linuxWaitFd(fd, std.os.posix.EPOLLET | std.os.posix.EPOLLIN);
143 continue;
144 },
145 else => return err,
146 };
147 }
148}
149pub async fn socketWrite(loop: *std.event.Loop, fd: i32, buffer: []const u8) !void {
150 while (true) {
151 return std.os.posixWrite(fd, buffer) catch |err| switch (err) {
152 error.WouldBlock => {
153 try await try async loop.linuxWaitFd(fd, std.os.posix.EPOLLET | std.os.posix.EPOLLOUT);
154 continue;
155 },
156 else => return err,
157 };
158 }
159}
160
113pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {161pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {
114 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733162 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
115163
116 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);164 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
117 errdefer std.os.close(sockfd);165 errdefer std.os.close(sockfd);
118166
119 try std.os.posixConnectAsync(sockfd, &address.os_addr);167 try std.os.posixConnectAsync(sockfd, &address.os_addr, @sizeOf(posix.sockaddr_in));
120 try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);168 try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
121 try std.os.posixGetSockOptConnectError(sockfd);169 try std.os.posixGetSockOptConnectError(sockfd);
122170
std/os/index.zig+2-2
...@@ -2677,9 +2677,9 @@ pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectEr...@@ -2677,9 +2677,9 @@ pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectEr
26772677
2678/// Same as posixConnect except it is for blocking socket file descriptors.2678/// Same as posixConnect except it is for blocking socket file descriptors.
2679/// It expects to receive EINPROGRESS.2679/// It expects to receive EINPROGRESS.
2680pub fn posixConnectAsync(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {2680pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
2681 while (true) {2681 while (true) {
2682 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));2682 const rc = posix.connect(sockfd, sockaddr, len);
2683 const err = posix.getErrno(rc);2683 const err = posix.getErrno(rc);
2684 switch (err) {2684 switch (err) {
2685 0, posix.EINPROGRESS => return,2685 0, posix.EINPROGRESS => return,
std/os/linux/index.zig+8-2
...@@ -1094,6 +1094,7 @@ pub const in_port_t = u16;...@@ -1094,6 +1094,7 @@ pub const in_port_t = u16;
1094pub const sa_family_t = u16;1094pub const sa_family_t = u16;
1095pub const socklen_t = u32;1095pub const socklen_t = u32;
10961096
1097/// This intentionally only has ip4 and ip6
1097pub const sockaddr = extern union {1098pub const sockaddr = extern union {
1098 in: sockaddr_in,1099 in: sockaddr_in,
1099 in6: sockaddr_in6,1100 in6: sockaddr_in6,
...@@ -1114,6 +1115,11 @@ pub const sockaddr_in6 = extern struct {...@@ -1114,6 +1115,11 @@ pub const sockaddr_in6 = extern struct {
1114 scope_id: u32,1115 scope_id: u32,
1115};1116};
11161117
1118pub const sockaddr_un = extern struct {
1119 family: sa_family_t,
1120 path: [108]u8,
1121};
1122
1117pub const iovec = extern struct {1123pub const iovec = extern struct {
1118 iov_base: [*]u8,1124 iov_base: [*]u8,
1119 iov_len: usize,1125 iov_len: usize,
...@@ -1148,8 +1154,8 @@ pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {...@@ -1148,8 +1154,8 @@ pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
1148 return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);1154 return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
1149}1155}
11501156
1151pub fn connect(fd: i32, addr: *const sockaddr, len: socklen_t) usize {1157pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
1152 return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));1158 return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len);
1153}1159}
11541160
1155pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {1161pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
test/cases/cast.zig+10
...@@ -537,3 +537,13 @@ pub const PFN_void = extern fn (*c_void) void;...@@ -537,3 +537,13 @@ pub const PFN_void = extern fn (*c_void) void;
537fn foobar(func: PFN_void) void {537fn foobar(func: PFN_void) void {
538 std.debug.assert(@ptrToInt(func) == @maxValue(usize));538 std.debug.assert(@ptrToInt(func) == @maxValue(usize));
539}539}
540
541test "implicit ptr to *c_void" {
542 var a: u32 = 1;
543 var ptr: *c_void = &a;
544 var b: *u32 = @ptrCast(*u32, ptr);
545 assert(b.* == 1);
546 var ptr2: ?*c_void = &a;
547 var c: *u32 = @ptrCast(*u32, ptr2.?);
548 assert(c.* == 1);
549}
test/compile_errors.zig+12
...@@ -1,6 +1,18 @@...@@ -1,6 +1,18 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "don't implicit cast double pointer to *c_void",
6 \\export fn entry() void {
7 \\ var a: u32 = 1;
8 \\ var ptr: *c_void = &a;
9 \\ var b: *u32 = @ptrCast(*u32, ptr);
10 \\ var ptr2: *c_void = &b;
11 \\}
12 ,
13 ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'",
14 );
15
4 cases.add(16 cases.add(
5 "runtime index into comptime type slice",17 "runtime index into comptime type slice",
6 \\const Struct = struct {18 \\const Struct = struct {