This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Skip over state declarations at run time
[perl5.git] / t / op / coresubs.t
CommitLineData
7fa5bd9b
FC
1#!./perl
2
bfce6a3e
FC
3# This script tests the inlining and prototype of CORE:: subs. Any generic
4# tests that are not specific to &foo-style calls should go in this
5# file, too.
7fa5bd9b
FC
6
7BEGIN {
8 chdir 't' if -d 't';
9 @INC = qw(. ../lib);
1ae3d757 10 require "./test.pl";
47ac839d 11 skip_all_without_dynamic_extension('B');
7fa5bd9b
FC
12 $^P |= 0x100;
13}
7fa5bd9b 14
47ac839d
FC
15use B::Deparse;
16my $bd = new B::Deparse '-p';
7fa5bd9b 17
6c871ae8
FC
18my %unsupported = map +($_=>1), qw (
19 __DATA__ __END__ AUTOLOAD BEGIN UNITCHECK CORE DESTROY END INIT CHECK and
d51f8b19 20 cmp default do dump else elsif eq eval for foreach
498a02d8 21 format ge given goto grep gt if last le local lt m map my ne next
919ad5f7 22 no or our package print printf q qq qr qw qx redo require
46bef06f 23 return s say sort state sub tr unless until use
6c871ae8
FC
24 when while x xor y
25);
47ac839d
FC
26my %args_for = (
27 dbmopen => '%1,$2,$3',
a69823cd
FC
28 (dbmclose => '%1',
29 keys =>
30 values =>
31 each =>)[0,1,2,1,3,1,4,1],
eb31eb35 32 delete => '$1[2]',
d51f8b19 33 exists => '$1[2]',
a69823cd
FC
34 (push => '@1',
35 pop =>
36 shift =>
37 unshift =>
38 splice =>)[0,1,2,1,3,1,4,1,5,1],
46e00a91 39);
1efec5ed
FC
40my %desc = (
41 pos => 'match position',
42);
46e00a91 43
47ac839d
FC
44use File::Spec::Functions;
45my $keywords_file = catfile(updir,'regen','keywords.pl');
46open my $kh, $keywords_file
47 or die "$0 cannot open $keywords_file: $!";
48while(<$kh>) {
49 if (m?__END__?..${\0} and /^[+-]/) {
50 chomp(my $word = $');
6c871ae8 51 if($unsupported{$word}) {
47ac839d 52 $tests ++;
9da346da 53 ok !defined &{"CORE::$word"}, "no CORE::$word";
46e00a91 54 }
47ac839d 55 else {
5e33e2aa 56 $tests += 2;
9da346da
FC
57
58 ok defined &{"CORE::$word"}, "defined &{'CORE::$word'}";
47ac839d
FC
59
60 my $proto = prototype "CORE::$word";
61 *{"my$word"} = \&{"CORE::$word"};
62 is prototype \&{"my$word"}, $proto, "prototype of &CORE::$word";
63
64 CORE::state $protochar = qr/([^\\]|\\(?:[^[]|\[[^]]+\]))/;
65 my $numargs =
d51f8b19 66 $word eq 'delete' || $word eq 'exists' ? 1 :
eb31eb35 67 (() = $proto =~ s/;.*//r =~ /\G$protochar/g);
47ac839d 68
5e33e2aa 69 inlinable_ok($word, $args_for{$word} || join ",", map "\$$_", 1..$numargs);
47ac839d
FC
70
71 # High-precedence tests
72 my $hpcode;
73 if (!$proto && defined $proto) { # nullary
74 $hpcode = "sub { () = my$word + 1 }";
46e00a91 75 }
47ac839d
FC
76 elsif ($proto =~ /^;?$protochar\z/) { # unary
77 $hpcode = "sub { () = my$word "
78 . ($args_for{$word}||'$a') . ' > $b'
79 .'}';
80 }
81 if ($hpcode) {
82 $tests ++;
c4c61c60
FC
83 # __FILE__ won’t fold with warnings on, and then we get
84 # ‘(eval 21)’ vs ‘(eval 22)’.
85 no warnings 'numeric';
47ac839d
FC
86 $core = $bd->coderef2text(eval $hpcode =~ s/my/CORE::/r or die);
87 $my = $bd->coderef2text(eval $hpcode or die);
88 is $my, $core, "precedence of CORE::$word without parens";
46e00a91 89 }
93f0bc49 90
47ac839d
FC
91 next if ($proto =~ /\@/);
92 # These ops currently accept any number of args, despite their
93 # prototypes, if they have any:
919ad5f7
FC
94 next if $word =~ /^(?:chom?p|exec|keys|each|not
95 |(?:prototyp|read(?:lin|pip))e
7d789282 96 |reset|system|values|l?stat)|evalbytes/x;
bf0571fd 97
bccb6c7b 98 $tests ++;
47ac839d
FC
99 $code =
100 "sub { () = (my$word("
101 . (
102 $args_for{$word}
103 ? $args_for{$word}.',$7'
104 : join ",", map "\$$_", 1..$numargs+5+(
105 $proto =~ /;/
106 ? () = $' =~ /\G$protochar/g
107 : 0
108 )
109 )
110 . "))}";
111 eval $code;
1efec5ed
FC
112 my $desc = $desc{$word} || $word;
113 like $@, qr/^Too many arguments for $desc/,
47ac839d
FC
114 "inlined CORE::$word with too many args"
115 or warn $code;
116
bccb6c7b
FC
117 }
118 }
119}
7fa5bd9b 120
5e33e2aa
AC
121sub inlinable_ok {
122 my ($word, $args, $desc_suffix) = @_;
123 $tests += 2;
124
125 $desc_suffix //= '';
126
127 for ([with => "($args)"], [without => " $args"]) {
128 my ($preposition, $full_args) = @$_;
129 my $core_code =
130 "#line 1 This-line-makes-__FILE__-easier-to-test.
131 sub { () = (CORE::$word$full_args) }";
132 my $my_code = $core_code =~ s/CORE::$word/my$word/r;
133 my $core = $bd->coderef2text(eval $core_code or die);
134 my $my = $bd->coderef2text(eval $my_code or die);
135 is $my, $core, "inlinability of CORE::$word $preposition parens $desc_suffix";
136 }
137}
138
309aab3a
FC
139$tests++;
140# This subroutine is outside the warnings scope:
141sub foo { goto &CORE::abs }
142use warnings;
143$SIG{__WARN__} = sub { like shift, qr\^Use of uninitialized\ };
144foo(undef);
145
0f8d4b5e
FC
146$tests+=2;
147is runperl(prog => 'print CORE->lc, qq-\n-'), "core\n",
148 'methods calls autovivify coresubs';
149is runperl(prog => '@ISA=CORE; print main->uc, qq-\n-'), "MAIN\n",
150 'inherted method calls autovivify coresubs';
151
83d52ea4 152{ # RT #117607
83d52ea4
TC
153 $tests++;
154 like runperl(prog => '$foo/; \&CORE::lc', stderr => 1),
155 qr/^syntax error/, "RT #117607: \\&CORE::foo doesn't crash in error context";
156}
157
7e68c38b
FC
158$tests++;
159ok eval { *CORE::exit = \42 },
160 '[rt.cpan.org #74289] *CORE::foo is not accidentally made read-only';
161
66c742d5
AC
162for my $word (qw<keys values each>) {
163 # mykeys() etc were aliased to \&CORE::keys etc above
164 my $code = qq{
165 no warnings 'experimental::autoderef';
166 my \$x = [];
167 () = my$word(\$x);
168 'ok'
169 };
170 $tests++;
171 is(eval($code), 'ok', "inlined $word() on autoderef array") or diag $@;
172}
173
174inlinable_ok($_, '$_{k}', 'on hash')
175 for qw<delete exists>;
176
5811c07e
FC
177@UNIVERSAL::ISA = CORE;
178is "just another "->ucfirst . "perl hacker,\n"->ucfirst,
179 "Just another Perl hacker,\n", 'coresubs do not return TARG';
180++$tests;
181
ab157fa5 182done_testing $tests;
7fa5bd9b 183
47ac839d 184CORE::__END__