diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index c4868a81f..7a695cdc5 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1457,19 +1457,13 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); mrb_int n0; if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data0, &n0)) { - /* OP_ADDI/OP_SUBI takes upto 8bits */ - if (n > UINT8_MAX || n < -UINT8_MAX) goto normal; + /* Fold to OP_ADDI/OP_SUBI only for non-negative 8-bit n; flipping op + for negative n would change the method sent on user override (#2557). */ + if (n < 0 || n > UINT8_MAX) goto normal; rewind_pc(s); if (n == 0) return; - if (n > 0) { - if (op == OP_ADD) genop_2(s, OP_ADDI, dst, (uint16_t)n); - else genop_2(s, OP_SUBI, dst, (uint16_t)n); - } - else { /* n < 0 */ - n = -n; - if (op == OP_ADD) genop_2(s, OP_SUBI, dst, (uint16_t)n); - else genop_2(s, OP_ADDI, dst, (uint16_t)n); - } + if (op == OP_ADD) genop_2(s, OP_ADDI, dst, (uint16_t)n); + else genop_2(s, OP_SUBI, dst, (uint16_t)n); return; } if (op == OP_ADD) { diff --git a/test/t/literals.rb b/test/t/literals.rb index 03f0cb699..de30e816b 100644 --- a/test/t/literals.rb +++ b/test/t/literals.rb @@ -383,4 +383,20 @@ qwe] assert_equal :'{foo bar}', h end +assert('operator override with negative integer literal', '#2557') do + cls = Class.new { + def +(x); ['add', x]; end + def -(x); ['sub', x]; end + } + q = cls.new + assert_equal ['add', 5], q + 5 + assert_equal ['add', -5], q + -5 + assert_equal ['sub', 5], q - 5 + assert_equal ['sub', -5], q - -5 + assert_equal ['add', 500], q + 500 + assert_equal ['add', -500], q + -500 + assert_equal ['sub', 500], q - 500 + assert_equal ['sub', -500], q - -500 +end + # Not Implemented ATM assert('Literals Regular expression', '8.7.6.5') do