summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2015-09-02 12:28:12 +0100
committerDavid Mitchell <davem@iabyn.com>2015-09-02 13:24:07 +0100
commit9ae0115f0b854d654461d3c5bbcaa938516d0f4e (patch)
treef616832001893b6be1fa106e3d1b4bd7be6e8c4d
parentebc643cee5f3ca37421efb5ec01dc07b7be2904e (diff)
downloadperl-9ae0115f0b854d654461d3c5bbcaa938516d0f4e.tar.gz
pp_aassign(): fix ($x,$y) = (undef, $x)
With 808ce5578203, I tweaked the OPpASSIGN_COMMON flagging to mark as safe when the LHS or RHS only contains only one var. This turned out to be flawed for the RHS logic, as position as well as oneness is important: (undef, $x) = ...; # only 1 scalar on LHS: always safe ($x, $y) = (undef, $x); # 2 scalars on RHS: unsafe So this commit makes undef on the RHS count towards the scalar var count.
-rw-r--r--op.c13
-rw-r--r--pp_hot.c1
-rw-r--r--t/op/aassign.t8
-rw-r--r--t/perf/benchmarks5
4 files changed, 25 insertions, 2 deletions
diff --git a/op.c b/op.c
index ff2848a290..a08be2efc0 100644
--- a/op.c
+++ b/op.c
@@ -12314,6 +12314,15 @@ S_aassign_scan(pTHX_ OP* o, bool rhs, bool top, int *scalars_p)
break;
case OP_UNDEF:
+ /* undef counts as a scalar on the RHS:
+ * (undef, $x) = ...; # only 1 scalar on LHS: always safe
+ * ($x, $y) = (undef, $x); # 2 scalars on RHS: unsafe
+ */
+ if (rhs)
+ (*scalars_p)++;
+ flags = AAS_SAFE_SCALAR;
+ break;
+
case OP_PUSHMARK:
case OP_STUB:
/* these are all no-ops; they don't push a potentially common SV
@@ -14247,7 +14256,7 @@ Perl_rpeep(pTHX_ OP *o)
|| !r /* .... = (); */
|| !(l & ~AAS_SAFE_SCALAR) /* (undef, pos()) = ...; */
|| !(r & ~AAS_SAFE_SCALAR) /* ... = (1,2,length,undef); */
- || (lscalars < 2) /* ($x) = ... */
+ || (lscalars < 2) /* ($x, undef) = ... */
) {
NOOP; /* always safe */
}
@@ -14291,7 +14300,7 @@ Perl_rpeep(pTHX_ OP *o)
/* ... = ($x)
* may have to handle aggregate on LHS, but we can't
- * have common scalars*/
+ * have common scalars. */
if (rscalars < 2)
o->op_private &=
~(OPpASSIGN_COMMON_SCALAR|OPpASSIGN_COMMON_RC1);
diff --git a/pp_hot.c b/pp_hot.c
index dd991ae731..bed0a27ce3 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1102,6 +1102,7 @@ S_aassign_copy_common(pTHX_ SV **firstlelem, SV **lastlelem,
#ifdef DEBUGGING
if (fake) {
+ /* op_dump(PL_op); */
Perl_croak(aTHX_
"panic: aassign skipped needed copy of common RH elem %"
UVuf, (UV)(relem - firstrelem));
diff --git a/t/op/aassign.t b/t/op/aassign.t
index 58650b72f3..0fe74c95e6 100644
--- a/t/op/aassign.t
+++ b/t/op/aassign.t
@@ -334,5 +334,13 @@ SKIP: {
}
+{
+ my $x = 1;
+ my $y = 2;
+ ($x,$y) = (undef, $x);
+ is($x, undef, 'single scalar on RHS, but two on LHS: x');
+ is($y, 1, 'single scalar on RHS, but two on LHS: y');
+}
+
done_testing();
diff --git a/t/perf/benchmarks b/t/perf/benchmarks
index 6baa3b29da..7fcc1fd253 100644
--- a/t/perf/benchmarks
+++ b/t/perf/benchmarks
@@ -618,6 +618,11 @@
'expr::aassign::2l_1l' => {
desc => 'single lexical RHS',
setup => 'my $x = 1;',
+ code => '($x,$x) = ($x)',
+ },
+ 'expr::aassign::2l_1ul' => {
+ desc => 'undef and single lexical RHS',
+ setup => 'my $x = 1;',
code => '($x,$x) = (undef, $x)',
},