Commit 72b96f4680 for perl
commit 72b96f4680f6559f9b21cbbd48e4a2c65e77984b
Author: Yves Orton <demerphq@gmail.com>
Date: Tue Oct 27 21:36:20 2026 +0100
regcomp: name capture reference properties
Name the capture number, saved start, named-capture slot, and volatile
flag used by capture references and conditions. These accessors make the
physical capture number and the other stored properties explicit at
their compiler, debug, and execution call sites.
diff --git a/regcomp.c b/regcomp.c
index 1bab08cee8..1a94ca3970 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2941,7 +2941,7 @@ S_handle_named_backref(pTHX_ RExC_state_t *pRExC_state,
: REFFN),
num, RExC_nestroot);
if (RExC_nestroot && num >= (U32)RExC_nestroot)
- FLAGS(REGNODE_p(ret)) = VOLATILE_REF;
+ REF_IS_VOLATILE_SET(REGNODE_p(ret), TRUE);
*flagp |= HASWIDTH;
nextchar(pRExC_state);
@@ -6446,7 +6446,7 @@ S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
: REFF),
num, RExC_nestroot);
if (RExC_nestroot && num >= RExC_nestroot)
- FLAGS(REGNODE_p(ret)) = VOLATILE_REF;
+ REF_IS_VOLATILE_SET(REGNODE_p(ret), TRUE);
if (OP(REGNODE_p(ret)) == REFF) {
RExC_seen_d_op = true;
}
diff --git a/regcomp.h b/regcomp.h
index a8f900582c..65d4e53f81 100644
--- a/regcomp.h
+++ b/regcomp.h
@@ -525,6 +525,51 @@ struct regnode_ssc {
else ARG2b_SET((p), (val)); \
} STMT_END
+#define REF_CAPTURE(p) \
+ (assert(REGNODE_TYPE(OP(p)) == REF && OP(p) < REFN), \
+ PREVENT_LVALUE(ARG1u(p)))
+#define REF_CAPTURE_SET(p, val) STMT_START { \
+ assert(REGNODE_TYPE(OP(p)) == REF && OP(p) < REFN); \
+ ARG1u_SET((p), (val)); \
+} STMT_END
+
+#define NAMED_CAPTURE_LIST_SLOT(p) \
+ (assert((REGNODE_TYPE(OP(p)) == REF && OP(p) >= REFN) || OP(p) == \
+ GROUPPN), PREVENT_LVALUE(ARG1u(p)))
+#define NAMED_CAPTURE_LIST_SLOT_SET(p, val) STMT_START { \
+ assert((REGNODE_TYPE(OP(p)) == REF && OP(p) >= REFN) || OP(p) == GROUPPN);\
+ ARG1u_SET((p), (val)); \
+} STMT_END
+
+#define REF_CAPTURE_SAVE_START(p) \
+ (assert(REGNODE_TYPE(OP(p)) == REF), PREVENT_LVALUE(ARG2u(p)))
+#define REF_CAPTURE_SAVE_START_SET(p, val) STMT_START { \
+ assert(REGNODE_TYPE(OP(p)) == REF); \
+ ARG2u_SET((p), (val)); \
+} STMT_END
+
+#define GROUPP_CAPTURE(p) \
+ (assert(OP(p) == GROUPP), PREVENT_LVALUE(ARG1u(p)))
+#define GROUPP_CAPTURE_SET(p, val) STMT_START { \
+ assert(OP(p) == GROUPP); \
+ ARG1u_SET((p), (val)); \
+} STMT_END
+
+#define INSUBP_CAPTURE(p) \
+ (assert(OP(p) == INSUBP), PREVENT_LVALUE(ARG1u(p)))
+#define INSUBP_CAPTURE_SET(p, val) STMT_START { \
+ assert(OP(p) == INSUBP); \
+ ARG1u_SET((p), (val)); \
+} STMT_END
+
+#define REF_IS_VOLATILE(p) \
+ (assert(REGNODE_TYPE(OP(p)) == REF), PREVENT_LVALUE((FLAGS(p) & \
+ VOLATILE_REF) != 0))
+#define REF_IS_VOLATILE_SET(p, val) STMT_START { \
+ assert(REGNODE_TYPE(OP(p)) == REF); \
+ FLAGS(p) = (val) ? VOLATILE_REF : 0; \
+} STMT_END
+
/* the following define was set to 0xde in 075abff3
* as part of some linting logic. I have set it to 0
diff --git a/regcomp_debug.c b/regcomp_debug.c
index e651a79229..c09406d54c 100644
--- a/regcomp_debug.c
+++ b/regcomp_debug.c
@@ -652,7 +652,8 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
AV *name_list= NULL;
U32 parno = (op == ACCEPT) ? ARG2u(o) :
(op == OPEN || op == CLOSE) ? PARNO(o) :
- ARG1u(o);
+ (k == GROUPP) ? GROUPP_CAPTURE(o) :
+ (op >= REFN) ? NAMED_CAPTURE_LIST_SLOT(o) : REF_CAPTURE(o);
if ( RXp_PAREN_NAMES(prog) ) {
name_list = MUTABLE_AV(progi->data->data[progi->name_list_idx]);
} else if ( pRExC_state ) {
@@ -704,10 +705,10 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
}
if ( k == REF ) {
- sv_catpvf(sv, " <%" IVdf ">", (IV)ARG2i(o));
+ sv_catpvf(sv, " <%" IVdf ">", (IV)REF_CAPTURE_SAVE_START(o));
}
if ( k == REF && reginfo) {
- U32 n = ARG1u(o); /* which paren pair */
+ U32 n = op >= REFN ? NAMED_CAPTURE_LIST_SLOT(o) : REF_CAPTURE(o);
I32 ln = RXp_OFFS_START(prog,n);
if (RXp_LASTPAREN(prog) < n || ln == -1 || RXp_OFFS_END(prog,n) == -1)
sv_catpvf(sv, ": FAIL");
diff --git a/regexec.c b/regexec.c
index 986a49154e..596f84ea03 100644
--- a/regexec.c
+++ b/regexec.c
@@ -5126,7 +5126,7 @@ S_reg_check_named_buff_matched(const regexp *rex, const regnode *scan)
I32 n;
RXi_GET_DECL(rex,rexi);
- SV *sv_dat= MUTABLE_SV(rexi->data->data[ ARG1u( scan ) ]);
+ SV *sv_dat= MUTABLE_SV(rexi->data->data[ NAMED_CAPTURE_LIST_SLOT( scan ) ]);
I32 *nums = (I32*)SvPVX(sv_dat);
for ( n = 0; n < SvIVX(sv_dat); n++ ) {
@@ -8815,7 +8815,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
do_ref:
type = OP(scan);
- n = ARG1u(scan); /* which paren pair */
+ n = REF_CAPTURE(scan); /* which paren pair */
if (rex->logical_to_parno) {
/* The compiler has already mapped this from logical to
* physical; only search the other physical buffers sharing
@@ -8889,8 +8889,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
locinput += ln;
}
ref_yes:
- if (FLAGS(scan)) { /* == VOLATILE_REF but only other value is 0 */
- ST.cp = regcppush(rex, ARG2u(scan) - 1, maxopenparen);
+ if (REF_IS_VOLATILE(scan)) { /* == VOLATILE_REF but only other value is 0 */
+ ST.cp = regcppush(rex, REF_CAPTURE_SAVE_START(scan) - 1, maxopenparen);
REGCP_SET(ST.lastcp);
PUSH_STATE_GOTO(REF_next, next, locinput, loceol,
script_run_begin);
@@ -9461,7 +9461,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
/* NOTREACHED */
case GROUPP: /* (?(1)) */
- n = ARG1u(scan); /* which paren pair */
+ n = GROUPP_CAPTURE(scan); /* which paren pair */
sw = cBOOL(RXp_LASTPAREN(rex) >= n && RXp_OFFS_END(rex,n) != -1);
break;
@@ -9471,7 +9471,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
break;
case INSUBP: /* (?(R)) */
- n = ARG1u(scan);
+ n = INSUBP_CAPTURE(scan);
/* this does not need to use EVAL_CLOSE_PAREN macros, as the arg
* of SCAN is already set up as matches a eval.close_paren */
sw = cur_eval && (n == 0 || CUR_EVAL.close_paren == n);