This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regcomp.c: White-space only, wrap comment to fit
[perl5.git] / regcomp.c
index bf29fdd..1a1cd1c 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -2838,7 +2838,8 @@ S_join_exact(pTHX_ RExC_state_t *pRExC_state, regnode *scan, UV *min_subtract, b
                     OP(scan) = EXACTFU_SS;
                     s += 2;
                 }
-                else if (len == 6   /* len is the same in both ASCII and EBCDIC for these */
+                else if (len == 6   /* len is the same in both ASCII and EBCDIC
+                                       for these */
                          && (memEQ(s, GREEK_SMALL_LETTER_IOTA_UTF8
                                       COMBINING_DIAERESIS_UTF8
                                       COMBINING_ACUTE_ACCENT_UTF8,
@@ -4883,7 +4884,7 @@ Perl_re_compile(pTHX_ SV * const pattern, U32 rx_flags)
 
 static void
 S_pat_upgrade_to_utf8(pTHX_ RExC_state_t * const pRExC_state,
-                   char **pat_p, STRLEN *plen_p)
+                   char **pat_p, STRLEN *plen_p, int num_code_blocks)
 {
     U8 *const src = (U8*)*pat_p;
     U8 *dst;
@@ -4905,7 +4906,7 @@ S_pat_upgrade_to_utf8(pTHX_ RExC_state_t * const pRExC_state,
             dst[d++] = (U8)UTF8_EIGHT_BIT_HI(uv);
             dst[d]   = (U8)UTF8_EIGHT_BIT_LO(uv);
         }
-        if (n < pRExC_state->num_code_blocks) {
+        if (n < num_code_blocks) {
             if (!do_end && pRExC_state->code_blocks[n].start == s) {
                 pRExC_state->code_blocks[n].start = d;
                 assert(dst[d] == '(');
@@ -4932,31 +4933,89 @@ S_pat_upgrade_to_utf8(pTHX_ RExC_state_t * const pRExC_state,
 
 /* S_concat_pat(): concatenate a list of args to the pattern string pat,
  * while recording any code block indices, and handling overloading,
- * nested qr// objects etc.
- * Returns pat (or the first arg, if pat was null , i.e. there is only
- * one arg).
+ * nested qr// objects etc.  If pat is null, it will allocate a new
+ * string, or just return the first arg, if there's only one.
+ *
+ * Returns the malloced/updated pat.
  * patternp and pat_count is the array of SVs to be concatted;
  * oplist is the optional list of ops that generated the SVs;
  * recompile_p is a pointer to a boolean that will be set if
  *   the regex will need to be recompiled.
+ * delim, if non-null is an SV that will be inserted between each element
  */
 
 static SV*
 S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
                 SV *pat, SV ** const patternp, int pat_count,
-                OP *oplist, bool *recompile_p)
+                OP *oplist, bool *recompile_p, SV *delim)
 {
     SV **svp;
     int n = 0;
+    bool use_delim = FALSE;
+    bool alloced = FALSE;
 
-    assert(!pat || pat_count > 1);
+    /* if we know we have at least two args, create an empty string,
+     * then concatenate args to that. For no args, return an empty string */
+    if (!pat && pat_count != 1) {
+        pat = newSVpvn("", 0);
+        SAVEFREESV(pat);
+        alloced = TRUE;
+    }
 
     for (svp = patternp; svp < patternp + pat_count; svp++) {
         SV *sv;
         SV *rx  = NULL;
         STRLEN orig_patlen = 0;
         bool code = 0;
-        SV *msv = *svp;
+        SV *msv = use_delim ? delim : *svp;
+
+        /* if we've got a delimiter, we go round the loop twice for each
+         * svp slot (except the last), using the delimiter the second
+         * time round */
+        if (use_delim) {
+            svp--;
+            use_delim = FALSE;
+        }
+        else if (delim)
+            use_delim = TRUE;
+
+        if (SvTYPE(msv) == SVt_PVAV) {
+            /* we've encountered an interpolated array within
+             * the pattern, e.g. /...@a..../. Expand the list of elements,
+             * then recursively append elements.
+             * The code in this block is based on S_pushav() */
+
+            AV *const av = (AV*)msv;
+            const I32 maxarg = AvFILL(av) + 1;
+            SV **array;
+
+            if (oplist) {
+                assert(oplist->op_type == OP_PADAV
+                    || oplist->op_type == OP_RV2AV); 
+                oplist = oplist->op_sibling;;
+            }
+
+            if (SvRMAGICAL(av)) {
+                U32 i;
+
+                Newx(array, maxarg, SV*);
+                SAVEFREEPV(array);
+                for (i=0; i < (U32)maxarg; i++) {
+                    SV ** const svp = av_fetch(av, i, FALSE);
+                    array[i] = svp ? *svp : &PL_sv_undef;
+                }
+            }
+            else
+                array = AvARRAY(av);
+
+            pat = S_concat_pat(aTHX_ pRExC_state, pat,
+                                array, maxarg, NULL, recompile_p,
+                                /* $" */
+                                GvSV((gv_fetchpvs("\"", GV_ADDMULTI, SVt_PV))));
+
+            continue;
+        }
+
 
         /* we make the assumption here that each op in the list of
          * op_siblings maps to one SV pushed onto the stack,
@@ -5024,6 +5083,7 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
             }
             if (SvROK(msv) && SvTYPE(SvRV(msv)) == SVt_REGEXP)
                 msv = SvRV(msv);
+
             if (pat) {
                 /* this is a partially unrolled
                  *     sv_catsv_nomg(pat, msv);
@@ -5034,7 +5094,7 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
                 const char *src = SvPV_flags_const(msv, slen, 0);
                 orig_patlen = dlen;
                 if (SvUTF8(msv) && !SvUTF8(pat)) {
-                    S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &dst, &dlen);
+                    S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &dst, &dlen, n);
                     sv_setpvn(pat, dst, dlen);
                     SvUTF8_on(pat);
                 }
@@ -5043,6 +5103,7 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
             }
             else
                 pat = msv;
+
             if (code)
                 pRExC_state->code_blocks[n-1].end = SvCUR(pat)-1;
         }
@@ -5084,6 +5145,10 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
             }
         }
     }
+    /* avoid calling magic multiple times on a single element e.g. =~ $qr */
+    if (alloced)
+        SvSETMAGIC(pat);
+
     return pat;
 }
 
@@ -5419,7 +5484,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     I32 flags;
     I32 minlen = 0;
     U32 rx_flags;
-    SV *pat = NULL;
+    SV *pat;
     SV *code_blocksv = NULL;
     SV** new_patternp = patternp;
 
@@ -5563,50 +5628,42 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
 
     }
 
-        DEBUG_PARSE_r(PerlIO_printf(Perl_debug_log,
-            "Assembling pattern from %d elements%s\n", pat_count,
-                orig_rx_flags & RXf_SPLIT ? " for split" : ""));
-
-        /* set expr to the first arg op */
-
-        if (pRExC_state->num_code_blocks
-             && expr->op_type != OP_CONST)
-        {
-                expr = cLISTOPx(expr)->op_first;
-                assert(   expr->op_type == OP_PUSHMARK
-                       || (expr->op_type == OP_NULL && expr->op_targ == OP_PUSHMARK)
-                       || expr->op_type == OP_PADRANGE);
-                expr = expr->op_sibling;
-        }
+    DEBUG_PARSE_r(PerlIO_printf(Perl_debug_log,
+        "Assembling pattern from %d elements%s\n", pat_count,
+            orig_rx_flags & RXf_SPLIT ? " for split" : ""));
 
-        if (pat_count > 1) {
-           pat = newSVpvn("", 0);
-           SAVEFREESV(pat);
-        }
+    /* set expr to the first arg op */
 
-        pat = S_concat_pat(aTHX_ pRExC_state, pat, new_patternp, pat_count,
-                            expr, &recompile);
+    if (pRExC_state->num_code_blocks
+         && expr->op_type != OP_CONST)
+    {
+            expr = cLISTOPx(expr)->op_first;
+            assert(   expr->op_type == OP_PUSHMARK
+                   || (expr->op_type == OP_NULL && expr->op_targ == OP_PUSHMARK)
+                   || expr->op_type == OP_PADRANGE);
+            expr = expr->op_sibling;
+    }
 
-        if (pat_count > 1)
-            SvSETMAGIC(pat);
+    pat = S_concat_pat(aTHX_ pRExC_state, NULL, new_patternp, pat_count,
+                        expr, &recompile, NULL);
 
-       /* handle bare (possibly after overloading) regex: foo =~ $re */
-       {
-           SV *re = pat;
-           if (SvROK(re))
-               re = SvRV(re);
-           if (SvTYPE(re) == SVt_REGEXP) {
-               if (is_bare_re)
-                   *is_bare_re = TRUE;
-               SvREFCNT_inc(re);
-               Safefree(pRExC_state->code_blocks);
-                DEBUG_PARSE_r(PerlIO_printf(Perl_debug_log,
-                    "Precompiled pattern%s\n",
-                        orig_rx_flags & RXf_SPLIT ? " for split" : ""));
+    /* handle bare (possibly after overloading) regex: foo =~ $re */
+    {
+        SV *re = pat;
+        if (SvROK(re))
+            re = SvRV(re);
+        if (SvTYPE(re) == SVt_REGEXP) {
+            if (is_bare_re)
+                *is_bare_re = TRUE;
+            SvREFCNT_inc(re);
+            Safefree(pRExC_state->code_blocks);
+            DEBUG_PARSE_r(PerlIO_printf(Perl_debug_log,
+                "Precompiled pattern%s\n",
+                    orig_rx_flags & RXf_SPLIT ? " for split" : ""));
 
-               return (REGEXP*)re;
-           }
-       }
+            return (REGEXP*)re;
+        }
+    }
 
     exp = SvPV_nomg(pat, plen);
 
@@ -5690,7 +5747,8 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
        if (!S_compile_runtime_code(aTHX_ pRExC_state, exp, plen)) {
            /* whoops, we have a non-utf8 pattern, whilst run-time code
             * got compiled as utf8. Try again with a utf8 pattern */
-            S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &exp, &plen);
+            S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &exp, &plen,
+                                    pRExC_state->num_code_blocks);
             goto redo_first_pass;
        }
     }
@@ -5756,10 +5814,11 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
         thing.
         -- dmq */
         if (flags & RESTART_UTF8) {
-            S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &exp, &plen);
+            S_pat_upgrade_to_utf8(aTHX_ pRExC_state, &exp, &plen,
+                                    pRExC_state->num_code_blocks);
             goto redo_first_pass;
         }
-        Perl_croak(aTHX_ "panic: reg returned NULL to re_op_compile for sizing pass, flags=%#X", flags);
+        Perl_croak(aTHX_ "panic: reg returned NULL to re_op_compile for sizing pass, flags=%#"UVxf"", (UV) flags);
     }
     if (code_blocksv)
        SvLEN_set(code_blocksv,0); /* no you can't have it, sv_clear */
@@ -5931,7 +5990,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
     REGC((U8)REG_MAGIC, (char*) RExC_emit++);
     if (reg(pRExC_state, 0, &flags,1) == NULL) {
        ReREFCNT_dec(rx);   
-        Perl_croak(aTHX_ "panic: reg returned NULL to re_op_compile for generation pass, flags=%#X", flags);
+        Perl_croak(aTHX_ "panic: reg returned NULL to re_op_compile for generation pass, flags=%#"UVxf"", (UV) flags);
     }
     /* XXXX To minimize changes to RE engine we always allocate
        3-units-long substrs field. */
@@ -8342,7 +8401,7 @@ S_parse_lparen_question_flags(pTHX_ struct RExC_state_t *pRExC_state)
 #define WASTED_O  0x01
 #define WASTED_G  0x02
 #define WASTED_C  0x04
-#define WASTED_GC (0x02|0x04)
+#define WASTED_GC (WASTED_G|WASTED_C)
     I32 wastedflags = 0x00;
     U32 posflags = 0, negflags = 0;
     U32 *flagsp = &posflags;
@@ -8543,7 +8602,10 @@ S_parse_lparen_question_flags(pTHX_ struct RExC_state_t *pRExC_state)
    cannot happen.  */
 STATIC regnode *
 S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
-    /* paren: Parenthesized? 0=top, 1=(, inside: changed to letter. */
+    /* paren: Parenthesized? 0=top; 1,2=inside '(': changed to letter.
+     * 2 is like 1, but indicates that nextchar() has been called to advance
+     * RExC_parse beyond the '('.  Things like '(?' are indivisible tokens, and
+     * this flag alerts us to the need to check for that */
 {
     dVAR;
     regnode *ret;              /* Will be the head of the group. */
@@ -8571,6 +8633,13 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
 
     /* Make an OPEN node, if parenthesized. */
     if (paren) {
+
+        /* Under /x, space and comments can be gobbled up between the '(' and
+         * here (if paren ==2).  The forms '(*VERB' and '(?...' disallow such
+         * intervening space, as the sequence is a token, and a token should be
+         * indivisible */
+        bool has_intervening_patws = paren == 2 && *(RExC_parse - 1) != '(';
+
         if ( *RExC_parse == '*') { /* (*VERB:ARG) */
            char *start_verb = RExC_parse;
            STRLEN verb_len = 0;
@@ -8578,6 +8647,10 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
            unsigned char op = 0;
            int argok = 1;
            int internal_argval = 0; /* internal_argval is only useful if !argok */
+
+            if (has_intervening_patws && SIZE_ONLY) {
+                ckWARNregdep(RExC_parse + 1, "In '(*VERB...)', splitting the initial '(*' is deprecated");
+            }
            while ( *RExC_parse && *RExC_parse != ')' ) {
                if ( *RExC_parse == ':' ) {
                    start_arg = RExC_parse + 1;
@@ -8679,6 +8752,9 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
        if (*RExC_parse == '?') { /* (?...) */
            bool is_logical = 0;
            const char * const seqstart = RExC_parse;
+            if (has_intervening_patws && SIZE_ONLY) {
+                ckWARNregdep(RExC_parse + 1, "In '(?...)', splitting the initial '(?' is deprecated");
+            }
 
            RExC_parse++;
            paren = *RExC_parse++;
@@ -8840,6 +8916,18 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
            case '@':           /* (?@...) */
                vFAIL2("Sequence (?%c...) not implemented", (int)paren);
                break;
+            case '#':           /* (?#...) */
+                /* XXX As soon as we disallow separating the '?' and '*' (by
+                 * spaces or (?#...) comment), it is believed that this case
+                 * will be unreachable and can be removed.  See
+                 * [perl #117327] */
+                while (*RExC_parse && *RExC_parse != ')')
+                   RExC_parse++;
+               if (*RExC_parse != ')')
+                   FAIL("Sequence (?#... not terminated");
+               nextchar(pRExC_state);
+               *flagp = TRYAGAIN;
+               return NULL;
            case '0' :           /* (?0) */
            case 'R' :           /* (?R) */
                if (*RExC_parse != ')')
@@ -9089,8 +9177,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                             *flagp = RESTART_UTF8;
                             return NULL;
                         }
-                        FAIL2("panic: regbranch returned NULL, flags=%#X",
-                              flags);
+                        FAIL2("panic: regbranch returned NULL, flags=%#"UVxf"",
+                              (UV) flags);
                     } else
                         REGTAIL(pRExC_state, br, reganode(pRExC_state, LONGJMP, 0));
                    c = *nextchar(pRExC_state);
@@ -9105,8 +9193,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                                 *flagp = RESTART_UTF8;
                                 return NULL;
                             }
-                            FAIL2("panic: regbranch returned NULL, flags=%#X",
-                                  flags);
+                            FAIL2("panic: regbranch returned NULL, flags=%#"UVxf"",
+                                  (UV) flags);
                         }
                         REGTAIL(pRExC_state, ret, lastbr);
                        if (flags&HASWIDTH)
@@ -9194,7 +9282,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
             *flagp = RESTART_UTF8;
             return NULL;
         }
-        FAIL2("panic: regbranch returned NULL, flags=%#X", flags);
+        FAIL2("panic: regbranch returned NULL, flags=%#"UVxf"", (UV) flags);
     }
     if (*RExC_parse == '|') {
        if (!SIZE_ONLY && RExC_extralen) {
@@ -9239,7 +9327,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                 *flagp = RESTART_UTF8;
                 return NULL;
             }
-            FAIL2("panic: regbranch returned NULL, flags=%#X", flags);
+            FAIL2("panic: regbranch returned NULL, flags=%#"UVxf"", (UV) flags);
         }
         REGTAIL(pRExC_state, lastbr, br);               /* BRANCH -> BRANCH. */
        lastbr = br;
@@ -9252,7 +9340,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
        case ':':
            ender = reg_node(pRExC_state, TAIL);
            break;
-       case 1:
+       case 1: case 2:
            ender = reganode(pRExC_state, CLOSE, parno);
            if (!SIZE_ONLY && RExC_seen & REG_SEEN_RECURSE) {
                DEBUG_OPTIMISE_MORE_r(PerlIO_printf(Perl_debug_log,
@@ -9369,7 +9457,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
 
     /* Check for proper termination. */
     if (paren) {
-       RExC_flags = oregflags;
+        /* restore original flags, but keep (?p) */
+       RExC_flags = oregflags | (RExC_flags & RXf_PMf_KEEPCOPY);
        if (RExC_parse >= RExC_end || *nextchar(pRExC_state) != ')') {
            RExC_parse = oregcomp_parse;
            vFAIL("Unmatched (");
@@ -9443,7 +9532,7 @@ S_regbranch(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, I32 first, U32 depth)
                 *flagp = RESTART_UTF8;
                 return NULL;
             }
-            FAIL2("panic: regpiece returned NULL, flags=%#X", flags);
+            FAIL2("panic: regpiece returned NULL, flags=%#"UVxf"", (UV) flags);
        }
        else if (ret == NULL)
            ret = latest;
@@ -9513,7 +9602,7 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
        if (flags & (TRYAGAIN|RESTART_UTF8))
            *flagp |= flags & (TRYAGAIN|RESTART_UTF8);
         else
-            FAIL2("panic: regatom returned NULL, flags=%#X", flags);
+            FAIL2("panic: regatom returned NULL, flags=%#"UVxf"", (UV) flags);
        return(NULL);
     }
 
@@ -9955,8 +10044,8 @@ S_grok_bslash_N(pTHX_ RExC_state_t *pRExC_state, regnode** node_p, UV *valuep, I
                 *flagp = RESTART_UTF8;
                 return FALSE;
             }
-            FAIL2("panic: reg returned NULL to grok_bslash_N, flags=%#X",
-                  flags);
+            FAIL2("panic: reg returned NULL to grok_bslash_N, flags=%#"UVxf"",
+                  (UV) flags);
         } 
        *flagp |= flags&(HASWIDTH|SPSTART|SIMPLE|POSTPONED);
 
@@ -10043,8 +10132,9 @@ S_alloc_maybe_populate_EXACT(pTHX_ RExC_state_t *pRExC_state, regnode *node, I32
      * additionally will populate the node's STRING with <code_point>, if <len>
      * is 0.  In both cases <*flagp> is appropriately set
      *
-     * It knows that under FOLD, UTF characters and the Latin Sharp S must be
-     * folded (the latter only when the rules indicate it can match 'ss') */
+     * 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
+     * match 'ss') */
 
     bool len_passed_in = cBOOL(len != 0);
     U8 character[UTF8_MAXBYTES_CASE+1];
@@ -10053,8 +10143,15 @@ S_alloc_maybe_populate_EXACT(pTHX_ RExC_state_t *pRExC_state, regnode *node, I32
 
     if (! len_passed_in) {
         if (UTF) {
-            if (FOLD) {
-                to_uni_fold(NATIVE_TO_UNI(code_point), character, &len);
+            if (FOLD && (! LOC || code_point > 255)) {
+                _to_uni_fold_flags(NATIVE_TO_UNI(code_point),
+                                   character,
+                                   &len,
+                                   FOLD_FLAGS_FULL | ((LOC)
+                                                     ? FOLD_FLAGS_LOCALE
+                                                     : (ASCII_FOLD_RESTRICTED)
+                                                       ? FOLD_FLAGS_NOMIX_ASCII
+                                                       : 0));
             }
             else {
                 uvchr_to_utf8( character, code_point);
@@ -10233,8 +10330,8 @@ tryagain:
         if (ret == NULL) {
             if (*flagp & RESTART_UTF8)
                 return NULL;
-            FAIL2("panic: regclass returned NULL to regatom, flags=%#X",
-                  *flagp);
+            FAIL2("panic: regclass returned NULL to regatom, flags=%#"UVxf"",
+                  (UV) *flagp);
         }
        nextchar(pRExC_state);
         Set_Node_Length(ret, RExC_parse - oregcomp_parse + 1); /* MJD */
@@ -10242,7 +10339,7 @@ tryagain:
     }
     case '(':
        nextchar(pRExC_state);
-        ret = reg(pRExC_state, 1, &flags,depth+1);
+        ret = reg(pRExC_state, 2, &flags,depth+1);
        if (ret == NULL) {
                if (flags & TRYAGAIN) {
                    if (RExC_parse == RExC_end) {
@@ -10256,7 +10353,7 @@ tryagain:
                     *flagp = RESTART_UTF8;
                     return NULL;
                 }
-                FAIL2("panic: reg returned NULL to regatom, flags=%#X", flags);
+                FAIL2("panic: reg returned NULL to regatom, flags=%#"UVxf"", (UV) flags);
        }
        *flagp |= flags&(HASWIDTH|SPSTART|SIMPLE|POSTPONED);
        break;
@@ -10451,8 +10548,8 @@ tryagain:
                 /* regclass() can only return RESTART_UTF8 if multi-char folds
                    are allowed.  */
                 if (!ret)
-                    FAIL2("panic: regclass returned NULL to regatom, flags=%#X",
-                          *flagp);
+                    FAIL2("panic: regclass returned NULL to regatom, flags=%#"UVxf"",
+                          (UV) *flagp);
 
                RExC_parse--;
 
@@ -11575,8 +11672,8 @@ S_handle_regex_sets(pTHX_ RExC_state_t *pRExC_state, SV** return_invlist, I32 *f
                                   FALSE, /* don't allow multi-char folds */
                                   TRUE, /* silence non-portable warnings. */
                                   &current))
-                        FAIL2("panic: regclass returned NULL to handle_sets, flags=%#X",
-                              *flagp);
+                        FAIL2("panic: regclass returned NULL to handle_sets, flags=%#"UVxf"",
+                              (UV) *flagp);
 
                     /* function call leaves parse pointing to the ']', except
                      * if we faked it */
@@ -11741,8 +11838,8 @@ S_handle_regex_sets(pTHX_ RExC_state_t *pRExC_state, SV** return_invlist, I32 *f
                               FALSE, /* don't allow multi-char folds */
                               FALSE, /* don't silence non-portable warnings.  */
                               &current))
-                    FAIL2("panic: regclass returned NULL to handle_sets, flags=%#X",
-                          *flagp);
+                    FAIL2("panic: regclass returned NULL to handle_sets, flags=%#"UVxf"",
+                          (UV) *flagp);
                 /* regclass() will return with parsing just the \ sequence,
                  * leaving the parse pointer at the next thing to parse */
                 RExC_parse--;
@@ -11764,8 +11861,8 @@ S_handle_regex_sets(pTHX_ RExC_state_t *pRExC_state, SV** return_invlist, I32 *f
                              FALSE, /* don't allow multi-char folds */
                              FALSE, /* don't silence non-portable warnings.  */
                              &current))
-                    FAIL2("panic: regclass returned NULL to handle_sets, flags=%#X",
-                          *flagp);
+                    FAIL2("panic: regclass returned NULL to handle_sets, flags=%#"UVxf"",
+                          (UV) *flagp);
                 /* function call leaves parse pointing to the ']', except if we
                  * faked it */
                 if (is_posix_class) {