diff options
author | David Mitchell <davem@iabyn.com> | 2017-11-04 10:30:00 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2017-11-04 10:33:51 +0000 |
commit | b3ab0375cbf2dd5732e06233d36e4d80d37cf211 (patch) | |
tree | f34e884f2b056e6253f9e64ea5c1a36d4606504a /pp_hot.c | |
parent | b5af74de642f3be437a847539db9e6a9d6d5ed30 (diff) | |
download | perl-b3ab0375cbf2dd5732e06233d36e4d80d37cf211.tar.gz |
pp_multiconcat: don't stringify LHS overload arg
RT #132385
In something like
$a1 . $a2
where $a2 is overloaded, the concat overload method was being called
like
concat($a2, "$a1", 1);
(The 1 indicated that the args are reversed).
This commit changes it so that it's called as
concat($a2, $a1, 1);
i.e. that the original arg is passed in rather than a stringified copy
of it. This is important if for example $a1 is a ref.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 35 |
1 files changed, 35 insertions, 0 deletions
@@ -520,6 +520,41 @@ PP(pp_multiconcat) * FAKE implies an optimised sprintf which doesn't use * concat overloading, only "" overloading. */ + + if ( svpv_end == svpv_buf + 1 + /* no const string segments */ + && aux[PERL_MULTICONCAT_IX_LENGTHS].size == -1 + && aux[PERL_MULTICONCAT_IX_LENGTHS + 1].size == -1 + ) { + /* special case: if the overloaded sv is the + * second arg in the concat chain, stop at the + * first arg rather than this, so that + * + * $arg1 . $arg2 + * + * invokes overloading as + * + * concat($arg2, $arg1, 1) + * + * rather than + * + * concat($arg2, "$arg1", 1) + * + * This means that if for example arg1 is a ref, + * it gets passed as-is to the concat method + * rather than a stringified copy. If it's not the + * first arg, it doesn't matter, as in $arg0 . + * $arg1 . $arg2, where the result of ($arg0 . + * $arg1) will already be a string. + * THis isn't perfect: we'll have already + * done SvPV($arg1) on the previous iteration; + * and are now throwing away that result and + * hoping arg1 hasn;t been affected. + */ + svpv_end--; + SP--; + } + setup_overload: dsv = newSVpvn_flags("", 0, SVs_TEMP); |