aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--test/ruby/test_array.rb22
-rw-r--r--vm_eval.c22
-rw-r--r--vm_method.c25
4 files changed, 51 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 2baa5eba62..0575566d77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Thu Aug 20 14:13:27 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (check_funcall_respond_to): share the behavior with
+ rb_obj_respond_to. [ruby-core:70460] [Bug #11465]
+
+ * vm_method.c (vm_respond_to): extract from rb_obj_respond_to and
+ merge r39881.
+
Thu Aug 20 08:53:09 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* vm_method.c (rb_obj_respond_to): reuse found method entry
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index 977c14cfa0..ea551dbeba 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -855,6 +855,28 @@ class TestArray < Test::Unit::TestCase
assert_match(/reentered/, e.message, '[ruby-dev:34798]')
end
+ def test_flatten_respond_to_missing
+ bug11465 = '[ruby-core:70460] [Bug #11465]'
+
+ obj = Class.new do
+ def respond_to_missing?(method, stuff)
+ return false if method == :to_ary
+ super
+ end
+
+ def method_missing(*args)
+ super
+ end
+ end.new
+
+ ex = nil
+ trace = TracePoint.new(:raise) do |tp|
+ ex = tp.raised_exception
+ end
+ trace.enable {[obj].flatten}
+ assert_nil(ex, bug11465)
+ end
+
def test_permutation_with_callcc
need_continuation
n = 1000
diff --git a/vm_eval.c b/vm_eval.c
index 25d9f3251c..3d20ceb8a0 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -378,27 +378,7 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
static int
check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
{
- const rb_callable_method_entry_t *me = rb_callable_method_entry(klass, idRespond_to);
-
- if (me && !METHOD_ENTRY_BASIC(me)) {
- const rb_block_t *passed_block = th->passed_block;
- VALUE args[2], result;
- int arity = rb_method_entry_arity((const rb_method_entry_t *)me);
-
- if (arity > 2)
- rb_raise(rb_eArgError, "respond_to? must accept 1 or 2 arguments (requires %d)", arity);
-
- if (arity < 1) arity = 2;
-
- args[0] = ID2SYM(mid);
- args[1] = Qtrue;
- result = vm_call0(th, recv, idRespond_to, arity, args, me);
- th->passed_block = passed_block;
- if (!RTEST(result)) {
- return FALSE;
- }
- }
- return TRUE;
+ return vm_respond_to(th, klass, recv, mid, 1);
}
static int
diff --git a/vm_method.c b/vm_method.c
index fd000fa95a..e74de0d49c 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1829,10 +1829,9 @@ basic_obj_respond_to(VALUE obj, ID id, int pub)
}
}
-int
-rb_obj_respond_to(VALUE obj, ID id, int priv)
+static int
+vm_respond_to(rb_thread_t *th, VALUE klass, VALUE obj, ID id, int priv)
{
- VALUE klass = CLASS_OF(obj);
VALUE defined_class;
const ID resid = idRespond_to;
const rb_method_entry_t *const me =
@@ -1845,12 +1844,20 @@ rb_obj_respond_to(VALUE obj, ID id, int priv)
else {
int argc = 1;
VALUE args[2];
+ VALUE result;
const rb_callable_method_entry_t *cme;
+ const rb_block_t *passed_block = th->passed_block;
args[0] = ID2SYM(id);
args[1] = Qtrue;
if (priv) {
- if (rb_method_entry_arity(me) != 1) {
+ argc = rb_method_entry_arity(me);
+ if (argc > 2) {
+ rb_raise(rb_eArgError,
+ "respond_to? must accept 1 or 2 arguments (requires %d)",
+ argc);
+ }
+ if (argc != 1) {
argc = 2;
}
else if (!NIL_P(ruby_verbose)) {
@@ -1871,11 +1878,19 @@ rb_obj_respond_to(VALUE obj, ID id, int priv)
}
}
cme = prepare_callable_method_entry(defined_class, resid, me);
- return RTEST(vm_call0(GET_THREAD(), obj, resid, argc, args, cme));
+ result = vm_call0(th, obj, resid, argc, args, cme);
+ th->passed_block = passed_block;
+ return RTEST(result);
}
}
int
+rb_obj_respond_to(VALUE obj, ID id, int priv)
+{
+ return vm_respond_to(GET_THREAD(), CLASS_OF(obj), obj, id, priv);
+}
+
+int
rb_respond_to(VALUE obj, ID id)
{
return rb_obj_respond_to(obj, id, FALSE);