From 69cee6fee50f63cd52d59325dc3780a6fc4e5ae2 Mon Sep 17 00:00:00 2001 From: "NARUSE, Yui" Date: Wed, 20 Mar 2024 20:05:31 +0900 Subject: merge revision(s) 771a2f039b9a059a73e8f111d1d46590fa697f63: [Backport #20213] (#10297) Fix incorrect use of VM_CALL_KW_SPLAT_MUT in zsuper with keyword splat For zsuper calls with a keyword splat but no actual keywords, the keyword splat is passed directly, so it cannot be mutable, because if the callee accepts a keyword splat, changes to the keyword splat by the callee would be reflected in the caller. While here, simplify the logic when the method supports literal keywords. I don't think it is possible for a method with has_kw param flags to not have keywords, so add an assertion for that, and set VM_CALL_KW_SPLAT_MUT in a single place. --- compile.c | 11 ++++------- test/ruby/test_super.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/compile.c b/compile.c index afc2061b12..4fd562a678 100644 --- a/compile.c +++ b/compile.c @@ -9371,14 +9371,11 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i if (local_body->param.flags.has_kwrest) { int idx = local_body->local_table_size - local_kwd->rest_start; ADD_GETLOCAL(args, node, idx, lvar_level); - if (local_kwd->num > 0) { - ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0)); - flag |= VM_CALL_KW_SPLAT_MUT; - } + assert(local_kwd->num > 0); + ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0)); } else { ADD_INSN1(args, node, newhash, INT2FIX(0)); - flag |= VM_CALL_KW_SPLAT_MUT; } for (i = 0; i < local_kwd->num; ++i) { ID id = local_kwd->table[i]; @@ -9387,13 +9384,13 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i ADD_GETLOCAL(args, node, idx, lvar_level); } ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1)); - flag |= VM_CALL_KW_SPLAT; + flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT; } else if (local_body->param.flags.has_kwrest) { int idx = local_body->local_table_size - local_kwd->rest_start; ADD_GETLOCAL(args, node, idx, lvar_level); argc++; - flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT; + flag |= VM_CALL_KW_SPLAT; } } diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index 6a575b88c5..ce78e66c52 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -558,6 +558,18 @@ class TestSuper < Test::Unit::TestCase end end + def test_zsuper_kw_splat_not_mutable + extend(Module.new{def a(**k) k[:a] = 1 end}) + extend(Module.new do + def a(**k) + before = k.dup + super + [before, k] + end + end) + assert_equal(*a) + end + def test_from_eval bug10263 = '[ruby-core:65122] [Bug #10263a]' a = Class.new do -- cgit v1.2.3