Commit 32ac8f2762 for perl

commit 32ac8f27627f87cf00002ea63ad85408a3273dde
Author: Yves Orton <demerphq@gmail.com>
Date:   Tue Oct 27 21:36:15 2026 +0100

    regcomp: name BRANCH capture ranges

    Use named readers and setters for the capture range stored in branch
    nodes. The accessors handle the different ARG slots in BRANCH and
    BRANCHJ, so compiler, trie, debug, and execution code can use the same
    property names.

diff --git a/regcomp.c b/regcomp.c
index cb03736813..1bab08cee8 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -4468,13 +4468,13 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp, U32 depth)
     if (*RExC_parse == '|') {
         if (RExC_use_BRANCHJ) {
             reginsert(pRExC_state, BRANCHJ, br, depth+1);
-            ARG2a_SET(REGNODE_p(br), npar_before_regbranch);
-            ARG2b_SET(REGNODE_p(br), (U16)RExC_npar - 1);
+            BRANCH_CAPTURE_FLOOR_SET(REGNODE_p(br), npar_before_regbranch);
+            BRANCH_LAST_CAPTURE_SET(REGNODE_p(br), (U16)RExC_npar - 1);
         }
         else {
             reginsert(pRExC_state, BRANCH, br, depth+1);
-            ARG1a_SET(REGNODE_p(br), (U16)npar_before_regbranch);
-            ARG1b_SET(REGNODE_p(br), (U16)RExC_npar - 1);
+            BRANCH_CAPTURE_FLOOR_SET(REGNODE_p(br), (U16)npar_before_regbranch);
+            BRANCH_LAST_CAPTURE_SET(REGNODE_p(br), (U16)RExC_npar - 1);
         }
         have_branch = 1;
     }
@@ -4519,19 +4519,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp, U32 depth)
         }
         assert(OP(REGNODE_p(br)) == BRANCH || OP(REGNODE_p(br))==BRANCHJ);
         assert(OP(REGNODE_p(lastbr)) == BRANCH || OP(REGNODE_p(lastbr))==BRANCHJ);
-        if (OP(REGNODE_p(br)) == BRANCH) {
-            if (OP(REGNODE_p(lastbr)) == BRANCH)
-                ARG1b_SET(REGNODE_p(lastbr),ARG1a(REGNODE_p(br)));
-            else
-                ARG2b_SET(REGNODE_p(lastbr),ARG1a(REGNODE_p(br)));
-        }
-        else
-        if (OP(REGNODE_p(br)) == BRANCHJ) {
-            if (OP(REGNODE_p(lastbr)) == BRANCH)
-                ARG1b_SET(REGNODE_p(lastbr),ARG2a(REGNODE_p(br)));
-            else
-                ARG2b_SET(REGNODE_p(lastbr),ARG2a(REGNODE_p(br)));
-        }
+        BRANCH_LAST_CAPTURE_SET(REGNODE_p(lastbr),
+                                BRANCH_CAPTURE_FLOOR(REGNODE_p(br)));

         lastbr = br;
         *flagp |= flags & (HASWIDTH | POSTPONED);
@@ -4607,11 +4596,11 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp, U32 depth)
             );
         });
         if (OP(REGNODE_p(lastbr)) == BRANCH) {
-            ARG1b_SET(REGNODE_p(lastbr),(U16)RExC_npar-1);
+            BRANCH_LAST_CAPTURE_SET(REGNODE_p(lastbr),(U16)RExC_npar-1);
         }
         else
         if (OP(REGNODE_p(lastbr)) == BRANCHJ) {
-            ARG2b_SET(REGNODE_p(lastbr),(U16)RExC_npar-1);
+            BRANCH_LAST_CAPTURE_SET(REGNODE_p(lastbr),(U16)RExC_npar-1);
         }

         if (! REGTAIL(pRExC_state, lastbr, ender)) {
@@ -4790,11 +4779,11 @@ S_regbranch(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, I32 first, U32 depth)
         if (RExC_use_BRANCHJ) {
             ret = reg2node(pRExC_state, BRANCHJ, 0, 0);
             branch_node = REGNODE_p(ret);
-            ARG2a_SET(branch_node, (U16)RExC_npar-1);
+            BRANCH_CAPTURE_FLOOR_SET(branch_node, (U16)RExC_npar-1);
         } else {
             ret = reg1node(pRExC_state, BRANCH, 0);
             branch_node = REGNODE_p(ret);
-            ARG1a_SET(branch_node, (U16)RExC_npar-1);
+            BRANCH_CAPTURE_FLOOR_SET(branch_node, (U16)RExC_npar-1);
         }
     }

diff --git a/regcomp.h b/regcomp.h
index 633fce5768..a8f900582c 100644
--- a/regcomp.h
+++ b/regcomp.h
@@ -502,6 +502,30 @@ struct regnode_ssc {
 #define CURLY_FIRST_CAPTURE_SET(p, val) ARG3a_SET((p), (val))
 #define CURLY_LAST_CAPTURE_SET(p, val)  ARG3b_SET((p), (val))

+/* Named properties for arguments and overloaded header fields. Capture
+ * numbers are physical. Offsets are relative to the node, in regnode units.
+ * GOSUB_FIXUP_INDEX and GOSUB_TARGET_OFFSET name the same field before and
+ * after final fixup. Generic node construction uses the ARG primitives.
+ */
+#define BRANCH_CAPTURE_FLOOR(p)                                               \
+    (assert(OP(p) == BRANCH || OP(p) == BRANCHJ), PREVENT_LVALUE((OP(p) ==    \
+        BRANCH ? ARG1a(p) : ARG2a(p))))
+#define BRANCH_CAPTURE_FLOOR_SET(p, val) STMT_START {                         \
+    assert(OP(p) == BRANCH || OP(p) == BRANCHJ);                              \
+    if (OP(p) == BRANCH) ARG1a_SET((p), (val));                               \
+    else ARG2a_SET((p), (val));                                               \
+} STMT_END
+
+#define BRANCH_LAST_CAPTURE(p)                                                \
+    (assert(OP(p) == BRANCH || OP(p) == BRANCHJ), PREVENT_LVALUE((OP(p) ==    \
+        BRANCH ? ARG1b(p) : ARG2b(p))))
+#define BRANCH_LAST_CAPTURE_SET(p, val) STMT_START {                          \
+    assert(OP(p) == BRANCH || OP(p) == BRANCHJ);                              \
+    if (OP(p) == BRANCH) ARG1b_SET((p), (val));                               \
+    else ARG2b_SET((p), (val));                                               \
+} STMT_END
+
+
 /* the following define was set to 0xde in 075abff3
  * as part of some linting logic. I have set it to 0
  * as otherwise in every place where we /might/ set flags
diff --git a/regcomp_debug.c b/regcomp_debug.c
index 71a63fd455..e651a79229 100644
--- a/regcomp_debug.c
+++ b/regcomp_debug.c
@@ -574,11 +574,9 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
     sv_catpv(sv, REGNODE_NAME(op)); /* Take off const! */

     k = REGNODE_TYPE(op);
-    if (op == BRANCH) {
-        sv_catpvf(sv, " (buf:%" IVdf "/%" IVdf ")", (IV)ARG1a(o),(IV)ARG1b(o));
-    }
-    else if (op == BRANCHJ) {
-        sv_catpvf(sv, " (buf:%" IVdf "/%" IVdf ")", (IV)ARG2a(o),(IV)ARG2b(o));
+    if (op == BRANCH || op == BRANCHJ) {
+        sv_catpvf(sv, " (buf:%" IVdf "/%" IVdf ")",
+                    (IV)BRANCH_CAPTURE_FLOOR(o), (IV)BRANCH_LAST_CAPTURE(o));
     }
     else if (k == EXACT) {
         sv_catpvs(sv, " ");
diff --git a/regcomp_trie.c b/regcomp_trie.c
index f8891af4ea..dd5efcc391 100644
--- a/regcomp_trie.c
+++ b/regcomp_trie.c
@@ -962,18 +962,8 @@ Perl_make_trie(pTHX_ RExC_state_t *pRExC_state, regnode *startbranch,
                     assert((noper_next - convert) >= 0);
                     assert((noper_next - convert) <= TRIE_JUMP_TYPE_MAX);
                     trie->jump[curword] = noper_next - convert;
-                    U16 set_before_paren;
-                    U16 set_after_paren;
-                    if (OP(cur) == BRANCH) {
-                        set_before_paren = ARG1a(cur);
-                        set_after_paren = ARG1b(cur);
-                    }
-                    else {
-                        set_before_paren = ARG2a(cur);
-                        set_after_paren = ARG2b(cur);
-                    }
-                    trie->j_before_paren[curword] = set_before_paren;
-                    trie->j_after_paren[curword] = set_after_paren;
+                    trie->j_before_paren[curword] = BRANCH_CAPTURE_FLOOR(cur);
+                    trie->j_after_paren[curword] = BRANCH_LAST_CAPTURE(cur);
                     if (!jumper)
                         jumper = noper_next;
                     if (!nextbranch)
@@ -1001,13 +991,9 @@ Perl_make_trie(pTHX_ RExC_state_t *pRExC_state, regnode *startbranch,
             trie->prop_flags |= TRIE_CP_NO_LATIN1_WORDS;

         /* The list pass has also completed the source analysis. */
-        trie->before_paren = OP(first) == BRANCH
-                     ? ARG1a(first)
-                     : ARG2a(first); /* BRANCHJ */
+        trie->before_paren = BRANCH_CAPTURE_FLOOR(first);

-        trie->after_paren = OP(lastbranch) == BRANCH
-                     ? ARG1b(lastbranch)
-                     : ARG2b(lastbranch); /* BRANCHJ */
+        trie->after_paren = BRANCH_LAST_CAPTURE(lastbranch);
         DEBUG_TRIE_COMPILE_r(
             re_indentf(
                     "TRIE(%s): W:%d C:%d Uq:%d Min:%d Max:%d\n",
diff --git a/regexec.c b/regexec.c
index c39fa4ce95..986a49154e 100644
--- a/regexec.c
+++ b/regexec.c
@@ -9917,14 +9917,14 @@ NULL
             next = scan + ARG1u(scan);
             if (next == scan)
                 next = NULL;
-            ST.before_paren = ARG2a(scan);
-            ST.after_paren = ARG2b(scan);
+            ST.before_paren = BRANCH_CAPTURE_FLOOR(scan);
+            ST.after_paren = BRANCH_LAST_CAPTURE(scan);
             goto branch_logic;
             NOT_REACHED; /* NOTREACHED */

         case BRANCH:	    /*  /(...|A|...)/ */
-            ST.before_paren = ARG1a(scan);
-            ST.after_paren = ARG1b(scan);
+            ST.before_paren = BRANCH_CAPTURE_FLOOR(scan);
+            ST.after_paren = BRANCH_LAST_CAPTURE(scan);
           branch_logic:
             scan = REGNODE_AFTER_opcode(scan,state_num); /* scan now points to inner node */
             assert(scan);