diff --git c/ext/-test-/iter/break.c i/ext/-test-/iter/break.c new file mode 100644 index 0000000..78c7da6 --- /dev/null +++ i/ext/-test-/iter/break.c @@ -0,0 +1,15 @@ +#include + +static VALUE +iter_break_value(VALUE self, VALUE val) +{ + rb_iter_break_value(val); + return self; /* not reached */ +} + +void +Init_break(void) +{ + VALUE breakable = rb_define_module_under(rb_define_module("Bug"), "Breakable"); + rb_define_module_function(breakable, "iter_break", iter_break_value, 1); +} diff --git c/ext/-test-/iter/extconf.rb i/ext/-test-/iter/extconf.rb new file mode 100644 index 0000000..695b5e9 --- /dev/null +++ i/ext/-test-/iter/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/iter/break") diff --git c/include/ruby/ruby.h i/include/ruby/ruby.h index 200a648..753e374 100644 --- c/include/ruby/ruby.h +++ i/include/ruby/ruby.h @@ -1185,6 +1185,7 @@ NORETURN(void rb_bug_errno(const char*, int)); NORETURN(void rb_sys_fail(const char*)); NORETURN(void rb_mod_sys_fail(VALUE, const char*)); NORETURN(void rb_iter_break(void)); +NORETURN(void rb_iter_break_value(VALUE)); NORETURN(void rb_exit(int)); NORETURN(void rb_notimplement(void)); VALUE rb_syserr_new(int, const char *); diff --git c/test/-ext-/iter/test_iter_break.rb i/test/-ext-/iter/test_iter_break.rb new file mode 100644 index 0000000..5276653 --- /dev/null +++ i/test/-ext-/iter/test_iter_break.rb @@ -0,0 +1,8 @@ +require 'test/unit' +require '-test-/iter/break' + +class TestIterBreak < Test::Unit::TestCase + def test_iter_break + assert_equal(42, 1.times{Bug::Breakable.iter_break(42)}) + end +end diff --git c/vm.c i/vm.c index 2cc8c5a..f8920bc 100644 --- c/vm.c +++ i/vm.c @@ -987,23 +987,29 @@ rb_vm_jump_tag_but_local_jump(int state, VALUE val) JUMP_TAG(state); } -NORETURN(static void vm_iter_break(rb_thread_t *th)); +NORETURN(static void vm_iter_break(rb_thread_t *th, VALUE val)); static void -vm_iter_break(rb_thread_t *th) +vm_iter_break(rb_thread_t *th, VALUE val) { rb_control_frame_t *cfp = th->cfp; VALUE *dfp = GC_GUARDED_PTR_REF(*cfp->dfp); th->state = TAG_BREAK; - th->errinfo = (VALUE)NEW_THROW_OBJECT(Qnil, (VALUE)dfp, TAG_BREAK); + th->errinfo = (VALUE)NEW_THROW_OBJECT(val, (VALUE)dfp, TAG_BREAK); TH_JUMP_TAG(th, TAG_BREAK); } void rb_iter_break(void) { - vm_iter_break(GET_THREAD()); + vm_iter_break(GET_THREAD(), Qnil); +} + +void +rb_iter_break_value(VALUE val) +{ + vm_iter_break(GET_THREAD(), val); } /* optimization: redefine management */ @@ -1355,6 +1361,7 @@ vm_exec(rb_thread_t *th) #endif } th->errinfo = Qnil; + th->state = 0; goto vm_loop_start; } } diff --git c/vm_eval.c i/vm_eval.c index 7b37b10..0ee8179 100644 --- c/vm_eval.c +++ i/vm_eval.c @@ -906,6 +906,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1, state = 0; th->state = 0; th->errinfo = Qnil; + retval = GET_THROWOBJ_VAL(err); /* check skipped frame */ while (th->cfp != cfp) {