summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c11
-rw-r--r--iseq.h14
-rw-r--r--test/ruby/test_iterator.rb4
-rw-r--r--vm_insnhelper.c4
4 files changed, 28 insertions, 5 deletions
diff --git a/compile.c b/compile.c
index 7a6d6f3e2f..db88bab809 100644
--- a/compile.c
+++ b/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;
}
diff --git a/iseq.h b/iseq.h
index 3f3ed8a195..5c55aa0e40 100644
--- a/iseq.h
+++ b/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;
diff --git a/test/ruby/test_iterator.rb b/test/ruby/test_iterator.rb
index 4a9cfe46f0..9bfa947607 100644
--- a/test/ruby/test_iterator.rb
+++ b/test/ruby/test_iterator.rb
@@ -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
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index e70cb646da..aee9b81927 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -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;
}