This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Regenerate known_pod_issues.dat
[perl5.git] / t / op / attrs.t
CommitLineData
9c6390c7 1#!./perl
09bef843
SB
2
3# Regression tests for attributes.pm and the C< : attrs> syntax.
4
5BEGIN {
6 chdir 't' if -d 't';
20822f61 7 @INC = '../lib';
1ce0b88c 8 require './test.pl';
62e452a4 9 skip_all_if_miniperl("miniperl can't load attributes");
09bef843
SB
10}
11
98d0ccc7
RGS
12use warnings;
13
09bef843
SB
14$SIG{__WARN__} = sub { die @_ };
15
42262798
NC
16sub eval_ok ($;$) {
17 eval shift;
18 is( $@, '', @_);
09bef843
SB
19}
20
8e5dadda 21our $anon1; eval_ok '$anon1 = sub : method { $_[0]++ }';
09bef843
SB
22
23eval 'sub e1 ($) : plugh ;';
1ce0b88c 24like $@, qr/^Invalid CODE attributes?: ["']?plugh["']? at/;
09bef843
SB
25
26eval 'sub e2 ($) : plugh(0,0) xyzzy ;';
1ce0b88c 27like $@, qr/^Invalid CODE attributes: ["']?plugh\(0,0\)["']? /;
09bef843
SB
28
29eval 'sub e3 ($) : plugh(0,0 xyzzy ;';
1ce0b88c 30like $@, qr/Unterminated attribute parameter in attribute list at/;
09bef843 31
5f211341 32eval 'sub e4 ($) : plugh + XYZZY ;';
1ce0b88c
RGS
33like $@, qr/Invalid separator character '[+]' in attribute list at/;
34
35eval_ok 'my main $x : = 0;';
36eval_ok 'my $x : = 0;';
37eval_ok 'my $x ;';
38eval_ok 'my ($x) : = 0;';
39eval_ok 'my ($x) ;';
40eval_ok 'my ($x) : ;';
41eval_ok 'my ($x,$y) : = 0;';
42eval_ok 'my ($x,$y) ;';
43eval_ok 'my ($x,$y) : ;';
09bef843
SB
44
45eval 'my ($x,$y) : plugh;';
1ce0b88c 46like $@, qr/^Invalid SCALAR attribute: ["']?plugh["']? at/;
09bef843 47
8e7ae056
RGS
48# bug #16080
49eval '{my $x : plugh}';
50like $@, qr/^Invalid SCALAR attribute: ["']?plugh["']? at/;
51eval '{my ($x,$y) : plugh(})}';
52like $@, qr/^Invalid SCALAR attribute: ["']?plugh\(}\)["']? at/;
53
c9124e92
RGS
54# More syntax tests from the attributes manpage
55eval 'my $x : switch(10,foo(7,3)) : expensive;';
56like $@, qr/^Invalid SCALAR attributes: ["']?switch\(10,foo\(7,3\)\) : expensive["']? at/;
57eval q/my $x : Ugly('\(") :Bad;/;
58like $@, qr/^Invalid SCALAR attributes: ["']?Ugly\('\\\("\) : Bad["']? at/;
59eval 'my $x : _5x5;';
60like $@, qr/^Invalid SCALAR attribute: ["']?_5x5["']? at/;
61eval 'my $x : locked method;';
62like $@, qr/^Invalid SCALAR attributes: ["']?locked : method["']? at/;
63eval 'my $x : switch(10,foo();';
64like $@, qr/^Unterminated attribute parameter in attribute list at/;
65eval q/my $x : Ugly('(');/;
66like $@, qr/^Unterminated attribute parameter in attribute list at/;
67eval 'my $x : 5x5;';
68like $@, qr/error/;
69eval 'my $x : Y2::north;';
70like $@, qr/Invalid separator character ':' in attribute list at/;
71
09bef843
SB
72sub A::MODIFY_SCALAR_ATTRIBUTES { return }
73eval 'my A $x : plugh;';
1ce0b88c 74like $@, qr/^SCALAR package attribute may clash with future reserved word: ["']?plugh["']? at/;
09bef843
SB
75
76eval 'my A $x : plugh plover;';
1ce0b88c 77like $@, qr/^SCALAR package attributes may clash with future reserved words: ["']?plugh["']? /;
09bef843 78
9c6390c7
RGS
79no warnings 'reserved';
80eval 'my A $x : plugh;';
81is $@, '';
82
3f8f4626 83eval 'package Cat; my Cat @socks;';
d5e98372
VP
84like $@, '';
85
86eval 'my Cat %nap;';
87like $@, '';
3f8f4626 88
09bef843
SB
89sub X::MODIFY_CODE_ATTRIBUTES { die "$_[0]" }
90sub X::foo { 1 }
91*Y::bar = \&X::foo;
92*Y::bar = \&X::foo; # second time for -w
0256094b 93eval 'package Z; sub Y::bar : foo';
1ce0b88c 94like $@, qr/^X at /;
09bef843 95
09bef843 96@attrs = eval 'attributes::get $anon1';
8e5dadda 97is "@attrs", "method";
09bef843
SB
98
99sub Z::DESTROY { }
100sub Z::FETCH_CODE_ATTRIBUTES { return 'Z' }
8e5dadda 101my $thunk = eval 'bless +sub : method { 1 }, "Z"';
1ce0b88c 102is ref($thunk), "Z";
09bef843
SB
103
104@attrs = eval 'attributes::get $thunk';
8e5dadda 105is "@attrs", "method Z";
09bef843 106
61dbb99a
SF
107# Test attributes on predeclared subroutines:
108eval 'package A; sub PS : lvalue';
109@attrs = eval 'attributes::get \&A::PS';
110is "@attrs", "lvalue";
111
eac910c8
GG
112# Test attributes on predeclared subroutines, after definition
113eval 'package A; sub PS : lvalue; sub PS { }';
114@attrs = eval 'attributes::get \&A::PS';
115is "@attrs", "lvalue";
116
d3cea301 117# Test ability to modify existing sub's (or XSUB's) attributes.
885ef6f5 118eval 'package A; sub X { $_[0] } sub X : method';
d3cea301 119@attrs = eval 'attributes::get \&A::X';
885ef6f5 120is "@attrs", "method";
d3cea301 121
020f0e03
SB
122# Above not with just 'pure' built-in attributes.
123sub Z::MODIFY_CODE_ATTRIBUTES { (); }
885ef6f5 124eval 'package Z; sub L { $_[0] } sub L : Z method';
020f0e03 125@attrs = eval 'attributes::get \&Z::L';
885ef6f5 126is "@attrs", "method Z";
020f0e03 127
95f0a2f1
SB
128# Begin testing attributes that tie
129
130{
131 package Ttie;
132 sub DESTROY {}
133 sub TIESCALAR { my $x = $_[1]; bless \$x, $_[0]; }
134 sub FETCH { ${$_[0]} }
135 sub STORE {
1ce0b88c 136 ::pass;
95f0a2f1
SB
137 ${$_[0]} = $_[1]*2;
138 }
139 package Tloop;
140 sub MODIFY_SCALAR_ATTRIBUTES { tie ${$_[1]}, 'Ttie', -1; (); }
141}
142
1ce0b88c 143eval_ok '
95f0a2f1
SB
144 package Tloop;
145 for my $i (0..2) {
146 my $x : TieLoop = $i;
1ce0b88c 147 $x != $i*2 and ::is $x, $i*2;
95f0a2f1
SB
148 }
149';
09bef843 150
1ce0b88c
RGS
151# bug #15898
152eval 'our ${""} : foo = 1';
fab01b8e 153like $@, qr/Can't declare scalar dereference in "our"/;
1ce0b88c 154eval 'my $$foo : bar = 1';
fab01b8e 155like $@, qr/Can't declare scalar dereference in "my"/;
42262798
NC
156
157
c32124fe 158my @code = qw(lvalue method);
f1a3ce43
NC
159my @other = qw(shared);
160my @deprecated = qw(locked unique);
42262798
NC
161my %valid;
162$valid{CODE} = {map {$_ => 1} @code};
163$valid{SCALAR} = {map {$_ => 1} @other};
164$valid{ARRAY} = $valid{HASH} = $valid{SCALAR};
c32124fe
NC
165my %deprecated;
166$deprecated{CODE} = { locked => 1 };
f1a3ce43 167$deprecated{ARRAY} = $deprecated{HASH} = $deprecated{SCALAR} = { unique => 1 };
42262798 168
adb2fcba 169our ($scalar, @array, %hash);
42262798
NC
170foreach my $value (\&foo, \$scalar, \@array, \%hash) {
171 my $type = ref $value;
172 foreach my $negate ('', '-') {
c32124fe 173 foreach my $attr (@code, @other, @deprecated) {
42262798
NC
174 my $attribute = $negate . $attr;
175 eval "use attributes __PACKAGE__, \$value, '$attribute'";
c32124fe
NC
176 if ($deprecated{$type}{$attr}) {
177 like $@, qr/^Attribute "$attr" is deprecated at \(eval \d+\)/,
178 "$type attribute $attribute deprecated";
179 } elsif ($valid{$type}{$attr}) {
42262798
NC
180 if ($attribute eq '-shared') {
181 like $@, qr/^A variable may not be unshared/;
182 } else {
183 is( $@, '', "$type attribute $attribute");
184 }
185 } else {
186 like $@, qr/^Invalid $type attribute: $attribute/,
187 "Bogus $type attribute $attribute should fail";
188 }
189 }
190 }
191}
6e592b3a
BM
192
193# this will segfault if it fails
194sub PVBM () { 'foo' }
195{ my $dummy = index 'foo', PVBM }
196
197ok !defined(attributes::get(\PVBM)),
198 'PVBMs don\'t segfault attributes::get';
09330df8 199
8314a0a6 200{
93f09d7b 201 # [perl #49472] Attributes + Unknown Error
8314a0a6
NC
202 eval '
203 use strict;
204 sub MODIFY_CODE_ATTRIBUTE{}
205 sub f:Blah {$nosuchvar};
206 ';
207
208 my $err = $@;
209 like ($err, qr/Global symbol "\$nosuchvar" requires /, 'perl #49472');
210}
211
09330df8
Z
212# Test that code attributes always get applied to the same CV that
213# we're left with at the end (bug#66970).
214{
215 package bug66970;
216 our $c;
217 sub MODIFY_CODE_ATTRIBUTES { $c = $_[1]; () }
218 $c=undef; eval 'sub t0 :Foo';
219 main::ok $c == \&{"t0"};
220 $c=undef; eval 'sub t1 :Foo { }';
221 main::ok $c == \&{"t1"};
222 $c=undef; eval 'sub t2';
223 our $t2a = \&{"t2"};
224 $c=undef; eval 'sub t2 :Foo';
225 main::ok $c == \&{"t2"} && $c == $t2a;
226 $c=undef; eval 'sub t3';
227 our $t3a = \&{"t3"};
228 $c=undef; eval 'sub t3 :Foo { }';
229 main::ok $c == \&{"t3"} && $c == $t3a;
230 $c=undef; eval 'sub t4 :Foo';
231 our $t4a = \&{"t4"};
232 our $t4b = $c;
233 $c=undef; eval 'sub t4 :Foo';
234 main::ok $c == \&{"t4"} && $c == $t4b && $c == $t4a;
235 $c=undef; eval 'sub t5 :Foo';
236 our $t5a = \&{"t5"};
237 our $t5b = $c;
238 $c=undef; eval 'sub t5 :Foo { }';
239 main::ok $c == \&{"t5"} && $c == $t5b && $c == $t5a;
240}
2dc78664
NC
241
242my @tests = grep {/^[^#]/} split /\n/, <<'EOT';
243# This one is fine as an empty attribute list
244my $holy_Einstein : = '';
245# This one is deprecated
246my $krunch := 4;
247our $FWISK_FWISK_FWIZZACH_FWACH_ZACHITTY_ZICH_SHAZZATZ_FWISK := '';
248state $thump := 'Trumpets';
249# Lather rinse repeat in my usual obsessive style
250my @holy_perfect_pitch : = ();
251my @zok := ();
252our @GUKGUK := ();
253# state @widget_mark := ();
254my %holy_seditives : = ();
255my %bang := ();
256our %GIGAZING := ();
257# state %hex := ();
258my $holy_giveaways : = '';
259my $eee_yow := [];
260our $TWOYYOYYOING_THUK_UGH := 1 == 1;
261state $octothorn := 'Tinky Winky';
262my @holy_Taj_Mahal : = ();
263my @touche := ();
264our @PLAK_DAK_THUK_FRIT := ();
265# state @hash_mark := ();
266my %holy_priceless_collection_of_Etruscan_snoods : = ();
267my %wham_eth := ();
268our %THWUK := ();
269# state %octalthorpe := ();
270my $holy_sewer_pipe : = '';
271my $thunk := undef;
272our $BLIT := time;
273state $crunch := 'Laa Laa';
274my @glurpp := ();
275my @holy_harem : = ();
276our @FABADAP := ();
277# state @square := ();
278my %holy_pin_cushions : = ();
279my %swoosh := ();
280our %RRRRR := ();
281# state %scratchmark := ();
282EOT
283
284foreach my $test (@tests) {
285 use feature 'state';
286 eval $test;
287 if ($test =~ /:=/) {
288 like $@, qr/Use of := for an empty attribute list is not allowed/,
289 "Parse error for q{$test}";
290 } else {
291 is $@, '', "No error for q{$test}";
292 }
293}
294
541ed3a9
FC
295# [perl #68560] Calling closure prototypes (only accessible via :attr)
296{
297 package brength;
298 my $proto;
299 sub MODIFY_CODE_ATTRIBUTES { $proto = $_[1]; _: }
ba781e0d 300 eval q{
541ed3a9
FC
301 my $x;
302 () = sub :a0 { $x };
ba781e0d 303 };
541ed3a9
FC
304 package main;
305 eval { $proto->() }; # used to crash in pp_entersub
306 like $@, qr/^Closure prototype called/,
307 "Calling closure proto with (no) args";
308 eval { () = &$proto }; # used to crash in pp_leavesub
309 like $@, qr/^Closure prototype called/,
17e8b60c 310 'Calling closure proto with no @_ that returns a lexical';
541ed3a9
FC
311}
312
a1fba7eb
FC
313# [perl #68658] Attributes on stately variables
314{
315 package thwext;
316 sub MODIFY_SCALAR_ATTRIBUTES { () }
317 my $i = 0;
318 my $x_values = '';
319 eval 'sub foo { use 5.01; state $x :A0 = $i++; $x_values .= $x }';
320 foo(); foo();
321 package main;
322 is $x_values, '00', 'state with attributes';
323}
324
2dc78664 325done_testing();