This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regcomp.c: Optimize /[0-9]/ into /\d/a
[perl5.git] / regcomp.c
index 7827bb3..cfed452 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -133,7 +133,6 @@ typedef struct RExC_state_t {
     I32                nestroot;               /* root parens we are in - used by accept */
     I32                extralen;
     I32                seen_zerolen;
-    I32                seen_evals;
     regnode    **open_parens;          /* pointers to open parens */
     regnode    **close_parens;         /* pointers to close parens */
     regnode    *opend;                 /* END node in program */
@@ -194,7 +193,6 @@ typedef struct RExC_state_t {
 #define RExC_nestroot   (pRExC_state->nestroot)
 #define RExC_extralen  (pRExC_state->extralen)
 #define RExC_seen_zerolen      (pRExC_state->seen_zerolen)
-#define RExC_seen_evals        (pRExC_state->seen_evals)
 #define RExC_utf8      (pRExC_state->utf8)
 #define RExC_uni_semantics     (pRExC_state->uni_semantics)
 #define RExC_orig_utf8 (pRExC_state->orig_utf8)
@@ -3381,7 +3379,6 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                                  * the end pointer. */
                                 if ( !first ) {
                                     first = cur;
-                                    trietype = noper_trietype;
                                    if ( noper_trietype == NOTHING ) {
 #if !defined(DEBUGGING) && !defined(NOJUMPTRIE)
                                        regnode * const noper_next = regnext( noper );
@@ -3389,8 +3386,15 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                                        U8 noper_next_trietype = noper_next_type ? TRIE_TYPE( noper_next_type ) :0;
 #endif
 
-                                        if ( noper_next_trietype )
+                                        if ( noper_next_trietype ) {
                                            trietype = noper_next_trietype;
+                                        } else if (noper_next_type)  {
+                                            /* a NOTHING regop is 1 regop wide. We need at least two
+                                             * for a trie so we can't merge this in */
+                                            first = NULL;
+                                        }
+                                    } else {
+                                        trietype = noper_trietype;
                                     }
                                 } else {
                                     if ( trietype == NOTHING )
@@ -5043,7 +5047,7 @@ S_compile_runtime_code(pTHX_ RExC_state_t * const pRExC_state,
        int n = 0;
        STRLEN s;
        char *p, *newpat;
-       int newlen = plen + 5; /* allow for "qr''x" extra chars */
+       int newlen = plen + 6; /* allow for "qr''x\0" extra chars */
        SV *sv, *qr_ref;
        dSP;
 
@@ -5234,7 +5238,7 @@ S_compile_runtime_code(pTHX_ RExC_state_t * const pRExC_state,
 REGEXP *
 Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                    OP *expr, const regexp_engine* eng, REGEXP *VOL old_re,
-                    int *is_bare_re, U32 orig_rx_flags, U32 pm_flags)
+                    bool *is_bare_re, U32 orig_rx_flags, U32 pm_flags)
 {
     dVAR;
     REGEXP *rx;
@@ -5336,7 +5340,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     pRExC_state->num_code_blocks = 0;
 
     if (is_bare_re)
-       *is_bare_re = 0;
+       *is_bare_re = FALSE;
 
     if (expr && (expr->op_type == OP_LIST ||
                (expr->op_type == OP_NULL && expr->op_targ == OP_LIST))) {
@@ -5385,6 +5389,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
            OP *o = NULL;
            int n = 0;
            bool utf8 = 0;
+            STRLEN orig_patlen = 0;
 
            if (pRExC_state->num_code_blocks) {
                o = cLISTOPx(expr)->op_first;
@@ -5426,11 +5431,36 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                    o = o->op_sibling;;
                }
 
+               if ((SvAMAGIC(pat) || SvAMAGIC(msv)) &&
+                       (sv = amagic_call(pat, msv, concat_amg, AMGf_assign)))
+               {
+                   sv_setsv(pat, sv);
+                   /* overloading involved: all bets are off over literal
+                    * code. Pretend we haven't seen it */
+                   pRExC_state->num_code_blocks -= n;
+                   n = 0;
+                    rx = NULL;
+
+               }
+               else  {
+                    while (SvAMAGIC(msv)
+                            && (sv = AMG_CALLunary(msv, string_amg))
+                            && sv != msv)
+                    {
+                        msv = sv;
+                        SvGETMAGIC(msv);
+                    }
+                    if (SvROK(msv) && SvTYPE(SvRV(msv)) == SVt_REGEXP)
+                        msv = SvRV(msv);
+                    orig_patlen = SvCUR(pat);
+                    sv_catsv_nomg(pat, msv);
+                    rx = msv;
+                    if (code)
+                        pRExC_state->code_blocks[n-1].end = SvCUR(pat)-1;
+                }
+
                /* extract any code blocks within any embedded qr//'s */
-               rx = msv;
-               if (SvROK(rx))
-                   rx = SvRV(rx);
-               if (SvTYPE(rx) == SVt_REGEXP
+               if (rx && SvTYPE(rx) == SVt_REGEXP
                    && RX_ENGINE((REGEXP*)rx)->op_comp)
                {
 
@@ -5448,7 +5478,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                        pRExC_state->num_code_blocks += ri->num_code_blocks;
                        for (i=0; i < ri->num_code_blocks; i++) {
                            struct reg_code_block *src, *dst;
-                           STRLEN offset =  SvCUR(pat)
+                           STRLEN offset =  orig_patlen
                                + ((struct regexp *)SvANY(rx))->pre_prefix;
                            assert(n < pRExC_state->num_code_blocks);
                            src = &ri->code_blocks[i];
@@ -5464,32 +5494,20 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                        }
                    }
                }
-
-               if ((SvAMAGIC(pat) || SvAMAGIC(msv)) &&
-                       (sv = amagic_call(pat, msv, concat_amg, AMGf_assign)))
-               {
-                   sv_setsv(pat, sv);
-                   /* overloading involved: all bets are off over literal
-                    * code. Pretend we haven't seen it */
-                   pRExC_state->num_code_blocks -= n;
-                   n = 0;
-
-               }
-               else {
-                   if (SvROK(msv) && SvTYPE(SvRV(msv)) == SVt_REGEXP) {
-                       msv = SvRV(msv);
-                       PL_reginterp_cnt +=
-                           RX_SEEN_EVALS((REGEXP *)MUTABLE_PTR(msv));
-                   }
-                   sv_catsv_nomg(pat, msv);
-                   if (code)
-                       pRExC_state->code_blocks[n-1].end = SvCUR(pat)-1;
-               }
            }
            SvSETMAGIC(pat);
        }
-       else
+       else {
+            SV *sv;
            pat = *patternp;
+            while (SvAMAGIC(pat)
+                    && (sv = AMG_CALLunary(pat, string_amg))
+                    && sv != pat)
+            {
+                pat = sv;
+                SvGETMAGIC(pat);
+            }
+        }
 
        /* handle bare regex: foo =~ $re */
        {
@@ -5498,7 +5516,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                re = SvRV(re);
            if (SvTYPE(re) == SVt_REGEXP) {
                if (is_bare_re)
-                   *is_bare_re = 1;
+                   *is_bare_re = TRUE;
                SvREFCNT_inc(re);
                Safefree(pRExC_state->code_blocks);
                return (REGEXP*)re;
@@ -5718,7 +5736,6 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     RExC_seen = 0;
     RExC_in_lookbehind = 0;
     RExC_seen_zerolen = *exp == '^' ? -1 : 0;
-    RExC_seen_evals = 0;
     RExC_extralen = 0;
     RExC_override_recoding = 0;
 
@@ -5919,8 +5936,6 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     RExC_emit_bound = ri->program + RExC_size + 1;
     pRExC_state->code_index = 0;
 
-    /* Store the count of eval-groups for security checks: */
-    RExC_rx->seen_evals = RExC_seen_evals;
     REGC((U8)REG_MAGIC, (char*) RExC_emit++);
     if (reg(pRExC_state, 0, &flags,1) == NULL) {
        ReREFCNT_dec(rx);   
@@ -6367,6 +6382,8 @@ reStudy:
        r->intflags |= PREGf_VERBARG_SEEN;
     if (RExC_seen & REG_SEEN_CUTGROUP)
        r->intflags |= PREGf_CUTGROUP_SEEN;
+    if (pm_flags & PMf_USE_RE_EVAL)
+       r->intflags |= PREGf_USE_RE_EVAL;
     if (RExC_paren_names)
         RXp_PAREN_NAMES(r) = MUTABLE_HV(SvREFCNT_inc(RExC_paren_names));
     else
@@ -6854,8 +6871,10 @@ S_reg_scan_name(pTHX_ RExC_state_t *pRExC_state, U32 flags)
            do {
                RExC_parse++;
            } while (isALNUM(*RExC_parse));
+    } else {
+       RExC_parse++; /* so the <- from the vFAIL is after the offending character */
+        vFAIL("Group name must start with a non-digit word character");
     }
-
     if ( flags ) {
         SV* sv_name
            = newSVpvn_flags(name_start, (int)(RExC_parse - name_start),
@@ -6879,7 +6898,7 @@ S_reg_scan_name(pTHX_ RExC_state_t *pRExC_state, U32 flags)
             Perl_croak(aTHX_ "panic: bad flag %lx in reg_scan_name",
                       (unsigned long) flags);
         }
-        /* NOT REACHED */
+        assert(0); /* NOT REACHED */
     }
     return NULL;
 }
@@ -8493,7 +8512,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                     num = sv_dat ? *((I32 *)SvPVX(sv_dat)) : 0;
                 }
                 goto gen_recurse_regop;
-                /* NOT REACHED */
+                assert(0); /* NOT REACHED */
             case '+':
                 if (!(RExC_parse[0] >= '1' && RExC_parse[0] <= '9')) {
                     RExC_parse++;
@@ -8563,7 +8582,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                 nextchar(pRExC_state);
                 return ret;
             } /* named and numeric backreferences */
-            /* NOT REACHED */
+            assert(0); /* NOT REACHED */
 
            case '?':           /* (??...) */
                is_logical = 1;
@@ -8595,9 +8614,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                /* this is a pre-compiled code block (?{...}) */
                cb = &pRExC_state->code_blocks[pRExC_state->code_index];
                RExC_parse = RExC_start + cb->end;
-               if (SIZE_ONLY)
-                   RExC_seen_evals++;
-               else {
+               if (!SIZE_ONLY) {
                    OP *o = cb->block;
                    if (cb->src_regex) {
                        n = add_data(pRExC_state, 2, "rl");
@@ -8615,10 +8632,15 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                nextchar(pRExC_state);
 
                if (is_logical) {
+                    regnode *eval;
                    ret = reg_node(pRExC_state, LOGICAL);
-                   if (!SIZE_ONLY)
+                    eval = reganode(pRExC_state, EVAL, n);
+                   if (!SIZE_ONLY) {
                        ret->flags = 2;
-                    REGTAIL(pRExC_state, ret, reganode(pRExC_state, EVAL, n));
+                        /* for later propagation into (??{}) return value */
+                        eval->flags = (U8) (RExC_flags & RXf_PMf_COMPILETIME);
+                    }
+                    REGTAIL(pRExC_state, ret, eval);
                     /* deal with the length of this later - MJD */
                    return ret;
                }
@@ -9148,7 +9170,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
        }
        else
            FAIL("Junk on end of regexp");      /* "Can't happen". */
-       /* NOTREACHED */
+       assert(0); /* NOTREACHED */
     }
 
     if (RExC_in_lookbehind) {
@@ -9697,8 +9719,46 @@ S_reg_recode(pTHX_ const char value, SV **encp)
    sequence, we return.
 
    Note: we have to be careful with escapes, as they can be both literal
-   and special, and in the case of \10 and friends can either, depending
-   on context. Specifically there are two separate switches for handling
+   and special, and in the case of \10 and friends, context determines which.
+
+   A summary of the code structure is:
+
+   switch (first_byte) {
+       cases for each special:
+           handle this special;
+           break;
+       case '\\':
+           switch (2nd byte) {
+               cases for each unambiguous special:
+                   handle this special;
+                   break;
+               cases for each ambigous special/literal:
+                   disambiguate;
+                   if (special)  handle here
+                   else goto defchar;
+               default: // unambiguously literal:
+                   goto defchar;
+           }
+       default:  // is a literal char
+           // FALL THROUGH
+       defchar:
+           create EXACTish node for literal;
+           while (more input and node isn't full) {
+               switch (input_byte) {
+                  cases for each special;
+                       make sure parse pointer is set so that the next call to
+                           regatom will see this special first
+                       goto loopdone; // EXACTish node terminated by prev. char
+                  default:
+                      append char to EXACTISH node;
+               }
+               get next input byte;
+           }
+        loopdone:
+   }
+   return the generated node;
+
+   Specifically there are two separate switches for handling
    escape sequences, with the one for handling literal escapes requiring
    a dummy entry for all of the special escapes that are actually handled
    by the other.
@@ -9852,43 +9912,17 @@ tryagain:
            *flagp |= HASWIDTH;
            goto finish_meta_pat;
        case 'w':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = ALNUML;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = ALNUMU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = ALNUMA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = ALNUM;
-                   break;
-               default:
-                   goto bad_charset;
+           op = ALNUM + get_regex_charset(RExC_flags);
+            if (op > ALNUMA) {  /* /aa is same as /a */
+                op = ALNUMA;
             }
            ret = reg_node(pRExC_state, op);
            *flagp |= HASWIDTH|SIMPLE;
            goto finish_meta_pat;
        case 'W':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = NALNUML;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = NALNUMU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = NALNUMA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = NALNUM;
-                   break;
-               default:
-                   goto bad_charset;
+           op = NALNUM + get_regex_charset(RExC_flags);
+            if (op > NALNUMA) { /* /aa is same as /a */
+                op = NALNUMA;
             }
            ret = reg_node(pRExC_state, op);
            *flagp |= HASWIDTH|SIMPLE;
@@ -9896,22 +9930,9 @@ tryagain:
        case 'b':
            RExC_seen_zerolen++;
            RExC_seen |= REG_SEEN_LOOKBEHIND;
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = BOUNDL;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = BOUNDU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = BOUNDA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = BOUND;
-                   break;
-               default:
-                   goto bad_charset;
+           op = BOUND + get_regex_charset(RExC_flags);
+            if (op > BOUNDA) {  /* /aa is same as /a */
+                op = BOUNDA;
             }
            ret = reg_node(pRExC_state, op);
            FLAGS(ret) = get_regex_charset(RExC_flags);
@@ -9920,103 +9941,45 @@ tryagain:
        case 'B':
            RExC_seen_zerolen++;
            RExC_seen |= REG_SEEN_LOOKBEHIND;
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = NBOUNDL;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = NBOUNDU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = NBOUNDA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = NBOUND;
-                   break;
-               default:
-                   goto bad_charset;
+           op = NBOUND + get_regex_charset(RExC_flags);
+            if (op > NBOUNDA) { /* /aa is same as /a */
+                op = NBOUNDA;
             }
            ret = reg_node(pRExC_state, op);
            FLAGS(ret) = get_regex_charset(RExC_flags);
            *flagp |= SIMPLE;
            goto finish_meta_pat;
        case 's':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = SPACEL;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = SPACEU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = SPACEA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = SPACE;
-                   break;
-               default:
-                   goto bad_charset;
+           op = SPACE + get_regex_charset(RExC_flags);
+            if (op > SPACEA) {  /* /aa is same as /a */
+                op = SPACEA;
             }
            ret = reg_node(pRExC_state, op);
            *flagp |= HASWIDTH|SIMPLE;
            goto finish_meta_pat;
        case 'S':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = NSPACEL;
-                   break;
-               case REGEX_UNICODE_CHARSET:
-                   op = NSPACEU;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = NSPACEA;
-                   break;
-               case REGEX_DEPENDS_CHARSET:
-                   op = NSPACE;
-                   break;
-               default:
-                   goto bad_charset;
-            }
-           ret = reg_node(pRExC_state, op);
-           *flagp |= HASWIDTH|SIMPLE;
-           goto finish_meta_pat;
-       case 'd':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = DIGITL;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = DIGITA;
-                   break;
-               case REGEX_DEPENDS_CHARSET: /* No difference between these */
-               case REGEX_UNICODE_CHARSET:
-                   op = DIGIT;
-                   break;
-               default:
-                   goto bad_charset;
+           op = NSPACE + get_regex_charset(RExC_flags);
+            if (op > NSPACEA) { /* /aa is same as /a */
+                op = NSPACEA;
             }
            ret = reg_node(pRExC_state, op);
            *flagp |= HASWIDTH|SIMPLE;
            goto finish_meta_pat;
        case 'D':
-           switch (get_regex_charset(RExC_flags)) {
-               case REGEX_LOCALE_CHARSET:
-                   op = NDIGITL;
-                   break;
-               case REGEX_ASCII_RESTRICTED_CHARSET:
-               case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
-                   op = NDIGITA;
-                   break;
-               case REGEX_DEPENDS_CHARSET: /* No difference between these */
-               case REGEX_UNICODE_CHARSET:
-                   op = NDIGIT;
-                   break;
-               default:
-                   goto bad_charset;
+            op = NDIGIT;
+            goto join_D_and_d;
+       case 'd':
+            op = DIGIT;
+        join_D_and_d:
+            {
+                U8 offset = get_regex_charset(RExC_flags);
+                if (offset == REGEX_UNICODE_CHARSET) {
+                    offset = REGEX_DEPENDS_CHARSET;
+                }
+                else if (offset == REGEX_ASCII_MORE_RESTRICTED_CHARSET) {
+                    offset = REGEX_ASCII_RESTRICTED_CHARSET;
+                }
+                op += offset;
             }
            ret = reg_node(pRExC_state, op);
            *flagp |= HASWIDTH|SIMPLE;
@@ -10167,6 +10130,7 @@ tryagain:
                         vFAIL("Reference to nonexistent or unclosed group");
                 }
                if (!isg && num > 9 && num >= RExC_npar)
+                    /* Probably a character specified in octal, e.g. \35 */
                    goto defchar;
                else {
                    char * const parse_start = RExC_parse - 1; /* MJD */
@@ -10244,14 +10208,18 @@ tryagain:
            bool is_exactfu_sharp_s;
 
            ender = 0;
-            node_type = ((! FOLD) ? EXACT
-                       : (LOC)
-                         ? EXACTFL
-                         : (MORE_ASCII_RESTRICTED)
-                           ? EXACTFA
-                           : (AT_LEAST_UNI_SEMANTICS)
-                             ? EXACTFU
-                             : EXACTF);
+            if (! FOLD) {
+                node_type = EXACT;
+            }
+            else {
+                node_type = get_regex_charset(RExC_flags);
+                if (node_type >= REGEX_ASCII_RESTRICTED_CHARSET) {
+                    node_type--; /* /a is same as /u, and map /aa's offset to
+                                    what /a's would have been, so there is no
+                                    hole */
+                }
+                node_type += EXACTF;
+            }
            ret = reg_node(pRExC_state, node_type);
            s = STRING(ret);
 
@@ -10381,38 +10349,39 @@ tryagain:
                            break;
                        }
                    case 'x':
-                       if (*++p == '{') {
-                           char* const e = strchr(p, '}');
+                       {
+                           STRLEN brace_len = len;
+                           UV result;
+                           const char* error_msg;
 
-                           if (!e) {
-                               RExC_parse = p + 1;
-                               vFAIL("Missing right brace on \\x{}");
+                           bool valid = grok_bslash_x(p,
+                                                      &result,
+                                                      &brace_len,
+                                                      &error_msg,
+                                                      1);
+                           p += brace_len;
+                           if (! valid) {
+                               RExC_parse = p; /* going to die anyway; point
+                                                  to exact spot of failure */
+                               vFAIL(error_msg);
                            }
                            else {
-                                I32 flags = PERL_SCAN_ALLOW_UNDERSCORES
-                                    | PERL_SCAN_DISALLOW_PREFIX;
-                                STRLEN numlen = e - p - 1;
-                               ender = grok_hex(p + 1, &numlen, &flags, NULL);
-                               if (ender > 0xff)
-                                   REQUIRE_UTF8;
-                               p = e + 1;
+                               ender = result;
                            }
+                           if (PL_encoding && ender < 0x100) {
+                               goto recode_encoding;
+                           }
+                           if (ender > 0xff) {
+                               REQUIRE_UTF8;
+                           }
+                           break;
                        }
-                       else {
-                            I32 flags = PERL_SCAN_DISALLOW_PREFIX;
-                           STRLEN numlen = 2;
-                           ender = grok_hex(p, &numlen, &flags, NULL);
-                           p += numlen;
-                       }
-                       if (PL_encoding && ender < 0x100)
-                           goto recode_encoding;
-                       break;
                    case 'c':
                        p++;
                        ender = grok_bslash_c(*p++, UTF, SIZE_ONLY);
                        break;
                    case '0': case '1': case '2': case '3':case '4':
-                   case '5': case '6': case '7': case '8':case '9':
+                   case '5': case '6': case '7':
                        if (*p == '0' ||
                            (isDIGIT(p[1]) && atoi(p) >= RExC_npar))
                        {
@@ -10445,7 +10414,7 @@ tryagain:
                            FAIL("Trailing \\");
                        /* FALL THROUGH */
                    default:
-                       if (!SIZE_ONLY&& isALPHA(*p)) {
+                       if (!SIZE_ONLY&& isALNUMC(*p)) {
                            ckWARN2reg(p + 1, "Unrecognized escape \\%.1s passed through", p);
                        }
                        goto normal_default;
@@ -10644,11 +10613,6 @@ tryagain:
     }
 
     return(ret);
-
-/* Jumped to when an unrecognized character set is encountered */
-bad_charset:
-    Perl_croak(aTHX_ "panic: Unknown regex character set encoding: %u", get_regex_charset(RExC_flags));
-    return(NULL);
 }
 
 STATIC char *
@@ -10967,171 +10931,6 @@ S_checkposixcc(pTHX_ RExC_state_t *pRExC_state)
        }                                                                  \
     }
 
-STATIC U8
-S_set_regclass_bit_fold(pTHX_ RExC_state_t *pRExC_state, regnode* node, const U8 value, SV** invlist_ptr, AV** alternate_ptr)
-{
-
-    /* Handle the setting of folds in the bitmap for non-locale ANYOF nodes.
-     * Locale folding is done at run-time, so this function should not be
-     * called for nodes that are for locales.
-     *
-     * This function sets the bit corresponding to the fold of the input
-     * 'value', if not already set.  The fold of 'f' is 'F', and the fold of
-     * 'F' is 'f'.
-     *
-     * It also knows about the characters that are in the bitmap that have
-     * folds that are matchable only outside it, and sets the appropriate lists
-     * and flags.
-     *
-     * It returns the number of bits that actually changed from 0 to 1 */
-
-    U8 stored = 0;
-    U8 fold;
-
-    PERL_ARGS_ASSERT_SET_REGCLASS_BIT_FOLD;
-
-    fold = (AT_LEAST_UNI_SEMANTICS) ? PL_fold_latin1[value]
-                                    : PL_fold[value];
-
-    /* It assumes the bit for 'value' has already been set */
-    if (fold != value && ! ANYOF_BITMAP_TEST(node, fold)) {
-        ANYOF_BITMAP_SET(node, fold);
-        stored++;
-    }
-    if (_HAS_NONLATIN1_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(value) && (! isASCII(value) || ! MORE_ASCII_RESTRICTED)) {
-       /* Certain Latin1 characters have matches outside the bitmap.  To get
-        * here, 'value' is one of those characters.   None of these matches is
-        * valid for ASCII characters under /aa, which have been excluded by
-        * the 'if' above.  The matches fall into three categories:
-        * 1) They are singly folded-to or -from an above 255 character, as
-        *    LATIN SMALL LETTER Y WITH DIAERESIS and LATIN CAPITAL LETTER Y
-        *    WITH DIAERESIS;
-        * 2) They are part of a multi-char fold with another character in the
-        *    bitmap, only LATIN SMALL LETTER SHARP S => "ss" fits that bill;
-        * 3) They are part of a multi-char fold with a character not in the
-        *    bitmap, such as various ligatures.
-        * We aren't dealing fully with multi-char folds, except we do deal
-        * with the pattern containing a character that has a multi-char fold
-        * (not so much the inverse).
-        * For types 1) and 3), the matches only happen when the target string
-        * is utf8; that's not true for 2), and we set a flag for it.
-        *
-        * The code below adds to the passed in inversion list the single fold
-        * closures for 'value'.  The values are hard-coded here so that an
-        * innocent-looking character class, like /[ks]/i won't have to go out
-        * to disk to find the possible matches.  XXX It would be better to
-        * generate these via regen, in case a new version of the Unicode
-        * standard adds new mappings, though that is not really likely. */
-       switch (value) {
-           case 'k':
-           case 'K':
-               /* KELVIN SIGN */
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr, 0x212A);
-               break;
-           case 's':
-           case 'S':
-               /* LATIN SMALL LETTER LONG S */
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr, 0x017F);
-               break;
-           case MICRO_SIGN:
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr,
-                                                GREEK_SMALL_LETTER_MU);
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr,
-                                                GREEK_CAPITAL_LETTER_MU);
-               break;
-           case LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE:
-           case LATIN_SMALL_LETTER_A_WITH_RING_ABOVE:
-               /* ANGSTROM SIGN */
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr, 0x212B);
-               if (DEPENDS_SEMANTICS) {    /* See DEPENDS comment below */
-                   *invlist_ptr = add_cp_to_invlist(*invlist_ptr,
-                                                    PL_fold_latin1[value]);
-               }
-               break;
-           case LATIN_SMALL_LETTER_Y_WITH_DIAERESIS:
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr,
-                                       LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS);
-               break;
-           case LATIN_SMALL_LETTER_SHARP_S:
-               *invlist_ptr = add_cp_to_invlist(*invlist_ptr,
-                                       LATIN_CAPITAL_LETTER_SHARP_S);
-
-               /* Under /a, /d, and /u, this can match the two chars "ss" */
-               if (! MORE_ASCII_RESTRICTED) {
-                   add_alternate(alternate_ptr, (U8 *) "ss", 2);
-
-                   /* And under /u or /a, it can match even if the target is
-                    * not utf8 */
-                   if (AT_LEAST_UNI_SEMANTICS) {
-                       ANYOF_FLAGS(node) |= ANYOF_NONBITMAP_NON_UTF8;
-                   }
-               }
-               break;
-           case 'F': case 'f':
-           case 'I': case 'i':
-           case 'L': case 'l':
-           case 'T': case 't':
-           case 'A': case 'a':
-           case 'H': case 'h':
-           case 'J': case 'j':
-           case 'N': case 'n':
-           case 'W': case 'w':
-           case 'Y': case 'y':
-                /* These all are targets of multi-character folds from code
-                 * points that require UTF8 to express, so they can't match
-                 * unless the target string is in UTF-8, so no action here is
-                 * necessary, as regexec.c properly handles the general case
-                 * for UTF-8 matching */
-               break;
-           default:
-               /* Use deprecated warning to increase the chances of this
-                * being output */
-               ckWARN2regdep(RExC_parse, "Perl folding rules are not up-to-date for 0x%x; please use the perlbug utility to report;", value);
-               break;
-       }
-    }
-    else if (DEPENDS_SEMANTICS
-           && ! isASCII(value)
-           && PL_fold_latin1[value] != value)
-    {
-          /* Under DEPENDS rules, non-ASCII Latin1 characters match their
-           * folds only when the target string is in UTF-8.  We add the fold
-           * here to the list of things to match outside the bitmap, which
-           * won't be looked at unless it is UTF8 (or else if something else
-           * says to look even if not utf8, but those things better not happen
-           * under DEPENDS semantics. */
-       *invlist_ptr = add_cp_to_invlist(*invlist_ptr, PL_fold_latin1[value]);
-    }
-
-    return stored;
-}
-
-
-PERL_STATIC_INLINE U8
-S_set_regclass_bit(pTHX_ RExC_state_t *pRExC_state, regnode* node, const U8 value, SV** invlist_ptr, AV** alternate_ptr)
-{
-    /* This inline function sets a bit in the bitmap if not already set, and if
-     * appropriate, its fold, returning the number of bits that actually
-     * changed from 0 to 1 */
-
-    U8 stored;
-
-    PERL_ARGS_ASSERT_SET_REGCLASS_BIT;
-
-    if (ANYOF_BITMAP_TEST(node, value)) {   /* Already set */
-       return 0;
-    }
-
-    ANYOF_BITMAP_SET(node, value);
-    stored = 1;
-
-    if (FOLD && ! LOC) {       /* Locale folds aren't known until runtime */
-       stored += set_regclass_bit_fold(pRExC_state, node, value, invlist_ptr, alternate_ptr);
-    }
-
-    return stored;
-}
-
 STATIC void
 S_add_alternate(pTHX_ AV** alternate_ptr, U8* string, STRLEN len)
 {
@@ -11179,6 +10978,13 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, U32 depth)
                               Optimizations may be possible if this is tiny */
     UV n;
 
+    /* Certain named classes have equivalents that can appear outside a
+     * character class, e.g. \w.  These flags are set for these classes.  The
+     * first flag indicates the op depends on the character set modifier, like
+     * /d, /u....  The second is for those that don't have this dependency. */
+    bool has_special_charset_op = FALSE;
+    bool has_special_non_charset_op = FALSE;
+
     /* Unicode properties are stored in a swash; this holds the current one
      * being parsed.  If this swash is the only above-latin1 component of the
      * character class, an optimization is to pass it directly on to the
@@ -11191,28 +10997,20 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, U32 depth)
      * on to the engine */
     UV has_user_defined_property = 0;
 
-    /* code points this node matches that can't be stored in the bitmap */
-    SV* nonbitmap = NULL;
-
-    /* The items that are to match that aren't stored in the bitmap, but are a
-     * result of things that are stored there.  This is the fold closure of
-     * such a character, either because it has DEPENDS semantics and shouldn't
-     * be matched unless the target string is utf8, or is a code point that is
-     * too large for the bit map, as for example, the fold of the MICRO SIGN is
-     * above 255.  This all is solely for performance reasons.  By having this
-     * code know the outside-the-bitmap folds that the bitmapped characters are
-     * involved with, we don't have to go out to disk to find the list of
-     * matches, unless the character class includes code points that aren't
-     * storable in the bit map.  That means that a character class with an 's'
-     * in it, for example, doesn't need to go out to disk to find everything
-     * that matches.  A 2nd list is used so that the 'nonbitmap' list is kept
-     * empty unless there is something whose fold we don't know about, and will
-     * have to go out to the disk to find. */
-    SV* l1_fold_invlist = NULL;
+    /* inversion list of code points this node matches only when the target
+     * string is in UTF-8.  (Because is under /d) */
+    SV* depends_list = NULL;
+
+    /* inversion list of code points this node matches.  For much of the
+     * function, it includes only those that match regardless of the utf8ness
+     * of the target string */
+    SV* cp_list = NULL;
 
     /* List of multi-character folds that are matched by this node */
     AV* unicode_alternate  = NULL;
 #ifdef EBCDIC
+    /* In a range, counts how many 0-2 of the ends of it came from literals,
+     * not escapes.  Thus we can tell if 'A' was input vs \x{C1} */
     UV literal_endpoint = 0;
 #endif
     UV stored = 0;  /* how many chars stored in the bitmap */
@@ -11489,22 +11287,18 @@ parseit:
                }
                break;
            case 'x':
-               if (*RExC_parse == '{') {
-                    I32 flags = PERL_SCAN_ALLOW_UNDERSCORES
-                        | PERL_SCAN_DISALLOW_PREFIX;
-                   char * const e = strchr(RExC_parse++, '}');
-                    if (!e)
-                        vFAIL("Missing right brace on \\x{}");
-
-                   numlen = e - RExC_parse;
-                   value = grok_hex(RExC_parse, &numlen, &flags, NULL);
-                   RExC_parse = e + 1;
-               }
-               else {
-                    I32 flags = PERL_SCAN_DISALLOW_PREFIX;
-                   numlen = 2;
-                   value = grok_hex(RExC_parse, &numlen, &flags, NULL);
+               RExC_parse--;   /* function expects to be pointed at the 'x' */
+               {
+                   const char* error_msg;
+                   bool valid = grok_bslash_x(RExC_parse,
+                                              &value,
+                                              &numlen,
+                                              &error_msg,
+                                              1);
                    RExC_parse += numlen;
+                   if (! valid) {
+                       vFAIL(error_msg);
+                   }
                }
                if (PL_encoding && value < 0x100)
                    goto recode_encoding;
@@ -11579,27 +11373,49 @@ parseit:
                    ckWARN4reg(RExC_parse,
                               "False [] range \"%*.*s\"",
                               w, w, rangebegin);
-
-                   stored +=
-                         set_regclass_bit(pRExC_state, ret, '-', &l1_fold_invlist, &unicode_alternate);
-                   if (prevvalue < 256) {
-                       stored +=
-                         set_regclass_bit(pRExC_state, ret, (U8) prevvalue, &l1_fold_invlist, &unicode_alternate);
-                   }
-                   else {
-                       nonbitmap = add_cp_to_invlist(nonbitmap, prevvalue);
-                   }
+                    cp_list = add_cp_to_invlist(cp_list, '-');
+                    cp_list = add_cp_to_invlist(cp_list, prevvalue);
                }
 
                range = 0; /* this was not a true range */
+                element_count += 2; /* So counts for three values */
            }
 
-           if (!SIZE_ONLY) {
+           if (SIZE_ONLY) {
+
+                /* In the first pass, do a little extra work so below can
+                 * possibly optimize the whole node to one of the nodes that
+                 * correspond to the classes given below */
+
+                /* The optimization will only take place if there is a single
+                 * element in the class, so can skip if there is more than one
+                 */
+                if (element_count == 1) {
 
                /* Possible truncation here but in some 64-bit environments
                 * the compiler gets heartburn about switch on 64-bit values.
                 * A similar issue a little earlier when switching on value.
                 * --jhi */
+                    switch ((I32)namedclass) {
+                        case ANYOF_ALNUM:
+                        case ANYOF_NALNUM:
+                        case ANYOF_DIGIT:
+                        case ANYOF_NDIGIT:
+                        case ANYOF_SPACE:
+                        case ANYOF_NSPACE:
+                            has_special_charset_op = TRUE;
+                            break;
+
+                        case ANYOF_HORIZWS:
+                        case ANYOF_NHORIZWS:
+                        case ANYOF_VERTWS:
+                        case ANYOF_NVERTWS:
+                            has_special_non_charset_op = TRUE;
+                            break;
+                    }
+                }
+            }
+            else {
                switch ((I32)namedclass) {
 
                case ANYOF_ALNUMC: /* C's alnum, in contrast to \w */
@@ -11660,10 +11476,12 @@ parseit:
                     * them */
                    DO_POSIX_LATIN1_ONLY_KNOWN_L1_RESOLVED(ret, namedclass, properties,
                         PL_PosixDigit, "XPosixDigit", listsv);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_NDIGIT:
                    DO_N_POSIX_LATIN1_ONLY_KNOWN(ret, namedclass, properties,
                         PL_PosixDigit, PL_PosixDigit, "XPosixDigit", listsv);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_GRAPH:
                    DO_POSIX_LATIN1_ONLY_KNOWN(ret, namedclass, properties,
@@ -11674,16 +11492,18 @@ parseit:
                         PL_PosixGraph, PL_L1PosixGraph, "XPosixGraph", listsv);
                    break;
                case ANYOF_HORIZWS:
-                   /* For these, we use the nonbitmap, as /d doesn't make a
+                   /* For these, we use the cp_list, as /d doesn't make a
                     * difference in what these match.  There would be problems
                     * if these characters had folds other than themselves, as
-                    * nonbitmap is subject to folding.  It turns out that \h
+                    * cp_list is subject to folding.  It turns out that \h
                     * is just a synonym for XPosixBlank */
-                   _invlist_union(nonbitmap, PL_XPosixBlank, &nonbitmap);
+                   _invlist_union(cp_list, PL_XPosixBlank, &cp_list);
+                    has_special_non_charset_op = TRUE;
                    break;
                case ANYOF_NHORIZWS:
-                    _invlist_union_complement_2nd(nonbitmap,
-                                                 PL_XPosixBlank, &nonbitmap);
+                    _invlist_union_complement_2nd(cp_list,
+                                                 PL_XPosixBlank, &cp_list);
+                    has_special_non_charset_op = TRUE;
                    break;
                case ANYOF_LOWER:
                case ANYOF_NLOWER:
@@ -11742,10 +11562,12 @@ parseit:
                case ANYOF_SPACE:
                     DO_POSIX(ret, namedclass, properties,
                                             PL_PerlSpace, PL_XPerlSpace);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_NSPACE:
                     DO_N_POSIX(ret, namedclass, properties,
                                             PL_PerlSpace, PL_XPerlSpace);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_UPPER:   /* Same as LOWER, above */
                case ANYOF_NUPPER:
@@ -11777,21 +11599,25 @@ parseit:
                case ANYOF_ALNUM:   /* Really is 'Word' */
                    DO_POSIX_LATIN1_ONLY_KNOWN(ret, namedclass, properties,
                             PL_PosixWord, PL_L1PosixWord, "XPosixWord", listsv);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_NALNUM:
                    DO_N_POSIX_LATIN1_ONLY_KNOWN(ret, namedclass, properties,
                             PL_PosixWord, PL_L1PosixWord, "XPosixWord", listsv);
+                    has_special_charset_op = TRUE;
                    break;
                case ANYOF_VERTWS:
-                   /* For these, we use the nonbitmap, as /d doesn't make a
+                   /* For these, we use the cp_list, as /d doesn't make a
                     * difference in what these match.  There would be problems
                     * if these characters had folds other than themselves, as
-                    * nonbitmap is subject to folding */
-                   _invlist_union(nonbitmap, PL_VertSpace, &nonbitmap);
+                    * cp_list is subject to folding */
+                   _invlist_union(cp_list, PL_VertSpace, &cp_list);
+                    has_special_non_charset_op = TRUE;
                    break;
                case ANYOF_NVERTWS:
-                    _invlist_union_complement_2nd(nonbitmap,
-                                                    PL_VertSpace, &nonbitmap);
+                    _invlist_union_complement_2nd(cp_list,
+                                                    PL_VertSpace, &cp_list);
+                    has_special_non_charset_op = TRUE;
                    break;
                case ANYOF_XDIGIT:
                     DO_POSIX(ret, namedclass, properties,
@@ -11838,9 +11664,8 @@ parseit:
                               "False [] range \"%*.*s\"",
                               w, w, rangebegin);
                    }
-                   if (!SIZE_ONLY)
-                       stored +=
-                            set_regclass_bit(pRExC_state, ret, '-', &l1_fold_invlist, &unicode_alternate);
+                    if (!SIZE_ONLY)
+                        cp_list = add_cp_to_invlist(cp_list, '-');
                } else
                    range = 1;  /* yeah, it's a range! */
                continue;       /* but do it the next time */
@@ -11855,118 +11680,356 @@ parseit:
 
        /* now is the next time */
        if (!SIZE_ONLY) {
-           if (prevvalue < 256) {
-               const IV ceilvalue = value < 256 ? value : 255;
-               IV i;
-#ifdef EBCDIC
-               /* In EBCDIC [\x89-\x91] should include
-                * the \x8e but [i-j] should not. */
-               if (literal_endpoint == 2 &&
-                   ((isLOWER(prevvalue) && isLOWER(ceilvalue)) ||
-                    (isUPPER(prevvalue) && isUPPER(ceilvalue))))
-               {
-                   if (isLOWER(prevvalue)) {
-                       for (i = prevvalue; i <= ceilvalue; i++)
-                           if (isLOWER(i) && !ANYOF_BITMAP_TEST(ret,i)) {
-                               stored +=
-                                  set_regclass_bit(pRExC_state, ret, (U8) i, &l1_fold_invlist, &unicode_alternate);
-                           }
-                   } else {
-                       for (i = prevvalue; i <= ceilvalue; i++)
-                           if (isUPPER(i) && !ANYOF_BITMAP_TEST(ret,i)) {
-                               stored +=
-                                  set_regclass_bit(pRExC_state, ret, (U8) i, &l1_fold_invlist, &unicode_alternate);
-                           }
-                   }
-               }
-               else
-#endif
-                     for (i = prevvalue; i <= ceilvalue; i++) {
-                       stored += set_regclass_bit(pRExC_state, ret, (U8) i, &l1_fold_invlist, &unicode_alternate);
-                     }
-         }
-         if (value > 255) {
-           const UV prevnatvalue  = NATIVE_TO_UNI(prevvalue);
-           const UV natvalue      = NATIVE_TO_UNI(value);
-           nonbitmap = _add_range_to_invlist(nonbitmap, prevnatvalue, natvalue);
-       }
-#ifdef EBCDIC
-           literal_endpoint = 0;
+#ifndef EBCDIC
+            cp_list = _add_range_to_invlist(cp_list, prevvalue, value);
+#else
+            UV* this_range = _new_invlist(1);
+            _append_range_to_invlist(this_range, prevvalue, value);
+
+            /* In EBCDIC, the ranges 'A-Z' and 'a-z' are each not contiguous.
+             * If this range was specified using something like 'i-j', we want
+             * to include only the 'i' and the 'j', and not anything in
+             * between, so exclude non-ASCII, non-alphabetics from it.
+             * However, if the range was specified with something like
+             * [\x89-\x91] or [\x89-j], all code points within it should be
+             * included.  literal_endpoint==2 means both ends of the range used
+             * a literal character, not \x{foo} */
+           if (literal_endpoint == 2
+                && (prevvalue >= 'a' && value <= 'z')
+                    || (prevvalue >= 'A' && value <= 'Z'))
+            {
+                _invlist_intersection(this_range, PL_ASCII, &this_range, );
+                _invlist_intersection(this_range, PL_Alpha, &this_range, );
+            }
+            _invlist_union(cp_list, this_range, &cp_list);
+            literal_endpoint = 0;
 #endif
         }
 
        range = 0; /* this range (if it was one) is done now */
     }
 
+    /* [\w] can be optimized into \w, but not if there is anything else in the
+     * brackets (except for an initial '^' which indictes omplementing).  We
+     * also can optimize the common special case /[0-9]/ into /\d/a */
+    if (element_count == 1 &&
+        (has_special_charset_op
+         || has_special_non_charset_op
+         || (prevvalue == '0' && value == '9')))
+    {
+        U8 op;
+        bool invert = ANYOF_FLAGS(ret) & ANYOF_INVERT;
+        const char * cur_parse = RExC_parse;
+
+        if (has_special_charset_op) {
+            U8 offset = get_regex_charset(RExC_flags);
+
+            /* /aa is the same as /a for these */
+            if (offset == REGEX_ASCII_MORE_RESTRICTED_CHARSET) {
+                offset = REGEX_ASCII_RESTRICTED_CHARSET;
+            }
+            switch ((I32)namedclass) {
+                case ANYOF_NALNUM:
+                    invert = ! invert;
+                    /* FALLTHROUGH */
+                case ANYOF_ALNUM:
+                    op = ALNUM;
+                    break;
+                case ANYOF_NSPACE:
+                    invert = ! invert;
+                    /* FALLTHROUGH */
+                case ANYOF_SPACE:
+                    op = SPACE;
+                    break;
+                case ANYOF_NDIGIT:
+                    invert = ! invert;
+                    /* FALLTHROUGH */
+                case ANYOF_DIGIT:
+                    op = DIGIT;
+
+                    /* There is no DIGITU */
+                    if (offset == REGEX_UNICODE_CHARSET) {
+                        offset = REGEX_DEPENDS_CHARSET;
+                    }
+                    break;
+                default:
+                    Perl_croak(aTHX_ "panic: Named character class %"IVdf" is not expected to have a non-[...] version", namedclass);
+            }
+
+            /* The number of varieties of each of these is the same, hence, so
+             * is the delta between the normal and complemented nodes */
+            if (invert) {
+                offset += NALNUM - ALNUM;
+            }
+
+            op += offset;
+        }
+        else if (has_special_non_charset_op) {
+            switch ((I32)namedclass) {
+                case ANYOF_NHORIZWS:
+                    invert = ! invert;
+                    /* FALLTHROUGH */
+                case ANYOF_HORIZWS:
+                    op = HORIZWS;
+                    break;
+                case ANYOF_NVERTWS:
+                    invert = ! invert;
+                    /* FALLTHROUGH */
+                case ANYOF_VERTWS:
+                    op = VERTWS;
+                    break;
+                default:
+                    Perl_croak(aTHX_ "panic: Named character class %"IVdf" is not expected to have a non-[...] version", namedclass);
+            }
+
+            /* The complement version of each of these nodes is adjacently next
+             * */
+            if (invert) {
+                op++;
+            }
+        }
+        else {  /* The remaining possibility is [0-9] */
+            op = (invert) ? NDIGITA : DIGITA;
+        }
 
+        /* Throw away this ANYOF regnode, and emit the calculated one, which
+         * should correspond to the beginning, not current, state of the parse
+         */
+        RExC_parse = (char *)orig_parse;
+        RExC_emit = (regnode *)orig_emit;
+        ret = reg_node(pRExC_state, op);
+        RExC_parse = (char *) cur_parse;
+
+        SvREFCNT_dec(listsv);
+        return ret;
+    }
 
     if (SIZE_ONLY)
         return ret;
     /****** !SIZE_ONLY AFTER HERE *********/
 
-    /* If folding and there are code points above 255, we calculate all
-     * characters that could fold to or from the ones already on the list */
-    if (FOLD && nonbitmap) {
+    /* If folding, we calculate all characters that could fold to or from the
+     * ones already on the list */
+    if (FOLD && cp_list) {
        UV start, end;  /* End points of code point ranges */
 
        SV* fold_intersection = NULL;
 
-       /* This is a list of all the characters that participate in folds
-           * (except marks, etc in multi-char folds */
-       if (! PL_utf8_foldable) {
-           SV* swash = swash_init("utf8", "Cased", &PL_sv_undef, 1, 0);
-           PL_utf8_foldable = _swash_to_invlist(swash);
-            SvREFCNT_dec(swash);
-       }
+        const UV highest_index = invlist_len(cp_list) - 1;
+
+        /* In the Latin1 range, the characters that can be folded-to or -from
+         * are precisely the alphabetic characters.  If the highest code point
+         * is within Latin1, we can use the compiled-in list, and not have to
+         * go out to disk.  If the last element in the array is in the
+         * inversion list set, it starts a range that goes to infinity, so the
+         * maximum of the inversion list is definitely above Latin1.
+         * Otherwise, it starts a range that isn't in the set, so the max is
+         * one less than it */
+        if (! ELEMENT_RANGE_MATCHES_INVLIST(highest_index)
+            && invlist_array(cp_list)[highest_index] <= 256)
+        {
+            _invlist_intersection(PL_L1PosixAlpha, cp_list, &fold_intersection);
+        }
+        else {
 
-       /* This is a hash that for a particular fold gives all characters
-           * that are involved in it */
-       if (! PL_utf8_foldclosures) {
+            /* This is a list of all the characters that participate in folds
+             * (except marks, etc in multi-char folds */
+            if (! PL_utf8_foldable) {
+                SV* swash = swash_init("utf8", "Cased", &PL_sv_undef, 1, 0);
+                PL_utf8_foldable = _swash_to_invlist(swash);
+                SvREFCNT_dec(swash);
+            }
 
-           /* If we were unable to find any folds, then we likely won't be
-            * able to find the closures.  So just create an empty list.
-            * Folding will effectively be restricted to the non-Unicode rules
-            * hard-coded into Perl.  (This case happens legitimately during
-            * compilation of Perl itself before the Unicode tables are
-            * generated) */
-           if (invlist_len(PL_utf8_foldable) == 0) {
-               PL_utf8_foldclosures = newHV();
-           } else {
-               /* If the folds haven't been read in, call a fold function
-                   * to force that */
-               if (! PL_utf8_tofold) {
-                   U8 dummy[UTF8_MAXBYTES+1];
-                   STRLEN dummy_len;
-
-                   /* This particular string is above \xff in both UTF-8 and
-                    * UTFEBCDIC */
-                   to_utf8_fold((U8*) "\xC8\x80", dummy, &dummy_len);
-                   assert(PL_utf8_tofold); /* Verify that worked */
-               }
-               PL_utf8_foldclosures = _swash_inversion_hash(PL_utf8_tofold);
-           }
-       }
+            /* This is a hash that for a particular fold gives all characters
+             * that are involved in it */
+            if (! PL_utf8_foldclosures) {
+
+                /* If we were unable to find any folds, then we likely won't be
+                 * able to find the closures.  So just create an empty list.
+                 * Folding will effectively be restricted to the non-Unicode
+                 * rules hard-coded into Perl.  (This case happens legitimately
+                 * during compilation of Perl itself before the Unicode tables
+                 * are generated) */
+                if (invlist_len(PL_utf8_foldable) == 0) {
+                    PL_utf8_foldclosures = newHV();
+                }
+                else {
+                    /* If the folds haven't been read in, call a fold function
+                     * to force that */
+                    if (! PL_utf8_tofold) {
+                        U8 dummy[UTF8_MAXBYTES+1];
+                        STRLEN dummy_len;
+
+                        /* This particular string is above \xff in both UTF-8
+                         * and UTFEBCDIC */
+                        to_utf8_fold((U8*) "\xC8\x80", dummy, &dummy_len);
+                        assert(PL_utf8_tofold); /* Verify that worked */
+                    }
+                    PL_utf8_foldclosures =
+                                        _swash_inversion_hash(PL_utf8_tofold);
+                }
+            }
 
-       /* Only the characters in this class that participate in folds need be
-        * checked.  Get the intersection of this class and all the possible
-        * characters that are foldable.  This can quickly narrow down a large
-        * class */
-       _invlist_intersection(PL_utf8_foldable, nonbitmap, &fold_intersection);
+            /* Only the characters in this class that participate in folds need
+             * be checked.  Get the intersection of this class and all the
+             * possible characters that are foldable.  This can quickly narrow
+             * down a large class */
+            _invlist_intersection(PL_utf8_foldable, cp_list,
+                                  &fold_intersection);
+        }
 
        /* Now look at the foldable characters in this class individually */
        invlist_iterinit(fold_intersection);
        while (invlist_iternext(fold_intersection, &start, &end)) {
            UV j;
 
+            /* Locale folding for Latin1 characters is deferred until runtime */
+            if (LOC && start < 256) {
+                start = 256;
+            }
+
            /* Look at every character in the range */
            for (j = start; j <= end; j++) {
 
-               /* Get its fold */
                U8 foldbuf[UTF8_MAXBYTES_CASE+1];
                STRLEN foldlen;
-               const UV f =
-                    _to_uni_fold_flags(j, foldbuf, &foldlen,
-                                       (allow_full_fold) ? FOLD_FLAGS_FULL : 0);
+                UV f;
+
+                if (j < 256) {
+
+                    /* We have the latin1 folding rules hard-coded here so that
+                     * an innocent-looking character class, like /[ks]/i won't
+                     * have to go out to disk to find the possible matches.
+                     * XXX It would be better to generate these via regen, in
+                     * case a new version of the Unicode standard adds new
+                     * mappings, though that is not really likely, and may be
+                     * caught by the default: case of the switch below. */
+
+                    if (PL_fold_latin1[j] != j) {
+
+                        /* ASCII is always matched; non-ASCII is matched only
+                         * under Unicode rules */
+                        if (isASCII(j) || AT_LEAST_UNI_SEMANTICS) {
+                            cp_list =
+                                add_cp_to_invlist(cp_list, PL_fold_latin1[j]);
+                        }
+                        else {
+                            depends_list =
+                                add_cp_to_invlist(depends_list, PL_fold_latin1[j]);
+                        }
+                    }
+
+                    if (HAS_NONLATIN1_FOLD_CLOSURE(j)
+                        && (! isASCII(j) || ! MORE_ASCII_RESTRICTED))
+                    {
+                        /* Certain Latin1 characters have matches outside
+                         * Latin1, or are multi-character.  To get here, 'j' is
+                         * one of those characters.   None of these matches is
+                         * valid for ASCII characters under /aa, which is why
+                         * the 'if' just above excludes those.  The matches
+                         * fall into three categories:
+                         * 1) They are singly folded-to or -from an above 255
+                         *    character, e.g., LATIN SMALL LETTER Y WITH
+                         *    DIAERESIS and LATIN CAPITAL LETTER Y WITH
+                         *    DIAERESIS;
+                         * 2) They are part of a multi-char fold with another
+                         *    latin1 character; only LATIN SMALL LETTER
+                         *    SHARP S => "ss" fits this;
+                         * 3) They are part of a multi-char fold with a
+                         *    character outside of Latin1, such as various
+                         *    ligatures.
+                        * We aren't dealing fully with multi-char folds, except
+                        * we do deal with the pattern containing a character
+                        * that has a multi-char fold (not so much the inverse).
+                        * For types 1) and 3), the matches only happen when the
+                        * target string is utf8; that's not true for 2), and we
+                        * set a flag for it.
+                        *
+                        * The code below adds the single fold closures for 'j'
+                        * to the inversion list. */
+                        switch (j) {
+                            case 'k':
+                            case 'K':
+                                /* KELVIN SIGN */
+                                cp_list =
+                                    add_cp_to_invlist(cp_list, 0x212A);
+                                break;
+                            case 's':
+                            case 'S':
+                                /* LATIN SMALL LETTER LONG S */
+                                cp_list =
+                                    add_cp_to_invlist(cp_list, 0x017F);
+                                break;
+                            case MICRO_SIGN:
+                                cp_list = add_cp_to_invlist(cp_list,
+                                                    GREEK_SMALL_LETTER_MU);
+                                cp_list = add_cp_to_invlist(cp_list,
+                                                    GREEK_CAPITAL_LETTER_MU);
+                                break;
+                            case LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE:
+                            case LATIN_SMALL_LETTER_A_WITH_RING_ABOVE:
+                                /* ANGSTROM SIGN */
+                                cp_list =
+                                        add_cp_to_invlist(cp_list, 0x212B);
+                                break;
+                            case LATIN_SMALL_LETTER_Y_WITH_DIAERESIS:
+                                cp_list = add_cp_to_invlist(cp_list,
+                                        LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS);
+                                break;
+                            case LATIN_SMALL_LETTER_SHARP_S:
+                                cp_list = add_cp_to_invlist(cp_list,
+                                                LATIN_CAPITAL_LETTER_SHARP_S);
+
+                                /* Under /a, /d, and /u, this can match the two
+                                 * chars "ss" */
+                                if (! MORE_ASCII_RESTRICTED) {
+                                    add_alternate(&unicode_alternate,
+                                                  (U8 *) "ss", 2);
+
+                                    /* And under /u or /a, it can match even if
+                                     * the target is not utf8 */
+                                    if (AT_LEAST_UNI_SEMANTICS) {
+                                        ANYOF_FLAGS(ret) |=
+                                                    ANYOF_NONBITMAP_NON_UTF8;
+                                    }
+                                }
+                                break;
+                            case 'F': case 'f':
+                            case 'I': case 'i':
+                            case 'L': case 'l':
+                            case 'T': case 't':
+                            case 'A': case 'a':
+                            case 'H': case 'h':
+                            case 'J': case 'j':
+                            case 'N': case 'n':
+                            case 'W': case 'w':
+                            case 'Y': case 'y':
+                                /* These all are targets of multi-character
+                                 * folds from code points that require UTF8 to
+                                 * express, so they can't match unless the
+                                 * target string is in UTF-8, so no action here
+                                 * is necessary, as regexec.c properly handles
+                                 * the general case for UTF-8 matching */
+                                break;
+                            default:
+                                /* Use deprecated warning to increase the
+                                 * chances of this being output */
+                                ckWARN2regdep(RExC_parse, "Perl folding rules are not up-to-date for 0x%"UVXf"; please use the perlbug utility to report;", j);
+                                break;
+                        }
+                    }
+                    continue;
+                }
+
+                /* Here is an above Latin1 character.  We don't have the rules
+                 * hard-coded for it.  First, get its fold */
+               f = _to_uni_fold_flags(j, foldbuf, &foldlen,
+                                    ((allow_full_fold) ? FOLD_FLAGS_FULL : 0)
+                                    | ((LOC)
+                                        ? FOLD_FLAGS_LOCALE
+                                        : (MORE_ASCII_RESTRICTED)
+                                            ? FOLD_FLAGS_NOMIX_ASCII
+                                            : 0));
 
                if (foldlen > (STRLEN)UNISKIP(f)) {
 
@@ -11982,54 +12045,25 @@ parseit:
 
                        /* If any of the folded characters of this are in the
                         * Latin1 range, tell the regex engine that this can
-                        * match a non-utf8 target string.  The only multi-byte
-                        * fold whose source is in the Latin1 range (U+00DF)
-                        * applies only when the target string is utf8, or
-                        * under unicode rules */
-                       if (j > 255 || AT_LEAST_UNI_SEMANTICS) {
-                           while (loc < e) {
-
-                               /* Can't mix ascii with non- under /aa */
-                               if (MORE_ASCII_RESTRICTED
-                                   && (isASCII(*loc) != isASCII(j)))
-                               {
-                                   goto end_multi_fold;
-                               }
-                               if (UTF8_IS_INVARIANT(*loc)
-                                   || UTF8_IS_DOWNGRADEABLE_START(*loc))
-                               {
-                                    /* Can't mix above and below 256 under LOC
-                                     */
-                                   if (LOC) {
-                                       goto end_multi_fold;
-                                   }
-                                   ANYOF_FLAGS(ret)
-                                           |= ANYOF_NONBITMAP_NON_UTF8;
-                                   break;
-                               }
-                               loc += UTF8SKIP(loc);
-                           }
-                       }
+                        * match a non-utf8 target string.  */
+                        while (loc < e) {
+                            if (UTF8_IS_INVARIANT(*loc)
+                                || UTF8_IS_DOWNGRADEABLE_START(*loc))
+                            {
+                                ANYOF_FLAGS(ret)
+                                        |= ANYOF_NONBITMAP_NON_UTF8;
+                                break;
+                            }
+                            loc += UTF8SKIP(loc);
+                        }
 
                        add_alternate(&unicode_alternate, foldbuf, foldlen);
-                   end_multi_fold: ;
-                   }
-
-                   /* This is special-cased, as it is the only letter which
-                    * has both a multi-fold and single-fold in Latin1.  All
-                    * the other chars that have single and multi-folds are
-                    * always in utf8, and the utf8 folding algorithm catches
-                    * them */
-                   if (! LOC && j == LATIN_CAPITAL_LETTER_SHARP_S) {
-                       stored += set_regclass_bit(pRExC_state,
-                                       ret,
-                                       LATIN_SMALL_LETTER_SHARP_S,
-                                       &l1_fold_invlist, &unicode_alternate);
                    }
                }
-               else {
-                   /* Single character fold.  Add everything in its fold
-                    * closure to the list that this node should match */
+                else {
+                    /* Single character fold of above Latin1.  Add everything
+                     * in its fold closure to the list that this node should
+                     * match */
                    SV** listp;
 
                    /* The fold closures data structure is a hash with the keys
@@ -12052,90 +12086,129 @@ parseit:
                            /* /aa doesn't allow folds between ASCII and non-;
                             * /l doesn't allow them between above and below
                             * 256 */
-                           if ((MORE_ASCII_RESTRICTED
-                                && (isASCII(c) != isASCII(j)))
-                                   || (LOC && ((c < 256) != (j < 256))))
+                           if ((MORE_ASCII_RESTRICTED && (isASCII(c) != isASCII(j)))
+                               || (LOC && ((c < 256) != (j < 256))))
                            {
                                continue;
                            }
 
-                           if (c < 256 && AT_LEAST_UNI_SEMANTICS) {
-                               stored += set_regclass_bit(pRExC_state,
-                                       ret,
-                                       (U8) c,
-                                       &l1_fold_invlist, &unicode_alternate);
-                           }
-                               /* It may be that the code point is already in
-                                * this range or already in the bitmap, in
-                                * which case we need do nothing */
-                           else if ((c < start || c > end)
-                                       && (c > 255
-                                           || ! ANYOF_BITMAP_TEST(ret, c)))
-                           {
-                               nonbitmap = add_cp_to_invlist(nonbitmap, c);
+                            /* Folds involving non-ascii Latin1 characters
+                             * under /d are added to a separate list */
+                           if (isASCII(c) || c > 255 || AT_LEAST_UNI_SEMANTICS)
+                            {
+                               cp_list = add_cp_to_invlist(cp_list, c);
+                            }
+                            else {
+                                depends_list = add_cp_to_invlist(depends_list, c);
                            }
                        }
                    }
                }
-           }
+            }
        }
        SvREFCNT_dec(fold_intersection);
     }
 
-    /* Combine the two lists into one. */
-    if (l1_fold_invlist) {
-       if (nonbitmap) {
-           _invlist_union(nonbitmap, l1_fold_invlist, &nonbitmap);
-           SvREFCNT_dec(l1_fold_invlist);
-       }
-       else {
-           nonbitmap = l1_fold_invlist;
-       }
-    }
-
     /* And combine the result (if any) with any inversion list from properties.
      * The lists are kept separate up to now because we don't want to fold the
      * properties */
     if (properties) {
-       if (nonbitmap) {
-           _invlist_union(nonbitmap, properties, &nonbitmap);
-           SvREFCNT_dec(properties);
-       }
-       else {
-           nonbitmap = properties;
-       }
+        if (AT_LEAST_UNI_SEMANTICS) {
+            if (cp_list) {
+                _invlist_union(cp_list, properties, &cp_list);
+                SvREFCNT_dec(properties);
+            }
+            else {
+                cp_list = properties;
+            }
+        }
+        else {
+
+            /* Under /d, we put the things that match only when the target
+             * string is utf8, into a separate list */
+            SV* nonascii_but_latin1_properties = NULL;
+            _invlist_intersection(properties, PL_Latin1,
+                                  &nonascii_but_latin1_properties);
+            _invlist_subtract(nonascii_but_latin1_properties, PL_ASCII,
+                              &nonascii_but_latin1_properties);
+            _invlist_subtract(properties, nonascii_but_latin1_properties,
+                              &properties);
+            if (cp_list) {
+                _invlist_union(cp_list, properties, &cp_list);
+                SvREFCNT_dec(properties);
+            }
+            else {
+                cp_list = properties;
+            }
+
+            if (depends_list) {
+                _invlist_union(depends_list, nonascii_but_latin1_properties,
+                               &depends_list);
+                SvREFCNT_dec(nonascii_but_latin1_properties);
+            }
+            else {
+                depends_list = nonascii_but_latin1_properties;
+            }
+        }
     }
 
-    /* Here, <nonbitmap> contains all the code points we can determine at
-     * compile time that we haven't put into the bitmap.  Go through it, and
-     * for things that belong in the bitmap, put them there, and delete from
-     * <nonbitmap> */
-    if (nonbitmap) {
+    /* Here, we have calculated what code points should be in the character
+     * class.
+     *
+     * Now we can see about various optimizations.  Fold calculation (which we
+     * did above) needs to take place before inversion.  Otherwise /[^k]/i
+     * would invert to include K, which under /i would match k, which it
+     * shouldn't. */
 
-       /* Above-ASCII code points in /d have to stay in <nonbitmap>, as they
-        * possibly only should match when the target string is UTF-8 */
-       UV max_cp_to_set = (DEPENDS_SEMANTICS) ? 127 : 255;
+    /* Optimize inverted simple patterns (e.g. [^a-z]).  Note that we haven't
+     * set the FOLD flag yet, so this does optimize those.  It doesn't
+     * optimize locale.  Doing so perhaps could be done as long as there is
+     * nothing like \w in it; some thought also would have to be given to the
+     * interaction with above 0x100 chars */
+    if ((ANYOF_FLAGS(ret) & ANYOF_INVERT)
+        && ! LOC
+       && ! depends_list
+       && ! unicode_alternate
+       && SvCUR(listsv) == initial_listsv_len)
+    {
+        _invlist_invert(cp_list);
+
+        /* Any swash can't be used as-is, because we've inverted things */
+        if (swash) {
+            SvREFCNT_dec(swash);
+            swash = NULL;
+        }
+
+       /* Clear the invert flag since have just done it here */
+       ANYOF_FLAGS(ret) &= ~ANYOF_INVERT;
+    }
+
+    /* Here, <cp_list> contains all the code points we can determine at
+     * compile time that match under all conditions.  Go through it, and
+     * for things that belong in the bitmap, put them there, and delete from
+     * <cp_list> */
+    if (cp_list) {
 
        /* This gets set if we actually need to modify things */
        bool change_invlist = FALSE;
 
        UV start, end;
 
-       /* Start looking through <nonbitmap> */
-       invlist_iterinit(nonbitmap);
-       while (invlist_iternext(nonbitmap, &start, &end)) {
+       /* Start looking through <cp_list> */
+       invlist_iterinit(cp_list);
+       while (invlist_iternext(cp_list, &start, &end)) {
            UV high;
            int i;
 
            /* Quit if are above what we should change */
-           if (start > max_cp_to_set) {
+           if (start > 255) {
                break;
            }
 
            change_invlist = TRUE;
 
            /* Set all the bits in the range, up to the max that we are doing */
-           high = (end < max_cp_to_set) ? end : max_cp_to_set;
+           high = (end < 255) ? end : 255;
            for (i = start; i <= (int) high; i++) {
                if (! ANYOF_BITMAP_TEST(ret, i)) {
                    ANYOF_BITMAP_SET(ret, i);
@@ -12147,140 +12220,27 @@ parseit:
        }
 
         /* Done with loop; remove any code points that are in the bitmap from
-         * <nonbitmap> */
+         * <cp_list> */
        if (change_invlist) {
-           _invlist_subtract(nonbitmap,
-                             (DEPENDS_SEMANTICS)
-                               ? PL_ASCII
-                               : PL_Latin1,
-                              &nonbitmap);
+           _invlist_subtract(cp_list, PL_Latin1, &cp_list);
        }
 
        /* If have completely emptied it, remove it completely */
-       if (invlist_len(nonbitmap) == 0) {
-           SvREFCNT_dec(nonbitmap);
-           nonbitmap = NULL;
+       if (invlist_len(cp_list) == 0) {
+           SvREFCNT_dec(cp_list);
+           cp_list = NULL;
        }
     }
 
-    /* Here, we have calculated what code points should be in the character
-     * class.  <nonbitmap> does not overlap the bitmap except possibly in the
-     * case of DEPENDS rules.
-     *
-     * Now we can see about various optimizations.  Fold calculation (which we
-     * did above) needs to take place before inversion.  Otherwise /[^k]/i
-     * would invert to include K, which under /i would match k, which it
-     * shouldn't. */
-
-    /* Optimize inverted simple patterns (e.g. [^a-z]).  Note that we haven't
-     * set the FOLD flag yet, so this does optimize those.  It doesn't
-     * optimize locale.  Doing so perhaps could be done as long as there is
-     * nothing like \w in it; some thought also would have to be given to the
-     * interaction with above 0x100 chars */
-    if ((ANYOF_FLAGS(ret) & ANYOF_INVERT)
-        && ! LOC
-       && ! unicode_alternate
-       /* In case of /d, there are some things that should match only when in
-        * not in the bitmap, i.e., they require UTF8 to match.  These are
-        * listed in nonbitmap, but if ANYOF_NONBITMAP_NON_UTF8 is set in this
-        * case, they don't require UTF8, so can invert here */
-       && (! nonbitmap
-           || ! DEPENDS_SEMANTICS
-           || (ANYOF_FLAGS(ret) & ANYOF_NONBITMAP_NON_UTF8))
-       && SvCUR(listsv) == initial_listsv_len)
-    {
-       int i;
-       if (! nonbitmap) {
-           for (i = 0; i < 256; ++i) {
-               if (ANYOF_BITMAP_TEST(ret, i)) {
-                   ANYOF_BITMAP_CLEAR(ret, i);
-               }
-               else {
-                   ANYOF_BITMAP_SET(ret, i);
-                   prevvalue = value;
-                   value = i;
-               }
-           }
-           /* The inversion means that everything above 255 is matched */
-           ANYOF_FLAGS(ret) |= ANYOF_UNICODE_ALL;
+    /* Combine the two lists into one. */
+    if (depends_list) {
+       if (cp_list) {
+           _invlist_union(cp_list, depends_list, &cp_list);
+           SvREFCNT_dec(depends_list);
        }
        else {
-           /* Here, also has things outside the bitmap that may overlap with
-            * the bitmap.  We have to sync them up, so that they get inverted
-            * in both places.  Earlier, we removed all overlaps except in the
-            * case of /d rules, so no syncing is needed except for this case
-            */
-           SV *remove_list = NULL;
-
-           if (DEPENDS_SEMANTICS) {
-               UV start, end;
-
-               /* Set the bits that correspond to the ones that aren't in the
-                * bitmap.  Otherwise, when we invert, we'll miss these.
-                * Earlier, we removed from the nonbitmap all code points
-                * < 128, so there is no extra work here */
-               invlist_iterinit(nonbitmap);
-               while (invlist_iternext(nonbitmap, &start, &end)) {
-                   if (start > 255) {  /* The bit map goes to 255 */
-                       break;
-                   }
-                   if (end > 255) {
-                       end = 255;
-                   }
-                   for (i = start; i <= (int) end; ++i) {
-                       ANYOF_BITMAP_SET(ret, i);
-                       prevvalue = value;
-                       value = i;
-                   }
-               }
-           }
-
-           /* Now invert both the bitmap and the nonbitmap.  Anything in the
-            * bitmap has to also be removed from the non-bitmap, but again,
-            * there should not be overlap unless is /d rules. */
-           _invlist_invert(nonbitmap);
-
-           /* Any swash can't be used as-is, because we've inverted things */
-           if (swash) {
-               SvREFCNT_dec(swash);
-               swash = NULL;
-           }
-
-           for (i = 0; i < 256; ++i) {
-               if (ANYOF_BITMAP_TEST(ret, i)) {
-                   ANYOF_BITMAP_CLEAR(ret, i);
-                   if (DEPENDS_SEMANTICS) {
-                       if (! remove_list) {
-                           remove_list = _new_invlist(2);
-                       }
-                       remove_list = add_cp_to_invlist(remove_list, i);
-                   }
-               }
-               else {
-                   ANYOF_BITMAP_SET(ret, i);
-                   prevvalue = value;
-                   value = i;
-               }
-           }
-
-           /* And do the removal */
-           if (DEPENDS_SEMANTICS) {
-               if (remove_list) {
-                   _invlist_subtract(nonbitmap, remove_list, &nonbitmap);
-                   SvREFCNT_dec(remove_list);
-               }
-           }
-           else {
-               /* There is no overlap for non-/d, so just delete anything
-                * below 256 */
-               _invlist_intersection(nonbitmap, PL_AboveLatin1, &nonbitmap);
-           }
+           cp_list = depends_list;
        }
-
-       stored = 256 - stored;
-
-       /* Clear the invert flag since have just done it here */
-       ANYOF_FLAGS(ret) &= ~ANYOF_INVERT;
     }
 
     /* Folding in the bitmap is taken care of above, but not for locale (for
@@ -12290,7 +12250,7 @@ parseit:
      * run-time fold flag for these */
     if (FOLD && (LOC
                || (DEPENDS_SEMANTICS
-                   && nonbitmap
+                   && cp_list
                    && ! (ANYOF_FLAGS(ret) & ANYOF_NONBITMAP_NON_UTF8))
                || unicode_alternate))
     {
@@ -12311,7 +12271,7 @@ parseit:
      * characters which only have the two folds; so things like 'fF' and 'Ii'
      * wouldn't work because they are part of the fold of 'LATIN SMALL LIGATURE
      * FI'. */
-    if (! nonbitmap
+    if (! cp_list
        && ! unicode_alternate
        && SvCUR(listsv) == initial_listsv_len
        && ! (ANYOF_FLAGS(ret) & (ANYOF_INVERT|ANYOF_UNICODE_ALL))
@@ -12398,7 +12358,7 @@ parseit:
        SvREFCNT_dec(swash);
        swash = NULL;
     }
-    if (! nonbitmap
+    if (! cp_list
        && SvCUR(listsv) == initial_listsv_len
        && ! unicode_alternate)
     {
@@ -12415,7 +12375,7 @@ parseit:
         *       swash is stored there now.
         * av[2] stores the multicharacter foldings, used later in
         *       regexec.c:S_reginclass().
-        * av[3] stores the nonbitmap inversion list for use in addition or
+        * av[3] stores the cp_list inversion list for use in addition or
         *       instead of av[0]; not used if av[1] isn't NULL
         * av[4] is set if any component of the class is from a user-defined
         *       property; not used if av[1] isn't NULL */
@@ -12427,12 +12387,12 @@ parseit:
                        : listsv);
        if (swash) {
            av_store(av, 1, swash);
-           SvREFCNT_dec(nonbitmap);
+           SvREFCNT_dec(cp_list);
        }
        else {
            av_store(av, 1, NULL);
-           if (nonbitmap) {
-               av_store(av, 3, nonbitmap);
+           if (cp_list) {
+               av_store(av, 3, cp_list);
                av_store(av, 4, newSVuv(has_user_defined_property));
            }
        }
@@ -13448,7 +13408,6 @@ Perl_reg_temp_copy (pTHX_ REGEXP *ret_x, REGEXP *rx)
 {
     struct regexp *ret;
     struct regexp *const r = (struct regexp *)SvANY(rx);
-    register const I32 npar = r->nparens+1;
 
     PERL_ARGS_ASSERT_REG_TEMP_COPY;
 
@@ -13468,8 +13427,11 @@ Perl_reg_temp_copy (pTHX_ REGEXP *ret_x, REGEXP *rx)
     SvLEN_set(ret_x, 0);
     SvSTASH_set(ret_x, NULL);
     SvMAGIC_set(ret_x, NULL);
-    Newx(ret->offs, npar, regexp_paren_pair);
-    Copy(r->offs, ret->offs, npar, regexp_paren_pair);
+    if (r->offs) {
+        const I32 npar = r->nparens+1;
+        Newx(ret->offs, npar, regexp_paren_pair);
+        Copy(r->offs, ret->offs, npar, regexp_paren_pair);
+    }
     if (r->substrs) {
         Newx(ret->substrs, 1, struct reg_substr_data);
        StructCopy(r->substrs, ret->substrs, struct reg_substr_data);
@@ -13911,8 +13873,6 @@ Perl_save_re_context(pTHX)
 
     Copy(&PL_reg_state, state, 1, struct re_save_state);
 
-    PL_reg_start_tmp = 0;
-    PL_reg_start_tmpl = 0;
     PL_reg_oldsaved = NULL;
     PL_reg_oldsavedlen = 0;
     PL_reg_maxiter = 0;