| ... | @@ -1789,6 +1789,11 @@ test "parseInt" { | ... | @@ -1789,6 +1789,11 @@ test "parseInt" { |
| 1789 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); | 1789 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); |
| 1790 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0o", 0)); | 1790 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0o", 0)); |
| 1791 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x", 0)); | 1791 | try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x", 0)); |
| | 1792 | |
| | 1793 | // edge cases which previously errored due to base overflowing T |
| | 1794 | try std.testing.expectEqual(@as(i2, -2), try std.fmt.parseInt(i2, "-10", 2)); |
| | 1795 | try std.testing.expectEqual(@as(i4, -8), try std.fmt.parseInt(i4, "-10", 8)); |
| | 1796 | try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); |
| 1792 | } | 1797 | } |
| 1793 | | 1798 | |
| 1794 | fn parseWithSign( | 1799 | fn parseWithSign( |
| ... | @@ -1829,27 +1834,33 @@ fn parseWithSign( | ... | @@ -1829,27 +1834,33 @@ fn parseWithSign( |
| 1829 | .neg => math.sub, | 1834 | .neg => math.sub, |
| 1830 | }; | 1835 | }; |
| 1831 | | 1836 | |
| 1832 | var x: T = 0; | 1837 | // accumulate into U which is always 8 bits or larger. this prevents |
| | 1838 | // `buf_base` from overflowing T. |
| | 1839 | const info = @typeInfo(T); |
| | 1840 | const U = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); |
| | 1841 | var x: U = 0; |
| 1833 | | 1842 | |
| 1834 | if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; | 1843 | if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; |
| 1835 | | 1844 | |
| 1836 | for (buf_start) |c| { | 1845 | for (buf_start) |c| { |
| 1837 | if (c == '_') continue; | 1846 | if (c == '_') continue; |
| 1838 | const digit = try charToDigit(c, buf_base); | 1847 | const digit = try charToDigit(c, buf_base); |
| 1839 | | | |
| 1840 | if (x != 0) { | 1848 | if (x != 0) { |
| 1841 | x = try math.mul(T, x, math.cast(T, buf_base) orelse return error.Overflow); | 1849 | x = try math.mul(U, x, math.cast(U, buf_base) orelse return error.Overflow); |
| 1842 | } else if (sign == .neg) { | 1850 | } else if (sign == .neg) { |
| 1843 | // The first digit of a negative number. | 1851 | // The first digit of a negative number. |
| 1844 | // Consider parsing "-4" as an i3. | 1852 | // Consider parsing "-4" as an i3. |
| 1845 | // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. | 1853 | // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. |
| 1846 | x = math.cast(T, -@as(i8, @intCast(digit))) orelse return error.Overflow; | 1854 | x = math.cast(U, -@as(i8, @intCast(digit))) orelse return error.Overflow; |
| 1847 | continue; | 1855 | continue; |
| 1848 | } | 1856 | } |
| 1849 | x = try add(T, x, math.cast(T, digit) orelse return error.Overflow); | 1857 | x = try add(U, x, math.cast(U, digit) orelse return error.Overflow); |
| 1850 | } | 1858 | } |
| 1851 | | 1859 | |
| 1852 | return x; | 1860 | return if (T == U) |
| | 1861 | x |
| | 1862 | else |
| | 1863 | math.cast(T, x) orelse return error.Overflow; |
| 1853 | } | 1864 | } |
| 1854 | | 1865 | |
| 1855 | /// Parses the string `buf` as unsigned representation in the specified base | 1866 | /// Parses the string `buf` as unsigned representation in the specified base |