mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
check break target correctly.
* compile.c (iseq_compile_each0): save target child_iseq in the catch-table for break. This iseq is not for continuation, but for search key at vm_throw_start(). * vm_insnhelper.c (vm_throw_start): check saved iseq first. * iseq.h: add comment for it. * test/ruby/test_iterator.rb (test_ljump): add a test for the issue: def call b; b.call; end call(Proc.new{break}){} #=> (1) should raise LocalJumpError call(Proc.new{break}) #=> (2) shoudd raies LocalJumpError, too. but (1) doesn't raise LocalJumpError. This issue is reported by Matz. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59043 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0318de23d4
commit
7d8a415bc2
4 changed files with 28 additions and 5 deletions
11
compile.c
11
compile.c
|
@ -4399,17 +4399,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
|
|||
const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
|
||||
LABEL *retry_label = NEW_LABEL(line);
|
||||
LABEL *retry_end_l = NEW_LABEL(line);
|
||||
const rb_iseq_t *child_iseq;
|
||||
|
||||
ADD_LABEL(ret, retry_label);
|
||||
if (nd_type(node) == NODE_FOR) {
|
||||
CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
|
||||
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
|
||||
NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_TYPE_BLOCK, line);
|
||||
ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), ISEQ_COMPILE_DATA(iseq)->current_block);
|
||||
ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
|
||||
}
|
||||
else {
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
|
||||
NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
|
||||
ISEQ_TYPE_BLOCK, line);
|
||||
CHECK(COMPILE(ret, "iter caller", node->nd_iter));
|
||||
}
|
||||
|
@ -4421,7 +4424,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
|
|||
|
||||
ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
|
||||
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, NULL, retry_end_l);
|
||||
ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
14
iseq.h
14
iseq.h
|
@ -151,7 +151,21 @@ struct iseq_catch_table_entry {
|
|||
CATCH_TYPE_REDO = INT2FIX(5),
|
||||
CATCH_TYPE_NEXT = INT2FIX(6)
|
||||
} type;
|
||||
|
||||
/*
|
||||
* iseq type:
|
||||
* CATCH_TYPE_RESCUE, CATCH_TYPE_ENSURE:
|
||||
* use iseq as continuation.
|
||||
*
|
||||
* CATCH_TYPE_BREAK (iter):
|
||||
* use iseq as key.
|
||||
*
|
||||
* CATCH_TYPE_BREAK (while), CATCH_TYPE_RETRY,
|
||||
* CATCH_TYPE_REDO, CATCH_TYPE_NEXT:
|
||||
* NULL.
|
||||
*/
|
||||
const rb_iseq_t *iseq;
|
||||
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
unsigned int cont;
|
||||
|
|
|
@ -279,6 +279,9 @@ class TestIterator < Test::Unit::TestCase
|
|||
def proc_call(&b)
|
||||
b.call
|
||||
end
|
||||
def proc_call2(b)
|
||||
b.call
|
||||
end
|
||||
def proc_yield()
|
||||
yield
|
||||
end
|
||||
|
@ -300,6 +303,7 @@ class TestIterator < Test::Unit::TestCase
|
|||
|
||||
def test_ljump
|
||||
assert_raise(LocalJumpError) {get_block{break}.call}
|
||||
assert_raise(LocalJumpError) {proc_call2(get_block{break}){}}
|
||||
|
||||
# cannot use assert_nothing_raised due to passing block.
|
||||
begin
|
||||
|
|
|
@ -1090,7 +1090,9 @@ vm_throw_start(rb_thread_t *const th, rb_control_frame_t *const reg_cfp, enum ru
|
|||
for (i=0; i<ct_size; i++) {
|
||||
const struct iseq_catch_table_entry * const entry = &ct->entries[i];
|
||||
|
||||
if (entry->type == CATCH_TYPE_BREAK && entry->start < epc && entry->end >= epc) {
|
||||
if (entry->type == CATCH_TYPE_BREAK &&
|
||||
entry->iseq == base_iseq &&
|
||||
entry->start < epc && entry->end >= epc) {
|
||||
if (entry->cont == epc) { /* found! */
|
||||
is_orphan = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue