1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#!./perl -w
# Uncomment this for testing, but don't leave it in for "production", as
# we've not yet verified that use works.
# use strict;
print "1..29\n";
my $test = 0;
# Historically constant folding was performed by evaluating the ops, and if
# they threw an exception compilation failed. This was seen as buggy, because
# even illegal constants in unreachable code would cause failure. So now
# illegal expressions are reported at runtime, if the expression is reached,
# making constant folding consistent with many other languages, and purely an
# optimisation rather than a behaviour change.
sub failed {
my ($got, $expected, $name) = @_;
print "not ok $test - $name\n";
my @caller = caller(1);
print "# Failed test at $caller[1] line $caller[2]\n";
if (defined $got) {
print "# Got '$got'\n";
} else {
print "# Got undef\n";
}
print "# Expected $expected\n";
return;
}
sub like {
my ($got, $pattern, $name) = @_;
$test = $test + 1;
if (defined $got && $got =~ $pattern) {
print "ok $test - $name\n";
# Principle of least surprise - maintain the expected interface, even
# though we aren't using it here (yet).
return 1;
}
failed($got, $pattern, $name);
}
sub is {
my ($got, $expect, $name) = @_;
$test = $test + 1;
if (defined $got && $got eq $expect) {
print "ok $test - $name\n";
return 1;
}
failed($got, "'$expect'", $name);
}
sub ok {
my ($got, $name) = @_;
$test = $test + 1;
if ($got) {
print "ok $test - $name\n";
return 1;
}
failed($got, "a true value", $name);
}
my $a;
$a = eval '$b = 0/0 if 0; 3';
is ($a, 3, 'constants in conditionals don\'t affect constant folding');
is ($@, '', 'no error');
my $b = 0;
$a = eval 'if ($b) {return sqrt -3} 3';
is ($a, 3, 'variables in conditionals don\'t affect constant folding');
is ($@, '', 'no error');
$a = eval q{
$b = eval q{if ($b) {return log 0} 4};
is ($b, 4, 'inner eval folds constant');
is ($@, '', 'no error');
5;
};
is ($a, 5, 'outer eval folds constant');
is ($@, '', 'no error');
# warn and die hooks should be disabled during constant folding
{
my $c = 0;
local $SIG{__WARN__} = sub { $c++ };
local $SIG{__DIE__} = sub { $c+= 2 };
eval q{
is($c, 0, "premature warn/die: $c");
my $x = "a"+5;
is($c, 1, "missing warn hook");
is($x, 5, "a+5");
$c = 0;
$x = 1/0;
};
like ($@, qr/division/, "eval caught division");
is($c, 2, "missing die hook");
}
# [perl #20444] Constant folding should not change the meaning of match
# operators.
{
local *_;
$_="foo"; my $jing = 1;
ok scalar $jing =~ (1 ? /foo/ : /bar/),
'lone m// is not bound via =~ after ? : folding';
ok scalar $jing =~ (0 || /foo/),
'lone m// is not bound via =~ after || folding';
ok scalar $jing =~ (1 ? s/foo/foo/ : /bar/),
'lone s/// is not bound via =~ after ? : folding';
ok scalar $jing =~ (0 || s/foo/foo/),
'lone s/// is not bound via =~ after || folding';
$jing = 3;
ok scalar $jing =~ (1 ? y/fo// : /bar/),
'lone y/// is not bound via =~ after ? : folding';
ok scalar $jing =~ (0 || y/fo//),
'lone y/// is not bound via =~ after || folding';
}
# [perl #78064] or print
package other { # hide the "ok" sub
BEGIN { $^W = 0 }
print 0 ? not_ok : ok;
print " ", ++$test, " - print followed by const ? BEAR : BEAR\n";
print 1 ? ok : not_ok;
print " ", ++$test, " - print followed by const ? BEAR : BEAR (again)\n";
print 1 && ok;
print " ", ++$test, " - print followed by const && BEAR\n";
print 0 || ok;
print " ", ++$test, " - print followed by const || URSINE\n";
BEGIN { $^W = 1 }
}
# or stat
print "not " unless stat(1 ? INSTALL : 0) eq stat("INSTALL");
print "ok ", ++$test, " - stat(const ? word : ....)\n";
# in case we are in t/
print "not " unless stat(1 ? TEST : 0) eq stat("TEST");
print "ok ", ++$test, " - stat(const ? word : ....)\n";
# or truncate
my $n = "for_fold_dot_t$$";
open F, ">$n" or die "open: $!";
print F "bralh blah blah \n";
close F or die "close $!";
eval "truncate 1 ? $n : 0, 0;";
print "not " unless -z $n;
print "ok ", ++$test, " - truncate(const ? word : ...)\n";
unlink $n;
# Constant folding should not change the mutability of returned values.
for(1+2) {
eval { $_++ };
print "not " unless $_ eq 4;
print "ok ", ++$test,
" - 1+2 returns mutable value, just like \$a+\$b",
"\n";
}
# [perl #119055]
# We hide the implementation detail that qq "foo" is implemented using
# constant folding.
eval { ${\"hello\n"}++ };
print "not " unless $@ =~ "Modification of a read-only value attempted at";
print "ok ", ++$test, " - qq with no vars is a constant\n";
# [perl #119501]
my @values;
for (1,2) { for (\(1+3)) { push @values, $$_; $$_++ } }
is "@values", "4 4",
'\1+3 folding making modification affect future retvals';
|