summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>2022-01-28 17:42:21 +0000
committerPaul Evans <leonerd@leonerd.org.uk>2022-01-31 10:03:58 +0000
commit40151a41a82470d0f49267cb2a406f38563a6a63 (patch)
treee1dc8081e535816240efda81e098d84396a3e165 /t
parent1c547c3e2c4bfadbdc54bc385291cf79d91b5f0e (diff)
downloadperl-40151a41a82470d0f49267cb2a406f38563a6a63.tar.gz
Emit experimental::snail_in_signatures warnings on uses of @_ (aka "snail") in signatured subs
Diffstat (limited to 't')
-rw-r--r--t/op/signatures.t93
1 files changed, 91 insertions, 2 deletions
diff --git a/t/op/signatures.t b/t/op/signatures.t
index d22d11b517..e70215afca 100644
--- a/t/op/signatures.t
+++ b/t/op/signatures.t
@@ -434,7 +434,10 @@ like $@, _create_flexible_mismatch_regexp('main::t128', 3, 2);
is $a, 123;
sub t130 { join(",", @_).";".scalar(@_) }
-sub t131 ($a = 222, $b = goto &t130) { "$a/$b" }
+{
+ no warnings 'experimental::args_array_with_signatures';
+ sub t131 ($a = 222, $b = goto &t130) { "$a/$b" }
+}
is prototype(\&t131), undef;
is eval("t131()"), ";0";
is eval("t131(0)"), "0;1";
@@ -1380,13 +1383,15 @@ is scalar(t145()), undef;
}
is ref(t149()), "ARRAY", "t149: closure can make new lexical a ref";
+ # Quiet the 'use of @_ is experimental' warnings
+ no warnings 'experimental::args_array_with_signatures';
+
sub t150 ($a = do {@_ = qw(a b c); 1}, $b = 2) {
is $a, 1, "t150: a: growing \@_";
is $b, "b", "t150: b: growing \@_";
}
t150();
-
sub t151 ($a = do {tie @_, 'Tie::StdArray'; @_ = qw(a b c); 1}, $b = 2) {
is $a, 1, "t151: a: tied \@_";
is $b, "b", "t151: b: tied \@_";
@@ -1608,6 +1613,90 @@ while(<$kh>) {
'f($1)';
}
+# check that various uses of @_ inside signatured subs causes "experimental"
+# warnings at compiletime
+{
+ sub warnings_from {
+ my ($code, $run) = @_;
+ my $warnings = "";
+ local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
+ my $cv = eval qq{ sub(\$x) { $code }} or die "Cannot eval() - $@";
+ $run and $cv->(123);
+ return $warnings;
+ }
+
+ sub snailwarns_ok {
+ my ($opname, $code) = @_;
+ my $warnings = warnings_from $code;
+ ok($warnings =~ m/[Uu]se of \@_ in $opname with signatured subroutine is experimental at \(eval /,
+ "`$code` warns of experimental \@_") or
+ diag("Warnings were:\n$warnings");
+ }
+
+ sub snailwarns_runtime_ok {
+ my ($opname, $code) = @_;
+ my $warnings = warnings_from $code, 1;
+ ok($warnings =~ m/[Uu]se of \@_ in $opname with signatured subroutine is experimental at \(eval /,
+ "`$code` warns of experimental \@_") or
+ diag("Warnings were:\n$warnings");
+ }
+
+ sub not_snailwarns_ok {
+ my ($code) = @_;
+ my $warnings = warnings_from $code;
+ ok($warnings !~ m/[Uu]se of \@_ in .* with signatured subroutine is experimental at \(eval /,
+ "`$code` warns of experimental \@_") or
+ diag("Warnings were:\n$warnings");
+ }
+
+ # implicit @_
+ snailwarns_ok 'shift', 'shift';
+ snailwarns_ok 'pop', 'pop';
+ snailwarns_ok 'goto', 'goto &SUB'; # tail-call
+ snailwarns_ok 'subroutine entry', '&SUB'; # perl4-style
+
+ # explicit @_
+ snailwarns_ok 'shift', 'shift @_';
+ snailwarns_ok 'pop', 'pop @_';
+ snailwarns_ok 'array element', '$_[0]';
+ snailwarns_ok 'array element', 'my $one = 1; $_[$one]';
+ snailwarns_ok 'push', 'push @_, 1';
+ snailwarns_ok 'unshift', 'unshift @_, 9';
+ snailwarns_ok 'splice', 'splice @_, 1, 2, 3';
+ snailwarns_ok 'keys on array', 'keys @_';
+ snailwarns_ok 'values on array', 'values @_';
+ snailwarns_ok 'each on array', 'each @_';
+ snailwarns_ok 'print', 'print "a", @_, "z"';
+ snailwarns_ok 'subroutine entry', 'func("a", @_, "z")';
+
+ # Also warns about @_ inside the signature params
+ like(warnings_from('sub ($x = shift) { }'),
+ qr/^Implicit use of \@_ in shift with signatured subroutine is experimental at \(eval /,
+ 'Warns of experimental @_ in param default');
+ like(warnings_from('sub ($x = $_[0]) { }'),
+ qr/^Use of \@_ in array element with signatured subroutine is experimental at \(eval /,
+ 'Warns of experimental @_ in param default');
+
+ # Inside eval() still counts, at runtime
+ snailwarns_runtime_ok 'array element', 'eval q( $_[0] )';
+
+ # still permitted without warning
+ not_snailwarns_ok 'my $f = sub { my $y = shift; }';
+ not_snailwarns_ok 'my $f = sub { my $y = $_[0]; }';
+ not_snailwarns_ok '\&SUB';
+}
+
+# Warnings can be disabled
+{
+ my $warnings = "";
+ local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
+ eval q{
+ no warnings 'experimental::snail_in_signatures';
+ sub($x) { @_ = (1,2,3) }
+ };
+ is($warnings, "", 'No warnings emitted within scope of no warnings "experimental"');
+}
+
done_testing;
1;