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
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;
|
const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
|
||||||
LABEL *retry_label = NEW_LABEL(line);
|
LABEL *retry_label = NEW_LABEL(line);
|
||||||
LABEL *retry_end_l = NEW_LABEL(line);
|
LABEL *retry_end_l = NEW_LABEL(line);
|
||||||
|
const rb_iseq_t *child_iseq;
|
||||||
|
|
||||||
ADD_LABEL(ret, retry_label);
|
ADD_LABEL(ret, retry_label);
|
||||||
if (nd_type(node) == NODE_FOR) {
|
if (nd_type(node) == NODE_FOR) {
|
||||||
CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
|
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);
|
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 {
|
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);
|
ISEQ_TYPE_BLOCK, line);
|
||||||
CHECK(COMPILE(ret, "iter caller", node->nd_iter));
|
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;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
14
iseq.h
14
iseq.h
@ -151,7 +151,21 @@ struct iseq_catch_table_entry {
|
|||||||
CATCH_TYPE_REDO = INT2FIX(5),
|
CATCH_TYPE_REDO = INT2FIX(5),
|
||||||
CATCH_TYPE_NEXT = INT2FIX(6)
|
CATCH_TYPE_NEXT = INT2FIX(6)
|
||||||
} type;
|
} 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;
|
const rb_iseq_t *iseq;
|
||||||
|
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
unsigned int end;
|
unsigned int end;
|
||||||
unsigned int cont;
|
unsigned int cont;
|
||||||
|
@ -279,6 +279,9 @@ class TestIterator < Test::Unit::TestCase
|
|||||||
def proc_call(&b)
|
def proc_call(&b)
|
||||||
b.call
|
b.call
|
||||||
end
|
end
|
||||||
|
def proc_call2(b)
|
||||||
|
b.call
|
||||||
|
end
|
||||||
def proc_yield()
|
def proc_yield()
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
@ -300,6 +303,7 @@ class TestIterator < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_ljump
|
def test_ljump
|
||||||
assert_raise(LocalJumpError) {get_block{break}.call}
|
assert_raise(LocalJumpError) {get_block{break}.call}
|
||||||
|
assert_raise(LocalJumpError) {proc_call2(get_block{break}){}}
|
||||||
|
|
||||||
# cannot use assert_nothing_raised due to passing block.
|
# cannot use assert_nothing_raised due to passing block.
|
||||||
begin
|
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++) {
|
for (i=0; i<ct_size; i++) {
|
||||||
const struct iseq_catch_table_entry * const entry = &ct->entries[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! */
|
if (entry->cont == epc) { /* found! */
|
||||||
is_orphan = 0;
|
is_orphan = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user