This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pack c/C on inf/nan.
[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);
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 ++;
83 $core = $bd->coderef2text(eval $hpcode =~ s/my/CORE::/r or die);
84 $my = $bd->coderef2text(eval $hpcode or die);
85 is $my, $core, "precedence of CORE::$word without parens";
46e00a91 86 }
93f0bc49 87
47ac839d
FC
88 next if ($proto =~ /\@/);
89 # These ops currently accept any number of args, despite their
90 # prototypes, if they have any:
919ad5f7
FC
91 next if $word =~ /^(?:chom?p|exec|keys|each|not
92 |(?:prototyp|read(?:lin|pip))e
7d789282 93 |reset|system|values|l?stat)|evalbytes/x;
bf0571fd 94
bccb6c7b 95 $tests ++;
47ac839d
FC
96 $code =
97 "sub { () = (my$word("
98 . (
99 $args_for{$word}
100 ? $args_for{$word}.',$7'
101 : join ",", map "\$$_", 1..$numargs+5+(
102 $proto =~ /;/
103 ? () = $' =~ /\G$protochar/g
104 : 0
105 )
106 )
107 . "))}";
108 eval $code;
1efec5ed
FC
109 my $desc = $desc{$word} || $word;
110 like $@, qr/^Too many arguments for $desc/,
47ac839d
FC
111 "inlined CORE::$word with too many args"
112 or warn $code;
113
bccb6c7b
FC
114 }
115 }
116}
7fa5bd9b 117
5e33e2aa
AC
118sub inlinable_ok {
119 my ($word, $args, $desc_suffix) = @_;
120 $tests += 2;
121
122 $desc_suffix //= '';
123
124 for ([with => "($args)"], [without => " $args"]) {
125 my ($preposition, $full_args) = @$_;
126 my $core_code =
127 "#line 1 This-line-makes-__FILE__-easier-to-test.
128 sub { () = (CORE::$word$full_args) }";
129 my $my_code = $core_code =~ s/CORE::$word/my$word/r;
130 my $core = $bd->coderef2text(eval $core_code or die);
131 my $my = $bd->coderef2text(eval $my_code or die);
132 is $my, $core, "inlinability of CORE::$word $preposition parens $desc_suffix";
133 }
134}
135
309aab3a
FC
136$tests++;
137# This subroutine is outside the warnings scope:
138sub foo { goto &CORE::abs }
139use warnings;
140$SIG{__WARN__} = sub { like shift, qr\^Use of uninitialized\ };
141foo(undef);
142
0f8d4b5e
FC
143$tests+=2;
144is runperl(prog => 'print CORE->lc, qq-\n-'), "core\n",
145 'methods calls autovivify coresubs';
146is runperl(prog => '@ISA=CORE; print main->uc, qq-\n-'), "MAIN\n",
147 'inherted method calls autovivify coresubs';
148
83d52ea4 149{ # RT #117607
83d52ea4
TC
150 $tests++;
151 like runperl(prog => '$foo/; \&CORE::lc', stderr => 1),
152 qr/^syntax error/, "RT #117607: \\&CORE::foo doesn't crash in error context";
153}
154
7e68c38b
FC
155$tests++;
156ok eval { *CORE::exit = \42 },
157 '[rt.cpan.org #74289] *CORE::foo is not accidentally made read-only';
158
66c742d5
AC
159for my $word (qw<keys values each>) {
160 # mykeys() etc were aliased to \&CORE::keys etc above
161 my $code = qq{
162 no warnings 'experimental::autoderef';
163 my \$x = [];
164 () = my$word(\$x);
165 'ok'
166 };
167 $tests++;
168 is(eval($code), 'ok', "inlined $word() on autoderef array") or diag $@;
169}
170
171inlinable_ok($_, '$_{k}', 'on hash')
172 for qw<delete exists>;
173
5811c07e
FC
174@UNIVERSAL::ISA = CORE;
175is "just another "->ucfirst . "perl hacker,\n"->ucfirst,
176 "Just another Perl hacker,\n", 'coresubs do not return TARG';
177++$tests;
178
ab157fa5 179done_testing $tests;
7fa5bd9b 180
47ac839d 181CORE::__END__