diff options
-rw-r--r-- | op.c | 50 | ||||
-rw-r--r-- | pod/perldiag.pod | 7 | ||||
-rw-r--r-- | t/op/state.t | 38 |
3 files changed, 83 insertions, 12 deletions
@@ -3968,6 +3968,8 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right) } if (is_list_assignment(left)) { + static const char no_list_state[] = "Initialization of state variables" + " in list context currently forbidden"; OP *curop; PL_modcount = 0; @@ -4061,6 +4063,54 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right) o->op_private |= OPpASSIGN_COMMON; } + if ((left->op_type == OP_LIST + || (left->op_type == OP_NULL && left->op_targ == OP_LIST))) { + OP* lop = ((LISTOP*)left)->op_first; + while (lop) { + if (lop->op_type == OP_PADSV || + lop->op_type == OP_PADAV || + lop->op_type == OP_PADHV || + lop->op_type == OP_PADANY) { + if (lop->op_private & OPpPAD_STATE) { + if (left->op_private & OPpLVAL_INTRO) { + /* Each variable in state($a, $b, $c) = ... */ + } + else { + /* Each state variable in + (state $a, my $b, our $c, $d, undef) = ... */ + } + yyerror(no_list_state); + } else { + /* Each my variable in + (state $a, my $b, our $c, $d, undef) = ... */ + } + } else { + /* Other ops in the list. undef may be interesting in + (state $a, undef, state $c) */ + } + lop = lop->op_sibling; + } + } + else if (((left->op_private & (OPpLVAL_INTRO | OPpPAD_STATE)) + == (OPpLVAL_INTRO | OPpPAD_STATE)) + && ( left->op_type == OP_PADSV + || left->op_type == OP_PADAV + || left->op_type == OP_PADHV + || left->op_type == OP_PADANY)) + { + /* All single variable list context state assignments, hence + state ($a) = ... + (state $a) = ... + state @a = ... + state (@a) = ... + (state @a) = ... + state %a = ... + state (%a) = ... + (state %a) = ... + */ + yyerror(no_list_state); + } + if (right && right->op_type == OP_SPLIT && !PL_madskills) { OP* tmpop = ((LISTOP*)right)->op_first; if (tmpop && (tmpop->op_type == OP_PUSHRE)) { diff --git a/pod/perldiag.pod b/pod/perldiag.pod index cd741abf7e..9123a01267 100644 --- a/pod/perldiag.pod +++ b/pod/perldiag.pod @@ -1999,6 +1999,13 @@ either consume text or fail. The <-- HERE shows in the regular expression about where the problem was discovered. +=item Initialization of state variables in list context currently forbidden + +(F) Currently the implementation of "state" only permits the initialization +of scalar variables in scalar context. Re-write C<state ($a) = 42> as +C<state $a = 42> to change from list to scalar context. Constructions such +as C<state (@a) = foo()> will be supported in a future perl release. + =item Insecure dependency in %s (F) You tried to do something that the tainting mechanism didn't like. diff --git a/t/op/state.t b/t/op/state.t index 7be16667d3..6d835c466d 100644 --- a/t/op/state.t +++ b/t/op/state.t @@ -10,7 +10,7 @@ BEGIN { use strict; use feature ":5.10"; -plan tests => 108; +plan tests => 117; ok( ! defined state $uninit, q(state vars are undef by default) ); @@ -301,17 +301,6 @@ foreach my $x (0 .. 4) { # -# List context reassigns, but scalar doesn't. -# -my @swords = qw [Stormbringer Szczerbiec Grimtooth Corrougue]; -foreach my $sword (@swords) { - state ($s1) = state $s2 = $sword; - is $s1, $swords [0], 'mixed context'; - is $s2, $swords [0], 'mixed context'; -} - - -# # Use with given. # my @spam = qw [spam ham bacon beans]; @@ -331,3 +320,28 @@ foreach my $spam (@spam) { state $x = "two"; is $x, "two", "masked" } + +foreach my $forbidden (<DATA>) { + chomp $forbidden; + no strict 'vars'; + eval $forbidden; + like $@, qr/Initialization of state variables in list context currently forbidden/, "Currently forbidden: $forbidden"; +} +__DATA__ +state ($a) = 1; +(state $a) = 1; +state @a = 1; +state (@a) = 1; +(state @a) = 1; +state %a = (); +state (%a) = (); +(state %a) = (); +state ($a, $b) = (); +state ($a, @b) = (); +(state $a, state $b) = (); +(state $a, $b) = (); +(state $a, my $b) = (); +(state $a, state @b) = (); +(state $a, local @b) = (); +(state $a, undef, state $b) = (); +state ($a, undef, $b) = (); |