[前][次][番号順一覧][スレッド一覧]

ruby-changes:47068

From: nobu <ko1@a...>
Date: Tue, 27 Jun 2017 15:57:39 +0900 (JST)
Subject: [ruby-changes:47068] nobu:r59183 (trunk): fix return in toplevel rescue/ensure

nobu	2017-06-27 15:57:34 +0900 (Tue, 27 Jun 2017)

  New Revision: 59183

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59183

  Log:
    fix return in toplevel rescue/ensure
    
    * compile.c (iseq_compile_each0): throw TAG_RETURN at return in
      toplevel rescue/ensure to adjust VM stack properly.
      [ruby-core:81777] [Bug #13682]
    
    * vm_insnhelper.c (vm_throw_start): allow return in toplevel
      rescue/ensure.

  Modified files:
    trunk/compile.c
    trunk/test/ruby/test_eval.rb
    trunk/test/ruby/test_syntax.rb
    trunk/vm_insnhelper.c
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 59182)
+++ vm_insnhelper.c	(revision 59183)
@@ -1126,6 +1126,7 @@ vm_throw_start(rb_thread_t *const th, rb https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1126
 	const VALUE *current_ep = GET_EP();
 	const VALUE *target_lep = VM_EP_LEP(current_ep);
 	int in_class_frame = 0;
+	int toplevel = 1;
 	escape_cfp = reg_cfp;
 
 	while (escape_cfp < eocfp) {
@@ -1144,6 +1145,7 @@ vm_throw_start(rb_thread_t *const th, rb https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1145
 
 	    if (lep == target_lep) {
 		if (VM_FRAME_LAMBDA_P(escape_cfp)) {
+		    toplevel = 0;
 		    if (in_class_frame) {
 			/* lambda {class A; ... return ...; end} */
 			goto valid_return;
@@ -1160,6 +1162,20 @@ vm_throw_start(rb_thread_t *const th, rb https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1162
 			}
 		    }
 		}
+		else if (VM_FRAME_RUBYFRAME_P(escape_cfp)) {
+		    switch (escape_cfp->iseq->body->type) {
+		      case ISEQ_TYPE_TOP:
+		      case ISEQ_TYPE_MAIN:
+			if (toplevel) goto valid_return;
+			break;
+		      case ISEQ_TYPE_EVAL:
+		      case ISEQ_TYPE_CLASS:
+			toplevel = 0;
+			break;
+		      default:
+			break;
+		    }
+		}
 	    }
 
 	    if (escape_cfp->ep == target_lep && escape_cfp->iseq->body->type == ISEQ_TYPE_METHOD) {
Index: test/ruby/test_eval.rb
===================================================================
--- test/ruby/test_eval.rb	(revision 59182)
+++ test/ruby/test_eval.rb	(revision 59183)
@@ -525,4 +525,14 @@ class TestEval < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_eval.rb#L525
       b.eval('yield')
     }, '[Bug #10368]'
   end
+
+  def test_return_in_eval_proc
+    x = proc {eval("return :ng")}
+    assert_raise(LocalJumpError) {x.call}
+  end
+
+  def test_return_in_eval_lambda
+    x = lambda {eval("return :ok")}
+    assert_equal(:ok, x.call)
+  end
 end
Index: test/ruby/test_syntax.rb
===================================================================
--- test/ruby/test_syntax.rb	(revision 59182)
+++ test/ruby/test_syntax.rb	(revision 59183)
@@ -976,6 +976,7 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L976
       return 1; raise
       "#{return}"
       raise((return; "should not raise"))
+      begin raise; ensure return; end; self
     end;
     all_assertions(feature4840) do |a|
       code.each_line do |s|
Index: compile.c
===================================================================
--- compile.c	(revision 59182)
+++ compile.c	(revision 59183)
@@ -5657,15 +5657,23 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK https://github.com/ruby/ruby/blob/trunk/compile.c#L5657
 	if (is) {
 	    enum iseq_type type = is->body->type;
 	    const rb_iseq_t *parent_iseq = is->body->parent_iseq;
-	    enum iseq_type parent_type = parent_iseq ? parent_iseq->body->type : type;
+	    enum iseq_type parent_type;
 
-	    if (type == ISEQ_TYPE_TOP || type == ISEQ_TYPE_MAIN ||
-		((type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE) &&
-		 (parent_type == ISEQ_TYPE_TOP || parent_type == ISEQ_TYPE_MAIN))) {
+	    if (type == ISEQ_TYPE_TOP || type == ISEQ_TYPE_MAIN) {
 		ADD_ADJUST(ret, line, 0);
 		ADD_INSN(ret, line, putnil);
 		ADD_INSN(ret, line, leave);
 	    }
+	    else if ((type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE) &&
+		     parent_iseq &&
+		     ((parent_type = parent_iseq->body->type) == ISEQ_TYPE_TOP ||
+		      parent_type == ISEQ_TYPE_MAIN)) {
+		ADD_INSN(ret, line, putnil);
+		ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETURN));
+		if (popped) {
+		    ADD_INSN(ret, line, pop);
+		}
+	    }
 	    else {
 		LABEL *splabel = 0;
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]