Add pushtoarray insn to fix segfault with forwarding + splat

Example insns diff for `def x = [3]; def a(...) = b(*x, 2, 3, ...)`

     == disasm: #<ISeq:a@-e:1 (1,13)-(1,42)>
     local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
     [ 1] "..."@0
     0000 putself                                                          (   1)[Ca]
     0000 putself
     0000 opt_send_without_block                 <calldata!mid:x, argc:0, FCALL|VCALL|ARGS_SIMPLE>
     0000 splatarray                             true
     0000 putobject                              2
     0000 putobject                              3
    +0000 pushtoarray                            2
     0000 getlocal_WC_0                          "..."@0
     0000 sendforward                            <calldata!mid:b, argc:1, ARGS_SPLAT|ARGS_SPLAT_MUT|FCALL|FORWARDING>, nil
     0000 leave                                  [Re]

This matches the insns produced by parse.y
This commit is contained in:
Randy Stauner 2026-01-12 18:35:12 -07:00 committed by Aaron Patterson
parent 9db0a8c7db
commit 1a0b356d40
Notes: git 2026-01-13 19:18:46 +00:00
2 changed files with 15 additions and 0 deletions

View File

@ -1427,3 +1427,10 @@ assert_equal 'ok', <<~RUBY
test
RUBY
assert_equal '[1, 2, 3]', %q{
def target(*args) = args
def x = [1]
def forwarder(...) = target(*x, 2, ...)
forwarder(3).inspect
}, '[Bug #21832] post-splat args before forwarding'

View File

@ -1833,6 +1833,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// foo(*a, b, c: :d)
// foo(*a, b, **c)
//
// If the next node is a forwarding argument:
//
// foo(*a, b, ...)
//
// If the next node is NULL (we have hit the end):
//
// foo(*a, b)
@ -1855,6 +1859,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
PUSH_INSN(ret, location, concatarray);
break;
}
case PM_FORWARDING_ARGUMENTS_NODE: {
PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
break;
}
default:
break;
}