* vm_insnhelper.c (vm_throw): fix "return" process from "lambda".

* bootstraptest/test_proc.rb: add a test.
* bootstraptest/pending.rb: add a pending bug.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17421 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2008-06-19 02:46:02 +00:00
parent 33e5cfee7b
commit c3e619c83d
4 changed files with 57 additions and 16 deletions

View File

@ -1,3 +1,11 @@
Thu Jun 19 11:40:55 2008 Koichi Sasada <ko1@atdot.net>
* vm_insnhelper.c (vm_throw): fix "return" process from "lambda".
* bootstraptest/test_proc.rb: add a test.
* bootstraptest/pending.rb: add a pending bug.
Thu Jun 19 00:33:40 2008 Yusuke Endoh <mame@tsg.ne.jp> Thu Jun 19 00:33:40 2008 Yusuke Endoh <mame@tsg.ne.jp>
* test/etc/test_etc.rb: avoid infinite loop. [ruby-dev:35158] * test/etc/test_etc.rb: avoid infinite loop. [ruby-dev:35158]

View File

@ -13,3 +13,20 @@ assert_equal 'A', %q{
B.new.a = 'B' B.new.a = 'B'
A.new.a A.new.a
}, '[ruby-core:17019]' }, '[ruby-core:17019]'
assert_equal 'ok', %q{
def m
lambda{
proc{
return :ng1
}
}.call.call
:ng2
end
begin
m()
rescue LocalJumpError
:ok
end
}

View File

@ -364,3 +364,17 @@ assert_equal 'ok', %q{
def12 def12
$x $x
}, '[ruby-core:17164]' }, '[ruby-core:17164]'
assert_equal 'ok', %q{
def m
pr = proc{
proc{
return :ok
}
}.call
pr.call
:ng
end
m()
}

View File

@ -1279,34 +1279,36 @@ vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp,
else if (state == TAG_RETURN) { else if (state == TAG_RETURN) {
rb_control_frame_t *cfp = GET_CFP(); rb_control_frame_t *cfp = GET_CFP();
VALUE *dfp = GET_DFP(); VALUE *dfp = GET_DFP();
int is_orphan = 1; VALUE * const lfp = GET_LFP();
/** /* check orphan and get dfp */
* check orphan:
*/
while ((VALUE *) cfp < th->stack + th->stack_size) { while ((VALUE *) cfp < th->stack + th->stack_size) {
if (dfp == cfp->dfp) { if (cfp->lfp == lfp) {
if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) {
/* in lambda */ VALUE *tdfp = dfp;
is_orphan = 0;
break;
}
if (GET_LFP() == dfp && cfp->iseq->type == ISEQ_TYPE_METHOD) { while (lfp != tdfp) {
is_orphan = 0; if (cfp->dfp == tdfp) {
break; /* in lambda */
dfp = cfp->dfp;
goto valid_return;
}
tdfp = GC_GUARDED_PTR_REF((VALUE *)*dfp);
}
} }
}
dfp = GC_GUARDED_PTR_REF(dfp[0]); if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_METHOD) {
dfp = lfp;
goto valid_return;
} }
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
} }
if (is_orphan) { vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
vm_localjump_error("unexpected return", throwobj, TAG_RETURN);
}
valid_return:
pt = dfp; pt = dfp;
} }
else { else {