This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perlform: #109408
[perl5.git] / regexec.c
index 1c20c54..0bb8d7e 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -408,6 +408,13 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
                (IV)(cp), (IV)PL_savestack_ix));                \
     regcpblow(cp)
 
+#define UNWIND_PAREN(lp, lcp)               \
+    for (n = rex->lastparen; n > lp; n--)   \
+        rex->offs[n].end = -1;              \
+    rex->lastparen = n;                     \
+    rex->lastcloseparen = lcp;
+
+
 STATIC void
 S_regcppop(pTHX_ regexp *rex)
 {
@@ -477,6 +484,18 @@ S_regcppop(pTHX_ regexp *rex)
 #endif
 }
 
+/* restore the parens and associated vars at savestack position ix,
+ * but without popping the stack */
+
+STATIC void
+S_regcp_restore(pTHX_ regexp *rex, I32 ix)
+{
+    I32 tmpix = PL_savestack_ix;
+    PL_savestack_ix = ix;
+    regcppop(rex);
+    PL_savestack_ix = tmpix;
+}
+
 #define regcpblow(cp) LEAVE_SCOPE(cp)  /* Ignores regcppush()ed data. */
 
 /*
@@ -2585,6 +2604,16 @@ phooey:
 }
 
 
+/* Set which rex is pointed to by PL_reg_state, handling ref counting.
+ * Do inc before dec, in case old and new rex are the same */
+#define SET_reg_curpm(Re2) \
+    if (PL_reg_state.re_state_eval_setup_done) {    \
+       (void)ReREFCNT_inc(Re2);                    \
+       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));       \
+       PM_SETRE((PL_reg_curpm), (Re2));            \
+    }
+
+
 /*
  - regtry - try match at specific point
  */
@@ -2643,16 +2672,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
             }
 #endif      
         }
-#ifdef USE_ITHREADS
-       /* It seems that non-ithreads works both with and without this code.
-          So for efficiency reasons it seems best not to have the code
-          compiled when it is not needed.  */
-       /* This is safe against NULLs: */
-       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));
-       /* PM_reg_curpm owns a reference to this regexp.  */
-       (void)ReREFCNT_inc(rx);
-#endif
-       PM_SETRE(PL_reg_curpm, rx);
+       SET_reg_curpm(rx);
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
        if (RXp_MATCH_COPIED(prog)) {
@@ -3071,11 +3091,6 @@ S_clear_backtrack_stack(pTHX_ void *p)
 }
 
 
-#define SETREX(Re1,Re2) \
-    if (PL_reg_state.re_state_eval_setup_done) \
-       PM_SETRE((PL_reg_curpm), (Re2)); \
-    Re1 = (Re2)
-
 STATIC I32                     /* 0 failure, 1 success */
 S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 {
@@ -3142,6 +3157,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     I32 gimme = G_SCALAR;
     CV *caller_cv = NULL;      /* who called us */
     CV *last_pushed_cv = NULL; /* most recently called (?{}) CV */
+    CHECKPOINT runops_cp;      /* savestack position before executing EVAL */
 
 #ifdef DEBUGGING
     GET_RE_DEBUG_FLAGS_DECL;
@@ -3298,7 +3314,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                               REPORT_CODE_OFF+depth*2, "", PL_colors[4], PL_colors[5])
                 );
                 sayNO_SILENT;
-                /* NOTREACHED */
+                assert(0); /* NOTREACHED */
             }
             /* FALL THROUGH */
        case TRIE:
@@ -3483,15 +3499,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                );
                goto trie_first_try; /* jump into the fail handler */
            }}
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case TRIE_next_fail: /* we failed - try next alternative */
             if ( ST.jump) {
                 REGCP_UNWIND(ST.cp);
-               for (n = rex->lastparen; n > ST.lastparen; n--)
-                   rex->offs[n].end = -1;
-               rex->lastparen = n;
-               rex->lastcloseparen = ST.lastcloseparen;
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            }
            if (!--ST.accepted) {
                DEBUG_EXECUTE_r({
@@ -3599,7 +3612,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
            if (ST.accepted > 1 || has_cutgroup) {
                PUSH_STATE_GOTO(TRIE_next, scan);
-               /* NOTREACHED */
+               assert(0); /* NOTREACHED */
            }
            /* only one choice left - just continue */
            DEBUG_EXECUTE_r({
@@ -3624,7 +3637,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            locinput = PL_reginput;
            nextchr = UCHARAT(locinput);
            continue; /* execute rest of RE */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 #undef  ST
 
        case EXACT: {
@@ -4245,7 +4258,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            re_sv = rex_sv;
             re = rex;
             rei = rexi;
-            (void)ReREFCNT_inc(rex_sv);
             if (OP(scan)==GOSUB) {
                 startpoint = scan + ARG2L(scan);
                 ST.close_paren = ARG(scan);
@@ -4254,7 +4266,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                 ST.close_paren = 0;
             }
             goto eval_recurse_doit;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case EVAL:  /*   /(?{A})B/   /(??{A})B/  and /(?(?{A})X|Y)B/   */        
             if (cur_eval && cur_eval->locinput==locinput) {
                if ( ++nochange_depth > max_nochange_depth )
@@ -4274,6 +4286,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                struct re_save_state saved_state;
                CV *newcv;
 
+               /* save *all* paren positions */
+               regcppush(rex, 0);
+               REGCP_SET(runops_cp);
+
                /* To not corrupt the existing regex state while executing the
                 * eval we would normally put it on the save stack, like with
                 * save_re_context. However, re-evals have a weird scoping so we
@@ -4316,6 +4332,26 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    nop = (OP*)rexi->data->data[n];
                }
 
+               /* normally if we're about to execute code from the same
+                * CV that we used previously, we just use the existing
+                * CX stack entry. However, its possible that in the
+                * meantime we may have backtracked, popped from the save
+                * stack, and undone the SAVECOMPPAD(s) associated with
+                * PUSH_MULTICALL; in which case PL_comppad no longer
+                * points to newcv's pad. */
+               if (newcv != last_pushed_cv || PL_comppad != last_pad)
+               {
+                   I32 depth = (newcv == caller_cv) ? 0 : 1;
+                   if (last_pushed_cv) {
+                       CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   else {
+                       PUSH_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   last_pushed_cv = newcv;
+               }
+               last_pad = PL_comppad;
+
                /* the initial nextstate you would normally execute
                 * at the start of an eval (which would cause error
                 * messages to come from the eval), may be optimised
@@ -4351,26 +4387,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
                    "  re EVAL PL_op=0x%"UVxf"\n", PTR2UV(nop)) );
 
-               /* normally if we're about to execute code from the same
-                * CV that we used previously, we just use the existing
-                * CX stack entry. However, its possible that in the
-                * meantime we may have backtracked, popped from the save
-                * stack, and undone the SAVECOMPPAD(s) associated with
-                * PUSH_MULTICALL; in which case PL_comppad no longer
-                * points to newcv's pad. */
-               if (newcv != last_pushed_cv || PL_comppad != last_pad)
-               {
-                   I32 depth = (newcv == caller_cv) ? 0 : 1;
-                   if (last_pushed_cv) {
-                       CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
-                   }
-                   else {
-                       PUSH_MULTICALL_WITHDEPTH(newcv, depth);
-                   }
-                   last_pushed_cv = newcv;
-               }
-               last_pad = PL_comppad;
-
                rex->offs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
 
                 if (sv_yes_mark) {
@@ -4392,6 +4408,44 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    PUTBACK;
                }
 
+               /* before restoring everything, evaluate the returned
+                * value, so that 'uninit' warnings don't use the wrong
+                * PL_op or pad. Also need to process any magic vars
+                * (e.g. $1) *before* parentheses are restored */
+
+               PL_op = NULL;
+
+                re_sv = NULL;
+               if (logical == 0)        /*   (?{})/   */
+                   sv_setsv(save_scalar(PL_replgv), ret); /* $^R */
+               else if (logical == 1) { /*   /(?(?{...})X|Y)/    */
+                   sw = cBOOL(SvTRUE(ret));
+                   logical = 0;
+               }
+               else {                   /*  /(??{})  */
+                   /*  if its overloaded, let the regex compiler handle
+                    *  it; otherwise extract regex, or stringify  */
+                   if (!SvAMAGIC(ret)) {
+                       SV *sv = ret;
+                       if (SvROK(sv))
+                           sv = SvRV(sv);
+                       if (SvTYPE(sv) == SVt_REGEXP)
+                           re_sv = (REGEXP*) sv;
+                       else if (SvSMAGICAL(sv)) {
+                           MAGIC *mg = mg_find(sv, PERL_MAGIC_qr);
+                           if (mg)
+                               re_sv = (REGEXP *) mg->mg_obj;
+                       }
+
+                       /* force any magic, undef warnings here */
+                       if (!re_sv) {
+                           ret = sv_mortalcopy(ret);
+                           (void) SvPV_force_nolen(ret);
+                       }
+                   }
+
+               }
+
                Copy(&saved_state, &PL_reg_state, 1, struct re_save_state);
 
                /* *** Note that at this point we don't restore
@@ -4401,84 +4455,60 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PL_op = oop;
                PL_curcop = ocurcop;
                PL_regeol = saved_regeol;
-               if (!logical) {
-                   /* /(?{...})/ */
-                   sv_setsv(save_scalar(PL_replgv), ret);
+               S_regcp_restore(aTHX_ rex, runops_cp);
+
+               if (logical != 2)
                    break;
-               }
            }
-           if (logical == 2) { /* Postponed subexpression: /(??{...})/ */
+
+               /* only /(??{})/  from now on */
                logical = 0;
                {
                    /* extract RE object from returned value; compiling if
                     * necessary */
-                   MAGIC *mg = NULL;
-                   REGEXP *rx = NULL;
-
-                   if (SvROK(ret)) {
-                       SV *const sv = SvRV(ret);
-
-                       if (SvTYPE(sv) == SVt_REGEXP) {
-                           rx = (REGEXP*) sv;
-                       } else if (SvSMAGICAL(sv)) {
-                           mg = mg_find(sv, PERL_MAGIC_qr);
-                           assert(mg);
-                       }
-                   } else if (SvTYPE(ret) == SVt_REGEXP) {
-                       rx = (REGEXP*) ret;
-                   } else if (SvSMAGICAL(ret)) {
-                       if (SvGMAGICAL(ret)) {
-                           /* I don't believe that there is ever qr magic
-                              here.  */
-                           assert(!mg_find(ret, PERL_MAGIC_qr));
-                           sv_unmagic(ret, PERL_MAGIC_qr);
-                       }
-                       else {
-                           mg = mg_find(ret, PERL_MAGIC_qr);
-                           /* testing suggests mg only ends up non-NULL for
-                              scalars who were upgraded and compiled in the
-                              else block below. In turn, this is only
-                              triggered in the "postponed utf8 string" tests
-                              in t/op/pat.t  */
-                       }
-                   }
 
-                   if (mg) {
-                       rx = (REGEXP *) mg->mg_obj; /*XXX:dmq*/
-                       assert(rx);
-                   }
-                   if (rx) {
-                       rx = reg_temp_copy(NULL, rx);
+                   if (re_sv) {
+                       re_sv = reg_temp_copy(NULL, re_sv);
                    }
                    else {
                        U32 pm_flags = 0;
                        const I32 osize = PL_regsize;
 
-                       if (DO_UTF8(ret)) {
-                           assert (SvUTF8(ret));
-                       } else if (SvUTF8(ret)) {
-                           /* Not doing UTF-8, despite what the SV says. Is
-                              this only if we're trapped in use 'bytes'?  */
-                           /* Make a copy of the octet sequence, but without
-                              the flag on, as the compiler now honours the
-                              SvUTF8 flag on ret.  */
+                       if (SvUTF8(ret) && IN_BYTES) {
+                           /* In use 'bytes': make a copy of the octet
+                            * sequence, but without the flag on */
                            STRLEN len;
                            const char *const p = SvPV(ret, len);
                            ret = newSVpvn_flags(p, len, SVs_TEMP);
                        }
-                       rx = CALLREGCOMP(ret, pm_flags);
+                       if (rex->intflags & PREGf_USE_RE_EVAL)
+                           pm_flags |= PMf_USE_RE_EVAL;
+
+                       /* if we got here, it should be an engine which
+                        * supports compiling code blocks and stuff */
+                       assert(rex->engine && rex->engine->op_comp);
+                        assert(!(scan->flags & ~RXf_PMf_COMPILETIME));
+                       re_sv = rex->engine->op_comp(aTHX_ &ret, 1, NULL,
+                                   rex->engine, NULL, NULL,
+                                    /* copy /msix etc to inner pattern */
+                                    scan->flags,
+                                    pm_flags);
+
                        if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY
                                 | SVs_GMG))) {
                            /* This isn't a first class regexp. Instead, it's
                               caching a regexp onto an existing, Perl visible
                               scalar.  */
-                           sv_magic(ret, MUTABLE_SV(rx), PERL_MAGIC_qr, 0, 0);
+                           sv_magic(ret, MUTABLE_SV(re_sv), PERL_MAGIC_qr, 0, 0);
                        }
                        PL_regsize = osize;
+                       /* safe to do now that any $1 etc has been
+                        * interpolated into the new pattern string and
+                        * compiled */
+                       S_regcp_restore(aTHX_ rex, runops_cp);
                    }
-                   re_sv = rx;
-                   re = (struct regexp *)SvANY(rx);
+                   re = (struct regexp *)SvANY(re_sv);
                }
                 RXp_MATCH_COPIED_off(re);
                 re->subbeg = rex->subbeg;
@@ -4496,7 +4526,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                ST.cp = regcppush(rex, 0);      /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
-               /* see regtry, specifically PL_reglast(?:close)?paren is a pointer! (i dont know why) :dmq */
                re->lastparen = 0;
                re->lastcloseparen = 0;
 
@@ -4515,7 +4544,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
                ST.prev_rex = rex_sv;
                ST.prev_curlyx = cur_curlyx;
-               SETREX(rex_sv,re_sv);
+               rex_sv = re_sv;
+               SET_reg_curpm(rex_sv);
                rex = re;
                rexi = rei;
                cur_curlyx = NULL;
@@ -4524,19 +4554,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                cur_eval = st;
                /* now continue from first node in postoned RE */
                PUSH_YES_STATE_GOTO(EVAL_AB, startpoint);
-               /* NOTREACHED */
-           }
-           /* logical is 1,   /(?(?{...})X|Y)/ */
-           sw = cBOOL(SvTRUE(ret));
-           logical = 0;
-           break;
+               assert(0); /* NOTREACHED */
        }
 
        case EVAL_AB: /* cleanup after a successful (??{A})B */
            /* note: this is called twice; first after popping B, then A */
            PL_reg_flags ^= ST.toggle_reg_flags; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex);
            regcpblow(ST.cp);
@@ -4553,8 +4578,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case EVAL_AB_fail: /* unsuccessfully ran A or B in (??{A})B */
            /* note: this is called twice; first after popping B, then A */
            PL_reg_flags ^= ST.toggle_reg_flags; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex); 
 
@@ -4780,19 +4805,19 @@ NULL
 
            PL_reginput = locinput;
            PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next));
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
        }
 
        case CURLYX_end: /* just finished matching all of A*B */
            cur_curlyx = ST.prev_curlyx;
            sayYES;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case CURLYX_end_fail: /* just failed to match all of A*B */
            regcpblow(ST.cp);
            cur_curlyx = ST.prev_curlyx;
            sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
 #undef ST
@@ -4827,7 +4852,7 @@ NULL
                REGCP_SET(ST.lastcp);
 
                PUSH_STATE_GOTO(WHILEM_A_pre, A);
-               /* NOTREACHED */
+               assert(0); /* NOTREACHED */
            }
 
            /* If degenerate A matches "", assume A done. */
@@ -4901,7 +4926,7 @@ NULL
                ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor);
                REGCP_SET(ST.lastcp);
                PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B);
-               /* NOTREACHED */
+               assert(0); /* NOTREACHED */
            }
 
            /* Prefer A over B for maximal matching. */
@@ -4911,24 +4936,24 @@ NULL
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
                PUSH_STATE_GOTO(WHILEM_A_max, A);
-               /* NOTREACHED */
+               assert(0); /* NOTREACHED */
            }
            goto do_whilem_B_max;
        }
-       /* NOTREACHED */
+       assert(0); /* NOTREACHED */
 
        case WHILEM_B_min: /* just matched B in a minimal match */
        case WHILEM_B_max: /* just matched B in a maximal match */
            cur_curlyx = ST.save_curlyx;
            sayYES;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_B_max_fail: /* just failed to match B in a maximal match */
            cur_curlyx = ST.save_curlyx;
            cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
            cur_curlyx->u.curlyx.count--;
            CACHEsayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_A_min_fail: /* just failed to match A in a minimal match */
            /* FALL THROUGH */
@@ -4938,7 +4963,7 @@ NULL
            cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
            cur_curlyx->u.curlyx.count--;
            CACHEsayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_A_max_fail: /* just failed to match A in a maximal match */
            REGCP_UNWIND(ST.lastcp);
@@ -4964,7 +4989,7 @@ NULL
            ST.save_curlyx = cur_curlyx;
            cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
            PUSH_YES_STATE_GOTO(WHILEM_B_max, ST.save_curlyx->u.curlyx.B);
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_B_min_fail: /* just failed to match B in a minimal match */
            cur_curlyx = ST.save_curlyx;
@@ -4997,7 +5022,7 @@ NULL
            REGCP_SET(ST.lastcp);
            PUSH_STATE_GOTO(WHILEM_A_min,
                /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS);
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 #undef  ST
 #define ST st->u.branch
@@ -5023,33 +5048,30 @@ NULL
            } else {
                PUSH_STATE_GOTO(BRANCH_next, scan);
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
         case CUTGROUP:
             PL_reginput = locinput;
             sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL :
                 MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
             PUSH_STATE_GOTO(CUTGROUP_next,next);
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case CUTGROUP_next_fail:
             do_cutgroup = 1;
             no_final = 1;
             if (st->u.mark.mark_name)
                 sv_commit = st->u.mark.mark_name;
             sayNO;         
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case BRANCH_next:
             sayYES;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
        case BRANCH_next_fail: /* that branch failed; try the next, if any */
            if (do_cutgroup) {
                do_cutgroup = 0;
                no_final = 0;
            }
            REGCP_UNWIND(ST.cp);
-           for (n = rex->lastparen; n > ST.lastparen; n--)
-               rex->offs[n].end = -1;
-           rex->lastparen = n;
-           rex->lastcloseparen = ST.lastcloseparen;
+            UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            scan = ST.next_branch;
            /* no more branches? */
            if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) {
@@ -5063,7 +5085,7 @@ NULL
                sayNO_SILENT;
             }
            continue; /* execute next BRANCH[J] op */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
     
        case MINMOD:
            minmod = 1;
@@ -5108,7 +5130,7 @@ NULL
          curlym_do_A: /* execute the A in /A{m,n}B/  */
            PL_reginput = locinput;
            PUSH_YES_STATE_GOTO(CURLYM_A, ST.A); /* match A */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case CURLYM_A: /* we've just matched an A */
            locinput = st->locinput;
@@ -5239,12 +5261,11 @@ NULL
            }
            
            PUSH_STATE_GOTO(CURLYM_B, ST.B); /* match B */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case CURLYM_B_fail: /* just failed to match a B */
            REGCP_UNWIND(ST.cp);
-           rex->lastparen      = ST.lastparen;
-           rex->lastcloseparen = ST.lastcloseparen;
+            UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            if (ST.minmod) {
                I32 max = ARG2(ST.me);
                if (max != REG_INFTY && ST.count == max)
@@ -5433,7 +5454,7 @@ NULL
                REGCP_SET(ST.cp);
                goto curly_try_B_max;
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        case CURLY_B_min_known_fail:
@@ -5441,6 +5462,9 @@ NULL
 
            PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /* Couldn't or didn't -- move forward. */
            ST.oldloc = locinput;
            if (utf8_target)
@@ -5509,13 +5533,16 @@ NULL
                }
                PUSH_STATE_GOTO(CURLY_B_min_known, ST.B);
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
 
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /* failed -- move forward one */
            PL_reginput = locinput;
            if (regrepeat(rex, ST.A, 1, depth)) {
@@ -5534,7 +5561,7 @@ NULL
                }
            }
            sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        curly_try_B_max:
@@ -5553,7 +5580,7 @@ NULL
                if (ST.c1 == CHRTEST_VOID || c == (UV)ST.c1 || c == (UV)ST.c2) {
                    CURLY_SETPAREN(ST.paren, ST.count);
                    PUSH_STATE_GOTO(CURLY_B_max, ST.B);
-                   /* NOTREACHED */
+                   assert(0); /* NOTREACHED */
                }
            }
            /* FALL THROUGH */
@@ -5561,6 +5588,9 @@ NULL
            /* failed to find B in a greedy match */
 
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /*  back up. */
            if (--ST.count < ST.min)
                sayNO;
@@ -5573,28 +5603,24 @@ NULL
            fake_end:
            if (cur_eval) {
                /* we've just finished A in /(??{A})B/; now continue with B */
-               I32 tmpix;
                st->u.eval.toggle_reg_flags
                            = cur_eval->u.eval.toggle_reg_flags;
                PL_reg_flags ^= st->u.eval.toggle_reg_flags; 
 
                st->u.eval.prev_rex = rex_sv;           /* inner */
                st->u.eval.cp = regcppush(rex, 0); /* Save *all* the positions. */
-               SETREX(rex_sv,cur_eval->u.eval.prev_rex);
+               rex_sv = cur_eval->u.eval.prev_rex;
+               SET_reg_curpm(rex_sv);
                rex = (struct regexp *)SvANY(rex_sv);
                rexi = RXi_GET(rex);
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
-               (void)ReREFCNT_inc(rex_sv);
 
                REGCP_SET(st->u.eval.lastcp);
                PL_reginput = locinput;
 
                /* Restore parens of the outer rex without popping the
                 * savestack */
-               tmpix = PL_savestack_ix;
-               PL_savestack_ix = cur_eval->u.eval.lastcp;
-               regcppop(rex);
-               PL_savestack_ix = tmpix;
+               S_regcp_restore(aTHX_ rex, cur_eval->u.eval.lastcp);
 
                st->u.eval.prev_eval = cur_eval;
                cur_eval = cur_eval->u.eval.prev_eval;
@@ -5671,7 +5697,7 @@ NULL
            
            /* execute body of (?...A) */
            PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)));
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case IFMATCH_A_fail: /* body of (?...A) failed */
            ST.wanted = !ST.wanted;
@@ -5710,13 +5736,13 @@ NULL
            if (!scan->flags)
                sv_yes_mark = sv_commit = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
            PUSH_STATE_GOTO(COMMIT_next,next);
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
        case COMMIT_next_fail:
            no_final = 1;    
            /* FALLTHROUGH */       
        case OPFAIL:
            sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 #define ST st->u.mark
         case MARKPOINT:
@@ -5726,11 +5752,11 @@ NULL
             mark_state = st;
             ST.mark_loc = PL_reginput = locinput;
             PUSH_YES_STATE_GOTO(MARKPOINT_next,next);
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case MARKPOINT_next:
             mark_state = ST.prev_mark;
             sayYES;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case MARKPOINT_next_fail:
             if (popmark && sv_eq(ST.mark_name,popmark)) 
             {
@@ -5750,7 +5776,7 @@ NULL
             sv_yes_mark = mark_state ? 
                 mark_state->u.mark.mark_name : NULL;
             sayNO;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case SKIP:
             PL_reginput = locinput;
             if (scan->flags) {
@@ -5794,7 +5820,7 @@ NULL
             } 
             no_final = 1; 
             sayNO;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
 #undef ST
         case LNBREAK:
             if ((n=is_LNBREAK(locinput,utf8_target))) {
@@ -5839,7 +5865,7 @@ NULL
         /* switch break jumps here */
        scan = next; /* prepare to execute the next op and ... */
        continue;    /* ... jump back to the top, reusing st */
-       /* NOTREACHED */
+       assert(0); /* NOTREACHED */
 
       push_yes_state:
        /* push a state that backtracks on success */
@@ -5883,7 +5909,7 @@ NULL
            nextchr = UCHARAT(locinput);
            st = newst;
            continue;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
        }
     }