[Bug #19021] Fix safe call w/ conditional assign
As of fbaac837cfba23a9d34dc7ee144d7940248222a2, when we were performing a safe call (`o&.x=`) with a conditional assign (`||= 1`) and discarding the result the stack would end up in a bad state due to a missing pop. This commit fixes that by adjusting the target label of the branchnil to be before a pop in that case (as was previously done in the non-conditional assignment case).
This commit is contained in:
parent
e3cc1a6cae
commit
b361bdc200
Notes:
git
2022-09-26 12:45:16 +09:00
18
compile.c
18
compile.c
@ -8728,10 +8728,6 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
|
||||
}
|
||||
|
||||
ADD_LABEL(ret, lfin);
|
||||
ADD_INSN(ret, node, pop);
|
||||
if (lskip) {
|
||||
ADD_LABEL(ret, lskip);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
|
||||
@ -8741,13 +8737,13 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
|
||||
ADD_INSN1(ret, node, topn, INT2FIX(1));
|
||||
}
|
||||
ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
|
||||
if (lskip && popped) {
|
||||
ADD_LABEL(ret, lskip);
|
||||
}
|
||||
ADD_INSN(ret, node, pop);
|
||||
if (lskip && !popped) {
|
||||
ADD_LABEL(ret, lskip);
|
||||
}
|
||||
}
|
||||
if (lskip && popped) {
|
||||
ADD_LABEL(ret, lskip);
|
||||
}
|
||||
ADD_INSN(ret, node, pop);
|
||||
if (lskip && !popped) {
|
||||
ADD_LABEL(ret, lskip);
|
||||
}
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
@ -47,12 +47,19 @@ class TestCall < Test::Unit::TestCase
|
||||
assert_equal(5, o.y)
|
||||
o&.z ||= 6
|
||||
assert_equal(6, o.z)
|
||||
o&.z &&= 7
|
||||
assert_equal(7, o.z)
|
||||
|
||||
o = nil
|
||||
assert_nil(o&.x)
|
||||
assert_nothing_raised(NoMethodError) {o&.x = raise}
|
||||
assert_nothing_raised(NoMethodError) {o&.x = raise; nil}
|
||||
assert_nothing_raised(NoMethodError) {o&.x *= raise}
|
||||
assert_nothing_raised(NoMethodError) {o&.x *= raise; nil}
|
||||
assert_nothing_raised(NoMethodError) {o&.x ||= raise}
|
||||
assert_nothing_raised(NoMethodError) {o&.x ||= raise; nil}
|
||||
assert_nothing_raised(NoMethodError) {o&.x &&= raise}
|
||||
assert_nothing_raised(NoMethodError) {o&.x &&= raise; nil}
|
||||
end
|
||||
|
||||
def test_safe_call_evaluate_arguments_only_method_call_is_made
|
||||
|
Loading…
x
Reference in New Issue
Block a user