ruby-changes:46929
From: ko1 <ko1@a...>
Date: Thu, 8 Jun 2017 13:13:59 +0900 (JST)
Subject: [ruby-changes:46929] ko1:r59043 (trunk): check break target correctly.
ko1 2017-06-08 13:13:51 +0900 (Thu, 08 Jun 2017) New Revision: 59043 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59043 Log: 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. Modified files: trunk/compile.c trunk/iseq.h trunk/test/ruby/test_iterator.rb trunk/vm_insnhelper.c Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 59042) +++ vm_insnhelper.c (revision 59043) @@ -1090,7 +1090,9 @@ vm_throw_start(rb_thread_t *const th, rb https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1090 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; } Index: compile.c =================================================================== --- compile.c (revision 59042) +++ compile.c (revision 59043) @@ -4399,17 +4399,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK https://github.com/ruby/ruby/blob/trunk/compile.c#L4399 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 https://github.com/ruby/ruby/blob/trunk/compile.c#L4424 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; } Index: test/ruby/test_iterator.rb =================================================================== --- test/ruby/test_iterator.rb (revision 59042) +++ test/ruby/test_iterator.rb (revision 59043) @@ -279,6 +279,9 @@ class TestIterator < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iterator.rb#L279 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::TestCas https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iterator.rb#L303 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 Index: iseq.h =================================================================== --- iseq.h (revision 59042) +++ iseq.h (revision 59043) @@ -151,7 +151,21 @@ struct iseq_catch_table_entry { https://github.com/ruby/ruby/blob/trunk/iseq.h#L151 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; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/