make local @tied, %tied, untied
David Mitchell [Tue, 4 May 2010 12:22:13 +0000 (13:22 +0100)]
Fix for RT #7938, #7939: when localising an array or hash, don't make the
new aggregate tied.

The old behaviour of { local @tied; ... } was equivalent to:

    {
my $saved = \@tied;
*tied = [];
tied(@tied) = tied(@$saved)  # if tied() were an lvalue function
...
*tied = $saved;
    }

This patch simply removes the 'tied(@tied) = ...' step

mg.c
t/op/local.t

diff --git a/mg.c b/mg.c
index 4be1b3c..ccb5b82 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -178,6 +178,7 @@ S_is_container_magic(const MAGIC *mg)
     case PERL_MAGIC_arylen_p:
     case PERL_MAGIC_rhash:
     case PERL_MAGIC_symtab:
+    case PERL_MAGIC_tied: /* treat as value, so 'local @tied' isn't tied */
        return 0;
     default:
        return 1;
index db9912a..f664df4 100644 (file)
@@ -5,7 +5,7 @@ BEGIN {
     @INC = qw(. ../lib);
     require './test.pl';
 }
-plan tests => 296;
+plan tests => 306;
 
 my $list_assignment_supported = 1;
 
@@ -325,6 +325,21 @@ ok(!defined $a[0]);
     local @a = @a;
     is("@a", $d);
 }
+# RT #7938: localising an array should make it temporarily untied
+{
+    @a = qw(a b c);
+    local @a = (6,7,8);
+    is("@a", "6 7 8", 'local @a assigned 6,7,8');
+    {
+       my $c = 0;
+       local *TA::STORE = sub { $c++ };
+       $a[0] = 9;
+       is($c, 0, 'STORE not called after array localised');
+    }
+    is("@a", "9 7 8", 'local @a should now be 9 7 8');
+}
+is("@a", "a b c", '@a should now contain original value');
+
 
 # local() should preserve the existenceness of tied array elements
 @a = ('a', 'b', 'c');
@@ -450,6 +465,7 @@ tie %h, 'TH';
 is($h{'a'}, 1);
 is($h{'b'}, 2);
 is($h{'c'}, 3);
+
 # local() should preserve the existenceness of tied hash elements
 ok(! exists $h{'y'});
 ok(! exists $h{'z'});
@@ -460,6 +476,24 @@ TODO: {
     is(join("\n", map { "$_=>$h{$_}" } sort keys %h), $d);
 }
 
+# RT #7939: localising a hash should make it temporarily untied
+{
+    %h = qw(a 1 b 2 c 3);
+    local %h = qw(x 6 y 7 z 8);
+    is(join('', sort keys   %h), "xyz", 'local %h has new keys');
+    is(join('', sort values %h), "678", 'local %h has new values');
+    {
+       my $c = 0;
+       local *TH::STORE = sub { $c++ };
+       $h{x} = 9;
+       is($c, 0, 'STORE not called after hash localised');
+    }
+    is($h{x}, 9, '$h{x} should now be 9');
+}
+is(join('', sort keys   %h), "abc", 'restored %h has original keys');
+is(join('', sort values %h), "123", 'restored %h has original values');
+
+
 %h = (a => 1, b => 2, c => 3, d => 4);
 {
     delete local $h{b};