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

--- Comment #8 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jakub Jelinek <[email protected]>:

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

commit r16-4212-gf256a13f8aed833fe964a2ba541b7b30ad9b4a76
Author: Jakub Jelinek <[email protected]>
Date:   Sat Oct 4 09:50:39 2025 +0200

    c++, gimplify: Implement C++26 P2795R5 - Erroneous behavior for
uninitialized reads [PR114457]

    The following patch implements the C++26 P2795R5 paper by enabling
something
    like -ftrivial-auto-var-init=zero by default for -std=c++26/-std=gnu++26.
    There is an important difference between explicit
-ftrivial-auto-var-init=zero
    and the implicitly enabled one, in particular the explicit one will try to
    clear padding bits on vars with explicit initializers, while the default
    C++26 mode does not - C++26 says that using the padding bits for anything
    but copying structures around is still undefined behavior rather than
    erroneous behavior.

    Users can still override the default C++26 behavior in both directions,
    with -ftrivial-auto-var-init=uninitialized even C++26 will act as C++23
    with treating all uninitialized var reads (except for copying) as UB rather
    than EB, with -ftrivial-auto-var-init=zero it will also clear padding bits
    on explicit initialization and with -ftrivial-auto-var-init=pattern it will
    initialize to pattern with clearing padding bits in between.

    There are other changes that had to be implemented.  First of all, we need
    to magicly preinitialize also temporary objects; this is implemented for
    both the C++26 implicit mode and explicit
    -ftrivial-auto-var-init={zero,pattern} by emitting .DEFERRED_INIT before
    construction of TARGET_EXPR temporaries (if they have void type
initializers,
    i.e. are initialized by code rather than some value).

    Second needed change is dropping *this ={v} {CLOBBER(bob)}; statements
    at the start of the constructors for -flifetime-dse=2, that says the old
    content of *this is irrelevant, which is not true anymore for C++26,
    where we want to treat it like that for -W*uninitialized purposes, but
    at runtime actually initialize the values.  Instead for -flifetime-dse=2
    we emit such {CLOBBER(bob)} before calling whole object constructor
    (on TARGET_EXPR with void type initializer or on DECL_EXPR).
    And a separate patch added and another one will be adding more
{CLOBBER(bob)}
    to new expressions.

    The third needed change is about gotos and switches across vacuous
    initialization.  C++26 says those are still valid, but don't make an
    exception for those in the EB rules.
    The patch now includes redirecting of forward/backward gotos
    which cross vacuous initializations for -std=c++26 and
    -ftrivial-auto-var-init={zero,pattern} by adding an artificial
    if (0) { lab1: v1 = .DEFERRED_INIT (...); lab2: v2 = .DEFERRED_INIT (...);
}
    etc. hunk before the user label (or for case labels moving the case
    label into it).  Only one per adjacent set of labels, with perhaps
    multiple artificial labels in it.  I believe (and testing seems to
    confirm that) that one only needs one set of such initialized vars
    per the adjacent label group, if some forward or backward jump
    crosses more vacuous inits, it will always cross a subset or superset
    of the others and when the vars are ordered right, it can jump into
    different positions in the same if (0).
    Furthermore, -Wimplicit-fallthrough and -Wswitch-unreachable warnings
    have been adjusted to deal with that.
    These changes mean that -Wtrivial-auto-var-init warning now doesn't
    make sense for C++, as there is nothing to warn about, all the switches
    and all the gotos are handled right for -ftrivial-auto-var-init= and
    are handled that way both for the implicit C++26 mode and for explicit
    -ftrivial-auto-var-init= options.

    The fourth change is to avoid regressions for code like
    struct A
    {
      int f, g;
      A () { f = g; // { dg-warning "g. is used uninitialized" } }
    } a;
    where with -flifetime-dse=2 -Wuninitialized we were able to warn
    about bugs like this because of the *this ={v} {CLOBBER(bob)};
    statements at the start of the constructors, but with their removal
    wouldn't warn about it.  Instead we now add a magic "clobber *this"
    attribute to the this PARM_DECL and use it in -W*uninitialized handling
    only as an implicit *this ={v} {CLOBBER(bob)}; at the start of the
    function.  If a function is inlined, this disappears, but that shouldn't
    be a problem, either it is inlined into another constructor and that
    should have "clobber *this" for its this argument or it is inlined into
    whole object construction spot and there should be an explicit
    {CLOBBER(bob)} for the variable or temporary object.

    The fifth change is adding [[indeterminate]] attribute support and
    using it to avoid .DEFERRED_INIT calls (like [[gnu::uninitialized]]
    is handled).

    Some regressions caused by this patch had bugs filed (but for cases
    where those already didn't work before with explicit
    -ftrivial-auto-var-init=zero), those have been xfailed for now.
    See PR121975 and PR122044.

    2025-10-04  Jakub Jelinek  <[email protected]>

            PR c++/114457
    gcc/
            * flag-types.h (enum auto_init_type): Add AUTO_INIT_CXX26.
            * tree.h (VACUOUS_INIT_LABEL_P): Define.
            * gimplify.cc (is_var_need_auto_init): Renamed to ...
            (var_needs_auto_init_p): ... this.  Don't return true for
            vars with "indeterminate" attribute.  Formatting fixes.
            (gimplify_decl_expr): Use var_needs_auto_init_p instead of
            is_var_need_auto_init.
            (emit_warn_switch_unreachable): Remove the flag_auto_var_init
            special cases.
            (warn_switch_unreachable_and_auto_init_r): Handle them here
            by doing just returning NULL.
            (last_stmt_in_scope): Don't skip just debug stmts to find
            the last stmt in seq, skip for
            flag_auto_var_init > AUTO_INIT_UNINITIALIZED also IFN_DEFERRED_INIT
            calls.
            (collect_fallthrough_labels): For
            flag_auto_var_init > AUTO_INIT_UNINITIALIZED ignore
            IFN_DEFERRED_INIT calls and GIMPLE_GOTOs to
            VACUOUS_INIT_LABEL_P.
            (should_warn_for_implicit_fallthrough): For
            flag_auto_var_init > AUTO_INIT_UNINITIALIZED also skip over
            IFN_DEFERRED_INIT calls.
            (expand_FALLTHROUGH_r): Likewise, and handle GIMPLE_GOTOs
            to VACUOUS_INIT_LABEL_P.
            (gimplify_init_constructor): Use var_needs_auto_init_p instead
            of is_var_need_auto_init and for flag_auto_var_init
            AUTO_INIT_CXX26 don't call gimple_add_padding_init_for_auto_var.
            (gimplify_target_expr): If var_needs_auto_init_p and init has
            void type, call gimple_add_init_for_auto_var and for
            AUTO_INIT_PATTERN also gimple_add_padding_init_for_auto_var.
            * tree-ssa-uninit.cc (maybe_warn_operand): Handle loads from *this
            at the start of the function with "clobber *this" attribute on the
            PARM_DECL.
            * ipa-split.cc (split_function): Remove "clobber *this" attribute
            from the first PARM_DECL (if any).
            * doc/invoke.texi (ftrivial-auto-var-init=): Adjust documentation.
    gcc/c-family/
            * c-opts.cc (c_common_post_options): For C++26 set
            flag_auto_var_init to AUTO_INIT_CXX26 if not specified explicitly.
            For C++ disable warn_trivial_auto_var_init.
    gcc/cp/
            * cp-tree.h: Implement C++26 P2795R5 - Erroneous behavior for
            uninitialized reads.
            (IF_STMT_VACUOUS_INIT_P): Define.
            (check_goto): Change argument type from tree to tree *.
            * call.cc (build_over_call): Add indeterminate attribute to
            TARGET_EXPR slots for indeterminate parameters.
            * constexpr.cc (cxx_eval_internal_function): Handle
IFN_DEFERRED_INIT.
            (cxx_eval_store_expression): Temporarily work around PR121965 bug.
            * cp-gimplify.cc (genericize_if_stmt): Handle
IF_STMT_VACUOUS_INIT_P.
            (maybe_emit_clobber_object_begin): New function.
            (cp_gimplify_expr): Call it for DECL_EXPRs and TARGET_EXPRs with
            void type non-NULL TARGET_EXPR_INITIAL.
            * decl.cc (struct named_label_fwd_direct_goto,
            struct named_label_bck_direct_goto): New types.
            (struct named_label_use_entry): Add direct_goto member.  Formatting
            fix.
            (struct named_label_entry): Add direct_goto member.  Turn bool
members
            into bool : 1.  Add has_bad_decls bitfield.
            (adjust_backward_gotos): New function.
            (pop_labels): For flag_auto_var_init > AUTO_INIT_UNINITIALIZED
            call adjust_backward_gotos if needed.
            (poplevel_named_label_1): For decl_jump_unsafe also set
            ent->has_bad_decls, and for decl_instrument_init_bypass_p decls
            push them into ent->bad_decls vector too.
            (duplicate_decls): Complain if indeterminate attribute on function
            parameter isn't present on the first function declaration.
            (decl_instrument_init_bypass_p): New function.
            (build_deferred_init_call): Likewise.
            (maybe_add_deferred_init_calls): Likewise.
            (adjust_backward_goto): Likewise.
            (check_previous_goto_1): Add direct_goto and case_label arguments.
            For decl_instrument_init_bypass_p decls seen if
            direct_goto || case_label move case label if needed, call
            maybe_add_deferred_init_calls and adjust GOTO_EXPR operands
remembered
            in direct_goto.  Change return type from bool to int, return 0 on
            error, 1 for success with no need to adjust vacuous inits and 2 for
            success with need to adjust those.
            (check_previous_goto): Adjust check_previous_goto_1 call, vec_free
            direct_goto vector.
            (check_switch_goto): Add case_label argument, adjust
            check_previous_goto_1 call.  Change return type from bool to int.
            (check_goto_1): Remove computed argument, add declp argument. 
Don't
            reuse previous ent->uses if
            ent->binding_level != current_binding_level.  Push declp into
            direct_goto vectors if needed.
            (check_goto): Remove decl argument, add declp argument.  Adjust
            check_goto_1 calls.
            (finish_case_label): Call check_switch_goto up to twice, first time
            to detect errors and find out if second call will be needed, and
            after c_add_case_label second time if needed.  In the first case
            pass NULL_TREE as new argument to it, in the second case r.
            (start_preparsed_function): Don't emit CLOBBER_OBJECT_BEGIN here
            for -flifetime-dse=2, instead add "clobber *this" attribute to
            current_class_ptr.
            * parser.cc (cp_parser_asm_label_list): Call check_goto only
            after the TREE_LIST is created and pass address of its TREE_VALUE
to
            it instead of the label.
            * semantics.cc (finish_goto_stmt): Call check_goto only after
            build_stmt has been called and pass it address of its first operand
            rather than destination.
            * tree.cc (handle_indeterminate_attribute): New function.
            (cxx_gnu_attributes): Add entry for indeterminate attribute.
    gcc/testsuite/
            * g++.dg/cpp1y/vla-initlist1.C: Remove dg-skip-if for powerpc.
            Initialize i to 43 for ctor from initializer_list and expect value
            43 instead of 42.
            * g++.dg/cpp26/attr-indeterminate1.C: New test.
            * g++.dg/cpp26/attr-indeterminate2.C: New test.
            * g++.dg/cpp26/attr-indeterminate3.C: New test.
            * g++.dg/cpp26/attr-indeterminate4.C: New test.
            * g++.dg/cpp26/erroneous1.C: New test.
            * g++.dg/cpp26/erroneous2.C: New test.
            * g++.dg/cpp26/erroneous3.C: New test.
            * g++.dg/cpp26/erroneous4.C: New test.
            * g++.dg/opt/store-merging-1.C: Add
            -ftrivial-auto-var-init=uninitialized to dg-options.
            * g++.dg/uninit-pred-loop-1_b.C: Expect a warning for C++26.
            * g++.dg/warn/Wuninitialized-13.C: Expect warning on a different
            line.
            * c-c++-common/ubsan/vla-1.c: Add
            -ftrivial-auto-var-init=uninitialized to dg-options.
            * c-c++-common/uninit-17.c: For c++26 expect warning on a different
            line.
            * g++.dg/warn/Warray-bounds-20.C: Expect warning on a different
line.
            * c-c++-common/analyzer/invalid-shift-1.c: Xfail for c++26 until
            PR122044 is fixed.
            * g++.dg/analyzer/exception-value-2.C: Skip for c++26 until
PR122044
            is fixed.
            * c-c++-common/goacc-gomp/nesting-1.c: Skip for c++26 until
PR121975
            is fixed.
            * c-c++-common/goacc/kernels-decompose-2.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr100400-1-1.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr100400-1-3.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104061-1-1.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104061-1-3.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104061-1-4.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104132-1.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104133-1.c: Likewise.
            * c-c++-common/goacc/kernels-decompose-pr104774-1.c: Likewise.
            * c-c++-common/goacc/mdc-1.c: Likewise.

Reply via email to