diff options
author | Jeremy Evans <code@jeremyevans.net> | 2019-10-24 09:47:30 -0700 |
---|---|---|
committer | Jeremy Evans <code@jeremyevans.net> | 2019-10-24 12:35:04 -0700 |
commit | d6a2507e494f0fffca375c9e2eede38b6a777874 (patch) | |
tree | 8216d116837c7c3d291018cf96aceb4e0ad90d54 | |
parent | 8c59b9250c25c66d6ed16429da139558295a4517 (diff) |
Duplicate hash when converting keyword hash to keywords
This mirrors the behavior when manually splatting a hash. This
mirrors the changes made in setup_parameters_complex in
6081ddd6e6f2297862b3c7e898d28a76b8f9240b, so that splatting to a
non-iseq method works the same as splatting to an iseq method.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/2606
-rw-r--r-- | test/ruby/test_keyword.rb | 8 | ||||
-rw-r--r-- | vm_insnhelper.c | 6 |
2 files changed, 12 insertions, 2 deletions
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 25337712fe..0f67c28963 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -2692,6 +2692,10 @@ class TestKeywordArguments < Test::Unit::TestCase args end + def pass_cfunc(*args) + self.class.new(*args).init_args + end + ruby2_keywords def block(*args) ->(*args, **kw){[args, kw]}.(*args) end @@ -2915,6 +2919,10 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal([[1], h1], o.foo(:pass_bar, 1, :a=>1)) end + assert_warn(/The last argument is used as the keyword parameter.* for `initialize'/m) do + assert_equal([[1], h1], o.foo(:pass_cfunc, 1, :a=>1)) + end + assert_warn(/Skipping set of ruby2_keywords flag for bar \(method accepts keywords or method does not accept argument splat\)/) do assert_nil(c.send(:ruby2_keywords, :bar)) end diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 44a44d5db1..c72ad6e9d7 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1783,14 +1783,16 @@ CALLER_SETUP_ARG(struct rb_control_frame_struct *restrict cfp, const struct rb_call_info *restrict ci) { if (UNLIKELY(IS_ARGS_SPLAT(ci))) { + VALUE final_hash; /* This expands the rest argument to the stack. * So, ci->flag & VM_CALL_ARGS_SPLAT is now inconsistent. */ vm_caller_setup_arg_splat(cfp, calling); if (!IS_ARGS_KW_OR_KW_SPLAT(ci) && calling->argc > 0 && - RB_TYPE_P(*(cfp->sp - 1), T_HASH) && - (((struct RHash *)*(cfp->sp - 1))->basic.flags & RHASH_PASS_AS_KEYWORDS)) { + RB_TYPE_P((final_hash = *(cfp->sp - 1)), T_HASH) && + (((struct RHash *)final_hash)->basic.flags & RHASH_PASS_AS_KEYWORDS)) { + *(cfp->sp - 1) = rb_hash_dup(final_hash); calling->kw_splat = 1; } } |