summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-11-04 10:30:00 +0000
committerDavid Mitchell <davem@iabyn.com>2017-11-04 10:33:51 +0000
commitb3ab0375cbf2dd5732e06233d36e4d80d37cf211 (patch)
treef34e884f2b056e6253f9e64ea5c1a36d4606504a /pp_hot.c
parentb5af74de642f3be437a847539db9e6a9d6d5ed30 (diff)
downloadperl-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.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 2ce77b38ef..d980db837c 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -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);