Fix my $x = 3; $x = length(undef);.
authorBen Morrow <ben@morrow.me.uk>
Fri, 20 Aug 2010 17:35:58 +0000 (18:35 +0100)
committerJan Dubois <jand@activestate.com>
Fri, 20 Aug 2010 22:57:11 +0000 (15:57 -0700)
Assignment of length() to a lexical is optimized by passing the
assigned-to variable as TARG, avoiding a pp_padsv and pp_sassign.
9f621b which changed length(undef) to return undef didn't take this into
account, and used SETs (which doesn't set TARG), so the code above left
$x == 3.

pp.c
t/op/length.t

diff --git a/pp.c b/pp.c
index 0da8bba..fcb7ff2 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -3105,8 +3105,10 @@ PP(pp_length)
            = sv_2pv_flags(sv, &len,
                           SV_UNDEF_RETURNS_NULL|SV_CONST_RETURN|SV_GMAGIC);
 
-       if (!p)
-           SETs(&PL_sv_undef);
+       if (!p) {
+           sv_setsv(TARG, &PL_sv_undef);
+           SETTARG;
+       }
        else if (DO_UTF8(sv)) {
            SETi(utf8_length((U8*)p, (U8*)p + len));
        }
@@ -3119,7 +3121,8 @@ PP(pp_length)
        else
            SETi(sv_len(sv));
     } else {
-       SETs(&PL_sv_undef);
+       sv_setsv_nomg(TARG, &PL_sv_undef);
+       SETTARG;
     }
     RETURN;
 }
index c73d4c5..705b9d5 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
     @INC = '../lib';
 }
 
-plan (tests => 30);
+plan (tests => 36);
 
 print "not " unless length("")    == 0;
 print "ok 1\n";
@@ -193,6 +193,21 @@ my $uo = bless [], 'U';
 
 is(length($uo), undef, "Length of overloaded reference");
 
+my $ul = 3;
+is(($ul = length(undef)), undef, 
+                    "Returned length of undef with result in TARG");
+is($ul, undef, "Assigned length of undef with result in TARG");
+
+$ul = 3;
+is(($ul = length($u)), undef,
+                "Returned length of tied undef with result in TARG");
+is($ul, undef, "Assigned length of tied undef with result in TARG");
+
+$ul = 3;
+is(($ul = length($uo)), undef,
+                "Returned length of overloaded undef with result in TARG");
+is($ul, undef, "Assigned length of overloaded undef with result in TARG");
+
 # ok(!defined $uo); Turns you can't test this. FIXME for pp_defined?
 
 is($warnings, 0, "There were no warnings");