[Bug c++/126335] [17 regression] Wrong code: trailing default-constructed element of a static array of class type left uninitialized since r17-1661

"cvs-commit at gcc dot gnu.org via Gcc-bugs" <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126335

--- Comment #4 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Marek Polacek <[email protected]>:

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

commit r17-2835-ge3da9acc2462e43e0ce3b9a5d414b988c35595c3
Author: Marek Polacek <[email protected]>
Date:   Thu Jul 30 15:18:14 2026 -0400

    c++: fix array initialization wrong code [PR126335]

    This is a wrong-code problem starting with the recent check_initializer
    simplification (r17-1661).  I thought the fix would be to bring some of
    those dropped conditions back, but now I think the change just uncovered
    a latent bug.

    Since r17-1661, when initializing 'm' of type 'M[2]' we no longer call
    build_aggr_init_full_exprs in check_initializer; instead, we go on to
    store_init_value -> split_nonconstant_init.  There we arrive with:

    {{.a=TARGET_EXPR <D.3136, <<< Unknown tree: aggr_init_expr
      3
      operator""_s
      D.3136 >>>>, .b=TARGET_EXPR <D.3139, <<< Unknown tree: aggr_init_expr
      3
      operator""_s
      D.3139 >>>>}, {.a={.p=&empty.str}, .b={.p=&empty.str}}}

    which so far seems OK.  The type is an array so split_nonconstant_init_1
    delegates to build_vec_init and returns true which, as the comment says,
    should mean that "the whole of the value was initialized by the generated
    statements".  This is inaccurate: since try_const and do_static_init are
    both true in build_vec_init, we have split out the constant initializer
    (the {.a={.p=&empty.str}, .b={.p=&empty.str}} part) into DECL_INITIAL:

    5374       else if (do_static_init && !vec_safe_is_empty (const_vec))
    5375         DECL_INITIAL (obase) = build_constructor (atype, const_vec);

    so we have both dynamic and static initializers.  But since
    split_nonconstant_init_1 returns bool, it's not ready to signal this case
    to split_nonconstant_init, which then does:

     943       if (split_nonconstant_init_1 (dest, init, true, &flags))
     944         init = NULL_TREE;

    and then overwrites DECL_INITIAL (dest).  So we've lost a half of the
    initializer and got wrong-code as the result.

    This patch fixes it by not throwing away the DECL_INITIAL that
    build_vec_init set for us.  I suppose another approach would be
    to somehow change split_nonconstant_init_1/ARRAY_TYPE to follow
    the element pruning/add_stmt like the rest of the function, but that
    seems more complicated.

            PR c++/126335

    gcc/cp/ChangeLog:

            * typeck2.cc (split_nonconstant_init): Assert that DECL_INITIAL
            is initially null.  Don't clear DECL_INITIAL if build_vec_init
            set it.  Only clear TREE_READONLY if CODE has side-effects.

    gcc/testsuite/ChangeLog:

            * g++.dg/init/array68.C: New test.

    Reviewed-by: Jason Merrill <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.