1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

numeric.c: bit op with non-integer

* numeric.c (rb_num_coerce_bit): enable bit operations with
  coercing by non-integer object.  [ruby-core:77783] [Bug #12875]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56543 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2016-11-01 22:34:30 +00:00
parent c7e99cbfc8
commit 13149a59d8
3 changed files with 76 additions and 20 deletions

View file

@ -1,3 +1,8 @@
Wed Nov 2 07:34:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* numeric.c (rb_num_coerce_bit): enable bit operations with
coercing by non-integer object. [ruby-core:77783] [Bug #12875]
Tue Nov 1 01:31:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in (ac_cv_func_round): round(3) in x86_64-w64-mingw32

View file

@ -293,21 +293,27 @@ num_funcall0(VALUE x, ID func)
return rb_exec_recursive(num_funcall_op_0, x, (VALUE)func);
}
static void
num_funcall_op_1_recursion(VALUE x, ID func, VALUE y)
{
const char *name = rb_id2name(func);
if (ISALNUM(name[0])) {
rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")",
x, ID2SYM(func), y);
}
else {
rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE,
x, ID2SYM(func), y);
}
}
static VALUE
num_funcall_op_1(VALUE y, VALUE arg, int recursive)
{
ID func = (ID)((VALUE *)arg)[0];
VALUE x = ((VALUE *)arg)[1];
if (recursive) {
const char *name = rb_id2name(func);
if (ISALNUM(name[0])) {
rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")",
x, ID2SYM(func), y);
}
else {
rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE,
x, ID2SYM(func), y);
}
num_funcall_op_1_recursion(x, func, y);
}
return rb_funcall(x, func, 1, y);
}
@ -4128,24 +4134,33 @@ int_comp(VALUE num)
return Qnil;
}
static int
bit_coerce(VALUE *x, VALUE *y)
static VALUE
num_funcall_bit_1(VALUE y, VALUE arg, int recursive)
{
if (!RB_INTEGER_TYPE_P(*y)) {
VALUE orig = *x;
do_coerce(x, y, TRUE);
if (!RB_INTEGER_TYPE_P(*x) && !RB_INTEGER_TYPE_P(*y)) {
coerce_failed(orig, *y);
}
ID func = (ID)((VALUE *)arg)[0];
VALUE x = ((VALUE *)arg)[1];
if (recursive) {
num_funcall_op_1_recursion(x, func, y);
}
return TRUE;
return rb_check_funcall(x, func, 1, &y);
}
VALUE
rb_num_coerce_bit(VALUE x, VALUE y, ID func)
{
bit_coerce(&x, &y);
return num_funcall1(x, func, y);
VALUE ret, args[3];
args[0] = (VALUE)func;
args[1] = x;
args[2] = y;
do_coerce(&args[1], &args[2], TRUE);
ret = rb_exec_recursive_paired(num_funcall_bit_1,
args[2], args[1], (VALUE)args);
if (ret == Qundef) {
/* show the original object, not coerced object */
coerce_failed(x, y);
}
return ret;
}
/*

View file

@ -302,6 +302,42 @@ class TestInteger < Test::Unit::TestCase
assert_equal(3 ^ 10, 3 ^ obj)
end
module CoercionToSelf
def coerce(other)
[self.class.new(other), self]
end
end
def test_bitwise_and_with_integer_coercion
obj = Struct.new(:value) do
include(CoercionToSelf)
def &(other)
self.value & other.value
end
end.new(10)
assert_equal(3 & 10, 3 & obj)
end
def test_bitwise_or_with_integer_coercion
obj = Struct.new(:value) do
include(CoercionToSelf)
def |(other)
self.value | other.value
end
end.new(10)
assert_equal(3 | 10, 3 | obj)
end
def test_bitwise_xor_with_integer_coercion
obj = Struct.new(:value) do
include(CoercionToSelf)
def ^(other)
self.value ^ other.value
end
end.new(10)
assert_equal(3 ^ 10, 3 ^ obj)
end
def test_bit_length
assert_equal(13, (-2**12-1).bit_length)
assert_equal(12, (-2**12).bit_length)