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

--- Comment #12 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:458773ac7bca792db044ad6c241f566c9ba87cb7

commit r16-3192-g458773ac7bca792db044ad6c241f566c9ba87cb7
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Wed Aug 13 22:07:27 2025 +0200

    c++: Implement C++26 P1306R5 - Expansion statements [PR120776]

    The following patch implements the C++26 P1306R5 - Expansion statements
    paper.
    When expansion statements are used outside of templates, the lowering
    of the statement uses push_tinst_level_loc and instantiates the body
    multiple times, otherwise when the new TEMPLATE_FOR_STMT statement is
    being instantiated and !processing_template_decl, it instantiates the
    body several times with just local_specialization_stack around each
    iteration but with the original args.
    Because the lowering of these statements is mostly about instantiation,
    I've put the lowering code into pt.cc rather than semantics.cc.
    Only destructuring expansion statements currently use in the patch
    temporary lifetime extension which matches the proposed resolution of
    https://cplusplus.github.io/CWG/issues/3043.html
    I'm not sure what will CWG decide about that if there will be some
    temporary lifetime extension for enumerating expansion statements and if
    yes, under what exact rules (e.g. whether it extends all the temporaries
    across one iteration of the body, or only if a reference is initialized
    or nothing at all).  And for iterating expansion statements, I think I
    don't understand the P2686R4 rules well yet, I think if the
    expansion-initializer is used in static constexpr rvalue reference, then
    it isn't needed, but not sure if it won't be needed if static would be
    dropped (whether
    struct S { constexpr S () : s (0) {} constexpr ~S () {} int s; };
    struct T { const S &t, &u; };
    void foo () { constexpr T t = { S {}, S {} }; use (t.t, t.u); }
    is ok under P2686R4; though without constexpr before T I see S::~S () being
    called after use, not at the end of the t declaration, so maybe it is
    fine also without static).
    As per
    https://cplusplus.github.io/CWG/issues/3044.html
    the patch uses build_int_cst (ptrdiff_type_node, i) to create second
    operand of begin + i and doesn't lookup overloaded comma operator (note,
I'm
    actually not even creating a lambda there, just using TARGET_EXPRs).
    I guess my preference would be dropping those 4 static keywords from
    [stmt.expand] but the patch does use those for now and it won't be possible
    to change that until the rest of P2686R4 is implemented.
    As per
    https://cplusplus.github.io/CWG/issues/3045.html
    it treats sk_template_for like sk_for for the purpose of redeclaration of
    vars in the body but doesn't yet reject [[fallthrough]]; in the expansion
    stmt body (when not nested in another switch).
    I'm not sure if cp_perform_range_for_lookup used in the patch is exactly
    what we want for the https://eel.is/c++draft/stmt.expand#3.2
    - it does finish_call_expr on the perform_koenig_lookup as well, shouldn't
    for the decision whether it is iterating or destructing (i.e. tf_none)
    just call perform_koenig_lookup and check if it found some
    FUNCTION_DECL/OVERLOAD/TEMPLATE_DECL?
    cp_decomp_size in the patch has tsubst_flags_t argument and attempts to be
    SFINAE friendly, even when it isn't needed strictly for this patch.
    This is with PR96185 __builtin_structured_binding_size implementation in
    mind (to follow clang).
    The new TEMPLATE_FOR_STMT statement is expected to be lowered to something
    that doesn't use the statement at all, I've implemented break/continue
    discovery in the body, so all I needed was to punt on TEMPLATE_FOR_STMT
    in potential_constant_expression_1 so that we don't try to constant
evaluate
    it when it is still dependent (and cxx_eval_constant_expression rejects
    it without any extra code).
    I think only enumerating and iterating expansion statements can have zero
    iteration, because for destructuring ones it doesn't use a structured
    binding pack and so valid structured binding has to have at least one
    iteration.  Though
    https://cplusplus.github.io/CWG/issues/3048.html
    could change that, this patch currently rejects it though.

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

            PR c++/120776
    gcc/c-family/
            * c-cppbuiltin.cc (c_cpp_builtins): Predefine
            __cpp_expansion_statements=202506L for C++26.
    gcc/cp/
            * cp-tree.def: Implement C++26 P1306R5 - Expansion statements.
            (TEMPLATE_FOR_STMT): New tree code.
            * cp-tree.h (struct saved_scope): Add expansion_stmt.
            (in_expansion_stmt): Define.
            (TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY,
            TEMPLATE_FOR_SCOPE, TEMPLATE_FOR_INIT_STMT): Define.
            (struct tinst_level): Adjust comment.
            (cp_decomp_size, finish_expansion_stmt, do_pushlevel,
            cp_build_range_for_decls, build_range_temp,
            cp_perform_range_for_lookup, begin_template_for_scope): Declare.
            (finish_range_for_stmt): Remove declaration.
            * cp-objcp-common.cc (cp_common_init_ts): Handle TEMPLATE_FOR_STMT.
            * name-lookup.h (enum scope_kind): Add sk_template_for enumerator.
            (struct cp_binding_level): Enlarge kind bitfield from 4 to 5 bits.
            Adjust comment with remaining space bits.
            * name-lookup.cc (check_local_shadow): Handle sk_template_for like
            sk_for.
            (cp_binding_level_descriptor): Add entry for sk_template_for.
            (begin_scope): Handle sk_template_for.
            * parser.h (IN_EXPANSION_STMT): Define.
            * parser.cc (cp_debug_parser): Print IN_EXPANSION_STMT bit.
            (cp_parser_lambda_expression): Temporarily clear in_expansion_stmt.
            (cp_parser_statement): Handle RID_TEMPLATE followed by RID_FOR for
            C++11.
            (cp_parser_label_for_labeled_statement): Complain about named
labels
            inside of expansion stmt body.
            (cp_hide_range_decl): New function.
            (cp_parser_range_for): Use it.  Adjust do_range_for_auto_deduction
            caller.  Remove second template argument from auto_vecs bindings
and
            names.
            (build_range_temp): No longer static.
            (do_range_for_auto_deduction): Add expansion_stmt argument.
            (cp_build_range_for_decls): New function.
            (cp_convert_range_for): Use it.  Call cp_perform_range_for_lookup
            rather than cp_parser_perform_range_for_lookup.
            (cp_parser_perform_range_for_lookup): Rename to ...
            (cp_perform_range_for_lookup): ... this.  No longer static.  Add
            complain argument and handle it.
            (cp_parser_range_for_member_function): Rename to ...
            (cp_range_for_member_function): ... this.
            (cp_parser_expansion_statement): New function.
            (cp_parser_jump_statement): Handle IN_EXPANSION_STMT.
            (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction
caller.
            Call cp_perform_range_for_lookup rather than
            cp_parser_perform_range_for_lookup.
            * error.cc (print_instantiation_full_context): Handle tldcl being
            TEMPLATE_FOR_STMT.
            (print_instantiation_partial_context_line): Likewise.
            * constexpr.cc (potential_constant_expression_1): Handle
            TEMPLATE_FOR_STMT.
            * decl.cc (poplevel_named_label_1): Use obl instead of
bl->level_chain.
            (finish_case_label): Diagnose case labels inside of template for.
            (find_decomp_class_base): Add complain argument, don't diagnose
            anything and just return error_mark_node if tf_none, adjust
recursive
            call.
            (cp_decomp_size): New function.
            (cp_finish_decomp): Adjust find_decomp_class_base caller.
            * semantics.cc (do_pushlevel): No longer static.
            (begin_template_for_scope): New function.
            * pt.cc (push_tinst_level_loc): Handle TEMPLATE_FOR_STMT.
            (reopen_tinst_level): Likewise.
            (tsubst_stmt): Handle TEMPLATE_FOR_STMT.
            (struct expansion_stmt_bc): New type.
            (expansion_stmt_find_bc_r, finish_expansion_stmt): New functions.
            * decl2.cc (decl_dependent_p): Return true for current function's
decl
            if in_expansion_stmt.
            * call.cc (extend_ref_init_temps): Don't extend_all_temps if
            TREE_STATIC (decl).
            * cxx-pretty-print.cc (cxx_pretty_printer::statement): Handle
            TEMPLATE_FOR_STMT.
    gcc/testsuite/
            * g++.dg/cpp1z/decomp64.C: New test.
            * g++.dg/cpp26/expansion-stmt1.C: New test.
            * g++.dg/cpp26/expansion-stmt2.C: New test.
            * g++.dg/cpp26/expansion-stmt3.C: New test.
            * g++.dg/cpp26/expansion-stmt4.C: New test.
            * g++.dg/cpp26/expansion-stmt5.C: New test.
            * g++.dg/cpp26/expansion-stmt6.C: New test.
            * g++.dg/cpp26/expansion-stmt7.C: New test.
            * g++.dg/cpp26/expansion-stmt8.C: New test.
            * g++.dg/cpp26/expansion-stmt9.C: New test.
            * g++.dg/cpp26/expansion-stmt10.C: New test.
            * g++.dg/cpp26/expansion-stmt11.C: New test.
            * g++.dg/cpp26/expansion-stmt12.C: New test.
            * g++.dg/cpp26/expansion-stmt13.C: New test.
            * g++.dg/cpp26/expansion-stmt14.C: New test.
            * g++.dg/cpp26/expansion-stmt15.C: New test.
            * g++.dg/cpp26/expansion-stmt16.C: New test.
            * g++.dg/cpp26/expansion-stmt17.C: New test.
            * g++.dg/cpp26/expansion-stmt18.C: New test.
            * g++.dg/cpp26/expansion-stmt19.C: New test.
            * g++.dg/cpp26/feat-cxx26.C: Add __cpp_expansion_statements
            tests.

Reply via email to