mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 23:16:42 +02: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) {
|
if (is) {
|
||||||
enum iseq_type type = is->body->type;
|
enum iseq_type type = is->body->type;
|
||||||
const rb_iseq_t *parent_iseq = is->body->parent_iseq;
|
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 ||
|
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))) {
|
|
||||||
ADD_ADJUST(ret, line, 0);
|
ADD_ADJUST(ret, line, 0);
|
||||||
ADD_INSN(ret, line, putnil);
|
ADD_INSN(ret, line, putnil);
|
||||||
ADD_INSN(ret, line, leave);
|
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 {
|
else {
|
||||||
LABEL *splabel = 0;
|
LABEL *splabel = 0;
|
||||||
|
|
||||||
|
|
|
@ -525,4 +525,14 @@ class TestEval < Test::Unit::TestCase
|
||||||
b.eval('yield')
|
b.eval('yield')
|
||||||
}, '[Bug #10368]'
|
}, '[Bug #10368]'
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -976,6 +976,7 @@ eom
|
||||||
return 1; raise
|
return 1; raise
|
||||||
"#{return}"
|
"#{return}"
|
||||||
raise((return; "should not raise"))
|
raise((return; "should not raise"))
|
||||||
|
begin raise; ensure return; end; self
|
||||||
end;
|
end;
|
||||||
all_assertions(feature4840) do |a|
|
all_assertions(feature4840) do |a|
|
||||||
code.each_line do |s|
|
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 *current_ep = GET_EP();
|
||||||
const VALUE *target_lep = VM_EP_LEP(current_ep);
|
const VALUE *target_lep = VM_EP_LEP(current_ep);
|
||||||
int in_class_frame = 0;
|
int in_class_frame = 0;
|
||||||
|
int toplevel = 1;
|
||||||
escape_cfp = reg_cfp;
|
escape_cfp = reg_cfp;
|
||||||
|
|
||||||
while (escape_cfp < eocfp) {
|
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 (lep == target_lep) {
|
||||||
if (VM_FRAME_LAMBDA_P(escape_cfp)) {
|
if (VM_FRAME_LAMBDA_P(escape_cfp)) {
|
||||||
|
toplevel = 0;
|
||||||
if (in_class_frame) {
|
if (in_class_frame) {
|
||||||
/* lambda {class A; ... return ...; end} */
|
/* lambda {class A; ... return ...; end} */
|
||||||
goto valid_return;
|
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) {
|
if (escape_cfp->ep == target_lep && escape_cfp->iseq->body->type == ISEQ_TYPE_METHOD) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue