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

merges r22494 and r22495 from trunk into ruby_1_9_1.

* 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: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_1@22551 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
yugui 2009-02-22 14:05:31 +00:00
parent 5fd244b440
commit 41031667c9
5 changed files with 74 additions and 22 deletions

View file

@ -1,3 +1,14 @@
Sun Feb 22 10:43:57 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
* 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.
Fri Feb 20 23:28:11 2009 NAKAMURA Usaku <usa@ruby-lang.org>
* util.c (rv_alloc, freedtoa): use our normal xmalloc()/xfree() because

View file

@ -1140,3 +1140,14 @@ assert_equal 'Object#foo', %q{
end
Foo.foo
}, '[ruby-dev:37587]'
assert_normal_exit %q{
class BasicObject
remove_method :method_missing
end
begin
"a".lalala!
rescue NoMethodError => e
e.message == "undefined method `lalala!' for \"a\":String" ? :ok : :ng
end
}, '[ruby-core:22298]'

View file

@ -195,6 +195,8 @@ NORETURN(void rb_fiber_start(void));
NORETURN(void rb_print_undef(VALUE, ID, int));
NORETURN(void rb_vm_localjump_error(const char *,VALUE, int));
NORETURN(void rb_vm_jump_tag_but_local_jump(int, VALUE));
NORETURN(void rb_raise_method_missing(rb_thread_t *th, int argc, VALUE *argv,
VALUE obj, int call_status));
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val);
NODE *rb_vm_cref(void);

View file

@ -255,6 +255,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
@ -290,12 +293,22 @@ 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");
}
@ -332,11 +345,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
@ -349,7 +362,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",
@ -371,6 +384,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)
{

View file

@ -403,20 +403,25 @@ vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv,
return val;
}
static inline void
vm_method_missing_args(rb_thread_t *th, VALUE *argv,
int num, rb_block_t *blockptr, int opt)
{
rb_control_frame_t * const reg_cfp = th->cfp;
MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
th->method_missing_reason = opt;
th->passed_block = blockptr;
POPN(num + 1);
}
static inline VALUE
vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
int num, rb_block_t *blockptr, int opt)
{
VALUE val;
rb_control_frame_t * const reg_cfp = th->cfp;
VALUE *argv = ALLOCA_N(VALUE, num + 1);
MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
vm_method_missing_args(th, argv, num, blockptr, opt);
argv[0] = ID2SYM(id);
th->method_missing_reason = opt;
th->passed_block = blockptr;
POPN(num + 1);
val = rb_funcall2(recv, idMethodMissing, num + 1, argv);
return val;
return rb_funcall2(recv, idMethodMissing, num + 1, argv);
}
static inline void
@ -581,17 +586,19 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
}
else {
/* method missing */
int stat = 0;
if (flag & VM_CALL_VCALL_BIT) {
stat |= NOEX_VCALL;
}
if (flag & VM_CALL_SUPER_BIT) {
stat |= NOEX_SUPER;
}
if (id == idMethodMissing) {
rb_bug("method missing");
VALUE *argv = ALLOCA_N(VALUE, num);
vm_method_missing_args(th, argv, num - 1, 0, stat);
rb_raise_method_missing(th, num, argv, recv, stat);
}
else {
int stat = 0;
if (flag & VM_CALL_VCALL_BIT) {
stat |= NOEX_VCALL;
}
if (flag & VM_CALL_SUPER_BIT) {
stat |= NOEX_SUPER;
}
val = vm_method_missing(th, id, recv, num, blockptr, stat);
}
}