Skip to content

Commit 2dd46bb

Browse files
committed
[Bug #20468] Fix safe navigation in for variable
1 parent 9d69619 commit 2dd46bb

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

compile.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5380,12 +5380,17 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
53805380

53815381
CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
53825382

5383+
bool safenav_call = false;
53835384
LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
53845385
iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
53855386
ASSUME(iobj);
5386-
ELEM_REMOVE(LAST_ELEMENT(pre));
5387-
ELEM_REMOVE((LINK_ELEMENT *)iobj);
5388-
pre->last = iobj->link.prev;
5387+
ELEM_REMOVE(insn_element);
5388+
if (!IS_INSN_ID(iobj, send)) {
5389+
safenav_call = true;
5390+
iobj = (INSN *)get_prev_insn(iobj);
5391+
ELEM_INSERT_NEXT(&iobj->link, insn_element);
5392+
}
5393+
(pre->last = iobj->link.prev)->next = 0;
53895394

53905395
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
53915396
int argc = vm_ci_argc(ci) + 1;
@@ -5404,7 +5409,9 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
54045409
return COMPILE_NG;
54055410
}
54065411

5407-
ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5412+
iobj->link.prev = lhs->last;
5413+
lhs->last->next = &iobj->link;
5414+
for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
54085415
if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
54095416
int argc = vm_ci_argc(ci);
54105417
bool dupsplat = false;
@@ -5437,9 +5444,11 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
54375444
}
54385445
INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
54395446
}
5440-
ADD_INSN(lhs, line_node, pop);
5441-
if (argc != 1) {
5447+
if (!safenav_call) {
54425448
ADD_INSN(lhs, line_node, pop);
5449+
if (argc != 1) {
5450+
ADD_INSN(lhs, line_node, pop);
5451+
}
54435452
}
54445453
for (int i=0; i < argc; i++) {
54455454
ADD_INSN(post, line_node, pop);

test/ruby/test_syntax.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,20 @@ def test_safe_call_in_massign_lhs
12481248
assert_syntax_error("a&.x,=0", /multiple assignment destination/)
12491249
end
12501250

1251+
def test_safe_call_in_for_variable
1252+
assert_valid_syntax("for x&.bar in []; end")
1253+
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
1254+
begin;
1255+
foo = nil
1256+
for foo&.bar in [1]; end
1257+
assert_nil(foo)
1258+
1259+
foo = Struct.new(:bar).new
1260+
for foo&.bar in [1]; end
1261+
assert_equal(1, foo.bar)
1262+
end;
1263+
end
1264+
12511265
def test_no_warning_logop_literal
12521266
assert_warning("") do
12531267
eval("true||raise;nil")

0 commit comments

Comments
 (0)