From 2a92fb2516251fb0ddfa2d1026930a2c7465e528 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 18 Aug 2020 22:12:28 +0900 Subject: Make division by zero cause `ZeroDivisionError`. As described in ISO 15.2.30. --- doc/limitations.md | 9 ++++++++- include/mruby.h | 1 + mrblib/10error.rb | 4 ++++ src/numeric.c | 20 +++----------------- src/vm.c | 13 +++++++------ test/t/superclass.rb | 2 +- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/doc/limitations.md b/doc/limitations.md index 7e58ca420..8ac959b98 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -63,8 +63,15 @@ end #### mruby [2.1.2 (2020-08-06)] -No exception is raised. +No exception is raised. Instead you have to do: +```ruby +begin + 1 / 0 +rescue => e + raise e +end +``` ## Fiber execution can't cross C function boundary mruby's `Fiber` is implemented in a similar way to Lua's co-routine. This diff --git a/include/mruby.h b/include/mruby.h index f07adbb13..959d1ac6d 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1292,6 +1292,7 @@ MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap); */ #define E_RUNTIME_ERROR (mrb_exc_get_id(mrb, MRB_SYM(RuntimeError))) #define E_TYPE_ERROR (mrb_exc_get_id(mrb, MRB_SYM(TypeError))) +#define E_ZERODIV_ERROR (mrb_exc_get_id(mrb, MRB_SYM(ZeroDivisionError))) #define E_ARGUMENT_ERROR (mrb_exc_get_id(mrb, MRB_SYM(ArgumentError))) #define E_INDEX_ERROR (mrb_exc_get_id(mrb, MRB_SYM(IndexError))) #define E_RANGE_ERROR (mrb_exc_get_id(mrb, MRB_SYM(RangeError))) diff --git a/mrblib/10error.rb b/mrblib/10error.rb index 0d9f38d58..054603514 100644 --- a/mrblib/10error.rb +++ b/mrblib/10error.rb @@ -21,6 +21,10 @@ end class TypeError < StandardError end +# ISO 15.2.30 +class ZeroDivisionError < StandardError +end + # ISO 15.2.31 class NameError < StandardError attr_accessor :name diff --git a/src/numeric.c b/src/numeric.c index 99d32f919..0cc7958e6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -156,7 +156,7 @@ integral_div(mrb_state *mrb, mrb_value xv) mrb_get_args(mrb, "i", &y); if (y == 0) { - mrb_raise(mrb, E_RUNTIME_ERROR, "devided by zero"); + mrb_raise(mrb, E_ZERODIV_ERROR, "devided by zero"); } return mrb_fixnum_value(mrb_fixnum(xv) / y); #else @@ -932,14 +932,7 @@ int_mod(mrb_state *mrb, mrb_value x) mrb_int mod; if (b == 0) { -#ifdef MRB_NO_FLOAT - /* ZeroDivisionError */ - return mrb_fixnum_value(0); -#else - if (a > 0) return mrb_float_value(mrb, INFINITY); - if (a < 0) return mrb_float_value(mrb, INFINITY); - return mrb_float_value(mrb, NAN); -#endif + mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0"); } fixdivmod(mrb, a, b, NULL, &mod); return mrb_fixnum_value(mod); @@ -971,14 +964,7 @@ int_divmod(mrb_state *mrb, mrb_value x) mrb_int div, mod; if (mrb_fixnum(y) == 0) { -#ifdef MRB_NO_FLOAT - return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0)); -#else - return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ? - mrb_float_value(mrb, NAN): - mrb_float_value(mrb, INFINITY)), - mrb_float_value(mrb, NAN)); -#endif + mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0"); } fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod); return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod)); diff --git a/src/vm.c b/src/vm.c index 979c67424..15a38c0e4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2315,12 +2315,13 @@ RETRY_TRY_BLOCK: { mrb_int x = mrb_fixnum(regs[a]); mrb_int y = mrb_fixnum(regs[a+1]); - if (y == 0 || (x == MRB_INT_MIN && y == -1)) { -#ifdef MRB_NO_FLOAT - SET_INT_VALUE(regs[a], y ? x / y : 0); -#else - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y); -#endif + + + if (y == 0) { + mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0"); + } + else if(x == MRB_INT_MIN && y == -1) { + mrb_raise(mrb, E_RANGE_ERROR, "integer overflow in division"); } else { mrb_int div, mod; diff --git a/test/t/superclass.rb b/test/t/superclass.rb index 10b6438d3..70d5c24d9 100644 --- a/test/t/superclass.rb +++ b/test/t/superclass.rb @@ -29,7 +29,7 @@ [:RegexpError, :StandardError, '12.2.27.2'], [:RuntimeError, :StandardError, '12.2.28.2'], [:TypeError, :StandardError, '12.2.29.2'], -# [:ZeroDivisionError, :StandardError, '12.2.30.2'], # No ZeroDivisionError in mruby + [:ZeroDivisionError, :StandardError, '12.2.30.2'], [:NameError, :StandardError, '15.2.31.2'], [:NoMethodError, :NameError, '15.2.32.2'], [:IndexError, :StandardError, '15.2.33.2'], -- cgit v1.2.3