state variables shouldn't be shared between anon subs
[p5sagit/p5-mst-13.2.git] / op.c
diff --git a/op.c b/op.c
index 4cbb5e6..1ebc84c 100644 (file)
--- a/op.c
+++ b/op.c
@@ -363,10 +363,12 @@ Perl_allocmy(pTHX_ const char *const name)
     {
        /* name[2] is true if strlen(name) > 2  */
        if (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1])) {
-           yyerror(Perl_form(aTHX_ "Can't use global %c^%c%s in \"my\"",
-                             name[0], toCTRL(name[1]), name + 2));
+           yyerror(Perl_form(aTHX_ "Can't use global %c^%c%s in \"%s\"",
+                             name[0], toCTRL(name[1]), name + 2,
+                             PL_parser->in_my == KEY_state ? "state" : "my"));
        } else {
-           yyerror(Perl_form(aTHX_ "Can't use global %s in \"my\"",name));
+           yyerror(Perl_form(aTHX_ "Can't use global %s in \"%s\"",name,
+                             PL_parser->in_my == KEY_state ? "state" : "my"));
        }
     }
 
@@ -393,6 +395,12 @@ Perl_allocmy(pTHX_ const char *const name)
                    0, /*  not fake */
                    PL_parser->in_my == KEY_state
     );
+    /* anon sub prototypes contains state vars should always be cloned,
+     * otherwise the state var would be shared between anon subs */
+
+    if (PL_parser->in_my == KEY_state && CvANON(PL_compcv))
+       CvCLONE_on(PL_compcv);
+
     return off;
 }
 
@@ -3966,6 +3974,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;
@@ -4059,6 +4069,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)) {