The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#!./perl
# Test that $lexical = <some op> optimises the assignment away correctly
# and causes no ill side-effects.
BEGIN {
chdir 't' if -d 't';
require './test.pl';
set_up_inc('../lib');
}
$| = 1;
umask 0;
$xref = \ "";
$runme = $^X;
@a = (1..5);
%h = (1..6);
$aref = \@a;
$href = \%h;
open OP, qq{$runme -le "print 'aaa Ok ok' for 1..100"|};
$chopit = 'aaaaaa';
@chopar = (113 .. 119);
$posstr = '123456';
$cstr = 'aBcD.eF';
pos $posstr = 3;
$nn = $n = 2;
sub subb {"in s"}
@INPUT = <DATA>;
@simple_input = grep /^\s*\w+\s*\$\w+\s*[#\n]/, @INPUT;
sub wrn {"@_"}
# Check correct optimization of ucfirst etc
my $a = "AB";
my $b = "\u\L$a";
is( $b, 'Ab', 'Check correct optimization of ucfirst, etc');
# Check correct destruction of objects:
my $dc = 0;
sub A::DESTROY {$dc += 1}
$a=8;
my $b;
{ my $c = 6; $b = bless \$c, "A"}
is($dc, 0, 'No destruction yet');
$b = $a+5;
is($dc, 1, 'object destruction via reassignment to variable');
my $xxx = 'b';
$xxx = 'c' . ($xxx || 'e');
is( $xxx, 'cb', 'variables can be read before being overwritten');
# Chains of assignments
my ($l1, $l2, $l3, $l4);
my $zzzz = 12;
$zzz1 = $l1 = $l2 = $zzz2 = $l3 = $l4 = 1 + $zzzz;
is($zzz1, 13, 'chain assignment, part1');
is($zzz2, 13, 'chain assignment, part2');
is($l1, 13, 'chain assignment, part3');
is($l2, 13, 'chain assignment, part4');
is($l3, 13, 'chain assignment, part5');
is($l4, 13, 'chain assignment, part6');
for (@INPUT) {
($op, undef, $comment) = /^([^\#]+)(\#\s+(.*))?/;
$comment = $op unless defined $comment;
chomp;
$op = "$op==$op" unless $op =~ /==/;
($op, $expectop) = $op =~ /(.*)==(.*)/;
$skip = ($op =~ /^'\?\?\?'/ or $comment =~ /skip\(.*\Q$^O\E.*\)/i);
$integer = ($comment =~ /^i_/) ? "use integer" : '' ;
if ($skip) {
SKIP: {
skip $comment, 1;
}
next;
}
eval <<EOE;
local \$SIG{__WARN__} = \\&wrn;
my \$a = 'fake';
$integer;
\$a = $op;
\$b = $expectop;
is (\$a, \$b, \$comment);
EOE
if ($@) {
$warning = $@;
chomp $warning;
if ($@ !~ /(?:is un|not )implemented/) {
fail($_ . ' ' . $warning);
}
}
}
{ # Check calling STORE
note('Tied variables, calling STORE');
my $sc = 0;
# do not use B:: namespace
sub BB::TIESCALAR {bless [11], 'BB'}
sub BB::FETCH { -(shift->[0]) }
sub BB::STORE { $sc++; my $o = shift; $o->[0] = 17 + shift }
my $m;
tie $m, 'BB';
$m = 100;
is( $sc, 1, 'STORE called when assigning scalar to tied variable' );
my $t = 11;
$m = $t + 89;
is( $sc, 2, 'and again' );
is( $m, -117, 'checking the tied variable result' );
$m += $t;
is( $sc, 3, 'called on self-increment' );
is( $m, 89, 'checking the tied variable result' );
for (@INPUT) {
($op, undef, $comment) = /^([^\#]+)(\#\s+(.*))?/;
$comment = $op unless defined $comment;
next if ($op =~ /^'\?\?\?'/ or $comment =~ /skip\(.*\Q$^O\E.*\)/i);
$op =~ s/==.*//;
$sc = 0;
local $SIG{__WARN__} = \&wrn;
eval "\$m = $op";
is $sc, $@ ? 0 : 1, "STORE count for $comment";
}
}
for (@simple_input) {
($op, undef, $comment) = /^([^\#]+)(\#\s+(.*))?/;
$comment = $op unless defined $comment;
chomp;
($operator, $variable) = /^\s*(\w+)\s*\$(\w+)/ or warn "misprocessed '$_'\n";
eval <<EOE;
local \$SIG{__WARN__} = \\&wrn;
my \$$variable = "Ac# Ca\\nxxx";
\$$variable = $operator \$$variable;
\$toself = \$$variable;
\$direct = $operator "Ac# Ca\\nxxx";
is(\$toself, \$direct);
EOE
if ($@) {
$warning = $@;
chomp $warning;
if ($@ =~ /(?:is un|not )implemented/) {
SKIP: {
skip $warning, 1;
pass($comment);
}
} elsif ($@ =~ /Can't (modify|take log of 0)/) {
SKIP: {
skip $warning . ' ' . $comment . ' syntax not good for selfassign', 1;
pass();
}
} else {
##Something bad happened
fail($_ . ' ' . $warning);
}
}
}
# [perl #123790] Assigning to a typeglob
# These used to die or crash.
# Once the bug is fixed for all ops, we can combine this with the tests
# above that use <DATA>.
for my $glob (*__) {
$glob = $y x $z;
{ use integer; $glob = $y <=> $z; }
$glob = $y cmp $z;
$glob = vec 1, 2, 4;
$glob = ~${\""};
$glob = split;
}
# XXX This test does not really belong here, as it has nothing to do with
# OPpTARGET_MY optimisation. But where should it go?
eval {
sub PVBM () { 'foo' }
index 'foo', PVBM;
my $x = PVBM;
my $str = 'foo';
my $pvlv = \substr $str, 0, 1;
$x = $pvlv;
1;
};
is($@, '', 'ex-PVBM assert'.$@);
# RT perl #127855
# Check that stringification and assignment to itself doesn't break
# anything. This is unlikely to actually fail the tests; its more something
# for valgrind to spot. It will also only fail if SvGROW or its caller
# decides to over-allocate (otherwise copying the string will skip the
# sv_grow(), as the new size is the same as the current size).
{
my $s;
for my $len (1..40) {
$s = 'x' x $len;
my $t = $s;
$t = "$t";
ok($s eq $t, "RT 127855: len=$len");
}
}
# time() can't be tested using the standard framework since two successive
# calls may return differing values.
{
my $a;
$a = time;
$b = time;
my $diff = $b - $a;
cmp_ok($diff, '>=', 0, "time is monotically increasing");
cmp_ok($diff, '<', 2, "time delta is small");
}
# GH #20132 and parts of GH ##20114
# During development of OP_PADSV_STORE, interactions with OP_PADRANGE
# caused BBC failures not picked up by any pre-existing core tests.
# (Problems only arose in list context, the void/scalar tests have been
# included for completeness.)
eval {
my $x = {}; my $y;
keys %{$y = $x};
1;
};
is($@, '', 'keys %{$y = $x}');
eval {
my $x = {}; my $y;
my $foo = keys %{$y = $x};
1;
};
is($@, '', 'my $foo = keys %{$y = $x}');
eval {
my $x = {}; my $y;
my @foo = keys %{$y = $x};
1;
};
is($@, '', 'my @foo = keys %{$y = $x}');
fresh_perl_is('my ($x, $y); (($y = $x))', '', {}, '(($y = $x))');
fresh_perl_is('my ($x, $y); my $z= (($y = $x))', '', {}, 'my $z= (($y = $x))');
fresh_perl_is('my ($x, $y); my @z= (($y = $x))', '', {}, 'my @z= (($y = $x))');
done_testing();
__END__
ref $xref # ref
ref $cstr # ref nonref
`$runme -e "print qq[1\\n]"` # backtick skip(MSWin32)
`$undefed` # backtick undef skip(MSWin32)
'???' # glob (not currently OA_TARGLEX)
<OP> # readline
'faked' # rcatline
(@z = (1 .. 3)) # aassign
(chop (@x=@chopar)) # chop
chop $chopit # schop
(chomp (@x=@chopar)) # chomp
chomp $chopit # schomp
pos $posstr # pos
pos $chopit # pos returns undef
$nn++==2 # postinc
$nn++==3 # i_postinc
$nn--==4 # postdec
$nn--==3 # i_postdec
$n ** $n # pow
$n * $n # multiply
$n * $n # i_multiply
$n / $n # divide
$n / $n # i_divide
$n % $n # modulo
$n % $n # i_modulo
$n x $n # repeat
$n + $n # add
$n + $n # i_add
$n - $n # subtract
$n - $n # i_subtract
$n . $n # concat
$n . $a=='2fake' # concat with self
"3$a"=='3fake' # concat with self in stringify
"$n" # stringify
$n << $n # left_shift
$n >> $n # right_shift
$n <=> $n # ncmp
$n <=> $n # i_ncmp
$n cmp $n # scmp
$n & $n # bit_and
$n ^ $n # bit_xor
$n | $n # bit_or
-$n # negate
-$n # i_negate
-$a=="-fake" # i_negate with string
~$n # complement
atan2 $n,$n # atan2
sin $n # sin
cos $n # cos
'???' # rand
exp $n # exp
log $n # log
sqrt $n # sqrt
int $n # int
hex $n # hex
oct $n # oct
abs $n # abs
length $posstr # length
substr $posstr, 2, 2 # substr
vec("abc",2,8) # vec
index $posstr, 2 # index
rindex $posstr, 2 # rindex
sprintf "%i%i", $n, $n # sprintf
ord $n # ord
chr $n # chr
chr ${\256} # chr $wide
crypt $n, $n # crypt
ucfirst ($cstr . "a") # ucfirst padtmp
ucfirst $cstr # ucfirst
lcfirst $cstr # lcfirst
uc $cstr # uc
lc $cstr # lc
quotemeta $cstr # quotemeta
@$aref # rv2av
@$undefed # rv2av undef
(each %h) % 2 == 1 # each
values %h # values
keys %h # keys
%$href # rv2hv
pack "C2", $n,$n # pack
split /a/, "abad" # split
join "a"; @a # join
push @a,3==6 # push
unshift @aaa # unshift
reverse @a # reverse
reverse $cstr # reverse - scal
grep $_, 1,0,2,0,3 # grepwhile
map "x$_", 1,0,2,0,3 # mapwhile
subb() # entersub
caller # caller
warn "ignore this\n" # warn
'faked' # die
open BLAH, "<non-existent" # open
fileno STDERR # fileno
umask 0 # umask
select STDOUT # sselect
select undef,undef,undef,0 # select
getc OP # getc
'???' # read
'???' # sysread
'???' # syswrite
'???' # send
'???' # recv
'???' # tell
'???' # fcntl
'???' # ioctl
'???' # flock
'???' # accept
'???' # shutdown
'???' # ftsize
'???' # ftmtime
'???' # ftatime
'???' # ftctime
chdir 'non-existent' # chdir
'???' # chown
'???' # chroot
unlink 'non-existent' # unlink
chmod 'non-existent' # chmod
utime 'non-existent' # utime
rename 'non-existent', 'non-existent1' # rename
link 'non-existent', 'non-existent1' # link
'???' # symlink
readlink 'non-existent', 'non-existent1' # readlink
'???' # mkdir
'???' # rmdir
'???' # telldir
'???' # fork
'???' # wait
'???' # waitpid
system "$runme -e 0" # system skip(VMS)
'???' # exec
'???' # kill
getppid # getppid
getpgrp # getpgrp
setpgrp # setpgrp
getpriority $$, $$ # getpriority
'???' # setpriority
'???' # time
localtime $^T # localtime
gmtime $^T # gmtime
'???' # sleep: can randomly fail
'???' # alarm
'???' # shmget
'???' # shmctl
'???' # shmread
'???' # shmwrite
'???' # msgget
'???' # msgctl
'???' # msgsnd
'???' # msgrcv
'???' # semget
'???' # semctl
'???' # semop
'???' # getlogin
'???' # syscall