In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/a1fba7eb664f6fea65549e94672040d8e47c905e?hp=9f0564c6a634ece822d85183eb4065e894294d7f>
- Log ----------------------------------------------------------------- commit a1fba7eb664f6fea65549e94672040d8e47c905e Author: Father Chrysostomos <[email protected]> Date: Wed Dec 8 16:52:08 2010 -0800 [perl #68658] attributes turn "state" into "my" This is for two reasons: ⢠In S_my_kid, the attribute-handling code comes before the code that marks the padop as being a state instead of a my, which it knows to do based on the value of PL_parser->in_my. The attribute-handling code begins by setting PL_parser->in_my to FALSE, preventing the code that follows from doing its job. So now PL_parser->in_my is read at the top of S_my_kid, before the attribute code, with the statehood recorded in a boolean. Then the code that marks the padop as being state checks that boolean instead of in_my. ⢠A lexical variable declaration that has an attribute and is assigned to in the same expression compiles to something similar to: (attributes->import(... \$x ...), my $x) = 3; where the list is actually in scalar context, returning the my $x which is then assigned to (something that cannot be expressed directly in Perl syntax). So Perl_ck_sassign needs to take that list op into account when creating the âonceâ op that actually makes state assignment work. Up till now it was just looking for a padsv on its LHS. This commit makes it check also for a list op whose last item is a padsv. ----------------------------------------------------------------------- Summary of changes: op.c | 11 +++++++++-- t/op/attrs.t | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/op.c b/op.c index 13462d1..09b1bbc 100644 --- a/op.c +++ b/op.c @@ -2143,6 +2143,7 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp) { dVAR; I32 type; + const bool stately = PL_parser && PL_parser->in_my == KEY_state; PERL_ARGS_ASSERT_MY_KID; @@ -2213,7 +2214,7 @@ S_my_kid(pTHX_ OP *o, OP *attrs, OP **imopsp) } o->op_flags |= OPf_MOD; o->op_private |= OPpLVAL_INTRO; - if (PL_parser->in_my == KEY_state) + if (stately) o->op_private |= OPpPAD_STATE; return o; } @@ -7937,7 +7938,13 @@ Perl_ck_sassign(pTHX_ OP *o) } if (kid->op_sibling) { OP *kkid = kid->op_sibling; - if (kkid->op_type == OP_PADSV + /* For state variable assignment, kkid is a list op whose op_last + is a padsv. */ + if ((kkid->op_type == OP_PADSV || + (kkid->op_type == OP_LIST && + (kkid = cLISTOPx(kkid)->op_last)->op_type == OP_PADSV + ) + ) && (kkid->op_private & OPpLVAL_INTRO) && SvPAD_STATE(*av_fetch(PL_comppad_name, kkid->op_targ, FALSE))) { const PADOFFSET target = kkid->op_targ; diff --git a/t/op/attrs.t b/t/op/attrs.t index 36d6bee..a8bcd6f 100644 --- a/t/op/attrs.t +++ b/t/op/attrs.t @@ -313,4 +313,16 @@ foreach my $test (@tests) { 'Calling closure proto with no @_ that returns a lexical'; } +# [perl #68658] Attributes on stately variables +{ + package thwext; + sub MODIFY_SCALAR_ATTRIBUTES { () } + my $i = 0; + my $x_values = ''; + eval 'sub foo { use 5.01; state $x :A0 = $i++; $x_values .= $x }'; + foo(); foo(); + package main; + is $x_values, '00', 'state with attributes'; +} + done_testing(); -- Perl5 Master Repository
