This fixes RT #55593.
gv = (GV *) sv;
} else {
#ifdef gv_fetchsv
- gv = gv_fetchsv(sv, GV_ADDMULTI, SVt_PVGV);
+ gv = gv_fetchsv(sv, GV_ADDMULTI, t);
#else
STRLEN len;
const char *name = SvPV_const(sv, len);
- gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, SVt_PVGV);
+ gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t);
#endif
}
will localize C<$Tool::tag> and not C<$Scope::tag>.
+Note that if C<$what> is a string denoting a variable that wasn't declared beforehand, the relevant slot will be vivified as needed and won't be deleted from the glob when the localization ends.
+This situation never arises with C<local> because it only compiles when the localized variable is already declared.
+Although I believe it shouldn't be a problem as glob slots definedness is pretty much an implementation detail, this behaviour may change in the future if proved harmful.
+
=back
=head2 C<localize_elem $what, $key, $value, $context>
If C<$what> is a glob, the slot to fill is determined from which type of reference C<$value> is ; otherwise it's inferred from the sigil.
C<$key> is either an array index or a hash key, depending of which kind of variable you localize.
+Just like for L</localize>, when C<$what> is a string pointing to an undeclared variable, it will be vivified but the variable itself will be empty when the localization ends (although it will still exist in its parent glob).
+
=head2 C<localize_delete $what, $key, $context>
Similiar to L</localize>, but for deleting variables or array/hash elements.
use strict;
use warnings;
-use Test::More tests => 21;
+use Test::More tests => 25;
use Scope::Upper qw/localize_elem UP HERE/;
is_deeply \@a, [ 4 .. 6 ], 'localize_elem "@a", 4, 12 => UP [end]';
}
+{
+ {
+ localize_elem '@nonexistent', 2, 7;
+ is_deeply eval('*nonexistent{ARRAY}'), [ undef, undef, 7 ],
+ 'localize_elem "@nonexistent", 2, 7 => HERE [ok]';
+ }
+ is_deeply eval('*nonexistent{ARRAY}'), [ ],
+ 'localize_elem "@nonexistent", 2, 7 => HERE [end]';
+}
+
# Hashes
our %h;
is_deeply \%h, { a => 1, b => 2 }, 'localize_elem "%h", "a", 5 => UP [end]';
}
+{
+ {
+ localize_elem '%nonexistent', 'a', 13;
+ is_deeply eval('*nonexistent{HASH}'), { a => 13 },
+ 'localize_elem "%nonexistent", "a", 13 => HERE [ok]';
+ }
+ is_deeply eval('*nonexistent{HASH}'), { },
+ 'localize_elem "%nonexistent", "a", 13 => HERE [end]';
+}
use strict;
use warnings;
-use Test::More tests => 36;
+use Test::More tests => 44;
use Scope::Upper qw/localize_delete UP HERE/;
is_deeply \@a, [ 4 .. 6 ], 'localize_delete "@a", 4 (exists) => UP [end]';
}
+{
+ {
+ localize_delete '@nonexistent', 2;
+ is_deeply eval('*nonexistent{ARRAY}'), [ ],
+ 'localize_delete "@nonexistent", anything => HERE [ok]';
+ }
+ is_deeply eval('*nonexistent{ARRAY}'), [ ],
+ 'localize_delete "@nonexistent", anything => HERE [end]';
+}
+
# Hashes
our %h;
is_deeply \%h, { a => 1, b => 2 }, 'localize_delete "%h", "a" => UP [end]';
}
+{
+ {
+ localize_delete '%nonexistent', 'a';
+ is_deeply eval('*nonexistent{HASH}'), { },
+ 'localize_delete "%nonexistent", anything => HERE [ok]';
+ }
+ is_deeply eval('*nonexistent{HASH}'), { },
+ 'localize_delete "%nonexistent", anything => HERE [end]';
+}
+
# Others
our $x = 1;
}
is $x, 1, 'localize_delete "$x", anything => HERE [end]';
+{
+ {
+ localize_delete '$nonexistent', 2;
+ is eval('${*nonexistent{SCALAR}}'), undef,
+ 'localize_delete "$nonexistent", anything => HERE [ok]';
+ }
+ is eval('${*nonexistent{SCALAR}}'), undef,
+ 'localize_delete "$nonexistent", anything => HERE [end]';
+}
+
sub x { 1 };
{
localize_delete '&x', 2 => HERE;
}
is x(), 1, 'localize_delete "&x", anything => HERE [end]';
+{
+ {
+ localize_delete '&nonexistent', 2;
+ is eval('exists &nonexistent'), !1,
+ 'localize_delete "&nonexistent", anything => HERE [ok]';
+ }
+ is eval('exists &nonexistent'), !1,
+ 'localize_delete "&nonexistent", anything => HERE [end]';
+}
+
{
localize_delete *x, sub { } => HERE;
is !exists(&x), 1, 'localize_delete *x, anything => HERE [ok 1]';