https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118822

--- Comment #11 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-14 branch has been updated by Jakub Jelinek
<ja...@gcc.gnu.org>:

https://gcc.gnu.org/g:db73411a72cf2052dddcf9fa0523588599a73537

commit r14-11788-gdb73411a72cf2052dddcf9fa0523588599a73537
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Thu Feb 13 10:21:29 2025 +0100

    c++: Fix up regressions caused by for/while loops with declarations
[PR118822]

    The recent PR86769 r15-7426 changes regressed the following two testcases,
    the first one is more important as it is derived from real-world code.

    The first problem is that the chosen
    prep = do_pushlevel (sk_block);
    // emit something
    body = push_stmt_list ();
    // emit further stuff
    body = pop_stmt_list (body);
    prep = do_poplevel (prep);
    way of constructing the {FOR,WHILE}_COND_PREP and {FOR,WHILE}_BODY
    isn't reliable.  If during parsing a label is seen in the body and then
    some decl with destructors, sk_cleanup transparent scope is added, but
    the correspondiong result from push_stmt_list is saved in
    *current_binding_level and pop_stmt_list then pops even that statement list
    but only do_poplevel actually attempts to pop the sk_cleanup scope and so
we
    ICE.
    The reason for not doing do_pushlevel (sk_block); do_pushlevel (sk_block);
    is that variables should be in the same scope (otherwise various e.g.
    redeclaration*.C tests FAIL) and doing do_pushlevel (sk_block);
do_pushlevel
    (sk_cleanup); wouldn't work either as do_poplevel would silently unwind
even
    the cleanup one.

    So, the following patch changes the earlier approach.  Nothing is removed
    from the {FOR,WHILE}_COND_PREP subtrees while doing adjust_loop_decl_cond,
    push_stmt_list isn't called either; all it does is remember as an integer
    the number of cleanups (CLEANUP_STMT at the end of the STATEMENT_LISTs)
    from querying stmt_list_stack and finding the initial *body_p in there
    (that integer is stored into {FOR,WHILE}_COND_CLEANUP), and temporarily
    {FOR,WHILE}_BODY is set to the last statement (if any) in the innermost
    STATEMENT_LIST at the adjust_loop_decl_cond time; then at
    finish_{for,while}_stmt a new finish_loop_cond_prep routine takes care of
    do_poplevel for the scope (which is in {FOR,WHILE}_COND_PREP) and finds
    given {FOR,WHILE}_COND_CLEANUP number and {FOR,WHILE}_BODY tree the right
    spot where body statements start and moves that into {FOR,WHILE}_BODY.
    Finally genericize_c_loop then inserts the cond, body, continue label, expr
    into the right subtree of {FOR,WHILE}_COND_PREP.
    The constexpr evaluation unfortunately had to be changed as well, because
    we don't want to evaluate everything in BIND_EXPR_BODY (*_COND_PREP ())
    right away, we want to evaluate it with the exception of the CLEANUP_STMT
    cleanups at the end (given {FOR,WHILE}_COND_CLEANUP levels), and defer
    the evaluation of the cleanups until after cond, body, expr are evaluated.

    2025-02-13  Jakub Jelinek  <ja...@redhat.com>

            PR c++/118822
    gcc/
            * tree-iterator.h (tsi_split_stmt_list): Declare.
            * tree-iterator.cc (tsi_split_stmt_list): New function.
    gcc/c-family/
            * c-common.h (WHILE_COND_CLEANUP): Change description in comment.
            (FOR_COND_CLEANUP): Likewise.
            * c-gimplify.cc (genericize_c_loop): Adjust for COND_CLEANUP
            being CLEANUP_STMT/TRY_FINALLY_EXPR trailing nesting depth
            instead of actual cleanup.
    gcc/cp/
            * semantics.cc (adjust_loop_decl_cond): Allow multiple trailing
            CLEANUP_STMT levels in *BODY_P.  Set *CLEANUP_P to the number
            of levels rather than one particular cleanup, keep the cleanups
            in *PREP_P.  Set *BODY_P to the last stmt in the cur_stmt_list
            or NULL if *CLEANUP_P and the innermost cur_stmt_list is empty.
            (finish_loop_cond_prep): New function.
            (finish_while_stmt, finish_for_stmt): Use it.  Don't call
            set_one_cleanup_loc.
            * constexpr.cc (cxx_eval_loop_expr): Adjust handling of
            {FOR,WHILE}_COND_{PREP,CLEANUP}.
    gcc/testsuite/
            * g++.dg/expr/for9.C: New test.

    (cherry picked from commit 26baa2c09b39abf037afad349a318dc5734eae25)

Reply via email to