| ... | @@ -2429,6 +2429,16 @@ fn failWithComptimeErrorRetTrace( | ... | @@ -2429,6 +2429,16 @@ fn failWithComptimeErrorRetTrace( |
| 2429 | return sema.failWithOwnedErrorMsg(block, msg); | 2429 | return sema.failWithOwnedErrorMsg(block, msg); |
| 2430 | } | 2430 | } |
| 2431 | | 2431 | |
| | 2432 | fn failWithInvalidPtrArithmetic(sema: *Sema, block: *Block, src: LazySrcLoc, arithmetic: []const u8, supports: []const u8) CompileError { |
| | 2433 | const msg = msg: { |
| | 2434 | const msg = try sema.errMsg(src, "invalid {s} arithmetic operator", .{arithmetic}); |
| | 2435 | errdefer msg.destroy(sema.gpa); |
| | 2436 | try sema.errNote(src, msg, "{s} arithmetic only supports {s}", .{ arithmetic, supports }); |
| | 2437 | break :msg msg; |
| | 2438 | }; |
| | 2439 | return sema.failWithOwnedErrorMsg(block, msg); |
| | 2440 | } |
| | 2441 | |
| 2432 | /// We don't return a pointer to the new error note because the pointer | 2442 | /// We don't return a pointer to the new error note because the pointer |
| 2433 | /// becomes invalid when you add another one. | 2443 | /// becomes invalid when you add another one. |
| 2434 | pub fn errNote( | 2444 | pub fn errNote( |
| ... | @@ -15146,7 +15156,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -15146,7 +15156,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 15146 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 15156 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 15147 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 15157 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 15148 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15158 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15149 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 15159 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 15150 | | 15160 | |
| 15151 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15161 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15152 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 15162 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -15312,7 +15322,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -15312,7 +15322,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15312 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 15322 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 15313 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 15323 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 15314 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15324 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15315 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 15325 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 15316 | | 15326 | |
| 15317 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15327 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15318 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 15328 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -15478,7 +15488,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -15478,7 +15488,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15478 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 15488 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 15479 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 15489 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 15480 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15490 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15481 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 15491 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 15482 | | 15492 | |
| 15483 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15493 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15484 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 15494 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -15589,7 +15599,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -15589,7 +15599,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15589 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 15599 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 15590 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 15600 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 15591 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15601 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15592 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 15602 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 15593 | | 15603 | |
| 15594 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15604 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15595 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 15605 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -15833,7 +15843,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -15833,7 +15843,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15833 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 15843 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 15834 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 15844 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 15835 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15845 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15836 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 15846 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 15837 | | 15847 | |
| 15838 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15848 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15839 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 15849 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -16019,7 +16029,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -16019,7 +16029,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 16019 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 16029 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 16020 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 16030 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 16021 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 16031 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 16022 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 16032 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 16023 | | 16033 | |
| 16024 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 16034 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 16025 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 16035 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -16115,7 +16125,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -16115,7 +16125,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 16115 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); | 16125 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 16116 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 16126 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 16117 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 16127 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 16118 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 16128 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); |
| 16119 | | 16129 | |
| 16120 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 16130 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 16121 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 16131 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -16458,17 +16468,78 @@ fn analyzeArithmetic( | ... | @@ -16458,17 +16468,78 @@ fn analyzeArithmetic( |
| 16458 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | 16468 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 16459 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 16469 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 16460 | | 16470 | |
| 16461 | if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize(mod)) { | 16471 | if (lhs_zig_ty_tag == .Pointer) { |
| 16462 | .One, .Slice => {}, | 16472 | if (rhs_zig_ty_tag == .Pointer) { |
| 16463 | .Many, .C => { | 16473 | if (lhs_ty.ptrSize(mod) != .Slice and rhs_ty.ptrSize(mod) != .Slice) { |
| 16464 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | 16474 | if (zir_tag != .sub) { |
| 16465 | .add => .ptr_add, | 16475 | return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction"); |
| 16466 | .sub => .ptr_sub, | 16476 | } |
| 16467 | else => return sema.fail(block, src, "invalid pointer arithmetic operator", .{}), | 16477 | if (!lhs_ty.elemType2(mod).eql(rhs_ty.elemType2(mod), mod)) { |
| 16468 | }; | 16478 | return sema.fail(block, src, "incompatible pointer arithmetic operands '{}' and '{}'", .{ |
| 16469 | return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); | 16479 | lhs_ty.fmt(pt), rhs_ty.fmt(pt), |
| 16470 | }, | 16480 | }); |
| 16471 | }; | 16481 | } |
| | 16482 | |
| | 16483 | const elem_size = lhs_ty.elemType2(mod).abiSize(pt); |
| | 16484 | if (elem_size == 0) { |
| | 16485 | return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ |
| | 16486 | lhs_ty.elemType2(mod).fmt(pt), |
| | 16487 | }); |
| | 16488 | } |
| | 16489 | |
| | 16490 | const runtime_src = runtime_src: { |
| | 16491 | if (try sema.resolveValue(lhs)) |lhs_value| { |
| | 16492 | if (try sema.resolveValue(rhs)) |rhs_value| { |
| | 16493 | const lhs_ptr = switch (mod.intern_pool.indexToKey(lhs_value.toIntern())) { |
| | 16494 | .undef => return sema.failWithUseOfUndef(block, lhs_src), |
| | 16495 | .ptr => |ptr| ptr, |
| | 16496 | else => unreachable, |
| | 16497 | }; |
| | 16498 | const rhs_ptr = switch (mod.intern_pool.indexToKey(rhs_value.toIntern())) { |
| | 16499 | .undef => return sema.failWithUseOfUndef(block, rhs_src), |
| | 16500 | .ptr => |ptr| ptr, |
| | 16501 | else => unreachable, |
| | 16502 | }; |
| | 16503 | // Make sure the pointers point to the same data. |
| | 16504 | if (!lhs_ptr.base_addr.eql(rhs_ptr.base_addr)) break :runtime_src src; |
| | 16505 | const address = std.math.sub(u64, lhs_ptr.byte_offset, rhs_ptr.byte_offset) catch |
| | 16506 | return sema.fail(block, src, "operation results in overflow", .{}); |
| | 16507 | const result = address / elem_size; |
| | 16508 | return try pt.intRef(Type.usize, result); |
| | 16509 | } else { |
| | 16510 | break :runtime_src lhs_src; |
| | 16511 | } |
| | 16512 | } else { |
| | 16513 | break :runtime_src rhs_src; |
| | 16514 | } |
| | 16515 | }; |
| | 16516 | |
| | 16517 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| | 16518 | const lhs_int = try block.addUnOp(.int_from_ptr, lhs); |
| | 16519 | const rhs_int = try block.addUnOp(.int_from_ptr, rhs); |
| | 16520 | const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int); |
| | 16521 | return try block.addBinOp(.div_exact, address, try pt.intRef(Type.usize, elem_size)); |
| | 16522 | } |
| | 16523 | } else { |
| | 16524 | switch (lhs_ty.ptrSize(mod)) { |
| | 16525 | .One, .Slice => {}, |
| | 16526 | .Many, .C => { |
| | 16527 | const air_tag: Air.Inst.Tag = switch (zir_tag) { |
| | 16528 | .add => .ptr_add, |
| | 16529 | .sub => .ptr_sub, |
| | 16530 | else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"), |
| | 16531 | }; |
| | 16532 | |
| | 16533 | if (!try sema.typeHasRuntimeBits(lhs_ty.elemType2(mod))) { |
| | 16534 | return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ |
| | 16535 | lhs_ty.elemType2(mod).fmt(pt), |
| | 16536 | }); |
| | 16537 | } |
| | 16538 | return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); |
| | 16539 | }, |
| | 16540 | } |
| | 16541 | } |
| | 16542 | } |
| 16472 | | 16543 | |
| 16473 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 16544 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 16474 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ | 16545 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ |
| ... | @@ -23762,7 +23833,7 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr | ... | @@ -23762,7 +23833,7 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr |
| 23762 | } | 23833 | } |
| 23763 | } | 23834 | } |
| 23764 | | 23835 | |
| 23765 | fn checkInvalidPtrArithmetic( | 23836 | fn checkInvalidPtrIntArithmetic( |
| 23766 | sema: *Sema, | 23837 | sema: *Sema, |
| 23767 | block: *Block, | 23838 | block: *Block, |
| 23768 | src: LazySrcLoc, | 23839 | src: LazySrcLoc, |
| ... | @@ -23773,12 +23844,7 @@ fn checkInvalidPtrArithmetic( | ... | @@ -23773,12 +23844,7 @@ fn checkInvalidPtrArithmetic( |
| 23773 | switch (try ty.zigTypeTagOrPoison(mod)) { | 23844 | switch (try ty.zigTypeTagOrPoison(mod)) { |
| 23774 | .Pointer => switch (ty.ptrSize(mod)) { | 23845 | .Pointer => switch (ty.ptrSize(mod)) { |
| 23775 | .One, .Slice => return, | 23846 | .One, .Slice => return, |
| 23776 | .Many, .C => return sema.fail( | 23847 | .Many, .C => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"), |
| 23777 | block, | | |
| 23778 | src, | | |
| 23779 | "invalid pointer arithmetic operator", | | |
| 23780 | .{}, | | |
| 23781 | ), | | |
| 23782 | }, | 23848 | }, |
| 23783 | else => return, | 23849 | else => return, |
| 23784 | } | 23850 | } |