In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/1e35563a537b4adfc8fe304382ca4593703e1a0e?hp=d68a48384ff2e631bc3a38a3fdb6c2bc75e0ea9f>
- Log ----------------------------------------------------------------- commit 1e35563a537b4adfc8fe304382ca4593703e1a0e Author: Father Chrysostomos <[email protected]> Date: Thu Mar 1 12:32:25 2012 -0800 attributes.pm: Consistent spaces after dots in pod M ext/attributes/attributes.pm commit c217304d4cf1ab81c53d2d565896c7dd34645864 Author: Father Chrysostomos <[email protected]> Date: Thu Mar 1 12:29:26 2012 -0800 attributes.pm: Add caveat about lvalue subs M ext/attributes/attributes.pm commit 345d70e3f599db40c8311185ac403b1a5b35d2a5 Author: Father Chrysostomos <[email protected]> Date: Thu Mar 1 12:24:38 2012 -0800 [perl #107366] Allow attributes to set :lvalue on defined sub This provides enough rope for those who want to hang themselves, and also for those who know how to use the rope without hanging them- selves. :-) Since this is not generally a reliable thing to be doing, a warning is emitted whenever :lvalue is turned on or off on a defined subroutine. But attributes.pm will flip the flag anyway. :lvalue in a sub declar- ation still refuses to modify a defined Perl sub, as before. M ext/attributes/attributes.pm M ext/attributes/attributes.xs M pod/perldiag.pod M t/op/attrs.t ----------------------------------------------------------------------- Summary of changes: ext/attributes/attributes.pm | 32 +++++++++++++++++++++++--------- ext/attributes/attributes.xs | 7 ++++--- pod/perldiag.pod | 22 ++++++++++++++-------- t/op/attrs.t | 22 +++++++++++----------- 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/ext/attributes/attributes.pm b/ext/attributes/attributes.pm index 4d27f4f..1f6dbae 100644 --- a/ext/attributes/attributes.pm +++ b/ext/attributes/attributes.pm @@ -39,8 +39,8 @@ sub _modify_attrs_and_deprecate { warnings::warnif( 'misc', "lvalue attribute " - . (/^-/ ? "cannot be removed" : "ignored") - . " after the subroutine has been defined" + . (/^-/ ? "removed from" : "applied to") + . " already-defined subroutine" ); 0; } : 1 @@ -199,8 +199,9 @@ So you want to know what C<import> actually does? First of all C<import> gets the type of the third parameter ('CODE' in this case). C<attributes.pm> checks if there is a subroutine called C<< MODIFY_<reftype>_ATTRIBUTES >> -in the caller's namespace (here: 'main'). In this case a subroutine C<MODIFY_CODE_ATTRIBUTES> is -required. Then this method is called to check if you have used a "bad attribute". +in the caller's namespace (here: 'main'). In this case a +subroutine C<MODIFY_CODE_ATTRIBUTES> is required. Then this +method is called to check if you have used a "bad attribute". The subroutine call in this example would look like MODIFY_CODE_ATTRIBUTES( 'main', \&foo, 'method' ); @@ -219,17 +220,28 @@ The following are the built-in attributes for subroutines: =item lvalue Indicates that the referenced subroutine is a valid lvalue and can -be assigned to. The subroutine must return a modifiable value such +be assigned to. The subroutine must return a modifiable value such as a scalar variable, as described in L<perlsub>. +This module allows one to set this attribute on a subroutine that is +already defined. For Perl subroutines (XSUBs are fine), it may or may not +do what you want, depending on the code inside the subroutine, with details +subject to change in future Perl versions. You may run into problems with +lvalue context not being propagated properly into the subroutine, or maybe +even assertion failures. For this reason, a warning is emitted if warnings +are enabled. In other words, you should only do this if you really know +what you are doing. You have been warned. + =item method -Indicates that the referenced subroutine is a method. A subroutine so marked +Indicates that the referenced subroutine +is a method. A subroutine so marked will not trigger the "Ambiguous call resolved as CORE::%s" warning. =item locked -The "locked" attribute has no effect in 5.10.0 and later. It was used as part +The "locked" attribute has no effect in +5.10.0 and later. It was used as part of the now-removed "Perl 5.005 threads". =back @@ -479,7 +491,8 @@ not your own. print "foo\n"; } -This example runs. At compile time C<MODIFY_CODE_ATTRIBUTES> is called. In that +This example runs. At compile time +C<MODIFY_CODE_ATTRIBUTES> is called. In that subroutine, we check if any attribute is disallowed and we return a list of these "bad attributes". @@ -501,7 +514,8 @@ As we return an empty list, everything is fine. } This example is aborted at compile time as we use the attribute "Test" which -isn't allowed. C<MODIFY_CODE_ATTRIBUTES> returns a list that contains a single +isn't allowed. C<MODIFY_CODE_ATTRIBUTES> +returns a list that contains a single element ('Test'). =back diff --git a/ext/attributes/attributes.xs b/ext/attributes/attributes.xs index d771889..e92f793 100644 --- a/ext/attributes/attributes.xs +++ b/ext/attributes/attributes.xs @@ -48,14 +48,15 @@ modify_SV_attributes(pTHX_ SV *sv, SV **retlist, SV **attrlist, int numattrs) switch (name[3]) { case 'l': if (memEQ(name, "lvalue", 6)) { - if (!CvISXSUB(MUTABLE_CV(sv)) + bool warn = + !CvISXSUB(MUTABLE_CV(sv)) && CvROOT(MUTABLE_CV(sv)) - && !CvLVALUE(MUTABLE_CV(sv)) != negated) - break; + && !CvLVALUE(MUTABLE_CV(sv)) != negated; if (negated) CvFLAGS(MUTABLE_CV(sv)) &= ~CVf_LVALUE; else CvFLAGS(MUTABLE_CV(sv)) |= CVf_LVALUE; + if (warn) break; continue; } break; diff --git a/pod/perldiag.pod b/pod/perldiag.pod index 1b67ccd..5f6ed83 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -2627,18 +2627,24 @@ You may wish to switch to using L<Math::BigInt> explicitly. by that? lstat() makes sense only on filenames. (Perl did a fstat() instead on the filehandle.) -=item lvalue attribute cannot be removed after the subroutine has been defined +=item lvalue attribute %s already-defined subroutine -(W misc) The lvalue attribute on a Perl subroutine cannot be turned off -once the subroutine is defined. +(W misc) Although L<attributes.pm|attributes> allows this, turning the lvalue +attribute on or off on a Perl subroutine that is already defined +does not always work properly. It may or may not do what you +want, depending on what code is inside the subroutine, with exact +details subject to change between Perl versions. Only do this +if you really know what you are doing. =item lvalue attribute ignored after the subroutine has been defined -(W misc) Making a Perl subroutine an lvalue subroutine after it has been -defined, whether by declaring the subroutine with an lvalue attribute -or by using L<attributes.pm|attributes>, is not possible. To make the subroutine an -lvalue subroutine, add the lvalue attribute to the definition, or put -the declaration before the definition. +(W misc) Using the C<:lvalue> declarative syntax to make a Perl +subroutine an lvalue subroutine after it has been defined is +not permitted. To make the subroutine an lvalue subroutine, +add the lvalue attribute to the definition, or put the C<sub +foo :lvalue;> declaration before the definition. + +See also L<attributes.pm|attributes>. =item Malformed integer in [] in pack diff --git a/t/op/attrs.t b/t/op/attrs.t index f3d1165..79ef361 100644 --- a/t/op/attrs.t +++ b/t/op/attrs.t @@ -341,28 +341,28 @@ foreach my $test (@tests) { sub ent {} sub lent :lvalue {} my $posmsg = - 'lvalue attribute ignored after the subroutine has been defined at ' + 'lvalue attribute applied to already-defined subroutine at ' .'\(eval'; my $negmsg = - 'lvalue attribute cannot be removed after the subroutine has been ' - .'defined at \(eval'; + 'lvalue attribute removed from already-defined subroutine at ' + .'\(eval'; eval 'use attributes __PACKAGE__, \&ent, "lvalue"'; like $w, qr/^$posmsg/, 'lvalue attr warning on def sub'; - is join("",&attributes::get(\&ent)), "",'lvalue attr ignored on def sub'; + is join("",&attributes::get(\&ent)), "lvalue",':lvalue applied anyway'; $w = ''; eval 'use attributes __PACKAGE__, \&lent, "lvalue"; 1' or die; is $w, "", 'no lvalue warning on def lvalue sub'; eval 'use attributes __PACKAGE__, \&lent, "-lvalue"'; - like $w, qr/^$negmsg/, 'lvalue attr warning on def sub'; - is join("",&attributes::get(\&lent)), "lvalue", - '-lvalue ignored on def sub'; + like $w, qr/^$negmsg/, '-lvalue attr warning on def sub'; + is join("",&attributes::get(\&lent)), "", + 'lvalue attribute removed anyway'; $w = ''; - eval 'use attributes __PACKAGE__, \&ent, "-lvalue"; 1' or die; - is $w, "", 'no lvalue warning on def lvalue sub'; + eval 'use attributes __PACKAGE__, \&lent, "-lvalue"; 1' or die; + is $w, "", 'no -lvalue warning on def non-lvalue sub'; no warnings 'misc'; - eval 'use attributes __PACKAGE__, \&ent, "lvalue"'; + eval 'use attributes __PACKAGE__, \&lent, "lvalue"'; is $w, "", 'no lvalue warnings under no warnings misc'; - eval 'use attributes __PACKAGE__, \&lent, "-lvalue"'; + eval 'use attributes __PACKAGE__, \&ent, "-lvalue"'; is $w, "", 'no -lvalue warnings under no warnings misc'; } -- Perl5 Master Repository
