| author | |
| committer | |
| log | 7caa3d9da71c38665340247a1c2bf9bedb8db925 |
| tree | dcb7637f26db5363d0bdc3c60fd05660f8a371fd |
| parent | f3445f8f6935b4532aab3f339f5d86319d2dca72 |
| parent | 7f60d2e4658ad78839ce0fce63a95dbcb893a256 |
| signature |
compiler: provide correct result types to `+=` and `-=`6 files changed, 90 insertions(+), 9 deletions(-)
lib/std/zig/AstGen.zig+20-2| ... | @@ -3785,8 +3785,26 @@ fn assignOp( | ... | @@ -3785,8 +3785,26 @@ fn assignOp( |
| 3785 | else => undefined, | 3785 | else => undefined, |
| 3786 | }; | 3786 | }; |
| 3787 | const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); | 3787 | const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); |
| 3788 | const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); | 3788 | |
| 3789 | const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = lhs_type } }, node_datas[infix_node].rhs); | 3789 | const rhs_res_ty = switch (op_inst_tag) { |
| 3790 | .add, | ||
| 3791 | .sub, | ||
| 3792 | => try gz.add(.{ | ||
| 3793 | .tag = .extended, | ||
| 3794 | .data = .{ .extended = .{ | ||
| 3795 | .opcode = .inplace_arith_result_ty, | ||
| 3796 | .small = @intFromEnum(@as(Zir.Inst.InplaceOp, switch (op_inst_tag) { | ||
| 3797 | .add => .add_eq, | ||
| 3798 | .sub => .sub_eq, | ||
| 3799 | else => unreachable, | ||
| 3800 | })), | ||
| 3801 | .operand = @intFromEnum(lhs), | ||
| 3802 | } }, | ||
| 3803 | }), | ||
| 3804 | else => try gz.addUnNode(.typeof, lhs, infix_node), // same as LHS type | ||
| 3805 | }; | ||
| 3806 | // Not `coerced_ty` since `add`/etc won't coerce to this type. | ||
| 3807 | const rhs = try expr(gz, scope, .{ .rl = .{ .ty = rhs_res_ty } }, node_datas[infix_node].rhs); | ||
| 3790 | 3808 | ||
| 3791 | switch (op_inst_tag) { | 3809 | switch (op_inst_tag) { |
| 3792 | .add, .sub, .mul, .div, .mod_rem => { | 3810 | .add, .sub, .mul, .div, .mod_rem => { |
lib/std/zig/Zir.zig+10| ... | @@ -2086,6 +2086,10 @@ pub const Inst = struct { | ... | @@ -2086,6 +2086,10 @@ pub const Inst = struct { |
| 2086 | /// `operand` is payload index to `UnNode`. | 2086 | /// `operand` is payload index to `UnNode`. |
| 2087 | /// `small` is unused. | 2087 | /// `small` is unused. |
| 2088 | branch_hint, | 2088 | branch_hint, |
| 2089 | /// Compute the result type for in-place arithmetic, e.g. `+=`. | ||
| 2090 | /// `operand` is `Zir.Inst.Ref` of the loaded LHS (*not* its type). | ||
| 2091 | /// `small` is an `Inst.InplaceOp`. | ||
| 2092 | inplace_arith_result_ty, | ||
| 2089 | 2093 | ||
| 2090 | pub const InstData = struct { | 2094 | pub const InstData = struct { |
| 2091 | opcode: Extended, | 2095 | opcode: Extended, |
| ... | @@ -3188,6 +3192,11 @@ pub const Inst = struct { | ... | @@ -3188,6 +3192,11 @@ pub const Inst = struct { |
| 3188 | calling_convention_inline, | 3192 | calling_convention_inline, |
| 3189 | }; | 3193 | }; |
| 3190 | 3194 | ||
| 3195 | pub const InplaceOp = enum(u16) { | ||
| 3196 | add_eq, | ||
| 3197 | sub_eq, | ||
| 3198 | }; | ||
| 3199 | |||
| 3191 | /// Trailing: | 3200 | /// Trailing: |
| 3192 | /// 0. tag_type: Ref, // if has_tag_type | 3201 | /// 0. tag_type: Ref, // if has_tag_type |
| 3193 | /// 1. captures_len: u32, // if has_captures_len | 3202 | /// 1. captures_len: u32, // if has_captures_len |
| ... | @@ -4032,6 +4041,7 @@ fn findDeclsInner( | ... | @@ -4032,6 +4041,7 @@ fn findDeclsInner( |
| 4032 | .field_parent_ptr, | 4041 | .field_parent_ptr, |
| 4033 | .builtin_value, | 4042 | .builtin_value, |
| 4034 | .branch_hint, | 4043 | .branch_hint, |
| 4044 | .inplace_arith_result_ty, | ||
| 4035 | => return, | 4045 | => return, |
| 4036 | 4046 | ||
| 4037 | // `@TypeOf` has a body. | 4047 | // `@TypeOf` has a body. |
src/Sema.zig+28| ... | @@ -1361,6 +1361,7 @@ fn analyzeBodyInner( | ... | @@ -1361,6 +1361,7 @@ fn analyzeBodyInner( |
| 1361 | .value_placeholder => unreachable, // never appears in a body | 1361 | .value_placeholder => unreachable, // never appears in a body |
| 1362 | .field_parent_ptr => try sema.zirFieldParentPtr(block, extended), | 1362 | .field_parent_ptr => try sema.zirFieldParentPtr(block, extended), |
| 1363 | .builtin_value => try sema.zirBuiltinValue(extended), | 1363 | .builtin_value => try sema.zirBuiltinValue(extended), |
| 1364 | .inplace_arith_result_ty => try sema.zirInplaceArithResultTy(extended), | ||
| 1364 | }; | 1365 | }; |
| 1365 | }, | 1366 | }, |
| 1366 | 1367 | ||
| ... | @@ -27342,6 +27343,33 @@ fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileErr | ... | @@ -27342,6 +27343,33 @@ fn zirBuiltinValue(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileErr |
| 27342 | return Air.internedToRef(ty.toIntern()); | 27343 | return Air.internedToRef(ty.toIntern()); |
| 27343 | } | 27344 | } |
| 27344 | 27345 | ||
| 27346 | fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | ||
| 27347 | const pt = sema.pt; | ||
| 27348 | const zcu = pt.zcu; | ||
| 27349 | |||
| 27350 | const lhs = try sema.resolveInst(@enumFromInt(extended.operand)); | ||
| 27351 | const lhs_ty = sema.typeOf(lhs); | ||
| 27352 | |||
| 27353 | const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small); | ||
| 27354 | const ty: Type = switch (op) { | ||
| 27355 | .add_eq => ty: { | ||
| 27356 | const ptr_size = lhs_ty.ptrSizeOrNull(zcu) orelse break :ty lhs_ty; | ||
| 27357 | switch (ptr_size) { | ||
| 27358 | .One, .Slice => break :ty lhs_ty, // invalid, let it error | ||
| 27359 | .Many, .C => break :ty .usize, // `[*]T + usize` | ||
| 27360 | } | ||
| 27361 | }, | ||
| 27362 | .sub_eq => ty: { | ||
| 27363 | const ptr_size = lhs_ty.ptrSizeOrNull(zcu) orelse break :ty lhs_ty; | ||
| 27364 | switch (ptr_size) { | ||
| 27365 | .One, .Slice => break :ty lhs_ty, // invalid, let it error | ||
| 27366 | .Many, .C => break :ty .generic_poison, // could be `[*]T - [*]T` or `[*]T - usize` | ||
| 27367 | } | ||
| 27368 | }, | ||
| 27369 | }; | ||
| 27370 | return Air.internedToRef(ty.toIntern()); | ||
| 27371 | } | ||
| 27372 | |||
| 27345 | fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { | 27373 | fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 27346 | const pt = sema.pt; | 27374 | const pt = sema.pt; |
| 27347 | const zcu = pt.zcu; | 27375 | const zcu = pt.zcu; |
src/arch/riscv64/CodeGen.zig+10-7| ... | @@ -3897,7 +3897,7 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3897,7 +3897,7 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3897 | 3897 | ||
| 3898 | if (array_ty.isVector(zcu)) { | 3898 | if (array_ty.isVector(zcu)) { |
| 3899 | // we need to load the vector, vslidedown to get the element we want | 3899 | // we need to load the vector, vslidedown to get the element we want |
| 3900 | // and store that element at in a load frame. | 3900 | // and store that element in a load frame. |
| 3901 | 3901 | ||
| 3902 | const src_reg, const src_lock = try func.allocReg(.vector); | 3902 | const src_reg, const src_lock = try func.allocReg(.vector); |
| 3903 | defer func.register_manager.unlockReg(src_lock); | 3903 | defer func.register_manager.unlockReg(src_lock); |
| ... | @@ -3970,12 +3970,15 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -3970,12 +3970,15 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3970 | }; | 3970 | }; |
| 3971 | defer if (index_lock) |lock| func.register_manager.unlockReg(lock); | 3971 | defer if (index_lock) |lock| func.register_manager.unlockReg(lock); |
| 3972 | 3972 | ||
| 3973 | const elem_ptr_reg = if (base_ptr_mcv.isRegister() and func.liveness.operandDies(inst, 0)) | 3973 | const elem_ptr_reg, const elem_ptr_lock = if (base_ptr_mcv.isRegister() and |
| 3974 | base_ptr_mcv.register | 3974 | func.liveness.operandDies(inst, 0)) |
| 3975 | else | 3975 | .{ base_ptr_mcv.register, null } |
| 3976 | try func.copyToTmpRegister(base_ptr_ty, base_ptr_mcv); | 3976 | else blk: { |
| 3977 | const elem_ptr_lock = func.register_manager.lockRegAssumeUnused(elem_ptr_reg); | 3977 | const reg, const lock = try func.allocReg(.int); |
| 3978 | defer func.register_manager.unlockReg(elem_ptr_lock); | 3978 | try func.genSetReg(base_ptr_ty, reg, base_ptr_mcv); |
| 3979 | break :blk .{ reg, lock }; | ||
| 3980 | }; | ||
| 3981 | defer if (elem_ptr_lock) |lock| func.register_manager.unlockReg(lock); | ||
| 3979 | 3982 | ||
| 3980 | try func.genBinOp( | 3983 | try func.genBinOp( |
| 3981 | .ptr_add, | 3984 | .ptr_add, |
src/print_zir.zig+7| ... | @@ -620,6 +620,7 @@ const Writer = struct { | ... | @@ -620,6 +620,7 @@ const Writer = struct { |
| 620 | .closure_get => try self.writeClosureGet(stream, extended), | 620 | .closure_get => try self.writeClosureGet(stream, extended), |
| 621 | .field_parent_ptr => try self.writeFieldParentPtr(stream, extended), | 621 | .field_parent_ptr => try self.writeFieldParentPtr(stream, extended), |
| 622 | .builtin_value => try self.writeBuiltinValue(stream, extended), | 622 | .builtin_value => try self.writeBuiltinValue(stream, extended), |
| 623 | .inplace_arith_result_ty => try self.writeInplaceArithResultTy(stream, extended), | ||
| 623 | } | 624 | } |
| 624 | } | 625 | } |
| 625 | 626 | ||
| ... | @@ -2781,6 +2782,12 @@ const Writer = struct { | ... | @@ -2781,6 +2782,12 @@ const Writer = struct { |
| 2781 | try self.writeSrcNode(stream, @bitCast(extended.operand)); | 2782 | try self.writeSrcNode(stream, @bitCast(extended.operand)); |
| 2782 | } | 2783 | } |
| 2783 | 2784 | ||
| 2785 | fn writeInplaceArithResultTy(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { | ||
| 2786 | const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small); | ||
| 2787 | try self.writeInstRef(stream, @enumFromInt(extended.operand)); | ||
| 2788 | try stream.print(", {s}))", .{@tagName(op)}); | ||
| 2789 | } | ||
| 2790 | |||
| 2784 | fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { | 2791 | fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { |
| 2785 | if (ref == .none) { | 2792 | if (ref == .none) { |
| 2786 | return stream.writeAll(".none"); | 2793 | return stream.writeAll(".none"); |
test/behavior/pointers.zig+15| ... | @@ -98,6 +98,21 @@ test "pointer subtraction" { | ... | @@ -98,6 +98,21 @@ test "pointer subtraction" { |
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | test "pointer arithmetic with non-trivial RHS" { | ||
| 102 | var t: bool = undefined; | ||
| 103 | t = true; | ||
| 104 | |||
| 105 | var ptr: [*]const u8 = "Hello, World!"; | ||
| 106 | ptr += if (t) 5 else 2; | ||
| 107 | try expect(ptr[0] == ','); | ||
| 108 | ptr += if (!t) 4 else 2; | ||
| 109 | try expect(ptr[0] == 'W'); | ||
| 110 | ptr -= if (t) @as(usize, 6) else 3; | ||
| 111 | try expect(ptr[0] == 'e'); | ||
| 112 | ptr -= if (!t) @as(usize, 0) else 1; | ||
| 113 | try expect(ptr[0] == 'H'); | ||
| 114 | } | ||
| 115 | |||
| 101 | test "double pointer parsing" { | 116 | test "double pointer parsing" { |
| 102 | comptime assert(PtrOf(PtrOf(i32)) == **i32); | 117 | comptime assert(PtrOf(PtrOf(i32)) == **i32); |
| 103 | } | 118 | } |