Skip to content

Commit 14ad339

Browse files
authored
Merge pull request #22761 from JuliaLang/teh/overflow
Make OverflowError more informative
2 parents 4fea203 + d5cb6d1 commit 14ad339

15 files changed

+41
-24
lines changed

NEWS.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,12 @@ Deprecated or removed
251251
* `fieldnames` now operates only on types. To get the names of fields in an object, use
252252
`fieldnames(typeof(x))` ([#22350]).
253253

254-
* `InexactError` and `DomainError` now take
254+
* `InexactError`, `DomainError`, and `OverflowError` now take
255255
arguments. `InexactError(func::Symbol, type, -3)` now prints as
256-
`ERROR: InexactError: func(type, -3)`, and `DomainError(val,
257-
[msg])` prints as `ERROR: DomainError with val:\nmsg`. ([#20005],
258-
[#22751])
256+
"ERROR: InexactError: func(type, -3)", `DomainError(val,
257+
[msg])` prints as "ERROR: DomainError with val:\nmsg",
258+
and `OverflowError(msg)` prints as "ERROR: OverflowError: msg".
259+
([#20005], [#22751], [#22761])
259260

260261
* The operating system identification functions: `is_linux`, `is_bsd`, `is_apple`, `is_unix`,
261262
and `is_windows`, have been deprecated in favor of `Sys.islinux`, `Sys.isbsd`, `Sys.isapple`,
@@ -1127,6 +1128,7 @@ Command-line option changes
11271128
[#22723]: https://github.com/JuliaLang/julia/issues/22723
11281129
[#22732]: https://github.com/JuliaLang/julia/issues/22732
11291130
[#22751]: https://github.com/JuliaLang/julia/issues/22751
1131+
[#22761]: https://github.com/JuliaLang/julia/issues/22761
11301132
[#22762]: https://github.com/JuliaLang/julia/issues/22762
11311133
[#22793]: https://github.com/JuliaLang/julia/issues/22793
11321134
[#22796]: https://github.com/JuliaLang/julia/issues/22796

base/boot.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ struct BoundsError <: Exception
212212
BoundsError(@nospecialize(a), i) = (@_noinline_meta; new(a,i))
213213
end
214214
struct DivideError <: Exception end
215-
struct OverflowError <: Exception end
216215
struct OutOfMemoryError <: Exception end
217216
struct ReadOnlyMemoryError<: Exception end
218217
struct SegmentationFault <: Exception end
@@ -241,6 +240,9 @@ struct InexactError <: Exception
241240

242241
InexactError(f::Symbol, @nospecialize(T), @nospecialize(val)) = (@_noinline_meta; new(f, T, val))
243242
end
243+
struct OverflowError <: Exception
244+
msg
245+
end
244246

245247
abstract type DirectIndexString <: AbstractString end
246248

base/checked.jl

+12-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Core.Intrinsics:
1313
checked_srem_int,
1414
checked_uadd_int, checked_usub_int, checked_umul_int, checked_udiv_int,
1515
checked_urem_int
16-
import Base: no_op_err, @_inline_meta
16+
import Base: no_op_err, @_inline_meta, @_noinline_meta
1717

1818
# define promotion behavior for checked operations
1919
checked_add(x::Integer, y::Integer) = checked_add(promote(x,y)...)
@@ -90,16 +90,18 @@ The overflow protection may impose a perceptible performance penalty.
9090
function checked_neg(x::T) where T<:Integer
9191
checked_sub(T(0), x)
9292
end
93+
throw_overflowerr_negation(x) = (@_noinline_meta;
94+
throw(OverflowError("checked arithmetic: cannot compute -x for x = $x::$(typeof(x))")))
9395
if BrokenSignedInt != Union{}
9496
function checked_neg(x::BrokenSignedInt)
9597
r = -x
96-
(x<0) & (r<0) && throw(OverflowError())
98+
(x<0) & (r<0) && throw_overflowerr_negation(x)
9799
r
98100
end
99101
end
100102
if BrokenUnsignedInt != Union{}
101103
function checked_neg(x::T) where T<:BrokenUnsignedInt
102-
x != 0 && throw(OverflowError())
104+
x != 0 && throw_overflowerr_negation(x)
103105
T(0)
104106
end
105107
end
@@ -117,7 +119,7 @@ function checked_abs end
117119

118120
function checked_abs(x::SignedInt)
119121
r = ifelse(x<0, -x, x)
120-
r<0 && throw(OverflowError())
122+
r<0 && throw(OverflowError(string("checked arithmetic: cannot compute |x| for x = ", x, "::", typeof(x))))
121123
r
122124
end
123125
checked_abs(x::UnsignedInt) = x
@@ -152,6 +154,9 @@ end
152154
end
153155

154156

157+
throw_overflowerr_binaryop(op, x, y) = (@_noinline_meta;
158+
throw(OverflowError("$x $op $y overflowed for type $(typeof(x))")))
159+
155160
"""
156161
Base.checked_add(x, y)
157162
@@ -162,7 +167,7 @@ The overflow protection may impose a perceptible performance penalty.
162167
function checked_add(x::T, y::T) where T<:Integer
163168
@_inline_meta
164169
z, b = add_with_overflow(x, y)
165-
b && throw(OverflowError())
170+
b && throw_overflowerr_binaryop(:+, x, y)
166171
z
167172
end
168173

@@ -219,7 +224,7 @@ The overflow protection may impose a perceptible performance penalty.
219224
function checked_sub(x::T, y::T) where T<:Integer
220225
@_inline_meta
221226
z, b = sub_with_overflow(x, y)
222-
b && throw(OverflowError())
227+
b && throw_overflowerr_binaryop(:-, x, y)
223228
z
224229
end
225230

@@ -284,7 +289,7 @@ The overflow protection may impose a perceptible performance penalty.
284289
function checked_mul(x::T, y::T) where T<:Integer
285290
@_inline_meta
286291
z, b = mul_with_overflow(x, y)
287-
b && throw(OverflowError())
292+
b && throw_overflowerr_binaryop(:*, x, y)
288293
z
289294
end
290295

base/combinatorics.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ end
1616

1717
function factorial_lookup(n::Integer, table, lim)
1818
n < 0 && throw(DomainError(n, "`n` must not be negative."))
19-
n > lim && throw(OverflowError())
19+
n > lim && throw(OverflowError(string(n, " is too large to look up in the table")))
2020
n == 0 && return one(n)
2121
@inbounds f = table[n]
2222
return oftype(n, f)

base/deprecated.jl

+6
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,12 @@ function DomainError()
15431543
DomainError(nothing)
15441544
end
15451545

1546+
# PR #22761
1547+
function OverflowError()
1548+
depwarn("OverflowError now supports a message string, use `OverflowError(msg)` instead.", :OverflowError)
1549+
OverflowError("")
1550+
end
1551+
15461552
# PR #22703
15471553
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, isupper::Bool) Bidiagonal(dv, ev, ifelse(isupper, :U, :L))
15481554
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, uplo::Char) Bidiagonal(dv, ev, ifelse(uplo == 'U', :U, :L))

base/docs/helpdb/Base.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ used only with extreme caution, as it can cause memory use to grow without bound
15201520
gc_enable
15211521

15221522
"""
1523-
OverflowError()
1523+
OverflowError(msg)
15241524
15251525
The result of an expression is too large for the specified type and will cause a wraparound.
15261526
"""

base/gmp.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ isqrt(x::BigInt) = MPZ.sqrt(x)
494494

495495
function bigint_pow(x::BigInt, y::Integer)
496496
if y<0; throw(DomainError(y, "`y` cannot be negative.")); end
497+
@noinline throw1(y) =
498+
throw(OverflowError("exponent $y is too large and computation will overflow"))
497499
if x== 1; return x; end
498500
if x==-1; return isodd(y) ? x : -x; end
499501
if y>typemax(Culong)
@@ -507,7 +509,7 @@ function bigint_pow(x::BigInt, y::Integer)
507509
#
508510
#Assume that the answer will definitely overflow.
509511

510-
throw(OverflowError())
512+
throw1(y)
511513
end
512514
return x^convert(Culong, y)
513515
end

base/intfuncs.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ end
2828
# binary GCD (aka Stein's) algorithm
2929
# about 1.7x (2.1x) faster for random Int64s (Int128s)
3030
function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
31+
@noinline throw1(a, b) = throw(OverflowError("gcd($a, $b) overflows"))
3132
a == 0 && return abs(b)
3233
b == 0 && return abs(a)
3334
za = trailing_zeros(a)
@@ -44,7 +45,7 @@ function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
4445
end
4546
r = u << k
4647
# T(r) would throw InexactError; we want OverflowError instead
47-
r > typemax(T) && throw(OverflowError())
48+
r > typemax(T) && throw1(a, b)
4849
r % T
4950
end
5051

@@ -841,6 +842,7 @@ julia> factorial(5) ÷ (factorial(5-3) * factorial(3))
841842
```
842843
"""
843844
function binomial(n::T, k::T) where T<:Integer
845+
n0, k0 = n, k
844846
k < 0 && return zero(T)
845847
sgn = one(T)
846848
if n < 0
@@ -861,7 +863,7 @@ function binomial(n::T, k::T) where T<:Integer
861863
while rr <= k
862864
xt = div(widemul(x, nn), rr)
863865
x = xt
864-
x == xt || throw(OverflowError())
866+
x == xt || throw(OverflowError("binomial($n0, $k0) overflows"))
865867
rr += 1
866868
nn += 1
867869
end

base/parse.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::
112112
n, ov_mul = mul_with_overflow(n, base)
113113
n, ov_add = add_with_overflow(n, d)
114114
if ov_mul | ov_add
115-
raise && throw(OverflowError())
115+
raise && throw(OverflowError("overflow parsing $(repr(SubString(s,startpos,endpos)))"))
116116
return _n
117117
end
118118
(i > endpos) && return Nullable{T}(n)

base/rational.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,11 @@ isinteger(x::Rational) = x.den == 1
233233

234234
-(x::Rational) = (-x.num) // x.den
235235
function -(x::Rational{T}) where T<:Signed
236-
x.num == typemin(T) && throw(OverflowError())
236+
x.num == typemin(T) && throw(OverflowError("rational numerator is typemin(T)"))
237237
(-x.num) // x.den
238238
end
239239
function -(x::Rational{T}) where T<:Unsigned
240-
x.num != zero(T) && throw(OverflowError())
240+
x.num != zero(T) && throw(OverflowError("cannot negate unsigned number"))
241241
x
242242
end
243243

base/replutil.jl

+1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ showerror(io::IO, ex::KeyError) = print(io, "KeyError: key $(repr(ex.key)) not f
275275
showerror(io::IO, ex::InterruptException) = print(io, "InterruptException:")
276276
showerror(io::IO, ex::ArgumentError) = print(io, "ArgumentError: $(ex.msg)")
277277
showerror(io::IO, ex::AssertionError) = print(io, "AssertionError: $(ex.msg)")
278+
showerror(io::IO, ex::OverflowError) = print(io, "OverflowError: $(ex.msg)")
278279

279280
function showerror(io::IO, ex::UndefVarError)
280281
if ex.var in [:UTF16String, :UTF32String, :WString, :utf16, :utf32, :wstring, :RepString]

src/codegen.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -6022,7 +6022,6 @@ static void init_julia_llvm_env(Module *m)
60226022
global_jlvalue_to_llvm("jl_emptytuple", &jl_emptytuple, m);
60236023
global_jlvalue_to_llvm("jl_diverror_exception", &jl_diverror_exception, m);
60246024
global_jlvalue_to_llvm("jl_undefref_exception", &jl_undefref_exception, m);
6025-
global_jlvalue_to_llvm("jl_overflow_exception", &jl_overflow_exception, m);
60266025

60276026
jlRTLD_DEFAULT_var =
60286027
new GlobalVariable(*m, T_pint8,

src/datatype.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
347347
return;
348348
throw_ovf:
349349
if (descsz >= jl_page_size) free(desc);
350-
jl_throw(jl_overflow_exception);
350+
jl_errorf("type %s has field offset %d that exceeds the page size", jl_symbol_name(st->name), descsz);
351351
}
352352

353353
extern int jl_boot_file_loaded;

src/init.c

-1
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,6 @@ void jl_get_builtin_hooks(void)
785785
jl_errorexception_type = (jl_datatype_t*)core("ErrorException");
786786
jl_stackovf_exception = jl_new_struct_uninit((jl_datatype_t*)core("StackOverflowError"));
787787
jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError"));
788-
jl_overflow_exception = jl_new_struct_uninit((jl_datatype_t*)core("OverflowError"));
789788
jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError"));
790789
jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError");
791790
jl_interrupt_exception = jl_new_struct_uninit((jl_datatype_t*)core("InterruptException"));

src/julia.h

-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,6 @@ extern JL_DLLEXPORT jl_value_t *jl_stackovf_exception;
529529
extern JL_DLLEXPORT jl_value_t *jl_memory_exception;
530530
extern JL_DLLEXPORT jl_value_t *jl_readonlymemory_exception;
531531
extern JL_DLLEXPORT jl_value_t *jl_diverror_exception;
532-
extern JL_DLLEXPORT jl_value_t *jl_overflow_exception;
533532
extern JL_DLLEXPORT jl_value_t *jl_undefref_exception;
534533
extern JL_DLLEXPORT jl_value_t *jl_interrupt_exception;
535534
extern JL_DLLEXPORT jl_datatype_t *jl_boundserror_type;

0 commit comments

Comments
 (0)