mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59183 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
c95cbf6aab
commit
1474acff3c
4 changed files with 39 additions and 4 deletions
16
compile.c
16
compile.c
|
@ -5657,15 +5657,23 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
|
|||
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;
|
||||
|
||||
|
|
|
@ -525,4 +525,14 @@ class TestEval < Test::Unit::TestCase
|
|||
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
|
||||
|
|
|
@ -976,6 +976,7 @@ eom
|
|||
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|
|
||||
|
|
|
@ -1126,6 +1126,7 @@ vm_throw_start(rb_thread_t *const th, rb_control_frame_t *const reg_cfp, enum ru
|
|||
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_control_frame_t *const reg_cfp, enum ru
|
|||
|
||||
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_control_frame_t *const reg_cfp, enum ru
|
|||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue