diff options
| author | Randy Stauner <randy@r4s6.net> | 2026-01-12 18:35:12 -0700 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2026-01-25 18:18:10 +0900 |
| commit | 02eb4eec87cbbb14c24b63678aa0cca625777414 (patch) | |
| tree | 4faa5e02755b7beb795f3fe66f0f83ccd1863632 | |
| parent | 86e65fa1677180f5108157206edb01cfd25f24b6 (diff) | |
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
| -rw-r--r-- | bootstraptest/test_method.rb | 15 | ||||
| -rw-r--r-- | prism_compile.c | 8 |
2 files changed, 23 insertions, 0 deletions
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb index 41823b5007..d8a8effbaf 100644 --- a/bootstraptest/test_method.rb +++ b/bootstraptest/test_method.rb @@ -1419,3 +1419,18 @@ assert_equal 'ok', %q{ "ok" end } + +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' + +assert_equal 'ok', <<~RUBY + def test(*, kw: false) + "ok" + end + + test +RUBY diff --git a/prism_compile.c b/prism_compile.c index 79c944d998..9d6a8141bd 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1821,6 +1821,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) @@ -1843,6 +1847,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; } |
