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

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

https://gcc.gnu.org/g:964577c31df206d780d5cc7bc07189d44de2719e

commit r15-3513-g964577c31df206d780d5cc7bc07189d44de2719e
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Sep 6 13:50:47 2024 +0200

    c++: Partially implement CWG 2867 - Order of initialization for structured
bindings [PR115769]

    The following patch partially implements CWG 2867
    - Order of initialization for structured bindings.
    The DR requires that initialization of e is sequenced before r_i and
    that r_i initialization is sequenced before r_j for j > i, we already do it
    that way, the former ordering is a necessity so that the get calls are
    actually emitted on already initialized variable, the rest just because
    we implemented it that way, by going through the structured binding
    vars in ascending order and doing their initialization.

    The hard part not implemented yet is the lifetime extension of the
    temporaries from the e initialization to after the get calls (if any).
    Unlike the range-for lifetime extension patch which I've posted recently
    where IMO we can just ignore lifetime extension of reference bound
    temporaries because all the temporaries are extended to the same spot,
    here lifetime extension of reference bound temporaries should last until
    the end of lifetime of e, while other temporaries only after all the get
    calls.

    The patch just attempts to deal with automatic structured bindings for now,
    I'll post a patch for static locals incrementally and I don't have a patch
    for namespace scope structured bindings yet, this patch should just keep
    existing behavior for both static locals and namespace scope structured
    bindings.

    What GCC currently emits is a CLEANUP_POINT_EXPR around the e
    initialization, followed optionally by nested CLEANUP_STMTs for cleanups
    like the e dtor if any and dtors of lifetime extended temporaries from
    reference binding; inside of the CLEANUP_STMT CLEANUP_BODY then the
    initialization of the individual variables for the tuple case, again with
    optional CLEANUP_STMT if e.g. lifetime extended temporaries from reference
    binding are needed in those.

    The following patch drops that first CLEANUP_POINT_EXPR and instead
    wraps the whole sequence of the e initialization and the individual
variable
    initialization with get calls after it into a single CLEANUP_POINT_EXPR.
    If there are any CLEANUP_STMTs needed, they are all emitted first, with
    the CLEANUP_POINT_EXPR for e initialization and the individual variable
    initialization inside of those, and a guard variable set after different
    phases in those expressions guarding the corresponding cleanups, so that
    they aren't invoked until the respective variables are constructed.
    This is implemented by cp_finish_decl doing cp_finish_decomp on its own
    when !processing_template_decl (otherwise we often don't cp_finish_decl
    or process it at a different time from when we want to call
    cp_finish_decomp) or unless the decl is erroneous (cp_finish_decl has
    too many early returns for erroneous cases, and for those we can actually
    call it even multiple times, for the non-erroneous cases
    non-processing_template_decl cases we need to call it just once).

    The two testcases try to construct various temporaries and variables and
    verify the order in which the temporaries and variables are constructed and
    destructed.

    2024-09-06  Jakub Jelinek  <ja...@redhat.com>

            PR c++/115769
            * cp-tree.h: Partially implement CWG 2867 - Order of initialization
            for structured bindings.
            (cp_finish_decomp): Add TEST_P argument defaulted to false.
            * decl.cc (initialize_local_var): Add DECOMP argument, if true,
            don't build cleanup and temporarily override stmts_are_full_exprs_p
            to 0 rather than 1.  Formatting fix.
            (cp_finish_decl): Invoke cp_finish_decomp for structured bindings
            here, first with test_p.  For automatic structured binding bases
            if the test cp_finish_decomp returned true wrap the initialization
            together with what non-test cp_finish_decomp emits with a
            CLEANUP_POINT_EXPR, and if there are any CLEANUP_STMTs needed, emit
            them around the whole CLEANUP_POINT_EXPR with guard variables for
the
            cleanups.  Call cp_finish_decomp using RAII if not called with
            decomp != NULL otherwise.
            (cp_finish_decomp): Add TEST_P argument, change return type from
            void to bool, if TEST_P is true, return true instead of emitting
            actual code for the tuple case, otherwise return false.
            * parser.cc (cp_convert_range_for): Don't call cp_finish_decomp
            after cp_finish_decl.
            (cp_parser_decomposition_declaration): Set DECL_DECOMP_BASE
            before cp_finish_decl call.  Don't call cp_finish_decomp after
            cp_finish_decl.
            (cp_finish_omp_range_for): Don't call cp_finish_decomp after
            cp_finish_decl.
            * pt.cc (tsubst_stmt): Likewise.

            * g++.dg/DRs/dr2867-1.C: New test.
            * g++.dg/DRs/dr2867-2.C: New test.

Reply via email to