This was discussed in the review of changes to support C++26
contracts [1].  Since the proposed change is independent of the
contracts implementation, I have split it out.

So far tested on powerpc64le-linux (and x86_64-darwin with the
contracts code, to ensure it still fixes the latent issue there).

comments?
OK for trunk?
thanks
Iain

[1] 
https://inbox.sourceware.org/gcc-patches/[email protected]/

--- 8< ---

This addresses a latent issue in C++ genericization (only seen
in development code, so far).

In the following code snippet using facilities from the proposed
C++26 contracts implementation:

    while (!SWAPPER::isFinished()) {
        uc = SWAPPER::swapBytes();
        if (0 != uc) {
        }
    }
    contract_assert( translator.d_capacity >= 1 );

During genericization, a statement list from the while loop is freed.
The expansion of the contract_assert then requires a 'new' statement list.

Since the statment list in the while has been visited, it was marked as
such.

A specific property of statement lists is that they are cached using a
LIFO stack.  So that the statement list picked for the contract_assert
is the one freed from the while loop.  However since that list entry
has already been marked as visited, the newly created contract expansion
is not visited (leading to an ICE).

The solution here is to forgo marking STATEMENT_LISTs as visited in this
code (which is provision for potential future cases, as well as resolving
the specific instance seen).

gcc/cp/ChangeLog:

        * cp-gimplify.cc (cp_genericize_r): Do not mark STATEMENT_LISTs
        as visited.

Signed-off-by: Iain Sandoe <[email protected]>
---
 gcc/cp/cp-gimplify.cc | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d65f61a96b27..cce3e0aa71c3 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2512,12 +2512,24 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
     case OMP_TILE:
     case OMP_UNROLL:
     case OACC_LOOP:
-    case STATEMENT_LIST:
       /* These cases are handled by shared code.  */
       c_genericize_control_stmt (stmt_p, walk_subtrees, data,
                                 cp_genericize_r, cp_walk_subtrees);
       break;
 
+    case STATEMENT_LIST:
+      /* As above, handled by shared code.  */
+      c_genericize_control_stmt (stmt_p, walk_subtrees, data,
+                                cp_genericize_r, cp_walk_subtrees);
+      /* If a statement list is freed as part of genericisation it will be
+        pushed onto the top of a statement list cache stack.  A subsequent
+        action can cause a new statement list to be required - and the one
+        just pushed will be returned.  If that is marked as visited, it can
+        prevent a tail recursion from processing the 'new' statement list,
+        so we do not mark statement lists as visited.  */
+      return NULL_TREE;
+      break;
+
     case BIT_CAST_EXPR:
       *stmt_p = build1_loc (EXPR_LOCATION (stmt), VIEW_CONVERT_EXPR,
                            TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
-- 
2.50.1 (Apple Git-155)

Reply via email to