summaryrefslogtreecommitdiffstats
path: root/vm_eval.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-22 01:43:59 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-22 01:43:59 +0000
commitfb1991448459be553b9140a80eb8c8c149b89464 (patch)
tree45adc1914ed6ec3198dbc48b7a7d91c57f531ac0 /vm_eval.c
parentd9f134e16fe95500ef072985c4e582c3d253122a (diff)
downloadruby-fb1991448459be553b9140a80eb8c8c149b89464.tar.gz
ruby-fb1991448459be553b9140a80eb8c8c149b89464.tar.xz
ruby-fb1991448459be553b9140a80eb8c8c149b89464.zip
* vm_eval.c (method_missing): should not pop cfp if missing method
is method_missing. [ruby-core:22298] * vm_eval.c (rb_raise_method_missing): new function to directly raise NoMethodError. * vm_insnhelper.c (vm_call_method): fixed the case method_missing is missing. git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@22494 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/vm_eval.c b/vm_eval.c
index b43e88d37..88113d328 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -256,6 +256,9 @@ rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope)
return rb_call0(klass, recv, mid, argc, argv, scope, Qundef);
}
+NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
+ VALUE obj, int call_status));
+
/*
* call-seq:
* obj.method_missing(symbol [, *args] ) => result
@@ -292,11 +295,21 @@ rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope)
static VALUE
rb_method_missing(int argc, const VALUE *argv, VALUE obj)
{
+ rb_thread_t *th = GET_THREAD();
+ raise_method_missing(th, argc, argv, obj, th->method_missing_reason);
+ return Qnil; /* not reached */
+}
+
+#define NOEX_MISSING 0x80
+
+static void
+raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj,
+ int last_call_status)
+{
ID id;
VALUE exc = rb_eNoMethodError;
const char *format = 0;
- rb_thread_t *th = GET_THREAD();
- int last_call_status = th->method_missing_reason;
+
if (argc == 0 || !SYMBOL_P(argv[0])) {
rb_raise(rb_eArgError, "no id given");
}
@@ -333,11 +346,11 @@ rb_method_missing(int argc, const VALUE *argv, VALUE obj)
}
exc = rb_class_new_instance(n, args, exc);
- th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+ if (!(last_call_status & NOEX_MISSING)) {
+ th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+ }
rb_exc_raise(exc);
}
-
- return Qnil; /* not reached */
}
static inline VALUE
@@ -350,7 +363,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
th->passed_block = 0;
if (id == idMethodMissing) {
- rb_method_missing(argc, argv, obj);
+ raise_method_missing(th, argc, argv, obj, call_status | NOEX_MISSING);
}
else if (id == ID_ALLOCATOR) {
rb_raise(rb_eTypeError, "allocator undefined for %s",
@@ -372,6 +385,14 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
return result;
}
+void
+rb_raise_method_missing(rb_thread_t *th, int argc, VALUE *argv,
+ VALUE obj, int call_status)
+{
+ th->passed_block = 0;
+ raise_method_missing(th, argc, argv, obj, call_status | NOEX_MISSING);
+}
+
VALUE
rb_apply(VALUE recv, ID mid, VALUE args)
{