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

--- Comment #4 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:0547dbb725b6d8e878a79e28a2e171eafcfbc1aa

commit r15-5746-g0547dbb725b6d8e878a79e28a2e171eafcfbc1aa
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Thu Nov 28 11:18:07 2024 +0100

    expr, c: Don't clear whole unions [PR116416]

    As discussed earlier, we currently clear padding bits even when we
    don't have to and that causes pessimization of emitted code,
    e.g. for
    union U { int a; long b[64]; };
    void bar (union U *);
    void
    foo (void)
    {
      union U u = { 0 };
      bar (&u);
    }
    we need to clear just u.a, not the whole union, but on the other side
    in cases where the standard requires padding bits to be zeroed, like for
    C23 {} initializers of aggregates with padding bits, or for C++11 zero
    initialization we don't do that.

    This patch
    a) moves some of the stuff into complete_ctor_at_level_p (but not
       all the *p_complete = 0; case, for that it would need to change
       so that it passes around the ctor rather than just its type) and
       changes the handling of unions
    b) introduces a new option, so that users can either get the new
       behavior (only what is guaranteed by the standards, the default),
       or previous behavior (union padding zero initialization, no such
       guarantees in structures) or also a guarantee in structures
    c) introduces a new CONSTRUCTOR flag which says that the padding bits
       (if any) should be zero initialized (and sets it for now in the C
       FE for C23 {} initializers).

    Am not sure the CONSTRUCTOR_ZERO_PADDING_BITS flag is really needed
    for C23, if there is just empty initializer, I think we already mark
    it as incomplete if there are any missing initializers.  Maybe with
    some designated initializer games, say
    void foo () {
      struct S { char a; long long b; };
      struct T { struct S c; } t = { .c = {}, .c.a = 1, .c.b = 2 };
    ...
    }
    Is this supposed to initialize padding bits in C23 and then the .c.a = 1
    and .c.b = 2 stores preserve those padding bits, so is that supposed
    to be different from struct T t2 = { .c = { 1, 2 } };
    ?  What about just struct T t3 = { .c.a = 1, .c.b = 2 }; ?

    And I haven't touched the C++ FE for the flag, because I'm afraid I'm lost
    on where exactly is zero-initialization done (vs. other types of
    initialization) and where is e.g. zero-initialization of a temporary then
    (member-wise) copied.
    Say
    struct S { char a; long long b; };
    struct T { constexpr T (int a, int b) : c () { c.a = a; c.b = b; } S c; };
    void bar (T *);

    void
    foo ()
    {
      T t (1, 2);
      bar (&t);
    }
    Is the c () value-initialization of t.c followed by c.a and c.b updates
    which preserve the zero initialized padding bits?  Or is there some
    copy construction involved which does member-wise copying and makes the
    padding bits undefined?
    Looking at (older) clang++ with -O2, it initializes also the padding bits
    when c () is used and doesn't with c {}.
    For GCC, note that there is that optimization from Alex to zero padding
bits
    for optimization purposes for small aggregates, so either one needs to look
    at -O0 -fdump-tree-gimple dumps, or use larger structures which aren't
    optimized that way.

    2024-11-28  Jakub Jelinek  <ja...@redhat.com>

            PR c++/116416
    gcc/
            * flag-types.h (enum zero_init_padding_bits_kind): New type.
            * tree.h (CONSTRUCTOR_ZERO_PADDING_BITS): Define.
            * common.opt (fzero-init-padding-bits=): New option.
            * expr.cc (categorize_ctor_elements_1): Handle
            CONSTRUCTOR_ZERO_PADDING_BITS or
            flag_zero_init_padding_bits == ZERO_INIT_PADDING_BITS_ALL.  Fix
            up *p_complete = -1; setting for unions.
            (complete_ctor_at_level_p): Handle unions differently for
            flag_zero_init_padding_bits == ZERO_INIT_PADDING_BITS_STANDARD.
            * gimple-fold.cc (type_has_padding_at_level_p): Fix up UNION_TYPE
            handling, return also true for UNION_TYPE with no FIELD_DECLs
            and non-zero size, handle QUAL_UNION_TYPE like UNION_TYPE.
            * doc/invoke.texi (-fzero-init-padding-bits=@var{value}): Document.
    gcc/c/
            * c-parser.cc (c_parser_braced_init): Set
CONSTRUCTOR_ZERO_PADDING_BITS
            for flag_isoc23 empty initializers.
            * c-typeck.cc (constructor_zero_padding_bits): New variable.
            (struct constructor_stack): Add zero_padding_bits member.
            (really_start_incremental_init): Save and clear
            constructor_zero_padding_bits.
            (push_init_level): Save constructor_zero_padding_bits.  Or into it
            CONSTRUCTOR_ZERO_PADDING_BITS from previous value if implicit.
            (pop_init_level): Set CONSTRUCTOR_ZERO_PADDING_BITS if
            constructor_zero_padding_bits and restore
            constructor_zero_padding_bits.
    gcc/testsuite/
            * gcc.dg/plugin/infoleak-1.c (test_union_2b, test_union_4b): Expect
            diagnostics.
            * gcc.dg/c23-empty-init-5.c: New test.
            * gcc.dg/gnu11-empty-init-1.c: New test.
            * gcc.dg/gnu11-empty-init-2.c: New test.
            * gcc.dg/gnu11-empty-init-3.c: New test.
            * gcc.dg/gnu11-empty-init-4.c: New test.

Reply via email to