This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
locale.c: Remove vars unused on some platforms
[perl5.git] / regcomp.c
index 97a5490..a82171a 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -159,7 +159,8 @@ struct RExC_state_t {
                                            within pattern */
     int                num_code_blocks;        /* size of code_blocks[] */
     int                code_index;             /* next code_blocks[] slot */
-#if ADD_TO_REGEXEC
+    SSize_t     maxlen;                        /* mininum possible number of chars in string to match */
+#ifdef ADD_TO_REGEXEC
     char       *starttry;              /* -Dr: where regtry was called. */
 #define RExC_starttry  (pRExC_state->starttry)
 #endif
@@ -196,6 +197,7 @@ struct RExC_state_t {
 #define RExC_sawback   (pRExC_state->sawback)
 #define RExC_seen      (pRExC_state->seen)
 #define RExC_size      (pRExC_state->size)
+#define RExC_maxlen        (pRExC_state->maxlen)
 #define RExC_npar      (pRExC_state->npar)
 #define RExC_nestroot   (pRExC_state->nestroot)
 #define RExC_extralen  (pRExC_state->extralen)
@@ -741,38 +743,41 @@ static const scan_data_t zero_scan_data =
         DEBUG_OPTIMISE_MORE_r({                                             \
             PerlIO_printf(Perl_debug_log,"RExC_seen: ");                    \
                                                                             \
-            if (RExC_seen & REG_SEEN_ZERO_LEN)                              \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_ZERO_LEN ");         \
+            if (RExC_seen & REG_ZERO_LEN_SEEN)                              \
+                PerlIO_printf(Perl_debug_log,"REG_ZERO_LEN_SEEN ");         \
                                                                             \
-            if (RExC_seen & REG_SEEN_LOOKBEHIND)                            \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_LOOKBEHIND ");       \
+            if (RExC_seen & REG_LOOKBEHIND_SEEN)                            \
+                PerlIO_printf(Perl_debug_log,"REG_LOOKBEHIND_SEEN ");       \
                                                                             \
-            if (RExC_seen & REG_SEEN_GPOS)                                  \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_GPOS ");             \
+            if (RExC_seen & REG_GPOS_SEEN)                                  \
+                PerlIO_printf(Perl_debug_log,"REG_GPOS_SEEN ");             \
                                                                             \
-            if (RExC_seen & REG_SEEN_CANY)                                  \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_CANY ");             \
+            if (RExC_seen & REG_CANY_SEEN)                                  \
+                PerlIO_printf(Perl_debug_log,"REG_CANY_SEEN ");             \
                                                                             \
-            if (RExC_seen & REG_SEEN_RECURSE)                               \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_RECURSE ");          \
+            if (RExC_seen & REG_RECURSE_SEEN)                               \
+                PerlIO_printf(Perl_debug_log,"REG_RECURSE_SEEN ");          \
                                                                             \
-            if (RExC_seen & REG_TOP_LEVEL_BRANCHES)                         \
-                PerlIO_printf(Perl_debug_log,"REG_TOP_LEVEL_BRANCHES ");    \
+            if (RExC_seen & REG_TOP_LEVEL_BRANCHES_SEEN)                         \
+                PerlIO_printf(Perl_debug_log,"REG_TOP_LEVEL_BRANCHES_SEEN ");    \
                                                                             \
-            if (RExC_seen & REG_SEEN_VERBARG)                               \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_VERBARG ");          \
+            if (RExC_seen & REG_VERBARG_SEEN)                               \
+                PerlIO_printf(Perl_debug_log,"REG_VERBARG_SEEN ");          \
                                                                             \
-            if (RExC_seen & REG_SEEN_CUTGROUP)                              \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_CUTGROUP ");         \
+            if (RExC_seen & REG_CUTGROUP_SEEN)                              \
+                PerlIO_printf(Perl_debug_log,"REG_CUTGROUP_SEEN ");         \
                                                                             \
-            if (RExC_seen & REG_SEEN_RUN_ON_COMMENT)                        \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_RUN_ON_COMMENT ");   \
+            if (RExC_seen & REG_RUN_ON_COMMENT_SEEN)                        \
+                PerlIO_printf(Perl_debug_log,"REG_RUN_ON_COMMENT_SEEN ");   \
                                                                             \
-            if (RExC_seen & REG_SEEN_EXACTF_SHARP_S)                        \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_EXACTF_SHARP_S ");   \
+            if (RExC_seen & REG_UNFOLDED_MULTI_SEEN)                        \
+                PerlIO_printf(Perl_debug_log,"REG_UNFOLDED_MULTI_SEEN ");   \
                                                                             \
-            if (RExC_seen & REG_SEEN_GOSTART)                               \
-                PerlIO_printf(Perl_debug_log,"REG_SEEN_GOSTART ");          \
+            if (RExC_seen & REG_GOSTART_SEEN)                               \
+                PerlIO_printf(Perl_debug_log,"REG_GOSTART_SEEN ");          \
+                                                                            \
+            if (RExC_seen & REG_UNBOUNDED_QUANTIFIER_SEEN)                               \
+                PerlIO_printf(Perl_debug_log,"REG_UNBOUNDED_QUANTIFIER_SEEN ");          \
                                                                             \
             PerlIO_printf(Perl_debug_log,"\n");                             \
         });
@@ -954,9 +959,6 @@ S_ssc_init(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc)
     if (RExC_contains_locale) {
        ANYOF_POSIXL_SETALL(ssc);
        ANYOF_FLAGS(ssc) |= ANYOF_LOCALE|ANYOF_POSIXL;
-        if (RExC_contains_i) {
-            ANYOF_FLAGS(ssc) |= ANYOF_LOC_FOLD;
-        }
     }
     else {
        ANYOF_POSIXL_ZERO(ssc);
@@ -989,16 +991,12 @@ S_ssc_is_cp_posixl_init(pTHX_ const RExC_state_t *pRExC_state,
         return FALSE;
     }
 
-    if (RExC_contains_locale) {
-        if (! (ANYOF_FLAGS(ssc) & ANYOF_LOCALE)
-            || ! (ANYOF_FLAGS(ssc) & ANYOF_POSIXL)
-            || ! ANYOF_POSIXL_TEST_ALL_SET(ssc))
-        {
-            return FALSE;
-        }
-        if (RExC_contains_i && ! (ANYOF_FLAGS(ssc) & ANYOF_LOC_FOLD)) {
-            return FALSE;
-        }
+    if (RExC_contains_locale
+        && ! ((ANYOF_FLAGS(ssc) & ANYOF_LOCALE)
+               || ! (ANYOF_FLAGS(ssc) & ANYOF_POSIXL)
+               || ! ANYOF_POSIXL_TEST_ALL_SET(ssc)))
+    {
+        return FALSE;
     }
 
     return TRUE;
@@ -1006,16 +1004,18 @@ S_ssc_is_cp_posixl_init(pTHX_ const RExC_state_t *pRExC_state,
 
 STATIC SV*
 S_get_ANYOF_cp_list_for_ssc(pTHX_ const RExC_state_t *pRExC_state,
-                                  const regnode_charclass_posixl* const node)
+                               const regnode_charclass_posixl_fold* const node)
 {
     /* Returns a mortal inversion list defining which code points are matched
      * by 'node', which is of type ANYOF.  Handles complementing the result if
      * appropriate.  If some code points aren't knowable at this time, the
-     * returned list must, and will, contain every possible code point. */
+     * returned list must, and will, contain every code point that is a
+     * possibility. */
 
     SV* invlist = sv_2mortal(_new_invlist(0));
     unsigned int i;
     const U32 n = ARG(node);
+    bool new_node_has_latin1 = FALSE;
 
     PERL_ARGS_ASSERT_GET_ANYOF_CP_LIST_FOR_SSC;
 
@@ -1062,6 +1062,7 @@ S_get_ANYOF_cp_list_for_ssc(pTHX_ const RExC_state_t *pRExC_state,
     for (i = 0; i < 256; i++) {
         if (ANYOF_BITMAP_TEST(node, i)) {
             invlist = add_cp_to_invlist(invlist, i);
+            new_node_has_latin1 = TRUE;
         }
     }
 
@@ -1079,6 +1080,21 @@ S_get_ANYOF_cp_list_for_ssc(pTHX_ const RExC_state_t *pRExC_state,
     if (ANYOF_FLAGS(node) & ANYOF_INVERT) {
         _invlist_invert(invlist);
     }
+    else if (new_node_has_latin1 && ANYOF_FLAGS(node) & ANYOF_LOC_FOLD) {
+
+        /* Under /li, any 0-255 could fold to any other 0-255, depending on the
+         * locale.  We can skip this if there are no 0-255 at all. */
+        _invlist_union(invlist, PL_Latin1, &invlist);
+    }
+
+    /* Similarly add the UTF-8 locale possible matches */
+    if (ANYOF_FLAGS(node) & ANYOF_LOC_FOLD && ANYOF_UTF8_LOCALE_INVLIST(node))
+    {
+        _invlist_union_maybe_complement_2nd(invlist,
+                                            ANYOF_UTF8_LOCALE_INVLIST(node),
+                                            ANYOF_FLAGS(node) & ANYOF_INVERT,
+                                            &invlist);
+    }
 
     return invlist;
 }
@@ -1151,7 +1167,7 @@ S_ssc_and(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc,
     }
     else {
         anded_cp_list = get_ANYOF_cp_list_for_ssc(pRExC_state,
-                                        (regnode_charclass_posixl*) and_with);
+                                     (regnode_charclass_posixl_fold*) and_with);
         anded_flags = ANYOF_FLAGS(and_with) & ANYOF_COMMON_FLAGS;
     }
 
@@ -1228,7 +1244,7 @@ S_ssc_and(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc,
              * standard, in particular almost everything by Microsoft.
              * The loop below just changes e.g., \w into \W and vice versa */
 
-            regnode_charclass_posixl temp;
+            regnode_charclass_posixl_fold temp;
             int add = 1;    /* To calculate the index of the complement */
 
             ANYOF_POSIXL_ZERO(&temp);
@@ -1300,7 +1316,7 @@ S_ssc_or(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc,
     }
     else {
         ored_cp_list = get_ANYOF_cp_list_for_ssc(pRExC_state,
-                                        (regnode_charclass_posixl*) or_with);
+                                     (regnode_charclass_posixl_fold*) or_with);
         ored_flags = ANYOF_FLAGS(or_with) & ANYOF_COMMON_FLAGS;
     }
 
@@ -1444,6 +1460,10 @@ S_ssc_finalize(pTHX_ RExC_state_t *pRExC_state, regnode_ssc *ssc)
 
     set_ANYOF_arg(pRExC_state, (regnode *) ssc, invlist, NULL, NULL, FALSE);
 
+    /* The code points that could match under /li are already incorporated into
+     * the inversion list and bit map */
+    ANYOF_FLAGS(ssc) &= ~ANYOF_LOC_FOLD;
+
     assert(! (ANYOF_FLAGS(ssc) & ANYOF_LOCALE) || RExC_contains_locale);
 }
 
@@ -3057,7 +3077,7 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
         PerlIO_printf(Perl_debug_log, "\n");
     });
     Safefree(q);
-    /*RExC_seen |= REG_SEEN_TRIEDFA;*/
+    /*RExC_seen |= REG_TRIEDFA_SEEN;*/
 }
 
 
@@ -3084,10 +3104,18 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
  *
  * If a node is to match under /i (folded), the number of characters it matches
  * can be different than its character length if it contains a multi-character
- * fold.  *min_subtract is set to the total delta of the input nodes.
+ * fold.  *min_subtract is set to the total delta number of characters of the
+ * input nodes.
  *
- * And *has_exactf_sharp_s is set to indicate whether or not the node is EXACTF
- * and contains LATIN SMALL LETTER SHARP S
+ * And *unfolded_multi_char is set to indicate whether or not the node contains
+ * an unfolded multi-char fold.  This happens when whether the fold is valid or
+ * not won't be known until runtime; namely for EXACTF nodes that contain LATIN
+ * SMALL LETTER SHARP S, as only if the target string being matched against
+ * turns out to be UTF-8 is that fold valid; and also for EXACTFL nodes whose
+ * folding rules depend on the locale in force at runtime.  (Multi-char folds
+ * whose components are all above the Latin1 range are not run-time locale
+ * dependent, and have already been folded by the time this function is
+ * called.)
  *
  * This is as good a place as any to discuss the design of handling these
  * multi-character fold sequences.  It's been wrong in Perl for a very long
@@ -3109,11 +3137,12 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
  *      character folded sequences.  Since a single character can fold into
  *      such a sequence, the minimum match length for this node is less than
  *      the number of characters in the node.  This routine returns in
- *      *min_subtract how much to subtract from the the actual length of the
- *      string to get a real minimum match length; it is 0 if there are no
- *      multi-char foldeds.  This delta is used by the caller to adjust the min
- *      length of the match, and the delta between min and max, so that the
- *      optimizer doesn't reject these possibilities based on size constraints.
+ *      *min_subtract how many characters to subtract from the the actual
+ *      length of the string to get a real minimum match length; it is 0 if
+ *      there are no multi-char foldeds.  This delta is used by the caller to
+ *      adjust the min length of the match, and the delta between min and max,
+ *      so that the optimizer doesn't reject these possibilities based on size
+ *      constraints.
  * 2)   For the sequence involving the Sharp s (\xDF), the node type EXACTFU_SS
  *      is used for an EXACTFU node that contains at least one "ss" sequence in
  *      it.  For non-UTF-8 patterns and strings, this is the only case where
@@ -3121,11 +3150,12 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
  *      EXACTFU node without UTF-8 involvement doesn't have to concern itself
  *      with length changes, and so can be processed faster.  regexec.c takes
  *      advantage of this.  Generally, an EXACTFish node that is in UTF-8 is
- *      pre-folded by regcomp.c.  This saves effort in regex matching.
- *      However, the pre-folding isn't done for non-UTF8 patterns because the
- *      fold of the MICRO SIGN requires UTF-8, and we don't want to slow things
- *      down by forcing the pattern into UTF8 unless necessary.  Also what
- *      EXACTF and EXACTFL nodes fold to isn't known until runtime.  The fold
+ *      pre-folded by regcomp.c (except EXACTFL, some of whose folds aren't
+ *      known until runtime).  This saves effort in regex matching.  However,
+ *      the pre-folding isn't done for non-UTF8 patterns because the fold of
+ *      the MICRO SIGN requires UTF-8, and we don't want to slow things down by
+ *      forcing the pattern into UTF8 unless necessary.  Also what EXACTF (and,
+ *      again, EXACTFL) nodes fold to isn't known until runtime.  The fold
  *      possibilities for the non-UTF8 patterns are quite simple, except for
  *      the sharp s.  All the ones that don't involve a UTF-8 target string are
  *      members of a fold-pair, and arrays are set up for all of them so that
@@ -3133,37 +3163,45 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
  *      this file makes sure that in EXACTFU nodes, the sharp s gets folded to
  *      'ss', even if the pattern isn't UTF-8.  This avoids the issues
  *      described in the next item.
- * 3)   A problem remains for the sharp s in EXACTF and EXACTFA nodes when the
- *      pattern isn't in UTF-8. (BTW, there cannot be an EXACTF node with a
- *      UTF-8 pattern.)  An assumption that the optimizer part of regexec.c
- *      (probably unwittingly, in Perl_regexec_flags()) makes is that a
- *      character in the pattern corresponds to at most a single character in
- *      the target string.  (And I do mean character, and not byte here, unlike
- *      other parts of the documentation that have never been updated to
- *      account for multibyte Unicode.)  sharp s in EXACTF nodes can match the
- *      two character string 'ss'; in EXACTFA nodes it can match
- *      "\x{17F}\x{17F}".  These violate the assumption, and they are the only
- *      instances where it is violated.  I'm reluctant to try to change the
- *      assumption, as the code involved is impenetrable to me (khw), so
- *      instead the code here punts.  This routine examines (when the pattern
- *      isn't UTF-8) EXACTF and EXACTFA nodes for the sharp s, and returns a
- *      boolean indicating whether or not the node contains a sharp s.  When it
- *      is true, the caller sets a flag that later causes the optimizer in this
- *      file to not set values for the floating and fixed string lengths, and
- *      thus avoids the optimizer code in regexec.c that makes the invalid
+ * 3)   A problem remains for unfolded multi-char folds. (These occur when the
+ *      validity of the fold won't be known until runtime, and so must remain
+ *      unfolded for now.  This happens for the sharp s in EXACTF and EXACTFA
+ *      nodes when the pattern isn't in UTF-8.  (Note, BTW, that there cannot
+ *      be an EXACTF node with a UTF-8 pattern.)  They also occur for various
+ *      folds in EXACTFL nodes, regardless of the UTF-ness of the pattern.)
+ *      The reason this is a problem is that the optimizer part of regexec.c
+ *      (probably unwittingly, in Perl_regexec_flags()) makes an assumption
+ *      that a character in the pattern corresponds to at most a single
+ *      character in the target string.  (And I do mean character, and not byte
+ *      here, unlike other parts of the documentation that have never been
+ *      updated to account for multibyte Unicode.)  sharp s in EXACTF and
+ *      EXACTFL nodes can match the two character string 'ss'; in EXACTFA nodes
+ *      it can match "\x{17F}\x{17F}".  These, along with other ones in EXACTFL
+ *      nodes, violate the assumption, and they are the only instances where it
+ *      is violated.  I'm reluctant to try to change the assumption, as the
+ *      code involved is impenetrable to me (khw), so instead the code here
+ *      punts.  This routine examines EXACTFL nodes, and (when the pattern
+ *      isn't UTF-8) EXACTF and EXACTFA for such unfolded folds, and returns a
+ *      boolean indicating whether or not the node contains such a fold.  When
+ *      it is true, the caller sets a flag that later causes the optimizer in
+ *      this file to not set values for the floating and fixed string lengths,
+ *      and thus avoids the optimizer code in regexec.c that makes the invalid
  *      assumption.  Thus, there is no optimization based on string lengths for
- *      non-UTF8-pattern EXACTF and EXACTFA nodes that contain the sharp s.
- *      (The reason the assumption is wrong only in these two cases is that all
- *      other non-UTF-8 folds are 1-1; and, for UTF-8 patterns, we pre-fold all
- *      other folds to their expanded versions.  We can't prefold sharp s to
- *      'ss' in EXACTF nodes because we don't know at compile time if it
- *      actually matches 'ss' or not.  It will match iff the target string is
- *      in UTF-8, unlike the EXACTFU nodes, where it always matches; and
- *      EXACTFA and EXACTFL where it never does.  In an EXACTFA node in a UTF-8
- *      pattern, sharp s is folded to "\x{17F}\x{17F}, avoiding the problem;
- *      but in a non-UTF8 pattern, folding it to that above-Latin1 string would
- *      require the pattern to be forced into UTF-8, the overhead of which we
- *      want to avoid.)
+ *      EXACTFL nodes that contain these few folds, nor for non-UTF8-pattern
+ *      EXACTF and EXACTFA nodes that contain the sharp s.  (The reason the
+ *      assumption is wrong only in these cases is that all other non-UTF-8
+ *      folds are 1-1; and, for UTF-8 patterns, we pre-fold all other folds to
+ *      their expanded versions.  (Again, we can't prefold sharp s to 'ss' in
+ *      EXACTF nodes because we don't know at compile time if it actually
+ *      matches 'ss' or not.  For EXACTF nodes it will match iff the target
+ *      string is in UTF-8.  This is in contrast to EXACTFU nodes, where it
+ *      always matches; and EXACTFA where it never does.  In an EXACTFA node in
+ *      a UTF-8 pattern, sharp s is folded to "\x{17F}\x{17F}, avoiding the
+ *      problem; but in a non-UTF8 pattern, folding it to that above-Latin1
+ *      string would require the pattern to be forced into UTF-8, the overhead
+ *      of which we want to avoid.  Similarly the unfolded multi-char folds in
+ *      EXACTFL nodes will match iff the locale at the time of match is a UTF-8
+ *      locale.)
  *
  *      Similarly, the code that generates tries doesn't currently handle
  *      not-already-folded multi-char folds, and it looks like a pain to change
@@ -3173,13 +3211,13 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
  *      using /iaa matching will be doing so almost entirely with ASCII
  *      strings, so this should rarely be encountered in practice */
 
-#define JOIN_EXACT(scan,min_subtract,has_exactf_sharp_s, flags) \
+#define JOIN_EXACT(scan,min_subtract,unfolded_multi_char, flags) \
     if (PL_regkind[OP(scan)] == EXACT) \
-        join_exact(pRExC_state,(scan),(min_subtract),has_exactf_sharp_s, (flags),NULL,depth+1)
+        join_exact(pRExC_state,(scan),(min_subtract),unfolded_multi_char, (flags),NULL,depth+1)
 
 STATIC U32
 S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
-                   UV *min_subtract, bool *has_exactf_sharp_s,
+                   UV *min_subtract, bool *unfolded_multi_char,
                    U32 flags,regnode *val, U32 depth)
 {
     /* Merge several consecutive EXACTish nodes into one. */
@@ -3227,8 +3265,9 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
             const unsigned int oldl = STR_LEN(scan);
             regnode * const nnext = regnext(n);
 
-            /* XXX I (khw) kind of doubt that this works on platforms where
-             * U8_MAX is above 255 because of lots of other assumptions */
+            /* XXX I (khw) kind of doubt that this works on platforms (should
+             * Perl ever run on one) where U8_MAX is above 255 because of lots
+             * of other assumptions */
             /* Don't join if the sum can't fit into a single node */
             if (oldl + STR_LEN(n) > U8_MAX)
                 break;
@@ -3263,7 +3302,7 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
     }
 
     *min_subtract = 0;
-    *has_exactf_sharp_s = FALSE;
+    *unfolded_multi_char = FALSE;
 
     /* Here, all the adjacent mergeable EXACTish nodes have been merged.  We
      * can now analyze for sequences of problematic code points.  (Prior to
@@ -3271,15 +3310,68 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
      * hence missed).  The sequences only happen in folding, hence for any
      * non-EXACT EXACTish node */
     if (OP(scan) != EXACT) {
-        const U8 * const s0 = (U8*) STRING(scan);
-        const U8 * s = s0;
-        const U8 * const s_end = s0 + STR_LEN(scan);
+        U8* s0 = (U8*) STRING(scan);
+        U8* s = s0;
+        U8* s_end = s0 + STR_LEN(scan);
+
+        int total_count_delta = 0;  /* Total delta number of characters that
+                                       multi-char folds expand to */
 
        /* One pass is made over the node's string looking for all the
-        * possibilities.  to avoid some tests in the loop, there are two main
+        * possibilities.  To avoid some tests in the loop, there are two main
         * cases, for UTF-8 patterns (which can't have EXACTF nodes) and
         * non-UTF-8 */
        if (UTF) {
+            U8* folded = NULL;
+
+            if (OP(scan) == EXACTFL) {
+                U8 *d;
+
+                /* An EXACTFL node would already have been changed to another
+                 * node type unless there is at least one character in it that
+                 * is problematic; likely a character whose fold definition
+                 * won't be known until runtime, and so has yet to be folded.
+                 * For all but the UTF-8 locale, folds are 1-1 in length, but
+                 * to handle the UTF-8 case, we need to create a temporary
+                 * folded copy using UTF-8 locale rules in order to analyze it.
+                 * This is because our macros that look to see if a sequence is
+                 * a multi-char fold assume everything is folded (otherwise the
+                 * tests in those macros would be too complicated and slow).
+                 * Note that here, the non-problematic folds will have already
+                 * been done, so we can just copy such characters.  We actually
+                 * don't completely fold the EXACTFL string.  We skip the
+                 * unfolded multi-char folds, as that would just create work
+                 * below to figure out the size they already are */
+
+                Newx(folded, UTF8_MAX_FOLD_CHAR_EXPAND * STR_LEN(scan) + 1, U8);
+                d = folded;
+                while (s < s_end) {
+                    STRLEN s_len = UTF8SKIP(s);
+                    if (! is_PROBLEMATIC_LOCALE_FOLD_utf8(s)) {
+                        Copy(s, d, s_len, U8);
+                        d += s_len;
+                    }
+                    else if (is_FOLDS_TO_MULTI_utf8(s)) {
+                        *unfolded_multi_char = TRUE;
+                        Copy(s, d, s_len, U8);
+                        d += s_len;
+                    }
+                    else if (isASCII(*s)) {
+                        *(d++) = toFOLD(*s);
+                    }
+                    else {
+                        STRLEN len;
+                        _to_utf8_fold_flags(s, d, &len, FOLD_FLAGS_FULL);
+                        d += len;
+                    }
+                    s += s_len;
+                }
+
+                /* Point the remainder of the routine to look at our temporary
+                 * folded copy */
+                s = folded;
+                s_end = d;
+            } /* End of creating folded copy of EXACTFL string */
 
             /* Examine the string for a multi-character fold sequence.  UTF-8
              * patterns have all characters pre-folded by the time this code is
@@ -3294,34 +3386,25 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
                     continue;
                 }
 
-                /* Nodes with 'ss' require special handling, except for EXACTFL
-                 * and EXACTFA-ish for which there is no multi-char fold to
-                 * this */
+                /* Nodes with 'ss' require special handling, except for
+                 * EXACTFA-ish for which there is no multi-char fold to this */
                 if (len == 2 && *s == 's' && *(s+1) == 's'
-                    && OP(scan) != EXACTFL
                     && OP(scan) != EXACTFA
                     && OP(scan) != EXACTFA_NO_TRIE)
                 {
                     count = 2;
-                    OP(scan) = EXACTFU_SS;
+                    if (OP(scan) != EXACTFL) {
+                        OP(scan) = EXACTFU_SS;
+                    }
                     s += 2;
                 }
                 else { /* Here is a generic multi-char fold. */
-                    const U8* multi_end  = s + len;
-
-                    /* Count how many characters in it.  In the case of /l and
-                     * /aa, no folds which contain ASCII code points are
-                     * allowed, so check for those, and skip if found.  (In
-                     * EXACTFL, no folds are allowed to any Latin1 code point,
-                     * not just ASCII.  But there aren't any of these
-                     * currently, nor ever likely, so don't take the time to
-                     * test for them.  The code that generates the
-                     * is_MULTI_foo() macros croaks should one actually get put
-                     * into Unicode .) */
-                    if (OP(scan) != EXACTFL
-                        && OP(scan) != EXACTFA
-                        && OP(scan) != EXACTFA_NO_TRIE)
-                    {
+                    U8* multi_end  = s + len;
+
+                    /* Count how many characters in it.  In the case of /aa, no
+                     * folds which contain ASCII code points are allowed, so
+                     * check for those, and skip if found. */
+                    if (OP(scan) != EXACTFA && OP(scan) != EXACTFA_NO_TRIE) {
                         count = utf8_length(s, multi_end);
                         s = multi_end;
                     }
@@ -3341,9 +3424,23 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
 
                 /* The delta is how long the sequence is minus 1 (1 is how long
                  * the character that folds to the sequence is) */
-                *min_subtract += count - 1;
-            next_iteration: ;
+                total_count_delta += count - 1;
+              next_iteration: ;
            }
+
+            /* We created a temporary folded copy of the string in EXACTFL
+             * nodes.  Therefore we need to be sure it doesn't go below zero,
+             * as the real string could be shorter */
+            if (OP(scan) == EXACTFL) {
+                int total_chars = utf8_length((U8*) STRING(scan),
+                                           (U8*) STRING(scan) + STR_LEN(scan));
+                if (total_count_delta > total_chars) {
+                    total_count_delta = total_chars;
+                }
+            }
+
+            *min_subtract += total_count_delta;
+            Safefree(folded);
        }
        else if (OP(scan) == EXACTFA) {
 
@@ -3356,32 +3453,32 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
            while (s < s_end) {
                 if (*s == LATIN_SMALL_LETTER_SHARP_S) {
                     OP(scan) = EXACTFA_NO_TRIE;
-                    *has_exactf_sharp_s = TRUE;
+                    *unfolded_multi_char = TRUE;
                     break;
                 }
                 s++;
                 continue;
             }
         }
-       else if (OP(scan) != EXACTFL) {
-
-            /* Non-UTF-8 pattern, not EXACTFA nor EXACTFL node.  Look for the
-             * multi-char folds that are all Latin1.  (This code knows that
-             * there are no current multi-char folds possible with EXACTFL,
-             * relying on fold_grind.t to catch any errors if the very unlikely
-             * event happens that some get added in future Unicode versions.)
-             * As explained in the comments preceding this function, we look
-             * also for the sharp s in EXACTF nodes; it can be in the final
-             * position.  Otherwise we can stop looking 1 byte earlier because
-             * have to find at least two characters for a multi-fold */
-           const U8* upper = (OP(scan) == EXACTF) ? s_end : s_end -1;
+       else {
+
+            /* Non-UTF-8 pattern, not EXACTFA node.  Look for the multi-char
+             * folds that are all Latin1.  As explained in the comments
+             * preceding this function, we look also for the sharp s in EXACTF
+             * and EXACTFL nodes; it can be in the final position.  Otherwise
+             * we can stop looking 1 byte earlier because have to find at least
+             * two characters for a multi-fold */
+           const U8* upper = (OP(scan) == EXACTF || OP(scan) == EXACTFL)
+                              ? s_end
+                              : s_end -1;
 
            while (s < upper) {
                 int len = is_MULTI_CHAR_FOLD_latin1(s);
                 if (! len) {    /* Not a multi-char fold. */
-                    if (*s == LATIN_SMALL_LETTER_SHARP_S && OP(scan) == EXACTF)
+                    if (*s == LATIN_SMALL_LETTER_SHARP_S
+                        && (OP(scan) == EXACTF || OP(scan) == EXACTFL))
                     {
-                        *has_exactf_sharp_s = TRUE;
+                        *unfolded_multi_char = TRUE;
                     }
                     s++;
                     continue;
@@ -3396,8 +3493,9 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan,
                      * changed so that a sharp s in the string can match this
                      * ss in the pattern, but they remain EXACTF nodes, as they
                      * won't match this unless the target string is is UTF-8,
-                     * which we don't know until runtime */
-                    if (OP(scan) != EXACTF) {
+                     * which we don't know until runtime.  EXACTFL nodes can't
+                     * transform into EXACTFU nodes */
+                    if (OP(scan) != EXACTF && OP(scan) != EXACTFL) {
                         OP(scan) = EXACTFU_SS;
                     }
                }
@@ -3447,8 +3545,6 @@ typedef struct scan_frame {
 } scan_frame;
 
 
-#define SCAN_COMMIT(s, data, m) scan_commit(s, data, m, is_inf)
-
 STATIC SSize_t
 S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                         SSize_t *minlenp, SSize_t *deltap,
@@ -3498,7 +3594,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
         UV min_subtract = 0;    /* How mmany chars to subtract from the minimum
                                    node length to get a real minimum (because
                                    the folded version may be shorter) */
-       bool has_exactf_sharp_s = FALSE;
+       bool unfolded_multi_char = FALSE;
        /* Peephole optimizer: */
         DEBUG_OPTIMISE_MORE_r(
         {
@@ -3530,7 +3626,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
         /* Its not clear to khw or hv why this is done here, and not in the
          * clauses that deal with EXACT nodes.  khw's guess is that it's
          * because of a previous design */
-        JOIN_EXACT(scan,&min_subtract, &has_exactf_sharp_s, 0);
+        JOIN_EXACT(scan,&min_subtract, &unfolded_multi_char, 0);
 
        /* Follow the next-chain of the current node and optimize
           away all the NOTHINGs from it.  */
@@ -3574,11 +3670,12 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                regnode_ssc accum;
                regnode * const startbranch=scan;
 
-               if (flags & SCF_DO_SUBSTR)
-                    SCAN_COMMIT(pRExC_state, data, minlenp); /* Cannot merge
-                                                                strings after
-                                                            this. */
-            if (flags & SCF_DO_STCLASS)
+                if (flags & SCF_DO_SUBSTR) {
+                    /* Cannot merge strings after this. */
+                    scan_commit(pRExC_state, data, minlenp, is_inf);
+                }
+
+                if (flags & SCF_DO_STCLASS)
                    ssc_init_zero(pRExC_state, &accum);
 
                while (OP(scan) == code) {
@@ -3968,7 +4065,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                                     if ( startbranch == first
                                          && scan == tail )
                                     {
-                                        RExC_seen &=~REG_TOP_LEVEL_BRANCHES;
+                                        RExC_seen &=~REG_TOP_LEVEL_BRANCHES_SEEN;
                                     }
                                 }
 #endif
@@ -4047,7 +4144,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                     /* some form of infinite recursion, assume infinite length
                      * */
                     if (flags & SCF_DO_SUBSTR) {
-                        SCAN_COMMIT(pRExC_state,data,minlenp);
+                        scan_commit(pRExC_state, data, minlenp, is_inf);
                         data->longest = &(data->longest_float);
                     }
                     is_inf = is_inf_internal = 1;
@@ -4144,15 +4241,15 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
            /* Search for fixed substrings supports EXACT only. */
            if (flags & SCF_DO_SUBSTR) {
                assert(data);
-               SCAN_COMMIT(pRExC_state, data, minlenp);
+                scan_commit(pRExC_state, data, minlenp, is_inf);
            }
            if (UTF) {
                const U8 * const s = (U8 *)STRING(scan);
                uc = utf8_to_uvchr_buf(s, s + l, NULL);
                l = utf8_length(s, s + l);
            }
-           if (has_exactf_sharp_s) {
-               RExC_seen |= REG_SEEN_EXACTF_SHARP_S;
+           if (unfolded_multi_char) {
+                RExC_seen |= REG_UNFOLDED_MULTI_SEEN;
            }
            min += l - min_subtract;
             assert (min >= 0);
@@ -4169,12 +4266,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
            }
             if (OP(scan) == EXACTFL) {
                 if (flags & SCF_DO_STCLASS_AND) {
-                    ssc_flags_and(data->start_class,
-                                                ANYOF_LOCALE|ANYOF_LOC_FOLD);
+                    ssc_flags_and(data->start_class, ANYOF_LOCALE);
                 }
                 else if (flags & SCF_DO_STCLASS_OR) {
-                    ANYOF_FLAGS(data->start_class)
-                                                |= ANYOF_LOCALE|ANYOF_LOC_FOLD;
+                    ANYOF_FLAGS(data->start_class) |= ANYOF_LOCALE;
                 }
 
                 /* We don't know what the folds are; it could be anything. XXX
@@ -4293,13 +4388,13 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                    scan = NEXTOPER(scan);
                    goto do_curly;
                }
-               is_inf = is_inf_internal = 1;
-               scan = regnext(scan);
                if (flags & SCF_DO_SUBSTR) {
-                    SCAN_COMMIT(pRExC_state, data, minlenp);
+                    scan_commit(pRExC_state, data, minlenp, is_inf);
                     /* Cannot extend fixed substrings */
                    data->longest = &(data->longest_float);
                }
+                is_inf = is_inf_internal = 1;
+                scan = regnext(scan);
                goto optimize_curly_tail;
            case CURLY:
                if (stopparen>0 && (OP(scan)==CURLYN || OP(scan)==CURLYM)
@@ -4320,7 +4415,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                next_is_eval = (OP(scan) == EVAL);
              do_curly:
                if (flags & SCF_DO_SUBSTR) {
-                   if (mincount == 0) SCAN_COMMIT(pRExC_state,data,minlenp);
+                    if (mincount == 0)
+                        scan_commit(pRExC_state, data, minlenp, is_inf);
                     /* Cannot extend fixed substrings */
                    pos_before = data->pos_min;
                }
@@ -4403,12 +4499,12 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                is_inf_internal |= deltanext == SSize_t_MAX
                          || (maxcount == REG_INFTY && minnext + deltanext > 0);
                is_inf |= is_inf_internal;
-               if (is_inf)
+                if (is_inf) {
                    delta = SSize_t_MAX;
-               else
+                } else {
                    delta += (minnext + deltanext) * maxcount
                              - minnext * mincount;
-
+                }
                /* Try powerful optimization CURLYX => CURLYN. */
                if (  OP(oscan) == CURLYX && data
                      && data->flags & SF_IN_PAR
@@ -4459,7 +4555,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                      && !(data->flags & SF_HAS_EVAL)
                      && !deltanext     /* atom is fixed width */
                      && minnext != 0   /* CURLYM can't handle zero width */
-                      && ! (RExC_seen & REG_SEEN_EXACTF_SHARP_S) /* Nor \xDF */
+
+                         /* Nor characters whose fold at run-time may be
+                          * multi-character */
+                      && ! (RExC_seen & REG_UNFOLDED_MULTI_SEEN)
                ) {
                    /* XXXX How to optimize if data == 0? */
                    /* Optimize to a simpler form.  */
@@ -4531,6 +4630,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                    pars++;
                if (flags & SCF_DO_SUBSTR) {
                    SV *last_str = NULL;
+                    STRLEN last_chrs = 0;
                    int counted = mincount != 0;
 
                     if (data->last_end > 0 && mincount != 0) { /* Ends with a
@@ -4546,9 +4646,12 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                        l -= old;
                        /* Get the added string: */
                        last_str = newSVpvn_utf8(s  + old, l, UTF);
+                        last_chrs = UTF ? utf8_length((U8*)(s + old),
+                                            (U8*)(s + old + l)) : l;
                        if (deltanext == 0 && pos_before == b) {
                            /* What was added is a constant string */
                            if (mincount > 1) {
+
                                SvGROW(last_str, (mincount * l) + 1);
                                repeatcpy(SvPVX(last_str) + l,
                                          SvPVX_const(last_str), l,
@@ -4564,8 +4667,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                                        SvUTF8(sv) && SvMAGICAL(sv) ?
                                        mg_find(sv, PERL_MAGIC_utf8) : NULL;
                                    if (mg && mg->mg_len >= 0)
-                                       mg->mg_len += CHR_SVLEN(last_str) - l;
+                                       mg->mg_len += last_chrs * (mincount-1);
                                }
+                                last_chrs *= mincount;
                                data->last_end += l * (mincount - 1);
                            }
                        } else {
@@ -4597,7 +4701,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                    if (mincount != maxcount) {
                         /* Cannot extend fixed substrings found inside
                            the group.  */
-                       SCAN_COMMIT(pRExC_state,data,minlenp);
+                        scan_commit(pRExC_state, data, minlenp, is_inf);
                        if (mincount && last_str) {
                            SV * const sv = data->last_found;
                            MAGIC * const mg = SvUTF8(sv) && SvMAGICAL(sv) ?
@@ -4607,12 +4711,10 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                                mg->mg_len = -1;
                            sv_setsv(sv, last_str);
                            data->last_end = data->pos_min;
-                           data->last_start_min =
-                               data->pos_min - CHR_SVLEN(last_str);
+                           data->last_start_min = data->pos_min - last_chrs;
                            data->last_start_max = is_inf
                                ? SSize_t_MAX
-                               : data->pos_min + data->pos_delta
-                               - CHR_SVLEN(last_str);
+                               : data->pos_min + data->pos_delta - last_chrs;
                        }
                        data->longest = &(data->longest_float);
                    }
@@ -4636,8 +4738,8 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
             case REF:
             case CLUMP:
                if (flags & SCF_DO_SUBSTR) {
-                    SCAN_COMMIT(pRExC_state,data,minlenp); /* Cannot expect
-                                                              anything... */
+                    /* Cannot expect anything... */
+                    scan_commit(pRExC_state, data, minlenp, is_inf);
                    data->longest = &(data->longest_float);
                }
                is_inf = is_inf_internal = 1;
@@ -4678,8 +4780,8 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
            min++;
            delta++;    /* Because of the 2 char string cr-lf */
             if (flags & SCF_DO_SUBSTR) {
-                SCAN_COMMIT(pRExC_state,data,minlenp); /* Cannot expect
-                                                           anything... */
+                /* Cannot expect anything... */
+                scan_commit(pRExC_state, data, minlenp, is_inf);
                data->pos_min += 1;
                data->pos_delta += 1;
                data->longest = &(data->longest_float);
@@ -4688,7 +4790,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
        else if (REGNODE_SIMPLE(OP(scan))) {
 
            if (flags & SCF_DO_SUBSTR) {
-               SCAN_COMMIT(pRExC_state,data,minlenp);
+                scan_commit(pRExC_state, data, minlenp, is_inf);
                data->pos_min++;
            }
            min++;
@@ -4818,10 +4920,12 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
 
                     /* NPOSIXD matches all upper Latin1 code points unless the
                      * target string being matched is UTF-8, which is
-                     * unknowable until match time */
-                    if (PL_regkind[OP(scan)] == NPOSIXD) {
-                        _invlist_union_complement_2nd(my_invlist,
-                                        PL_XPosix_ptrs[_CC_ASCII], &my_invlist);
+                     * unknowable until match time.  Since we are going to
+                     * invert, we want to get rid of all of them so that the
+                     * inversion will match all */
+                    if (OP(scan) == NPOSIXD) {
+                        _invlist_subtract(my_invlist, PL_UpperLatin1,
+                                          &my_invlist);
                     }
 
                   join_posix:
@@ -4844,7 +4948,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
            data->flags |= (OP(scan) == MEOL
                            ? SF_BEFORE_MEOL
                            : SF_BEFORE_SEOL);
-           SCAN_COMMIT(pRExC_state, data, minlenp);
+            scan_commit(pRExC_state, data, minlenp, is_inf);
 
        }
        else if (  PL_regkind[OP(scan)] == BRANCHJ
@@ -4971,7 +5075,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                     if ((flags & SCF_DO_SUBSTR) && data->last_found) {
                         f |= SCF_DO_SUBSTR;
                         if (scan->flags)
-                            SCAN_COMMIT(pRExC_state, &data_fake,minlenp);
+                            scan_commit(pRExC_state, &data_fake, minlenp, is_inf);
                         data_fake.last_found=newSVsv(data->last_found);
                     }
                 }
@@ -5021,7 +5125,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                     if ((flags & SCF_DO_SUBSTR) && data_fake.last_found) {
                         if (RExC_rx->minlen<*minnextp)
                             RExC_rx->minlen=*minnextp;
-                        SCAN_COMMIT(pRExC_state, &data_fake, minnextp);
+                        scan_commit(pRExC_state, &data_fake, minnextp, is_inf);
                         SvREFCNT_dec_NN(data_fake.last_found);
 
                         if ( data_fake.minlen_fixed != minlenp )
@@ -5065,7 +5169,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
        }
        else if ( PL_regkind[OP(scan)] == ENDLIKE ) {
            if (flags & SCF_DO_SUBSTR) {
-               SCAN_COMMIT(pRExC_state,data,minlenp);
+                scan_commit(pRExC_state, data, minlenp, is_inf);
                flags &= ~SCF_DO_SUBSTR;
            }
            if (data && OP(scan)==ACCEPT) {
@@ -5077,7 +5181,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
        else if (OP(scan) == LOGICAL && scan->flags == 2) /* Embedded follows */
        {
                if (flags & SCF_DO_SUBSTR) {
-                   SCAN_COMMIT(pRExC_state,data,minlenp);
+                    scan_commit(pRExC_state, data, minlenp, is_inf);
                    data->longest = &(data->longest_float);
                }
                is_inf = is_inf_internal = 1;
@@ -5086,15 +5190,15 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                flags &= ~SCF_DO_STCLASS;
        }
        else if (OP(scan) == GPOS) {
-           if (!(RExC_rx->extflags & RXf_GPOS_FLOAT) &&
+            if (!(RExC_rx->intflags & PREGf_GPOS_FLOAT) &&
                !(delta || is_inf || (data && data->pos_delta)))
            {
-               if (!(RExC_rx->extflags & RXf_ANCH) && (flags & SCF_DO_SUBSTR))
-                   RExC_rx->extflags |= RXf_ANCH_GPOS;
+                if (!(RExC_rx->intflags & PREGf_ANCH) && (flags & SCF_DO_SUBSTR))
+                    RExC_rx->intflags |= PREGf_ANCH_GPOS;
                if (RExC_rx->gofs < (STRLEN)min)
                    RExC_rx->gofs = min;
             } else {
-                RExC_rx->extflags |= RXf_GPOS_FLOAT;
+                RExC_rx->intflags |= PREGf_GPOS_FLOAT;
                 RExC_rx->gofs = 0;
             }
        }
@@ -5110,9 +5214,10 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
             SSize_t max1 = 0, min1 = SSize_t_MAX;
             regnode_ssc accum;
 
-            if (flags & SCF_DO_SUBSTR) /* XXXX Add !SUSPEND? */
-                SCAN_COMMIT(pRExC_state, data,minlenp); /* Cannot merge strings
-                                                           after this. */
+            if (flags & SCF_DO_SUBSTR) { /* XXXX Add !SUSPEND? */
+                /* Cannot merge strings after this. */
+                scan_commit(pRExC_state, data, minlenp, is_inf);
+            }
             if (flags & SCF_DO_STCLASS)
                 ssc_init_zero(pRExC_state, &accum);
 
@@ -5226,8 +5331,8 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
            delta += (trie->maxlen - trie->minlen);
            flags &= ~SCF_DO_STCLASS; /* xxx */
             if (flags & SCF_DO_SUBSTR) {
-                SCAN_COMMIT(pRExC_state,data,minlenp); /* Cannot expect
-                                                           anything... */
+                /* Cannot expect anything... */
+                scan_commit(pRExC_state, data, minlenp, is_inf);
                data->pos_min += trie->minlen;
                data->pos_delta += (trie->maxlen - trie->minlen);
                if (trie->maxlen != trie->minlen)
@@ -5270,6 +5375,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
 
     *scanp = scan;
     *deltap = is_inf_internal ? SSize_t_MAX : delta;
+
     if (flags & SCF_DO_SUBSTR && is_inf)
        data->pos_delta = SSize_t_MAX - data->pos_min;
     if (is_par > (I32)U8_MAX)
@@ -5289,7 +5395,15 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
 
     DEBUG_STUDYDATA("post-fin:",data,depth);
 
-    return min < stopmin ? min : stopmin;
+    {
+        SSize_t final_minlen= min < stopmin ? min : stopmin;
+
+        if (!(RExC_seen & REG_UNBOUNDED_QUANTIFIER_SEEN) && (RExC_maxlen < final_minlen + delta)) {
+            RExC_maxlen = final_minlen + delta;
+        }
+        return final_minlen;
+    }
+    /* not-reached */
 }
 
 STATIC U32
@@ -5955,8 +6069,8 @@ S_setup_longest(pTHX_ RExC_state_t *pRExC_state, SV* sv_longest,
            || (eol /* Can't have SEOL and MULTI */
                && (! meol || (RExC_flags & RXf_PMf_MULTILINE)))
           )
-            /* See comments for join_exact for why REG_SEEN_EXACTF_SHARP_S */
-        || (RExC_seen & REG_SEEN_EXACTF_SHARP_S))
+            /* See comments for join_exact for why REG_UNFOLDED_MULTI_SEEN */
+        || (RExC_seen & REG_UNFOLDED_MULTI_SEEN))
     {
         return FALSE;
     }
@@ -6274,6 +6388,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     RExC_sawback = 0;
 
     RExC_seen = 0;
+    RExC_maxlen = 0;
     RExC_in_lookbehind = 0;
     RExC_seen_zerolen = *exp == '^' ? -1 : 0;
     RExC_extralen = 0;
@@ -6414,8 +6529,8 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
         bool has_default =
                     (((r->extflags & RXf_PMf_STD_PMMOD) != RXf_PMf_STD_PMMOD)
                     || ! has_charset);
-       bool has_runon = ((RExC_seen & REG_SEEN_RUN_ON_COMMENT)
-                                                   == REG_SEEN_RUN_ON_COMMENT);
+        bool has_runon = ((RExC_seen & REG_RUN_ON_COMMENT_SEEN)
+                                                   == REG_RUN_ON_COMMENT_SEEN);
        U16 reganch = (U16)((r->extflags & RXf_PMf_STD_PMMOD)
                            >> RXf_PMf_STD_PMMOD_SHIFT);
        const char *fptr = STD_PAT_MODS;        /*"msix"*/
@@ -6479,13 +6594,13 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
 
     /* setup various meta data about recursion, this all requires
      * RExC_npar to be correctly set, and a bit later on we clear it */
-    if (RExC_seen & REG_SEEN_RECURSE) {
+    if (RExC_seen & REG_RECURSE_SEEN) {
         Newxz(RExC_open_parens, RExC_npar,regnode *);
         SAVEFREEPV(RExC_open_parens);
         Newxz(RExC_close_parens,RExC_npar,regnode *);
         SAVEFREEPV(RExC_close_parens);
     }
-    if (RExC_seen & (REG_SEEN_RECURSE | REG_SEEN_GOSTART)) {
+    if (RExC_seen & (REG_RECURSE_SEEN | REG_GOSTART_SEEN)) {
         /* Note, RExC_npar is 1 + the number of parens in a pattern.
          * So its 1 if there are no parens. */
         RExC_study_chunk_recursed_bytes= (RExC_npar >> 3) +
@@ -6549,10 +6664,10 @@ reStudy:
         DEBUG_OPTIMISE_r(PerlIO_printf(Perl_debug_log,"Restudying\n"));
 
         RExC_state = copyRExC_state;
-        if (seen & REG_TOP_LEVEL_BRANCHES)
-            RExC_seen |= REG_TOP_LEVEL_BRANCHES;
+        if (seen & REG_TOP_LEVEL_BRANCHES_SEEN)
+            RExC_seen |= REG_TOP_LEVEL_BRANCHES_SEEN;
         else
-            RExC_seen &= ~REG_TOP_LEVEL_BRANCHES;
+            RExC_seen &= ~REG_TOP_LEVEL_BRANCHES_SEEN;
        StructCopy(&zero_scan_data, &data, scan_data_t);
     }
 #else
@@ -6572,7 +6687,7 @@ reStudy:
 
     /* testing for BRANCH here tells us whether there is "must appear"
        data in the pattern. If there is then we can use it for optimisations */
-    if (!(RExC_seen & REG_TOP_LEVEL_BRANCHES)) { /*  Only one top-level choice.
+    if (!(RExC_seen & REG_TOP_LEVEL_BRANCHES_SEEN)) { /*  Only one top-level choice.
                                                   */
        SSize_t fake;
        STRLEN longest_float_length, longest_fixed_length;
@@ -6658,31 +6773,30 @@ reStudy:
                 PL_regkind[OP(first)] == NBOUND)
            ri->regstclass = first;
        else if (PL_regkind[OP(first)] == BOL) {
-           r->extflags |= (OP(first) == MBOL
-                          ? RXf_ANCH_MBOL
+            r->intflags |= (OP(first) == MBOL
+                           ? PREGf_ANCH_MBOL
                           : (OP(first) == SBOL
-                             ? RXf_ANCH_SBOL
-                             : RXf_ANCH_BOL));
+                              ? PREGf_ANCH_SBOL
+                              : PREGf_ANCH_BOL));
            first = NEXTOPER(first);
            goto again;
        }
        else if (OP(first) == GPOS) {
-           r->extflags |= RXf_ANCH_GPOS;
+            r->intflags |= PREGf_ANCH_GPOS;
            first = NEXTOPER(first);
            goto again;
        }
        else if ((!sawopen || !RExC_sawback) &&
            (OP(first) == STAR &&
            PL_regkind[OP(NEXTOPER(first))] == REG_ANY) &&
-           !(r->extflags & RXf_ANCH) && !pRExC_state->num_code_blocks)
+            !(r->intflags & PREGf_ANCH) && !pRExC_state->num_code_blocks)
        {
            /* turn .* into ^.* with an implied $*=1 */
            const int type =
                (OP(NEXTOPER(first)) == REG_ANY)
-                   ? RXf_ANCH_MBOL
-                   : RXf_ANCH_SBOL;
-           r->extflags |= type;
-           r->intflags |= PREGf_IMPLICIT;
+                    ? PREGf_ANCH_MBOL
+                    : PREGf_ANCH_SBOL;
+            r->intflags |= (type | PREGf_IMPLICIT);
            first = NEXTOPER(first);
            goto again;
        }
@@ -6751,9 +6865,11 @@ reStudy:
        if ( RExC_npar == 1 && data.longest == &(data.longest_fixed)
             && data.last_start_min == 0 && data.last_end > 0
             && !RExC_seen_zerolen
-            && !(RExC_seen & REG_SEEN_VERBARG)
-            && !((RExC_seen & REG_SEEN_GPOS) || (r->extflags & RXf_ANCH_GPOS)))
+             && !(RExC_seen & REG_VERBARG_SEEN)
+             && !(RExC_seen & REG_GPOS_SEEN)
+        ){
            r->extflags |= RXf_CHECK_ALL;
+        }
        scan_commit(pRExC_state, &data,&minlen,0);
 
        longest_float_length = CHR_SVLEN(data.longest_float);
@@ -6837,14 +6953,16 @@ reStudy:
         /* A temporary algorithm prefers floated substr to fixed one to dig
          * more info. */
        if (longest_fixed_length > longest_float_length) {
+           r->substrs->check_ix = 0;
            r->check_end_shift = r->anchored_end_shift;
            r->check_substr = r->anchored_substr;
            r->check_utf8 = r->anchored_utf8;
            r->check_offset_min = r->check_offset_max = r->anchored_offset;
-           if (r->extflags & RXf_ANCH_SINGLE)
-               r->extflags |= RXf_NOSCAN;
+            if (r->intflags & (PREGf_ANCH_SBOL|PREGf_ANCH_GPOS))
+                r->intflags |= PREGf_NOSCAN;
        }
        else {
+           r->substrs->check_ix = 1;
            r->check_end_shift = r->float_end_shift;
            r->check_substr = r->float_substr;
            r->check_utf8 = r->float_utf8;
@@ -6856,6 +6974,8 @@ reStudy:
            if (SvTAIL(r->check_substr ? r->check_substr : r->check_utf8))
                r->extflags |= RXf_INTUIT_TAIL;
        }
+        r->substrs->data[0].max_offset = r->substrs->data[0].min_offset;
+
        /* XXX Unneeded? dmq (shouldn't as this is handled elsewhere)
        if ( (STRLEN)minlen < longest_float_length )
             minlen= longest_float_length;
@@ -6911,31 +7031,39 @@ reStudy:
        }
     }
 
+    if (RExC_seen & REG_UNBOUNDED_QUANTIFIER_SEEN) {
+        r->extflags |= RXf_UNBOUNDED_QUANTIFIER_SEEN;
+        r->maxlen = REG_INFTY;
+    }
+    else {
+        r->maxlen = RExC_maxlen;
+    }
+
     /* Guard against an embedded (?=) or (?<=) with a longer minlen than
        the "real" pattern. */
     DEBUG_OPTIMISE_r({
-       PerlIO_printf(Perl_debug_log,"minlen: %"IVdf" r->minlen:%"IVdf"\n",
-                     (IV)minlen, (IV)r->minlen);
+        PerlIO_printf(Perl_debug_log,"minlen: %"IVdf" r->minlen:%"IVdf" maxlen:%ld\n",
+                      (IV)minlen, (IV)r->minlen, RExC_maxlen);
     });
     r->minlenret = minlen;
     if (r->minlen < minlen)
         r->minlen = minlen;
 
-    if (RExC_seen & REG_SEEN_GPOS)
-       r->extflags |= RXf_GPOS_SEEN;
-    if (RExC_seen & REG_SEEN_LOOKBEHIND)
+    if (RExC_seen & REG_GPOS_SEEN)
+        r->intflags |= PREGf_GPOS_SEEN;
+    if (RExC_seen & REG_LOOKBEHIND_SEEN)
         r->extflags |= RXf_NO_INPLACE_SUBST; /* inplace might break the
                                                 lookbehind */
     if (pRExC_state->num_code_blocks)
        r->extflags |= RXf_EVAL_SEEN;
-    if (RExC_seen & REG_SEEN_CANY)
-       r->extflags |= RXf_CANY_SEEN;
-    if (RExC_seen & REG_SEEN_VERBARG)
+    if (RExC_seen & REG_CANY_SEEN)
+        r->intflags |= PREGf_CANY_SEEN;
+    if (RExC_seen & REG_VERBARG_SEEN)
     {
        r->intflags |= PREGf_VERBARG_SEEN;
         r->extflags |= RXf_NO_INPLACE_SUBST; /* don't understand this! Yves */
     }
-    if (RExC_seen & REG_SEEN_CUTGROUP)
+    if (RExC_seen & REG_CUTGROUP_SEEN)
        r->intflags |= PREGf_CUTGROUP_SEEN;
     if (pm_flags & PMf_USE_RE_EVAL)
        r->intflags |= PREGf_USE_RE_EVAL;
@@ -6944,6 +7072,11 @@ reStudy:
     else
         RXp_PAREN_NAMES(r) = NULL;
 
+    /* If we have seen an anchor in our pattern then we set the extflag RXf_IS_ANCHORED
+     * so it can be used in pp.c */
+    if (r->intflags & PREGf_ANCH)
+        r->extflags |= RXf_IS_ANCHORED;
+
     {
         regnode *first = ri->program + 1;
         U8 fop = OP(first);
@@ -7307,7 +7440,7 @@ Perl_reg_numbered_buff_fetch(pTHX_ REGEXP * const r, const I32 paren,
     assert(s >= rx->subbeg);
     assert((STRLEN)rx->sublen >= (STRLEN)((s - rx->subbeg) + i) );
     if (i >= 0) {
-#if NO_TAINT_SUPPORT
+#ifdef NO_TAINT_SUPPORT
         sv_setpvn(sv, s, i);
 #else
         const int oldtainted = TAINT_get;
@@ -7315,7 +7448,7 @@ Perl_reg_numbered_buff_fetch(pTHX_ REGEXP * const r, const I32 paren,
         sv_setpvn(sv, s, i);
         TAINT_set(oldtainted);
 #endif
-        if ( (rx->extflags & RXf_CANY_SEEN)
+        if ( (rx->intflags & PREGf_CANY_SEEN)
             ? (RXp_MATCH_UTF8(rx)
                         && (!i || is_utf8_string((U8*)s, i)))
             : (RXp_MATCH_UTF8(rx)) )
@@ -9326,7 +9459,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                 /* [19:06] <TimToady> :: is then */
                 if ( memEQs(start_verb,verb_len,"THEN") ) {
                     op = CUTGROUP;
-                    RExC_seen |= REG_SEEN_CUTGROUP;
+                    RExC_seen |= REG_CUTGROUP_SEEN;
                 }
                 break;
            }
@@ -9359,7 +9492,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                     }
                }
                if (!internal_argval)
-                   RExC_seen |= REG_SEEN_VERBARG;
+                    RExC_seen |= REG_VERBARG_SEEN;
            } else if ( start_arg ) {
                vFAIL3("Verb pattern '%.*s' may not have an argument",
                        verb_len, start_verb);
@@ -9512,7 +9645,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                    paren = 1;
                    goto capturing_parens;
                }
-                RExC_seen |= REG_SEEN_LOOKBEHIND;
+                RExC_seen |= REG_LOOKBEHIND_SEEN;
                RExC_in_lookbehind++;
                RExC_parse++;
            case '=':           /* (?=...) */
@@ -9556,7 +9689,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                if (*RExC_parse != ')')
                    FAIL("Sequence (?R) not terminated");
                ret = reg_node(pRExC_state, GOSTART);
-                    RExC_seen |= REG_SEEN_GOSTART;
+                    RExC_seen |= REG_GOSTART_SEEN;
                *flagp |= POSTPONED;
                nextchar(pRExC_state);
                return ret;
@@ -9637,7 +9770,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                } else {
                    RExC_size++;
                }
-               RExC_seen |= REG_SEEN_RECURSE;
+                    RExC_seen |= REG_RECURSE_SEEN;
                 Set_Node_Length(ret, 1 + regarglen[OP(ret)]); /* MJD */
                Set_Node_Offset(ret, parse_start); /* MJD */
 
@@ -9897,7 +10030,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
            if (!SIZE_ONLY ){
                if (!RExC_nestroot)
                    RExC_nestroot = parno;
-               if (RExC_seen & REG_SEEN_RECURSE
+                if (RExC_seen & REG_RECURSE_SEEN
                    && !RExC_open_parens[parno-1])
                {
                    DEBUG_OPTIMISE_MORE_r(PerlIO_printf(Perl_debug_log,
@@ -9988,7 +10121,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
            break;
        case 1: case 2:
            ender = reganode(pRExC_state, CLOSE, parno);
-           if (!SIZE_ONLY && RExC_seen & REG_SEEN_RECURSE) {
+            if (!SIZE_ONLY && RExC_seen & REG_RECURSE_SEEN) {
                DEBUG_OPTIMISE_MORE_r(PerlIO_printf(Perl_debug_log,
                        "Setting close paren #%"IVdf" to %d\n",
                        (IV)parno, REG_NODE_NUM(ender)));
@@ -10035,7 +10168,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
        if (have_branch && !SIZE_ONLY) {
             char is_nothing= 1;
            if (depth==1)
-               RExC_seen |= REG_TOP_LEVEL_BRANCHES;
+                RExC_seen |= REG_TOP_LEVEL_BRANCHES_SEEN;
 
            /* Hook the tails of the branches to the closing node. */
            for (br = ret; br; br = regnext(br)) {
@@ -10358,6 +10491,8 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
                ARG1_SET(ret, (U16)min);
                ARG2_SET(ret, (U16)max);
            }
+            if (max == REG_INFTY)
+                RExC_seen |= REG_UNBOUNDED_QUANTIFIER_SEEN;
 
            goto nest_check;
        }
@@ -10395,6 +10530,7 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
        reginsert(pRExC_state, STAR, ret, depth+1);
        ret->flags = 0;
        RExC_naughty += 4;
+        RExC_seen |= REG_UNBOUNDED_QUANTIFIER_SEEN;
     }
     else if (op == '*') {
        min = 0;
@@ -10404,6 +10540,7 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
        reginsert(pRExC_state, PLUS, ret, depth+1);
        ret->flags = 0;
        RExC_naughty += 3;
+        RExC_seen |= REG_UNBOUNDED_QUANTIFIER_SEEN;
     }
     else if (op == '+') {
        min = 1;
@@ -10785,8 +10922,10 @@ S_alloc_maybe_populate_EXACT(pTHX_ RExC_state_t *pRExC_state,
      * If <len> is zero, the function assumes that the node is to contain only
      * the single character given by <code_point> and calculates what <len>
      * should be.  In pass 1, it sizes the node appropriately.  In pass 2, it
-     * additionally will populate the node's STRING with <code_point>, if <len>
-     * is 0.  In both cases <*flagp> is appropriately set
+     * additionally will populate the node's STRING with <code_point> or its
+     * fold if folding.
+     *
+     * In both cases <*flagp> is appropriately set
      *
      * It knows that under FOLD, the Latin Sharp S and UTF characters above
      * 255, must be folded (the former only when the rules indicate it can
@@ -10799,15 +10938,34 @@ S_alloc_maybe_populate_EXACT(pTHX_ RExC_state_t *pRExC_state,
 
     if (! len_passed_in) {
         if (UTF) {
-            if (FOLD && (! LOC || code_point > 255)) {
+            if (UNI_IS_INVARIANT(code_point)) {
+                if (LOC || ! FOLD) {    /* /l defers folding until runtime */
+                    *character = (U8) code_point;
+                }
+                else { /* Here is /i and not /l (toFOLD() is defined on just
+                          ASCII, which isn't the same thing as INVARIANT on
+                          EBCDIC, but it works there, as the extra invariants
+                          fold to themselves) */
+                    *character = toFOLD((U8) code_point);
+                }
+                len = 1;
+            }
+            else if (FOLD && (! LOC
+                              || ! is_PROBLEMATIC_LOCALE_FOLD_cp(code_point)))
+            {   /* Folding, and ok to do so now */
                 _to_uni_fold_flags(code_point,
                                    character,
                                    &len,
-                                   FOLD_FLAGS_FULL | ((LOC)
-                                                     ? FOLD_FLAGS_LOCALE
-                                                     : (ASCII_FOLD_RESTRICTED)
-                                                       ? FOLD_FLAGS_NOMIX_ASCII
-                                                       : 0));
+                                   FOLD_FLAGS_FULL | ((ASCII_FOLD_RESTRICTED)
+                                                      ? FOLD_FLAGS_NOMIX_ASCII
+                                                      : 0));
+            }
+            else if (code_point <= MAX_UTF8_TWO_BYTE) {
+
+                /* Not folding this cp, and can output it directly */
+                *character = UTF8_TWO_BYTE_HI(code_point);
+                *(character + 1) = UTF8_TWO_BYTE_LO(code_point);
+                len = 2;
             }
             else {
                 uvchr_to_utf8( character, code_point);
@@ -11075,7 +11233,7 @@ tryagain:
            goto finish_meta_pat;
        case 'G':
            ret = reg_node(pRExC_state, GPOS);
-           RExC_seen |= REG_SEEN_GPOS;
+            RExC_seen |= REG_GPOS_SEEN;
            *flagp |= SIMPLE;
            goto finish_meta_pat;
        case 'K':
@@ -11086,7 +11244,7 @@ tryagain:
             * be necessary here to avoid cases of memory corruption, as
             * with: C<$_="x" x 80; s/x\K/y/> -- rgs
             */
-           RExC_seen |= REG_SEEN_LOOKBEHIND;
+            RExC_seen |= REG_LOOKBEHIND_SEEN;
            goto finish_meta_pat;
        case 'Z':
            ret = reg_node(pRExC_state, SEOL);
@@ -11100,7 +11258,7 @@ tryagain:
            goto finish_meta_pat;
        case 'C':
            ret = reg_node(pRExC_state, CANY);
-           RExC_seen |= REG_SEEN_CANY;
+            RExC_seen |= REG_CANY_SEEN;
            *flagp |= HASWIDTH|SIMPLE;
            goto finish_meta_pat;
        case 'X':
@@ -11117,7 +11275,7 @@ tryagain:
 
        case 'b':
            RExC_seen_zerolen++;
-           RExC_seen |= REG_SEEN_LOOKBEHIND;
+            RExC_seen |= REG_LOOKBEHIND_SEEN;
            op = BOUND + get_regex_charset(RExC_flags);
             if (op > BOUNDA) {  /* /aa is same as /a */
                 op = BOUNDA;
@@ -11126,12 +11284,13 @@ tryagain:
            FLAGS(ret) = get_regex_charset(RExC_flags);
            *flagp |= SIMPLE;
            if (! SIZE_ONLY && (U8) *(RExC_parse + 1) == '{') {
-               ckWARNdep(RExC_parse, "\"\\b{\" is deprecated; use \"\\b\\{\" or \"\\b[{]\" instead");
+                /* diag_listed_as: Use "%s" instead of "%s" */
+               vFAIL("Use \"\\b\\{\" instead of \"\\b{\"");
            }
            goto finish_meta_pat;
        case 'B':
            RExC_seen_zerolen++;
-           RExC_seen |= REG_SEEN_LOOKBEHIND;
+            RExC_seen |= REG_LOOKBEHIND_SEEN;
            op = NBOUND + get_regex_charset(RExC_flags);
             if (op > NBOUNDA) { /* /aa is same as /a */
                 op = NBOUNDA;
@@ -11140,7 +11299,8 @@ tryagain:
            FLAGS(ret) = get_regex_charset(RExC_flags);
            *flagp |= SIMPLE;
            if (! SIZE_ONLY && (U8) *(RExC_parse + 1) == '{') {
-               ckWARNdep(RExC_parse, "\"\\B{\" is deprecated; use \"\\B\\{\" or \"\\B[{]\" instead");
+                /* diag_listed_as: Use "%s" instead of "%s" */
+               vFAIL("Use \"\\B\\{\" instead of \"\\B{\"");
            }
            goto finish_meta_pat;
 
@@ -11423,7 +11583,6 @@ tryagain:
            char foldbuf[MAX_NODE_STRING_SIZE+UTF8_MAXBYTES_CASE];
            char *s0;
            U8 upper_parse = MAX_NODE_STRING_SIZE;
-           STRLEN foldlen;
             U8 node_type = compute_EXACTish(pRExC_state);
             bool next_is_quantifier;
             char * oldp = NULL;
@@ -11431,9 +11590,15 @@ tryagain:
             /* We can convert EXACTF nodes to EXACTFU if they contain only
              * characters that match identically regardless of the target
              * string's UTF8ness.  The reason to do this is that EXACTF is not
-             * trie-able, EXACTFU is.  (We don't need to figure this out until
-             * pass 2) */
-            bool maybe_exactfu = node_type == EXACTF && PASS2;
+             * trie-able, EXACTFU is.
+             *
+             * Similarly, we can convert EXACTFL nodes to EXACTFU if they
+             * contain only above-Latin1 characters (hence must be in UTF8),
+             * which don't participate in folds with Latin1-range characters,
+             * as the latter's folds aren't known until runtime.  (We don't
+             * need to figure this out until pass 2) */
+            bool maybe_exactfu = PASS2
+                               && (node_type == EXACTF || node_type == EXACTFL);
 
             /* If a folding node contains only code points that don't
              * participate in folds, it can be changed into an EXACT node,
@@ -11450,10 +11615,9 @@ tryagain:
 
        reparse:
 
-            /* We do the EXACTFish to EXACT node only if folding, and not if in
-             * locale, as whether a character folds or not isn't known until
-             * runtime.  (And we don't need to figure this out until pass 2) */
-            maybe_exact = FOLD && ! LOC && PASS2;
+            /* We do the EXACTFish to EXACT node only if folding.  (And we
+             * don't need to figure this out until pass 2) */
+            maybe_exact = FOLD && PASS2;
 
            /* XXX The node can hold up to 255 bytes, yet this only goes to
              * 127.  I (khw) do not know why.  Keeping it somewhat less than
@@ -11630,7 +11794,7 @@ tryagain:
                        }
                    case 'c':
                        p++;
-                       ender = grok_bslash_c(*p++, UTF, SIZE_ONLY);
+                       ender = grok_bslash_c(*p++, SIZE_ONLY);
                        break;
                     case '8': case '9': /* must be a backreference */
                         --p;
@@ -11744,7 +11908,10 @@ tryagain:
                     goto loopdone;
                 }
 
-                if (! FOLD) {   /* The simple case, just append the literal */
+                if (! FOLD   /* The simple case, just append the literal */
+                    || (LOC  /* Also don't fold for tricky chars under /l */
+                        && is_PROBLEMATIC_LOCALE_FOLD_cp(ender)))
+                {
                     if (UTF) {
                         const STRLEN unilen = reguni(pRExC_state, ender, s);
                         if (unilen > 0) {
@@ -11762,15 +11929,27 @@ tryagain:
                     else {
                         REGC((char)ender, s++);
                     }
+
+                    /* Can get here if folding only if is one of the /l
+                     * characters whose fold depends on the locale.  The
+                     * occurrence of any of these indicate that we can't
+                     * simplify things */
+                    if (FOLD) {
+                        maybe_exact = FALSE;
+                        maybe_exactfu = FALSE;
+                    }
                 }
-                else /* FOLD */ if (! ( UTF
+                else             /* FOLD */
+                     if (! ( UTF
                         /* See comments for join_exact() as to why we fold this
                          * non-UTF at compile time */
                         || (node_type == EXACTFU
                             && ender == LATIN_SMALL_LETTER_SHARP_S)))
                 {
                     /* Here, are folding and are not UTF-8 encoded; therefore
-                     * the character must be in the range 0-255. */
+                     * the character must be in the range 0-255, and is not /l
+                     * (Not /l because we already handled these under /l in
+                     * is_PROBLEMATIC_LOCALE_FOLD_cp */
                     if (IS_IN_SOME_FOLD_L1(ender)) {
                         maybe_exact = FALSE;
 
@@ -11800,62 +11979,50 @@ tryagain:
                      * unfolded, and we have to calculate how many EXACTish
                      * nodes it will take; and we may run out of room in a node
                      * in the middle of a potential multi-char fold, and have
-                     * to back off accordingly. */
-
-                    /* Prime the casefolded buffer.  Locale rules, which apply
-                     * only to code points < 256, aren't known until execution,
-                     * so for them, just output the original character using
-                     * utf8.  If we start to fold non-UTF patterns, be sure to
-                     * update join_exact() */
-                    if (LOC && ender < 256) {
-                        if (UVCHR_IS_INVARIANT(ender)) {
-                            *s = (U8) ender;
-                            foldlen = 1;
-                        } else {
-                            *s = UTF8_TWO_BYTE_HI(ender);
-                            *(s + 1) = UTF8_TWO_BYTE_LO(ender);
-                            foldlen = 2;
-                        }
+                     * to back off accordingly.  (Hence we can't use REGC for
+                     * the simple case just below.) */
+
+                    UV folded;
+                    if (isASCII(ender)) {
+                        folded = toFOLD(ender);
+                        *(s)++ = (U8) folded;
+                    }
+                    else {
+                        STRLEN foldlen;
+
+                        folded = _to_uni_fold_flags(
+                                     ender,
+                                     (U8 *) s,
+                                     &foldlen,
+                                     FOLD_FLAGS_FULL | ((ASCII_FOLD_RESTRICTED)
+                                                        ? FOLD_FLAGS_NOMIX_ASCII
+                                                        : 0));
+                        s += foldlen;
+
+                        /* The loop increments <len> each time, as all but this
+                         * path (and one other) through it add a single byte to
+                         * the EXACTish node.  But this one has changed len to
+                         * be the correct final value, so subtract one to
+                         * cancel out the increment that follows */
+                        len += foldlen - 1;
                     }
-                    else {  /* ender >= 256 */
-                        UV folded = _to_uni_fold_flags(
-                                       ender,
-                                       (U8 *) s,
-                                       &foldlen,
-                                       FOLD_FLAGS_FULL
-                                       | ((LOC) ?  FOLD_FLAGS_LOCALE
-                                                : (ASCII_FOLD_RESTRICTED)
-                                                  ? FOLD_FLAGS_NOMIX_ASCII
-                                                  : 0)
-                                        );
-
-                        /* If this node only contains non-folding code points
-                         * so far, see if this new one is also non-folding */
-                        if (maybe_exact) {
-                            if (folded != ender) {
+                    /* If this node only contains non-folding code points so
+                     * far, see if this new one is also non-folding */
+                    if (maybe_exact) {
+                        if (folded != ender) {
+                            maybe_exact = FALSE;
+                        }
+                        else {
+                            /* Here the fold is the original; we have to check
+                             * further to see if anything folds to it */
+                            if (_invlist_contains_cp(PL_utf8_foldable,
+                                                        ender))
+                            {
                                 maybe_exact = FALSE;
                             }
-                            else {
-                                /* Here the fold is the original; we have
-                                 * to check further to see if anything
-                                 * folds to it */
-                                if (_invlist_contains_cp(PL_utf8_foldable,
-                                                         ender))
-                                {
-                                    maybe_exact = FALSE;
-                                }
-                            }
                         }
-                        ender = folded;
                     }
-                    s += foldlen;
-
-                    /* The loop increments <len> each time, as all but this
-                     * path (and one other) through it add a single byte to the
-                     * EXACTish node.  But this one has changed len to be the
-                     * correct final value, so subtract one to cancel out the
-                     * increment that follows */
-                    len += foldlen - 1;
+                    ender = folded;
                }
 
                if (next_is_quantifier) {
@@ -11904,9 +12071,8 @@ tryagain:
 
                if (! UTF) {
 
-                    /* These two have no multi-char folds to non-UTF characters
-                     */
-                    if (ASCII_FOLD_RESTRICTED || LOC) {
+                    /* This has no multi-char folds to non-UTF characters */
+                    if (ASCII_FOLD_RESTRICTED) {
                         goto loopdone;
                     }
 
@@ -11937,11 +12103,7 @@ tryagain:
                             }
                         }
                         else if (UTF8_IS_DOWNGRADEABLE_START(*s)) {
-
-                            /* No Latin1 characters participate in multi-char
-                             * folds under /l */
-                            if (LOC
-                                || ! IS_NON_FINAL_FOLD(TWO_BYTE_UTF8_TO_NATIVE(
+                            if (! IS_NON_FINAL_FOLD(TWO_BYTE_UTF8_TO_NATIVE(
                                                                   *s, *(s+1))))
                             {
                                 break;
@@ -12052,7 +12214,7 @@ tryagain:
                      * code points in the node that participate in folds;
                      * similarly for 'maybe_exactfu' and code points that match
                      * differently depending on UTF8ness of the target string
-                     * */
+                     * (for /u), or depending on locale for /l */
                     if (maybe_exact) {
                         OP(ret) = EXACT;
                     }
@@ -12099,7 +12261,7 @@ S_regwhite( RExC_state_t *pRExC_state, char *p )
                }
            } while (p < e);
            if (!ended)
-               RExC_seen |= REG_SEEN_RUN_ON_COMMENT;
+                RExC_seen |= REG_RUN_ON_COMMENT_SEEN;
        }
        else
            break;
@@ -12113,7 +12275,7 @@ S_regpatws( RExC_state_t *pRExC_state, char *p , const bool recognize_comment )
     /* Returns the next non-pattern-white space, non-comment character (the
      * latter only if 'recognize_comment is true) in the string p, which is
      * ended by RExC_end.  If there is no line break ending a comment,
-     * RExC_seen has added the REG_SEEN_RUN_ON_COMMENT flag; */
+     * RExC_seen has added the REG_RUN_ON_COMMENT_SEEN flag; */
     const char *e = RExC_end;
 
     PERL_ARGS_ASSERT_REGPATWS;
@@ -12133,7 +12295,7 @@ S_regpatws( RExC_state_t *pRExC_state, char *p , const bool recognize_comment )
                }
            } while (p < e);
            if (!ended)
-               RExC_seen |= REG_SEEN_RUN_ON_COMMENT;
+                RExC_seen |= REG_RUN_ON_COMMENT_SEEN;
        }
        else
            break;
@@ -13375,7 +13537,7 @@ parseit:
                    goto recode_encoding;
                break;
            case 'c':
-               value = grok_bslash_c(*RExC_parse++, UTF, SIZE_ONLY);
+               value = grok_bslash_c(*RExC_parse++, SIZE_ONLY);
                break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7':
@@ -13455,21 +13617,37 @@ parseit:
          * space will contain a bit for each named class that is to be matched
          * against.  This isn't needed for \p{} and pseudo-classes, as they are
          * not affected by locale, and hence are dealt with separately */
-        if (LOC
-            && ! need_class
-            && (ANYOF_LOCALE == ANYOF_POSIXL
-                || (namedclass > OOB_NAMEDCLASS
-                    && namedclass < ANYOF_POSIXL_MAX)))
-        {
-            need_class = 1;
-            if (SIZE_ONLY) {
-                RExC_size += ANYOF_POSIXL_SKIP - ANYOF_SKIP;
+        if (LOC) {
+            if (FOLD && ! need_class) {
+                need_class = 1;
+                if (SIZE_ONLY) {
+                    RExC_size += ANYOF_POSIXL_FOLD_SKIP - ANYOF_SKIP;
+                }
+                else {
+                    RExC_emit += ANYOF_POSIXL_FOLD_SKIP - ANYOF_SKIP;
+                }
+
+                /* We need to initialize this here because this node type has
+                 * this field, and will skip getting initialized when we get to
+                 * a posix class since are doing it here */
+                ANYOF_POSIXL_ZERO(ret);
             }
-            else {
-                RExC_emit += ANYOF_POSIXL_SKIP - ANYOF_SKIP;
+            if (ANYOF_LOCALE == ANYOF_POSIXL
+                || (namedclass > OOB_NAMEDCLASS
+                    && namedclass < ANYOF_POSIXL_MAX))
+            {
+                if (! need_class) {
+                    need_class = 1;
+                    if (SIZE_ONLY) {
+                        RExC_size += ANYOF_POSIXL_SKIP - ANYOF_SKIP;
+                    }
+                    else {
+                        RExC_emit += ANYOF_POSIXL_SKIP - ANYOF_SKIP;
+                    }
+                    ANYOF_POSIXL_ZERO(ret);
+                }
+                ANYOF_FLAGS(ret) |= ANYOF_POSIXL;
             }
-            ANYOF_POSIXL_ZERO(ret);
-            ANYOF_FLAGS(ret) |= ANYOF_POSIXL;
         }
 
        if (namedclass > OOB_NAMEDCLASS) { /* this is a named class \blah */
@@ -13510,9 +13688,6 @@ parseit:
 #ifndef HAS_ISASCII
                 && classnum != _CC_ASCII
 #endif
-#ifndef HAS_ISBLANK
-                && classnum != _CC_BLANK
-#endif
             ) {
 
                 /* See if it already matches the complement of this POSIX
@@ -13596,16 +13771,6 @@ parseit:
                                        ? &posixes
                                        : &nposixes;
                     SV** source_ptr = &PL_XPosix_ptrs[classnum];
-#ifndef HAS_ISBLANK
-                    /* If the platform doesn't have isblank(), we handle locale
-                     * with the hardcoded ASII values. */
-                    if (LOC && classnum == _CC_BLANK) {
-                        _invlist_subtract(*source_ptr,
-                                          PL_UpperLatin1,
-                                          source_ptr);
-                    }
-#endif
-
                     _invlist_union_maybe_complement_2nd(
                                                      *posixes_ptr,
                                                      *source_ptr,
@@ -13714,11 +13879,9 @@ parseit:
                                 value,
                                 foldbuf,
                                 &foldlen,
-                                FOLD_FLAGS_FULL
-                                | ((LOC) ?  FOLD_FLAGS_LOCALE
-                                            : (ASCII_FOLD_RESTRICTED)
-                                              ? FOLD_FLAGS_NOMIX_ASCII
-                                              : 0)
+                                FOLD_FLAGS_FULL | (ASCII_FOLD_RESTRICTED
+                                                   ? FOLD_FLAGS_NOMIX_ASCII
+                                                   : 0)
                                 );
 
                 /* Here, <folded> should be the first character of the
@@ -13975,14 +14138,6 @@ parseit:
                     if (op > POSIXA) { /* /aa is same as /a */
                         op = POSIXA;
                     }
-#ifndef HAS_ISBLANK
-                    if (op == POSIXL
-                        && (namedclass == ANYOF_BLANK
-                            || namedclass == ANYOF_NBLANK))
-                    {
-                        op = POSIXA;
-                    }
-#endif
 
                 join_posix:
                     /* The odd numbered ones are the complements of the
@@ -14083,6 +14238,19 @@ parseit:
             UV start, end;     /* End points of code point ranges */
 
             SV* fold_intersection = NULL;
+            SV** use_list;
+
+            /* Our calculated list will be for Unicode rules.  For locale
+             * matching, we have to keep a separate list that is consulted at
+             * runtime only when the locale indicates Unicode rules.  For
+             * non-locale, we just use to the general list */
+            if (LOC) {
+                use_list = &ANYOF_UTF8_LOCALE_INVLIST(ret);
+                *use_list = NULL;
+            }
+            else {
+                use_list = &cp_list;
+            }
 
             /* Only the characters in this class that participate in folds need
              * be checked.  Get the intersection of this class and all the
@@ -14118,15 +14286,8 @@ parseit:
             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++) {
-
                     U8 foldbuf[UTF8_MAXBYTES_CASE+1];
                     STRLEN foldlen;
                     SV** listp;
@@ -14145,9 +14306,10 @@ parseit:
                         if (IS_IN_SOME_FOLD_L1(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,
+                             * only under Unicode rules (which could happen
+                             * under /l if the locale is a UTF-8 one */
+                            if (isASCII(j) || ! DEPENDS_SEMANTICS) {
+                                *use_list = add_cp_to_invlist(*use_list,
                                                             PL_fold_latin1[j]);
                             }
                             else {
@@ -14172,32 +14334,31 @@ parseit:
                             switch (j) {
                                 case 'k':
                                 case 'K':
-                                    cp_list =
-                                        add_cp_to_invlist(cp_list, KELVIN_SIGN);
+                                  *use_list =
+                                     add_cp_to_invlist(*use_list, KELVIN_SIGN);
                                     break;
                                 case 's':
                                 case 'S':
-                                    cp_list = add_cp_to_invlist(cp_list,
+                                  *use_list = add_cp_to_invlist(*use_list,
                                                     LATIN_SMALL_LETTER_LONG_S);
                                     break;
                                 case MICRO_SIGN:
-                                    cp_list = add_cp_to_invlist(cp_list,
-                                                    GREEK_CAPITAL_LETTER_MU);
-                                    cp_list = add_cp_to_invlist(cp_list,
-                                                      GREEK_SMALL_LETTER_MU);
+                                  *use_list = add_cp_to_invlist(*use_list,
+                                                      GREEK_CAPITAL_LETTER_MU);
+                                  *use_list = add_cp_to_invlist(*use_list,
+                                                        GREEK_SMALL_LETTER_MU);
                                     break;
                                 case LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE:
                                 case LATIN_SMALL_LETTER_A_WITH_RING_ABOVE:
-                                    cp_list =
-                                        add_cp_to_invlist(cp_list,
-                                                                ANGSTROM_SIGN);
+                                  *use_list =
+                                   add_cp_to_invlist(*use_list, ANGSTROM_SIGN);
                                     break;
                                 case LATIN_SMALL_LETTER_Y_WITH_DIAERESIS:
-                                    cp_list = add_cp_to_invlist(cp_list,
+                                  *use_list = add_cp_to_invlist(*use_list,
                                         LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS);
                                     break;
                                 case LATIN_SMALL_LETTER_SHARP_S:
-                                    cp_list = add_cp_to_invlist(cp_list,
+                                  *use_list = add_cp_to_invlist(*use_list,
                                                  LATIN_CAPITAL_LETTER_SHARP_S);
                                     break;
                                 case 'F': case 'f':
@@ -14233,11 +14394,9 @@ parseit:
                      * the simple fold, as the multi-character folds have been
                      * handled earlier and separated out */
                     _to_uni_fold_flags(j, foldbuf, &foldlen,
-                                                   ((LOC)
-                                                   ? FOLD_FLAGS_LOCALE
-                                                   : (ASCII_FOLD_RESTRICTED)
-                                                      ? FOLD_FLAGS_NOMIX_ASCII
-                                                      : 0));
+                                                        (ASCII_FOLD_RESTRICTED)
+                                                        ? FOLD_FLAGS_NOMIX_ASCII
+                                                        : 0);
 
                     /* Single character fold of above Latin1.  Add everything in
                     * its fold closure to the list that this node should match.
@@ -14259,23 +14418,30 @@ parseit:
                             }
                             c = SvUV(*c_p);
 
-                            /* /aa doesn't allow folds between ASCII and non-;
-                             * /l doesn't allow them between above and below
-                             * 256 */
+                            /* /aa doesn't allow folds between ASCII and non- */
                             if ((ASCII_FOLD_RESTRICTED
-                                      && (isASCII(c) != isASCII(j)))
-                                || (LOC && c < 256)) {
+                                && (isASCII(c) != isASCII(j))))
+                            {
+                                continue;
+                            }
+
+                            /* Folds under /l which cross the 255/256 boundary
+                             * are added to a separate list.  (These are valid
+                             * only when the locale is UTF-8.) */
+                            if (c < 256 && LOC) {
+                                *use_list = add_cp_to_invlist(*use_list, c);
                                 continue;
                             }
 
-                            /* 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);
+                                /* Similarly folds involving non-ascii Latin1
+                                * characters under /d are added to their list */
+                                depends_list = add_cp_to_invlist(depends_list,
+                                                                 c);
                             }
                         }
                     }
@@ -14408,10 +14574,21 @@ parseit:
     /* If we didn't do folding, it's because some information isn't available
      * until runtime; set the run-time fold flag for these.  (We don't have to
      * worry about properties folding, as that is taken care of by the swash
-     * fetching) */
-    if (FOLD && LOC)
-    {
-       ANYOF_FLAGS(ret) |= ANYOF_LOC_FOLD;
+     * fetching).  We know to set the flag if we have a non-NULL list for UTF-8
+     * locales, or the class matches at least one 0-255 range code point */
+    if (LOC && FOLD) {
+        if (ANYOF_UTF8_LOCALE_INVLIST(ret)) {
+            ANYOF_FLAGS(ret) |= ANYOF_LOC_FOLD;
+        }
+        else if (cp_list) { /* Look to see if there a 0-255 code point is in
+                               the list */
+            UV start, end;
+            invlist_iterinit(cp_list);
+            if (invlist_iternext(cp_list, &start, &end) && start < 256) {
+                ANYOF_FLAGS(ret) |= ANYOF_LOC_FOLD;
+            }
+            invlist_iterfinish(cp_list);
+        }
     }
 
     /* Optimize inverted simple patterns (e.g. [^a-z]) when everything is known
@@ -14467,7 +14644,7 @@ parseit:
     if (cp_list
         && ! invert
         && ! depends_list
-        && ! (ANYOF_FLAGS(ret) & ANYOF_POSIXL)
+        && ! (ANYOF_FLAGS(ret) & (ANYOF_LOC_FOLD|ANYOF_POSIXL))
         && ! HAS_NONLOCALE_RUNTIME_PROPERTY_DEFINITION
 
            /* We don't optimize if we are supposed to make sure all non-Unicode
@@ -14682,7 +14859,7 @@ S_set_ANYOF_arg(pTHX_ RExC_state_t* const pRExC_state,
 
    Absorbs an /x style # comments from the input stream.
    Returns true if there is more text remaining in the stream.
-   Will set the REG_SEEN_RUN_ON_COMMENT flag if the comment
+   Will set the REG_RUN_ON_COMMENT_SEEN flag if the comment
    terminates the pattern without including a newline.
 
    Note its the callers responsibility to ensure that we are
@@ -14705,7 +14882,7 @@ S_reg_skipcomment(pTHX_ RExC_state_t *pRExC_state)
     if (!ended) {
         /* we ran off the end of the pattern without ending
            the comment, so we have to add an \n when wrapping */
-        RExC_seen |= REG_SEEN_RUN_ON_COMMENT;
+        RExC_seen |= REG_RUN_ON_COMMENT_SEEN;
         return 0;
     } else
         return 1;
@@ -15053,9 +15230,9 @@ S_regtail_study(pTHX_ RExC_state_t *pRExC_state, regnode *p,
         regnode * const temp = regnext(scan);
 #ifdef EXPERIMENTAL_INPLACESCAN
         if (PL_regkind[OP(scan)] == EXACT) {
-           bool has_exactf_sharp_s;    /* Unexamined in this routine */
+           bool unfolded_multi_char;   /* Unexamined in this routine */
             if (join_exact(pRExC_state, scan, &min,
-                           &has_exactf_sharp_s, 1, val, depth+1))
+                           &unfolded_multi_char, 1, val, depth+1))
                 return EXACT;
        }
 #endif
@@ -15238,7 +15415,7 @@ Perl_regdump(pTHX_ const regexp *r)
                      (r->check_substr == r->float_substr
                       && r->check_utf8 == r->float_utf8
                       ? "(checking floating" : "(checking anchored"));
-    if (r->extflags & RXf_NOSCAN)
+    if (r->intflags & PREGf_NOSCAN)
        PerlIO_printf(Perl_debug_log, " noscan");
     if (r->extflags & RXf_CHECK_ALL)
        PerlIO_printf(Perl_debug_log, " isall");
@@ -15249,19 +15426,19 @@ Perl_regdump(pTHX_ const regexp *r)
        regprop(r, sv, ri->regstclass);
        PerlIO_printf(Perl_debug_log, "stclass %s ", SvPVX_const(sv));
     }
-    if (r->extflags & RXf_ANCH) {
+    if (r->intflags & PREGf_ANCH) {
        PerlIO_printf(Perl_debug_log, "anchored");
-       if (r->extflags & RXf_ANCH_BOL)
+        if (r->intflags & PREGf_ANCH_BOL)
            PerlIO_printf(Perl_debug_log, "(BOL)");
-       if (r->extflags & RXf_ANCH_MBOL)
+        if (r->intflags & PREGf_ANCH_MBOL)
            PerlIO_printf(Perl_debug_log, "(MBOL)");
-       if (r->extflags & RXf_ANCH_SBOL)
+        if (r->intflags & PREGf_ANCH_SBOL)
            PerlIO_printf(Perl_debug_log, "(SBOL)");
-       if (r->extflags & RXf_ANCH_GPOS)
+        if (r->intflags & PREGf_ANCH_GPOS)
            PerlIO_printf(Perl_debug_log, "(GPOS)");
        PerlIO_putc(Perl_debug_log, ' ');
     }
-    if (r->extflags & RXf_GPOS_SEEN)
+    if (r->intflags & PREGf_GPOS_SEEN)
        PerlIO_printf(Perl_debug_log, "GPOS:%"UVuf" ", (UV)r->gofs);
     if (r->intflags & PREGf_SKIP)
        PerlIO_printf(Perl_debug_log, "plus ");
@@ -15470,8 +15647,8 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o)
             }
         }
 
-       if (flags & (ANYOF_ABOVE_LATIN1_ALL|ANYOF_ABOVE_LATIN1_ALL)
-            || ANYOF_NONBITMAP(o))
+       if ((flags & ANYOF_ABOVE_LATIN1_ALL)
+            || ANYOF_UTF8_LOCALE_INVLIST(o) || ANYOF_NONBITMAP(o))
         {
             if (do_sep) {
                 Perl_sv_catpvf(aTHX_ sv,"%s][%s",PL_colors[1],PL_colors[0]);
@@ -15545,6 +15722,25 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o)
                     SvREFCNT_dec_NN(lv);
                 }
             }
+
+            /* Output any UTF-8 locale code points */
+            if (flags & ANYOF_LOC_FOLD && ANYOF_UTF8_LOCALE_INVLIST(o)) {
+                UV start, end;
+                int max_entries = 256;
+
+                sv_catpvs(sv, "{utf8 locale}");
+                invlist_iterinit(ANYOF_UTF8_LOCALE_INVLIST(o));
+                while (invlist_iternext(ANYOF_UTF8_LOCALE_INVLIST(o),
+                                        &start, &end)) {
+                    put_range(sv, start, end);
+                    max_entries --;
+                    if (max_entries < 0) {
+                        sv_catpvs(sv, "...");
+                        break;
+                    }
+                }
+                invlist_iterfinish(ANYOF_UTF8_LOCALE_INVLIST(o));
+            }
        }
 
        Perl_sv_catpvf(aTHX_ sv, "%s]", PL_colors[1]);
@@ -16408,8 +16604,11 @@ S_dumpuntil(pTHX_ const regexp *r, const regnode *start, const regnode *node,
        }
        else if (PL_regkind[(U8)op] == ANYOF) {
            /* arglen 1 + class block */
-           node += 1 + ((ANYOF_FLAGS(node) & ANYOF_POSIXL)
-                   ? ANYOF_POSIXL_SKIP : ANYOF_SKIP);
+           node += 1 + ((ANYOF_FLAGS(node) & ANYOF_LOC_FOLD)
+                        ? ANYOF_POSIXL_FOLD_SKIP
+                         : (ANYOF_FLAGS(node) & ANYOF_POSIXL)
+                           ? ANYOF_POSIXL_SKIP
+                           : ANYOF_SKIP);
            node = NEXTOPER(node);
        }
        else if (PL_regkind[(U8)op] == EXACT) {