From: KUBO Takehiro Date: 2007-10-21T00:45:46+09:00 Subject: [ruby-dev:32111] Re: unsupported: th_call0 in 1.9 久保です。 > > KUBO Takehiro wrote in [ruby-dev:30396]: > > > ruby 1.9 で以下の条件のとき、[BUG] unsupported: th_call0 となりました。 > > > > > > 1. private なメソッドをサブクラスで public にする。 > > > 2. 拡張ライブラリからサブクラスで public にしたメソッドを rb_funcall > > > で呼び出す。 8ヶ月前のメールですが、この件、ずっと困っていたので proc.c の mnew() を参考にパッチを作りました。 [ruby-dev:30396]の試験プログラムは動くよ うになりました。 scope の扱いの部分が自信ないのですが、NODE_ZSUPER のときは、親 クラスのメソッドの scope ではなく、NODE_ZSUPER 自身の scope で もってチェックしたほうが良いのではと思い、最初に見付かったメソッド の noex を使用するようにしました。 以下、パッチです。 =================================================================== --- eval.c (revision 13745) +++ eval.c (working copy) @@ -1358,6 +1358,7 @@ rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope) { NODE *body, *method; + int noex_is_set = 0; int noex; ID id = mid; struct cache_entry *ent; @@ -1368,6 +1369,7 @@ "method `%s' called on terminated object (%p)", rb_id2name(mid), (void *)recv); } + again: /* is it in the method cache? */ ent = cache + EXPR1(klass, mid); @@ -1376,12 +1378,18 @@ return method_missing(recv, mid, argc, argv, scope == 2 ? NOEX_VCALL : 0); id = ent->mid0; - noex = ent->method->nd_noex; + if (!noex_is_set) { + noex = ent->method->nd_noex; + noex_is_set = 1; + } klass = ent->method->nd_clss; body = ent->method->nd_body; } - else if ((method = rb_get_method_body(klass, id, &id)) != 0) { - noex = method->nd_noex; + else if ((method = rb_get_method_body(klass, mid, &id)) != 0) { + if (!noex_is_set) { + noex = method->nd_noex; + noex_is_set = 1; + } klass = method->nd_clss; body = method->nd_body; } @@ -1392,7 +1400,10 @@ return method_missing(recv, mid, argc, argv, scope == 2 ? NOEX_VCALL : 0); } - + if (nd_type(body) == NODE_ZSUPER) { + klass = RCLASS_SUPER(klass); + goto again; + } if (mid != missing) { /* receiver specified form for private method */