| author | |
| committer | |
| log | 342bca7f4627454435e9f6c2d12b099f95a2fd47 |
| tree | 01b42262415f9cc16348bfaf3741e139527be790 |
| parent | d9e01be97386f008e4a4b4281658f25b50ff80f1 |
| signature | Commit is signed but in an unrecognized format. |
See #10596 files changed, 78 insertions(+), 20 deletions(-)
src/analyze.cpp+1-1| ... | ... | @@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 434 | 434 | uint32_t bit_offset_in_host, uint32_t host_int_bytes) |
| 435 | 435 | { |
| 436 | 436 | assert(!type_is_invalid(child_type)); |
| 437 | assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); | |
| 437 | assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); | |
| 438 | 438 | |
| 439 | 439 | if (byte_alignment != 0) { |
| 440 | 440 | uint32_t abi_alignment = get_abi_alignment(g, child_type); |
src/codegen.cpp+2-2| ... | ... | @@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2657 | 2657 | (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) || |
| 2658 | 2658 | (op1->value.type->id == ZigTypeIdPointer && |
| 2659 | 2659 | (op_id == IrBinOpAdd || op_id == IrBinOpSub) && |
| 2660 | op1->value.type->data.pointer.ptr_len == PtrLenUnknown) | |
| 2660 | op1->value.type->data.pointer.ptr_len != PtrLenSingle) | |
| 2661 | 2661 | ); |
| 2662 | 2662 | ZigType *operand_type = op1->value.type; |
| 2663 | 2663 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| ... | ... | @@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 2716 | 2716 | AddSubMulMul; |
| 2717 | 2717 | |
| 2718 | 2718 | if (scalar_type->id == ZigTypeIdPointer) { |
| 2719 | assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); | |
| 2719 | assert(scalar_type->data.pointer.ptr_len != PtrLenSingle); | |
| 2720 | 2720 | LLVMValueRef subscript_value; |
| 2721 | 2721 | if (operand_type->id == ZigTypeIdVector) |
| 2722 | 2722 | zig_panic("TODO: Implement vector operations on pointers."); |
src/ir.cpp+41-5| ... | ... | @@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t * |
| 8943 | 8943 | *errors = reallocate(*errors, old_errors_count, *errors_count); |
| 8944 | 8944 | } |
| 8945 | 8945 | |
| 8946 | static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) { | |
| 8946 | static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, | |
| 8947 | IrInstruction **instructions, size_t instruction_count) | |
| 8948 | { | |
| 8947 | 8949 | Error err; |
| 8948 | 8950 | assert(instruction_count >= 1); |
| 8949 | 8951 | IrInstruction *prev_inst = instructions[0]; |
| ... | ... | @@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT |
| 9260 | 9262 | continue; |
| 9261 | 9263 | } |
| 9262 | 9264 | |
| 9265 | if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC && | |
| 9266 | (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt)) | |
| 9267 | { | |
| 9268 | continue; | |
| 9269 | } | |
| 9270 | ||
| 9271 | if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC && | |
| 9272 | (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt)) | |
| 9273 | { | |
| 9274 | prev_inst = cur_inst; | |
| 9275 | continue; | |
| 9276 | } | |
| 9277 | ||
| 9263 | 9278 | if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { |
| 9264 | 9279 | continue; |
| 9265 | 9280 | } |
| ... | ... | @@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11852 | 11867 | case ZigTypeIdBool: |
| 11853 | 11868 | case ZigTypeIdMetaType: |
| 11854 | 11869 | case ZigTypeIdVoid: |
| 11855 | case ZigTypeIdPointer: | |
| 11856 | 11870 | case ZigTypeIdErrorSet: |
| 11857 | 11871 | case ZigTypeIdFn: |
| 11858 | 11872 | case ZigTypeIdOpaque: |
| ... | ... | @@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * |
| 11864 | 11878 | operator_allowed = is_equality_cmp; |
| 11865 | 11879 | break; |
| 11866 | 11880 | |
| 11881 | case ZigTypeIdPointer: | |
| 11882 | operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); | |
| 11883 | break; | |
| 11884 | ||
| 11867 | 11885 | case ZigTypeIdUnreachable: |
| 11868 | 11886 | case ZigTypeIdArray: |
| 11869 | 11887 | case ZigTypeIdStruct: |
| ... | ... | @@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) { |
| 12324 | 12342 | zig_unreachable(); |
| 12325 | 12343 | } |
| 12326 | 12344 | |
| 12345 | static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { | |
| 12346 | if (lhs_type->id != ZigTypeIdPointer) | |
| 12347 | return false; | |
| 12348 | switch (op) { | |
| 12349 | case IrBinOpAdd: | |
| 12350 | case IrBinOpSub: | |
| 12351 | break; | |
| 12352 | default: | |
| 12353 | return false; | |
| 12354 | } | |
| 12355 | switch (lhs_type->data.pointer.ptr_len) { | |
| 12356 | case PtrLenSingle: | |
| 12357 | return false; | |
| 12358 | case PtrLenUnknown: | |
| 12359 | case PtrLenC: | |
| 12360 | break; | |
| 12361 | } | |
| 12362 | return true; | |
| 12363 | } | |
| 12364 | ||
| 12327 | 12365 | static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { |
| 12328 | 12366 | IrInstruction *op1 = instruction->op1->child; |
| 12329 | 12367 | if (type_is_invalid(op1->value.type)) |
| ... | ... | @@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 12336 | 12374 | IrBinOp op_id = instruction->op_id; |
| 12337 | 12375 | |
| 12338 | 12376 | // look for pointer math |
| 12339 | if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && | |
| 12340 | (op_id == IrBinOpAdd || op_id == IrBinOpSub)) | |
| 12341 | { | |
| 12377 | if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { | |
| 12342 | 12378 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); |
| 12343 | 12379 | if (casted_op2 == ira->codegen->invalid_instruction) |
| 12344 | 12380 | return ira->codegen->invalid_instruction; |
src/translate_c.cpp+5-3| ... | ... | @@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im |
| 1677 | 1677 | return node; |
| 1678 | 1678 | } |
| 1679 | 1679 | case CK_NullToPointer: |
| 1680 | return trans_create_node(c, NodeTypeNullLiteral); | |
| 1680 | return trans_create_node_unsigned(c, 0); | |
| 1681 | 1681 | case CK_Dependent: |
| 1682 | 1682 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); |
| 1683 | 1683 | return nullptr; |
| ... | ... | @@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * |
| 2409 | 2409 | case BuiltinType::Float16: |
| 2410 | 2410 | return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); |
| 2411 | 2411 | case BuiltinType::NullPtr: |
| 2412 | return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); | |
| 2412 | return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, | |
| 2413 | trans_create_node_unsigned(c, 0)); | |
| 2413 | 2414 | |
| 2414 | 2415 | case BuiltinType::Void: |
| 2415 | 2416 | case BuiltinType::Half: |
| ... | ... | @@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * |
| 2494 | 2495 | break; |
| 2495 | 2496 | } |
| 2496 | 2497 | case Type::Pointer: |
| 2497 | return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); | |
| 2498 | return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, | |
| 2499 | trans_create_node_unsigned(c, 0)); | |
| 2498 | 2500 | |
| 2499 | 2501 | case Type::Typedef: |
| 2500 | 2502 | { |
test/stage1/behavior/pointers.zig+20| ... | ... | @@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" { |
| 56 | 56 | z.* += 1; |
| 57 | 57 | expect(y == 12); |
| 58 | 58 | } |
| 59 | ||
| 60 | test "C pointer comparison and arithmetic" { | |
| 61 | var one: usize = 1; | |
| 62 | var ptr1: [*c]u8 = 0; | |
| 63 | var ptr2 = ptr1 + 10; | |
| 64 | expect(ptr1 == 0); | |
| 65 | expect(ptr1 >= 0); | |
| 66 | expect(ptr1 <= 0); | |
| 67 | expect(ptr1 < 1); | |
| 68 | expect(ptr1 < one); | |
| 69 | expect(1 > ptr1); | |
| 70 | expect(one > ptr1); | |
| 71 | expect(ptr1 < ptr2); | |
| 72 | expect(ptr2 > ptr1); | |
| 73 | expect(ptr2 >= 10); | |
| 74 | expect(ptr2 == 10); | |
| 75 | expect(ptr2 <= 10); | |
| 76 | ptr2 -= 10; | |
| 77 | expect(ptr1 == ptr2); | |
| 78 | } |
test/translate_c.zig+9-9| ... | ... | @@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 610 | 610 | , |
| 611 | 611 | \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { |
| 612 | 612 | \\ if ((a != 0) and (b != 0)) return 0; |
| 613 | \\ if ((b != 0) and (c != null)) return 1; | |
| 614 | \\ if ((a != 0) and (c != null)) return 2; | |
| 613 | \\ if ((b != 0) and (c != 0)) return 1; | |
| 614 | \\ if ((a != 0) and (c != 0)) return 2; | |
| 615 | 615 | \\ if ((a != 0) or (b != 0)) return 3; |
| 616 | \\ if ((b != 0) or (c != null)) return 4; | |
| 617 | \\ if ((a != 0) or (c != null)) return 5; | |
| 616 | \\ if ((b != 0) or (c != 0)) return 4; | |
| 617 | \\ if ((a != 0) or (c != 0)) return 5; | |
| 618 | 618 | \\ return 6; |
| 619 | 619 | \\} |
| 620 | 620 | ); |
| ... | ... | @@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 778 | 778 | \\} |
| 779 | 779 | , |
| 780 | 780 | \\pub export fn foo() [*c]c_int { |
| 781 | \\ return null; | |
| 781 | \\ return 0; | |
| 782 | 782 | \\} |
| 783 | 783 | ); |
| 784 | 784 | |
| ... | ... | @@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1280 | 1280 | \\ return !(a == 0); |
| 1281 | 1281 | \\ return !(a != 0); |
| 1282 | 1282 | \\ return !(b != 0); |
| 1283 | \\ return !(c != null); | |
| 1283 | \\ return !(c != 0); | |
| 1284 | 1284 | \\} |
| 1285 | 1285 | ); |
| 1286 | 1286 | |
| ... | ... | @@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1337 | 1337 | \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { |
| 1338 | 1338 | \\ if (a != 0) return 0; |
| 1339 | 1339 | \\ if (b != 0) return 1; |
| 1340 | \\ if (c != null) return 2; | |
| 1340 | \\ if (c != 0) return 2; | |
| 1341 | 1341 | \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3; |
| 1342 | 1342 | \\ return 4; |
| 1343 | 1343 | \\} |
| ... | ... | @@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1354 | 1354 | \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { |
| 1355 | 1355 | \\ while (a != 0) return 0; |
| 1356 | 1356 | \\ while (b != 0) return 1; |
| 1357 | \\ while (c != null) return 2; | |
| 1357 | \\ while (c != 0) return 2; | |
| 1358 | 1358 | \\ return 3; |
| 1359 | 1359 | \\} |
| 1360 | 1360 | ); |
| ... | ... | @@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1370 | 1370 | \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { |
| 1371 | 1371 | \\ while (a != 0) return 0; |
| 1372 | 1372 | \\ while (b != 0) return 1; |
| 1373 | \\ while (c != null) return 2; | |
| 1373 | \\ while (c != 0) return 2; | |
| 1374 | 1374 | \\ return 3; |
| 1375 | 1375 | \\} |
| 1376 | 1376 | ); |