#!./perl
+# Test that $lexical = <some op> optimises the assignment away correctly
+# and causes no ill side-effects.
+
BEGIN {
chdir 't' if -d 't';
- @INC = '../lib';
+ require './test.pl';
+ set_up_inc('../lib');
}
-$ENV{PERL_DESTRUCT_LEVEL} = 0 unless $ENV{PERL_DESTRUCT_LEVEL} > 3;
+$| = 1;
umask 0;
$xref = \ "";
-$runme = ($^O eq 'VMS' ? 'MCR ' : '') . $^X;
+$runme = $^X;
@a = (1..5);
%h = (1..6);
$aref = \@a;
@INPUT = <DATA>;
@simple_input = grep /^\s*\w+\s*\$\w+\s*[#\n]/, @INPUT;
-print "1..", (10 + @INPUT + @simple_input), "\n";
-$ord = 0;
sub wrn {"@_"}
# Check correct optimization of ucfirst etc
-$ord++;
my $a = "AB";
my $b = "\u\L$a";
-print "not " unless $b eq 'Ab';
-print "ok $ord\n";
+is( $b, 'Ab', 'Check correct optimization of ucfirst, etc');
# Check correct destruction of objects:
my $dc = 0;
my $b;
{ my $c = 6; $b = bless \$c, "A"}
-$ord++;
-print "not " unless $dc == 0;
-print "ok $ord\n";
+is($dc, 0, 'No destruction yet');
$b = $a+5;
-$ord++;
-print "not " unless $dc == 1;
-print "ok $ord\n";
+is($dc, 1, 'object descruction via reassignment to variable');
-$ord++;
my $xxx = 'b';
$xxx = 'c' . ($xxx || 'e');
-print "not " unless $xxx eq 'cb';
-print "ok $ord\n";
-
-{ # Check calling STORE
- my $sc = 0;
- sub B::TIESCALAR {bless [11], 'B'}
- sub B::FETCH { -(shift->[0]) }
- sub B::STORE { $sc++; my $o = shift; $o->[0] = 17 + shift }
-
- my $m;
- tie $m, 'B';
- $m = 100;
-
- $ord++;
- print "not " unless $sc == 1;
- print "ok $ord\n";
-
- my $t = 11;
- $m = $t + 89;
-
- $ord++;
- print "not " unless $sc == 2;
- print "ok $ord\n";
-
- $ord++;
- print "# $m\nnot " unless $m == -117;
- print "ok $ord\n";
-
- $m += $t;
-
- $ord++;
- print "not " unless $sc == 3;
- print "ok $ord\n";
-
- $ord++;
- print "# $m\nnot " unless $m == 89;
- print "ok $ord\n";
-
-}
+is( $xxx, 'cb', 'variables can be read before being overwritten');
# Chains of assignments
my $zzzz = 12;
$zzz1 = $l1 = $l2 = $zzz2 = $l3 = $l4 = 1 + $zzzz;
-$ord++;
-print "# $zzz1 = $l1 = $l2 = $zzz2 = $l3 = $l4 = 13\nnot "
- unless $zzz1 == 13 and $zzz2 == 13 and $l1 == 13
- and $l2 == 13 and $l3 == 13 and $l4 == 13;
-print "ok $ord\n";
+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) {
- $ord++;
($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)
- ? "skip" : "# '$_'\nnot";
+ $skip = ($op =~ /^'\?\?\?'/ or $comment =~ /skip\(.*\Q$^O\E.*\)/i);
$integer = ($comment =~ /^i_/) ? "use integer" : '' ;
- (print "#skipping $comment:\nok $ord\n"), next if $skip eq 'skip';
+ if ($skip) {
+ SKIP: {
+ skip $comment, 1;
+ }
+ next;
+ }
eval <<EOE;
local \$SIG{__WARN__} = \\&wrn;
$integer;
\$a = $op;
\$b = $expectop;
- if (\$a ne \$b) {
- print "# \$comment: got `\$a', expected `\$b'\n";
- print "\$skip " if \$a ne \$b or \$skip eq 'skip';
- }
- print "ok \$ord\\n";
+ is (\$a, \$b, \$comment);
EOE
if ($@) {
- if ($@ =~ /is unimplemented/) {
- print "# skipping $comment: unimplemented:\nok $ord\n";
- } else {
- warn $@;
- print "# '$_'\nnot ok $ord\n";
+ $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) {
- $ord++;
($op, undef, $comment) = /^([^\#]+)(\#\s+(.*))?/;
$comment = $op unless defined $comment;
chomp;
\$$variable = $operator \$$variable;
\$toself = \$$variable;
\$direct = $operator "Ac# Ca\\nxxx";
- print "# \\\$$variable = $operator \\\$$variable\\nnot "
- unless \$toself eq \$direct;
- print "ok \$ord\\n";
+ is(\$toself, \$direct);
EOE
if ($@) {
- if ($@ =~ /is unimplemented/) {
- print "# skipping $comment: unimplemented:\nok $ord\n";
+ $warning = $@;
+ chomp $warning;
+ if ($@ =~ /(?:is un|not )implemented/) {
+ SKIP: {
+ skip $warning, 1;
+ pass($comment);
+ }
} elsif ($@ =~ /Can't (modify|take log of 0)/) {
- print "# skipping $comment: syntax not good for selfassign:\nok $ord\n";
+ SKIP: {
+ skip $warning . ' ' . $comment . ' syntax not good for selfassign', 1;
+ pass();
+ }
} else {
- warn $@;
- print "# '$_'\nnot ok $ord\n";
+ ##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");
+}
+
+
+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
+'???' # glob (not currently OA_TARGLEX)
<OP> # readline
'faked' # rcatline
(@z = (1 .. 3)) # aassign
-chop $chopit # chop
-(chop (@x=@chopar)) # schop
-chomp $chopit # chomp
-(chop (@x=@chopar)) # schomp
+(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
$n | $n # bit_or
-$n # negate
-$n # i_negate
+-$a=="-fake" # i_negate with string
~$n # complement
atan2 $n,$n # atan2
sin $n # sin
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
fileno STDERR # fileno
umask 0 # umask
select STDOUT # sselect
-select "","","",0 # select
+select undef,undef,undef,0 # select
getc OP # getc
'???' # read
'???' # sysread
'???' # kill
getppid # getppid
getpgrp # getpgrp
-'???' # setpgrp
+setpgrp # setpgrp
getpriority $$, $$ # getpriority
'???' # setpriority
-time # time
+'???' # time
localtime $^T # localtime
gmtime $^T # gmtime
'???' # sleep: can randomly fail