[Bug #3141] yield in an eigenclass definition

Bug #3141: yield in an eigenclass definition
http://redmine.ruby-lang.org/issues/show/3141

e$B5/I<<Te(B: Yusuke E.
e$B%9%F!<%?%9e(B: Open, e$BM%@hEYe(B: Normal
e$BC4Ev<Te(B: Yusuke E., e$B%+%F%4%je(B: core, Target version: 1.9.2
ruby -v: ruby 1.9.2dev (2010-04-13 trunk 27329) [i686-linux]

e$B$5$5$@$5$se(B
e$B1sF#$G$9!#e(B

#1018 e$B$K4XO"$7$^$9$,!"FC0[%/%i%9Dj5A$NCf$Ge(B yield
e$B$,$G$-$^$;$s!#e(B

class Object
def yield_eigenclass
class << self
yield self
end
end
end

Object.yield_eigenclass {|c| p c }

$ ruby19 t.rb
t.rb:4: Invalid yield
t.rb: compile error (SyntaxError)

e$BD4$Y$F$$$FCN$C$?$N$G$9$,!"e(Bdfp[0] e$B$K$Oe(B

  • ISEQ_TYPE_METHOD, _CFUNC, _FINISH, _TOP e$B$N>l9g$Oe(B rb_block_t*
  • e$B$=$l0J30$N>l9g$OA0$N%U%l!<%`$Ne(B dfp (vm_throw e$B$G;H$&e(B)

e$B$,F~$C$F$$$k$s$G$9$Me(B (e$B$J$s$H$$$&e(B dirty hack e$B!D!De(B)
e$B!#e(B
vm_push_frame e$B$Ne(B 5 e$BHVL$N0z?te(B (specval)
e$B$KEO$5$l$kCM$O$:$C$HFfe(B
e$B$G$7$?!#e(B

ISEQ_TYPE_CLASS e$B$Ne(B dfp[0] e$B$K$OA0$N%U%l!<%`$Ne(B dfp
e$B$,F~$C$F$$$^$9!#e(B
(e$B%V%m%C%/$X$N%]%$%s%?$H6hJL$G$-$k$h$&!“2<$+$ie(B 2
e$B%S%C%HL$rN)$F$Fe(B
e$B$*$/$H$$$&!”$5$i$J$ke(B dirty hack (RUBY_VM_CLASS_SPECIAL_P)
e$B$r8+$Fe(B
e$BL$,$D$V$l$^$7$?e(B)

e$B0lJ}$G!“e(BISEQ_TYPE_CLASS
e$B0J2<$NJ8L.$+$i$O%V%m%C%/$X$N;2>H$,$J$$e(B
e$B>uBV$K$J$C$F$$$k$H;W$$$^$7$?!#$3$3$^$G!”>-Mh$N<+J,$N$?$a$N%a%b!#e(B

e$B$=$3$G!"e(BISEQ_TYPE_CLASS e$B$Ne(B dfp[0] e$B$K$be(B rb_block_t*
e$B$rF~$l$k$3$H$Ke(B
e$B$7$^$;$s$+!#e(B

e$B%a%j%C%He(B:
- e$B>e5-$N%3!<%I$,F0$/e(B
- RUBY_VM_CLASS_SPECIAL_P e$B$Ne(B dirty hack e$B$,ITMW$K$J$ke(B

e$B%G%a%j%C%He(B:
- vm_throw e$B$GJ,4t$,A}$($k>l9g$,$"$ke(B

e$B%G%a%j%C%H$K$D$$$F$O!"e(Bbreak e$B$G0J2<$rH4$1$k$4$H$Ke(B 1
e$B2sJ,4t$,A}$(e(B
e$B$^$9!#e(B

  • e$B%/%i%9Dj5Ae(B 1.times { class C; break; end }
  • rescue e$B@ae(B 1.times { begin; …; rescue; break; end }
  • ensure e$B@ae(B 1.times { begin; …; ensure; break; end }

e$B$3$3$K%/%i%9Dj5A$,Mh$k$3$H$OHs>o$K%l%"$G$9$7!“e(Brescue e$B@a$de(B
ensure
e$B@a$r%M%9%H$9$k$3$H$b%l%”$@$H;W$&$N$G!“LdBj$K$J$i$J$$$s$8$c$J$$e(B
e$B$+$J!”$H;W$$$^$9!#e(B

e$B$H$$$&$o$1$G%Q%C%A$G$9!#e(B#1018 e$B$Ne(B wanabe
e$B$5$s$N%Q%C%A$b4^$$^$9!#e(B
make test-rubyspec e$B$He(B make check
e$B$GFC$K%(%i!<$,A}$($J$$46$8$Je(B
e$B$3$H$O3NG’$7$F$$$^$9!#%3%
%C%H$7$F$b$$$$$G$7$g$&$+!#e(B

diff --git a/compile.c b/compile.c
index 64411f9…7748fca 100644
— a/compile.c
+++ b/compile.c
@@ -4229,7 +4229,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
*ret, NODE * node, int poped)
rb_iseq_t *is = iseq;

if (is) {

  •  if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) {
    
  •  if (is->type == ISEQ_TYPE_TOP) {
    

    COMPILE_ERROR((ERROR_ARGS “Invalid return”));
    }
    else {
    @@ -4269,7 +4269,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR
    *ret, NODE * node, int poped)
    unsigned long flag = 0;

    INIT_ANCHOR(args);

  • if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) {
  • if (iseq->type == ISEQ_TYPE_TOP) {
    COMPILE_ERROR((ERROR_ARGS “Invalid yield”));
    }

diff --git a/insns.def b/insns.def
index 9541465…14485f2 100644
— a/insns.def
+++ b/insns.def
@@ -953,7 +953,7 @@ defineclass

 /* enter scope */
 vm_push_frame(th, class_iseq,
  •  VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_DFP() | 0x02,
    
  •  VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_BLOCK_PTR(),
     class_iseq->iseq_encoded, GET_SP(), 0,
     class_iseq->local_size);
    
    RESTORE_REGS();
    diff --git a/proc.c b/proc.c
    index eff7a0b…5fa46f1 100644
    — a/proc.c
    +++ b/proc.c
    @@ -374,16 +374,14 @@ proc_new(VALUE klass, int is_lambda)
    rb_control_frame_t *cfp = th->cfp;
    rb_block_t *block;
  • if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 &&
  • !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
  • if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0) {

block = GC_GUARDED_PTR_REF(cfp->lfp[0]);
}
else {
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);

  • if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 &&
  •  !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
    
  • if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0) {

    block = GC_GUARDED_PTR_REF(cfp->lfp[0]);
    

diff --git a/vm.c b/vm.c
index 678fcb8…e5de8ac 100644
— a/vm.c
+++ b/vm.c
@@ -477,7 +477,6 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t
*block, VALUE klass)
}

 if (GC_GUARDED_PTR_REF(cfp->lfp[0])) {
  • if (!RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) {
    rb_proc_t *p;

    blockprocval = vm_make_proc_from_block(
    

@@ -486,7 +485,6 @@ rb_vm_make_proc(rb_thread_t *th, const rb_block_t
*block, VALUE klass)
GetProcPtr(blockprocval, p);
*cfp->lfp = GC_GUARDED_PTR(&p->block);
}

  • }

    envval = rb_vm_make_env_object(th, cfp);

diff --git a/vm_core.h b/vm_core.h
index b5c1bf0…7ee1c1c 100644
— a/vm_core.h
+++ b/vm_core.h
@@ -592,8 +592,6 @@ typedef rb_control_frame_t *
#define RUBY_VM_NORMAL_ISEQ_P(ptr)
(ptr && !RUBY_VM_IFUNC_P(ptr))

-#define RUBY_VM_CLASS_SPECIAL_P(ptr) (((VALUE)(ptr)) & 0x02)

#define RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp) ((rb_block_t
*)(&(cfp)->self))
#define RUBY_VM_GET_CFP_FROM_BLOCK_PTR(b)
((rb_control_frame_t *)((VALUE *)(b) - 5))
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index cd74c8e…ae28ef3 100644
— a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -890,8 +890,9 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t
*reg_cfp, rb_num_t num, rb_n
const rb_block_t *block = GET_BLOCK_PTR();
rb_iseq_t *iseq;
int argc = (int)num;

  • int type = GET_ISEQ()->local_iseq->type;
  • if (GET_ISEQ()->local_iseq->type != ISEQ_TYPE_METHOD || block == 0)
    {
  • if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block
    == 0) {
    rb_vm_localjump_error(“no block given (yield)”, Qnil, 0);
    }
    iseq = block->iseq;
    @@ -1411,6 +1412,11 @@ vm_throw(rb_thread_t *th, rb_control_frame_t
    *reg_cfp,

    search_parent:
    

    if (cfp->iseq->type != ISEQ_TYPE_BLOCK) {

  •    if (cfp->iseq->type == ISEQ_TYPE_CLASS) {
    
  •  cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
    
  •  dfp = cfp->dfp;
    
  •  goto search_parent;
    
  •    }
       dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp);
       base_iseq = base_iseq->parent_iseq;
    

@@ -1476,10 +1482,17 @@ vm_throw(rb_thread_t *th, rb_control_frame_t
*reg_cfp,
else if (state == TAG_RETURN) {
rb_control_frame_t *cfp = GET_CFP();
VALUE *dfp = GET_DFP();

  • VALUE * const lfp = GET_LFP();
  • VALUE *lfp = GET_LFP();

    /* check orphan and get dfp */
    while ((VALUE *) cfp < th->stack + th->stack_size) {

  •    if (!lfp) {
    
  •  lfp = cfp->lfp;
    
  •    }
    
  •    if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) {
    
  •  lfp = 0;
    
  •    }
    
  •    if (cfp->lfp == lfp) {
     if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
         VALUE *tdfp = dfp;
    


Yusuke E. [email protected]

e$B%A%1%C%He(B #3141 e$B$,99?7$5$l$^$7$?!#e(B (by Koichi Sasada)

e$BJV;v$,CY$/$J$C$F$9$_$^$;$s!%e(B
e$B$3$l$,NI$$$H;W$$$^$9!%$h$m$7$/$*4j$$$7$^$9!%e(B

http://redmine.ruby-lang.org/issues/show/3141

e$B%A%1%C%He(B #3141 e$B$,99?7$5$l$^$7$?!#e(B (by Yusuke E.)

e$B%9%F!<%?%9e(B Opene$B$+$ie(BClosede$B$KJQ99e(B
e$B?JD=e(B % 0e$B$+$ie(B100e$B$KJQ99e(B

This issue was solved with changeset r27714.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


http://redmine.ruby-lang.org/issues/show/3141