| author | |
| committer | |
| log | b511231f9552d7c1de1574eda19dc6cf657e906e |
| tree | 41cfb8c26ff8aaf654930b7c282829e146d5d3d2 |
| parent | 8d95b713c54d9dcd13d7a0afa743254ddc224a5e |
Improve some error messages13 files changed, 181 insertions(+), 31 deletions(-)
ci/azure/pipelines.yml+1-1| ... | @@ -16,7 +16,7 @@ jobs: | ... | @@ -16,7 +16,7 @@ jobs: |
| 16 | vmImage: 'windows-2019' | 16 | vmImage: 'windows-2019' |
| 17 | variables: | 17 | variables: |
| 18 | TARGET: 'x86_64-windows-gnu' | 18 | TARGET: 'x86_64-windows-gnu' |
| 19 | ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.4560+828735ac0' | 19 | ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.11.0-dev.25+499dddb4c' |
| 20 | ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip' | 20 | ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip' |
| 21 | steps: | 21 | steps: |
| 22 | - pwsh: | | 22 | - pwsh: | |
lib/std/meta.zig+3-3| ... | @@ -304,7 +304,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { | ... | @@ -304,7 +304,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { |
| 304 | .Array = .{ | 304 | .Array = .{ |
| 305 | .len = array_info.len, | 305 | .len = array_info.len, |
| 306 | .child = array_info.child, | 306 | .child = array_info.child, |
| 307 | .sentinel = &sentinel_val, | 307 | .sentinel = @ptrCast(?*const anyopaque, &sentinel_val), |
| 308 | }, | 308 | }, |
| 309 | }), | 309 | }), |
| 310 | .is_allowzero = info.is_allowzero, | 310 | .is_allowzero = info.is_allowzero, |
| ... | @@ -322,7 +322,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { | ... | @@ -322,7 +322,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { |
| 322 | .address_space = info.address_space, | 322 | .address_space = info.address_space, |
| 323 | .child = info.child, | 323 | .child = info.child, |
| 324 | .is_allowzero = info.is_allowzero, | 324 | .is_allowzero = info.is_allowzero, |
| 325 | .sentinel = &sentinel_val, | 325 | .sentinel = @ptrCast(?*const anyopaque, &sentinel_val), |
| 326 | }, | 326 | }, |
| 327 | }), | 327 | }), |
| 328 | else => {}, | 328 | else => {}, |
| ... | @@ -340,7 +340,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { | ... | @@ -340,7 +340,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { |
| 340 | .address_space = ptr_info.address_space, | 340 | .address_space = ptr_info.address_space, |
| 341 | .child = ptr_info.child, | 341 | .child = ptr_info.child, |
| 342 | .is_allowzero = ptr_info.is_allowzero, | 342 | .is_allowzero = ptr_info.is_allowzero, |
| 343 | .sentinel = &sentinel_val, | 343 | .sentinel = @ptrCast(?*const anyopaque, &sentinel_val), |
| 344 | }, | 344 | }, |
| 345 | }), | 345 | }), |
| 346 | }, | 346 | }, |
lib/std/start_windows_tls.zig+1-1| ... | @@ -42,7 +42,7 @@ export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ | ... | @@ -42,7 +42,7 @@ export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ |
| 42 | .StartAddressOfRawData = &_tls_start, | 42 | .StartAddressOfRawData = &_tls_start, |
| 43 | .EndAddressOfRawData = &_tls_end, | 43 | .EndAddressOfRawData = &_tls_end, |
| 44 | .AddressOfIndex = &_tls_index, | 44 | .AddressOfIndex = &_tls_index, |
| 45 | .AddressOfCallBacks = &__xl_a, | 45 | .AddressOfCallBacks = @ptrCast(*anyopaque, &__xl_a), |
| 46 | .SizeOfZeroFill = 0, | 46 | .SizeOfZeroFill = 0, |
| 47 | .Characteristics = 0, | 47 | .Characteristics = 0, |
| 48 | }; | 48 | }; |
lib/std/zig/Ast.zig+9-1| ... | @@ -197,7 +197,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { | ... | @@ -197,7 +197,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 197 | }); | 197 | }); |
| 198 | }, | 198 | }, |
| 199 | .expected_labelable => { | 199 | .expected_labelable => { |
| 200 | return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{ | 200 | return stream.print("expected 'while', 'for', 'inline', or '{{', found '{s}'", .{ |
| 201 | token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(), | 201 | token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(), |
| 202 | }); | 202 | }); |
| 203 | }, | 203 | }, |
| ... | @@ -356,6 +356,12 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { | ... | @@ -356,6 +356,12 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 356 | .next_field => { | 356 | .next_field => { |
| 357 | return stream.writeAll("field after declarations here"); | 357 | return stream.writeAll("field after declarations here"); |
| 358 | }, | 358 | }, |
| 359 | .expected_var_const => { | ||
| 360 | return stream.writeAll("expected 'var' or 'const' before variable declaration"); | ||
| 361 | }, | ||
| 362 | .wrong_equal_var_decl => { | ||
| 363 | return stream.writeAll("variable initialized with '==' instead of '='"); | ||
| 364 | }, | ||
| 359 | 365 | ||
| 360 | .expected_token => { | 366 | .expected_token => { |
| 361 | const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)]; | 367 | const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)]; |
| ... | @@ -2579,6 +2585,8 @@ pub const Error = struct { | ... | @@ -2579,6 +2585,8 @@ pub const Error = struct { |
| 2579 | mismatched_binary_op_whitespace, | 2585 | mismatched_binary_op_whitespace, |
| 2580 | invalid_ampersand_ampersand, | 2586 | invalid_ampersand_ampersand, |
| 2581 | c_style_container, | 2587 | c_style_container, |
| 2588 | expected_var_const, | ||
| 2589 | wrong_equal_var_decl, | ||
| 2582 | 2590 | ||
| 2583 | zig_style_container, | 2591 | zig_style_container, |
| 2584 | previous_field, | 2592 | previous_field, |
lib/std/zig/parse.zig+24-2| ... | @@ -812,7 +812,18 @@ const Parser = struct { | ... | @@ -812,7 +812,18 @@ const Parser = struct { |
| 812 | const align_node = try p.parseByteAlign(); | 812 | const align_node = try p.parseByteAlign(); |
| 813 | const addrspace_node = try p.parseAddrSpace(); | 813 | const addrspace_node = try p.parseAddrSpace(); |
| 814 | const section_node = try p.parseLinkSection(); | 814 | const section_node = try p.parseLinkSection(); |
| 815 | const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); | 815 | const init_node: Node.Index = switch (p.token_tags[p.tok_i]) { |
| 816 | .equal_equal => blk: { | ||
| 817 | try p.warn(.wrong_equal_var_decl); | ||
| 818 | p.tok_i += 1; | ||
| 819 | break :blk try p.expectExpr(); | ||
| 820 | }, | ||
| 821 | .equal => blk: { | ||
| 822 | p.tok_i += 1; | ||
| 823 | break :blk try p.expectExpr(); | ||
| 824 | }, | ||
| 825 | else => 0, | ||
| 826 | }; | ||
| 816 | if (section_node == 0 and addrspace_node == 0) { | 827 | if (section_node == 0 and addrspace_node == 0) { |
| 817 | if (align_node == 0) { | 828 | if (align_node == 0) { |
| 818 | return p.addNode(.{ | 829 | return p.addNode(.{ |
| ... | @@ -1118,7 +1129,18 @@ const Parser = struct { | ... | @@ -1118,7 +1129,18 @@ const Parser = struct { |
| 1118 | if (loop_stmt != 0) return loop_stmt; | 1129 | if (loop_stmt != 0) return loop_stmt; |
| 1119 | 1130 | ||
| 1120 | if (label_token != 0) { | 1131 | if (label_token != 0) { |
| 1121 | return p.fail(.expected_labelable); | 1132 | const after_colon = p.tok_i; |
| 1133 | const node = try p.parseTypeExpr(); | ||
| 1134 | if (node != 0) { | ||
| 1135 | const a = try p.parseByteAlign(); | ||
| 1136 | const b = try p.parseAddrSpace(); | ||
| 1137 | const c = try p.parseLinkSection(); | ||
| 1138 | const d = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); | ||
| 1139 | if (a != 0 or b != 0 or c != 0 or d != 0) { | ||
| 1140 | return p.failMsg(.{ .tag = .expected_var_const, .token = label_token }); | ||
| 1141 | } | ||
| 1142 | } | ||
| 1143 | return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon }); | ||
| 1122 | } | 1144 | } |
| 1123 | 1145 | ||
| 1124 | return null_node; | 1146 | return null_node; |
lib/std/zig/parser_test.zig+34| ... | @@ -5145,6 +5145,40 @@ test "zig fmt: make single-line if no trailing comma" { | ... | @@ -5145,6 +5145,40 @@ test "zig fmt: make single-line if no trailing comma" { |
| 5145 | ); | 5145 | ); |
| 5146 | } | 5146 | } |
| 5147 | 5147 | ||
| 5148 | test "zig fmt: variable initialized with ==" { | ||
| 5149 | try testError( | ||
| 5150 | \\comptime { | ||
| 5151 | \\ var z: u32 == 12 + 1; | ||
| 5152 | \\} | ||
| 5153 | , &.{.wrong_equal_var_decl}); | ||
| 5154 | } | ||
| 5155 | |||
| 5156 | test "zig fmt: missing const/var before local variable" { | ||
| 5157 | try testError( | ||
| 5158 | \\comptime { | ||
| 5159 | \\ z: u32; | ||
| 5160 | \\} | ||
| 5161 | \\comptime { | ||
| 5162 | \\ z: u32 align(1); | ||
| 5163 | \\} | ||
| 5164 | \\comptime { | ||
| 5165 | \\ z: u32 addrspace(.generic); | ||
| 5166 | \\} | ||
| 5167 | \\comptime { | ||
| 5168 | \\ z: u32 linksection("foo"); | ||
| 5169 | \\} | ||
| 5170 | \\comptime { | ||
| 5171 | \\ z: u32 = 1; | ||
| 5172 | \\} | ||
| 5173 | , &.{ | ||
| 5174 | .expected_labelable, | ||
| 5175 | .expected_var_const, | ||
| 5176 | .expected_var_const, | ||
| 5177 | .expected_var_const, | ||
| 5178 | .expected_var_const, | ||
| 5179 | }); | ||
| 5180 | } | ||
| 5181 | |||
| 5148 | test "zig fmt: while continue expr" { | 5182 | test "zig fmt: while continue expr" { |
| 5149 | try testCanonical( | 5183 | try testCanonical( |
| 5150 | \\test { | 5184 | \\test { |
src/AstGen.zig+5| ... | @@ -6500,9 +6500,14 @@ fn switchExpr( | ... | @@ -6500,9 +6500,14 @@ fn switchExpr( |
| 6500 | } | 6500 | } |
| 6501 | 6501 | ||
| 6502 | const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none }; | 6502 | const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none }; |
| 6503 | astgen.advanceSourceCursorToNode(operand_node); | ||
| 6504 | const operand_line = astgen.source_line - parent_gz.decl_line; | ||
| 6505 | const operand_column = astgen.source_column; | ||
| 6503 | const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node); | 6506 | const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node); |
| 6504 | const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; | 6507 | const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; |
| 6505 | const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); | 6508 | const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); |
| 6509 | // Sema expects a dbg_stmt immediately after switch_cond(_ref) | ||
| 6510 | try emitDbgStmt(parent_gz, operand_line, operand_column); | ||
| 6506 | // We need the type of the operand to use as the result location for all the prong items. | 6511 | // We need the type of the operand to use as the result location for all the prong items. |
| 6507 | const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node); | 6512 | const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node); |
| 6508 | const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } }; | 6513 | const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } }; |
src/Sema.zig+57-6| ... | @@ -9662,6 +9662,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9662,6 +9662,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9662 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); | 9662 | const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index); |
| 9663 | 9663 | ||
| 9664 | const operand = try sema.resolveInst(extra.data.operand); | 9664 | const operand = try sema.resolveInst(extra.data.operand); |
| 9665 | // AstGen guarantees that the instruction immediately following | ||
| 9666 | // switch_cond(_ref) is a dbg_stmt | ||
| 9667 | const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1; | ||
| 9665 | 9668 | ||
| 9666 | var header_extra_index: usize = extra.end; | 9669 | var header_extra_index: usize = extra.end; |
| 9667 | 9670 | ||
| ... | @@ -10358,6 +10361,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10358,6 +10361,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10358 | if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and | 10361 | if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and |
| 10359 | (!operand_ty.isNonexhaustiveEnum() or union_originally)) | 10362 | (!operand_ty.isNonexhaustiveEnum() or union_originally)) |
| 10360 | { | 10363 | { |
| 10364 | try sema.zirDbgStmt(block, cond_dbg_node_index); | ||
| 10361 | const ok = try block.addUnOp(.is_named_enum_value, operand); | 10365 | const ok = try block.addUnOp(.is_named_enum_value, operand); |
| 10362 | try sema.addSafetyCheck(block, ok, .corrupt_switch); | 10366 | try sema.addSafetyCheck(block, ok, .corrupt_switch); |
| 10363 | } | 10367 | } |
| ... | @@ -10827,6 +10831,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10827,6 +10831,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10827 | if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and | 10831 | if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and |
| 10828 | operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) | 10832 | operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) |
| 10829 | { | 10833 | { |
| 10834 | try sema.zirDbgStmt(&case_block, cond_dbg_node_index); | ||
| 10830 | const ok = try case_block.addUnOp(.is_named_enum_value, operand); | 10835 | const ok = try case_block.addUnOp(.is_named_enum_value, operand); |
| 10831 | try sema.addSafetyCheck(&case_block, ok, .corrupt_switch); | 10836 | try sema.addSafetyCheck(&case_block, ok, .corrupt_switch); |
| 10832 | } | 10837 | } |
| ... | @@ -10850,6 +10855,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10850,6 +10855,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10850 | // We still need a terminator in this block, but we have proven | 10855 | // We still need a terminator in this block, but we have proven |
| 10851 | // that it is unreachable. | 10856 | // that it is unreachable. |
| 10852 | if (case_block.wantSafety()) { | 10857 | if (case_block.wantSafety()) { |
| 10858 | try sema.zirDbgStmt(&case_block, cond_dbg_node_index); | ||
| 10853 | _ = try sema.safetyPanic(&case_block, src, .corrupt_switch); | 10859 | _ = try sema.safetyPanic(&case_block, src, .corrupt_switch); |
| 10854 | } else { | 10860 | } else { |
| 10855 | _ = try case_block.addNoOp(.unreach); | 10861 | _ = try case_block.addNoOp(.unreach); |
| ... | @@ -16620,7 +16626,17 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16620,7 +16626,17 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16620 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; | 16626 | const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node }; |
| 16621 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; | 16627 | const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node }; |
| 16622 | 16628 | ||
| 16623 | const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type); | 16629 | const unresolved_elem_ty = blk: { |
| 16630 | const air_inst = try sema.resolveInst(extra.data.elem_type); | ||
| 16631 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { | ||
| 16632 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { | ||
| 16633 | try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); | ||
| 16634 | } | ||
| 16635 | return err; | ||
| 16636 | }; | ||
| 16637 | if (ty.tag() == .generic_poison) return error.GenericPoison; | ||
| 16638 | break :blk ty; | ||
| 16639 | }; | ||
| 16624 | const target = sema.mod.getTarget(); | 16640 | const target = sema.mod.getTarget(); |
| 16625 | 16641 | ||
| 16626 | var extra_i = extra.end; | 16642 | var extra_i = extra.end; |
| ... | @@ -18666,6 +18682,13 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -18666,6 +18682,13 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 18666 | } | 18682 | } |
| 18667 | 18683 | ||
| 18668 | try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); | 18684 | try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); |
| 18685 | if (dest_ty.intInfo(sema.mod.getTarget()).bits == 0) { | ||
| 18686 | if (block.wantSafety()) { | ||
| 18687 | const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, Value.zero)); | ||
| 18688 | try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); | ||
| 18689 | } | ||
| 18690 | return sema.addConstant(dest_ty, Value.zero); | ||
| 18691 | } | ||
| 18669 | const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); | 18692 | const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); |
| 18670 | if (block.wantSafety()) { | 18693 | if (block.wantSafety()) { |
| 18671 | const back = try block.addTyOp(.int_to_float, operand_ty, result); | 18694 | const back = try block.addTyOp(.int_to_float, operand_ty, result); |
| ... | @@ -18932,6 +18955,9 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18932,6 +18955,9 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18932 | if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { | 18955 | if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { |
| 18933 | return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)}); | 18956 | return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)}); |
| 18934 | } | 18957 | } |
| 18958 | if (dest_ty.zigTypeTag() == .Optional and sema.typeOf(ptr).zigTypeTag() != .Optional) { | ||
| 18959 | return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, operand_val)); | ||
| 18960 | } | ||
| 18935 | return sema.addConstant(aligned_dest_ty, operand_val); | 18961 | return sema.addConstant(aligned_dest_ty, operand_val); |
| 18936 | } | 18962 | } |
| 18937 | 18963 | ||
| ... | @@ -23919,9 +23945,20 @@ fn coerceExtra( | ... | @@ -23919,9 +23945,20 @@ fn coerceExtra( |
| 23919 | // cast from ?*T and ?[*]T to ?*anyopaque | 23945 | // cast from ?*T and ?[*]T to ?*anyopaque |
| 23920 | // but don't do it if the source type is a double pointer | 23946 | // but don't do it if the source type is a double pointer |
| 23921 | if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and | 23947 | if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and |
| 23922 | inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer) | 23948 | inst_ty.isPtrAtRuntime()) |
| 23923 | { | 23949 | anyopaque_check: { |
| 23924 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; | 23950 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; |
| 23951 | const elem_ty = inst_ty.elemType2(); | ||
| 23952 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | ||
| 23953 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ | ||
| 23954 | .actual = inst_ty, | ||
| 23955 | .wanted = dest_ty, | ||
| 23956 | } }; | ||
| 23957 | break :optional; | ||
| 23958 | } | ||
| 23959 | // Let the logic below handle wrapping the optional now that | ||
| 23960 | // it has been checked to correctly coerce. | ||
| 23961 | if (!inst_ty.isPtrLikeOptional()) break :anyopaque_check; | ||
| 23925 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 23962 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 23926 | } | 23963 | } |
| 23927 | 23964 | ||
| ... | @@ -24044,9 +24081,16 @@ fn coerceExtra( | ... | @@ -24044,9 +24081,16 @@ fn coerceExtra( |
| 24044 | 24081 | ||
| 24045 | // cast from *T and [*]T to *anyopaque | 24082 | // cast from *T and [*]T to *anyopaque |
| 24046 | // but don't do it if the source type is a double pointer | 24083 | // but don't do it if the source type is a double pointer |
| 24047 | if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and | 24084 | if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) { |
| 24048 | inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 24085 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 24049 | { | 24086 | const elem_ty = inst_ty.elemType2(); |
| 24087 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | ||
| 24088 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ | ||
| 24089 | .actual = inst_ty, | ||
| 24090 | .wanted = dest_ty, | ||
| 24091 | } }; | ||
| 24092 | break :pointer; | ||
| 24093 | } | ||
| 24050 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 24094 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 24051 | } | 24095 | } |
| 24052 | 24096 | ||
| ... | @@ -24528,6 +24572,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -24528,6 +24572,7 @@ const InMemoryCoercionResult = union(enum) { |
| 24528 | ptr_allowzero: Pair, | 24572 | ptr_allowzero: Pair, |
| 24529 | ptr_bit_range: BitRange, | 24573 | ptr_bit_range: BitRange, |
| 24530 | ptr_alignment: IntPair, | 24574 | ptr_alignment: IntPair, |
| 24575 | double_ptr_to_anyopaque: Pair, | ||
| 24531 | 24576 | ||
| 24532 | const Pair = struct { | 24577 | const Pair = struct { |
| 24533 | actual: Type, | 24578 | actual: Type, |
| ... | @@ -24820,6 +24865,12 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -24820,6 +24865,12 @@ const InMemoryCoercionResult = union(enum) { |
| 24820 | }); | 24865 | }); |
| 24821 | break; | 24866 | break; |
| 24822 | }, | 24867 | }, |
| 24868 | .double_ptr_to_anyopaque => |pair| { | ||
| 24869 | try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ | ||
| 24870 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | ||
| 24871 | }); | ||
| 24872 | break; | ||
| 24873 | }, | ||
| 24823 | }; | 24874 | }; |
| 24824 | } | 24875 | } |
| 24825 | }; | 24876 | }; |
src/type.zig-3| ... | @@ -3944,10 +3944,7 @@ pub const Type = extern union { | ... | @@ -3944,10 +3944,7 @@ pub const Type = extern union { |
| 3944 | .optional => { | 3944 | .optional => { |
| 3945 | var buf: Payload.ElemType = undefined; | 3945 | var buf: Payload.ElemType = undefined; |
| 3946 | const child_type = self.optionalChild(&buf); | 3946 | const child_type = self.optionalChild(&buf); |
| 3947 | // optionals of zero sized pointers behave like bools | ||
| 3948 | if (!child_type.hasRuntimeBits()) return false; | ||
| 3949 | if (child_type.zigTypeTag() != .Pointer) return false; | 3947 | if (child_type.zigTypeTag() != .Pointer) return false; |
| 3950 | |||
| 3951 | const info = child_type.ptrInfo().data; | 3948 | const info = child_type.ptrInfo().data; |
| 3952 | switch (info.size) { | 3949 | switch (info.size) { |
| 3953 | .Slice, .C => return false, | 3950 | .Slice, .C => return false, |
test/behavior/cast.zig+8| ... | @@ -1411,3 +1411,11 @@ test "peer type resolution of const and non-const pointer to array" { | ... | @@ -1411,3 +1411,11 @@ test "peer type resolution of const and non-const pointer to array" { |
| 1411 | try std.testing.expect(@TypeOf(a, b) == *const [1024]u8); | 1411 | try std.testing.expect(@TypeOf(a, b) == *const [1024]u8); |
| 1412 | try std.testing.expect(a == b); | 1412 | try std.testing.expect(a == b); |
| 1413 | } | 1413 | } |
| 1414 | |||
| 1415 | test "floatToInt to zero-bit int" { | ||
| 1416 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1417 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1418 | |||
| 1419 | var a: f32 = 0.0; | ||
| 1420 | comptime try std.testing.expect(@floatToInt(u0, a) == 0); | ||
| 1421 | } |
test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var a: u32 = 1; | ||
| 3 | var ptr: *align(@alignOf(u32)) anyopaque = &a; | ||
| 4 | var b: *u32 = @ptrCast(*u32, ptr); | ||
| 5 | var ptr2: *anyopaque = &b; | ||
| 6 | _ = ptr2; | ||
| 7 | } | ||
| 8 | |||
| 9 | // error | ||
| 10 | // backend=stage2 | ||
| 11 | // target=native | ||
| 12 | // | ||
| 13 | // :5:28: error: expected type '*anyopaque', found '**u32' | ||
| 14 | // :5:28: note: pointer type child '*u32' cannot cast into pointer type child 'anyopaque' | ||
test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig created+28| ... | @@ -0,0 +1,28 @@ | ||
| 1 | pub export fn entry1() void { | ||
| 2 | const x: usize = 5; | ||
| 3 | |||
| 4 | const ptr: *const anyopaque = &(&x); | ||
| 5 | _ = ptr; | ||
| 6 | } | ||
| 7 | pub export fn entry2() void { | ||
| 8 | var val: [*:0]u8 = undefined; | ||
| 9 | func(&val); | ||
| 10 | } | ||
| 11 | fn func(_: ?*anyopaque) void {} | ||
| 12 | pub export fn entry3() void { | ||
| 13 | var x: *?*usize = undefined; | ||
| 14 | |||
| 15 | const ptr: *const anyopaque = x; | ||
| 16 | _ = ptr; | ||
| 17 | } | ||
| 18 | |||
| 19 | // error | ||
| 20 | // backend=stage2 | ||
| 21 | // target=native | ||
| 22 | // | ||
| 23 | // :4:35: error: expected type '*const anyopaque', found '*const *const usize' | ||
| 24 | // :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque' | ||
| 25 | // :9:10: error: expected type '?*anyopaque', found '*[*:0]u8' | ||
| 26 | // :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque' | ||
| 27 | // :15:35: error: expected type '*const anyopaque', found '*?*usize' | ||
| 28 | // :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque' | ||
test/cases/compile_errors/incorrect_pointer_dereference_syntax.zig created+11| ... | @@ -0,0 +1,11 @@ | ||
| 1 | pub export fn entry() void { | ||
| 2 | var a: *u32 = undefined; | ||
| 3 | _ = *a; | ||
| 4 | } | ||
| 5 | |||
| 6 | // error | ||
| 7 | // backend=stage2 | ||
| 8 | // target=native | ||
| 9 | // | ||
| 10 | // :3:10: error: expected type 'type', found '*u32' | ||
| 11 | // :3:10: note: use '.*' to dereference pointer | ||