> On Sep 4, 2025, at 11:01, Jakub Jelinek <ja...@redhat.com> wrote:
>
> On Thu, Sep 04, 2025 at 02:45:16PM +0200, Jakub Jelinek via Gcc wrote:
>> On Wed, Sep 03, 2025 at 03:38:53PM +0200, Jakub Jelinek via Gcc wrote:
>>> But there is one thing the paper doesn't care about, which looks like a show
>>> stopper to me, in particular the stuff -Wtrivial-auto-var-init warning warns
>>> about. Consider:
>>
>> I've filed https://github.com/cplusplus/CWG/issues/758 for that.
>
> Here is an untested WIP.
>
> Regarding temporaries, I wonder if we want to .DEFERRED_INIT them when
> expanding TARGET_EXPRs in the gimplifier (but whether to do that always
> when flag_auto_var_init != AUTO_INIT_UNINITIALIZED or for C++26 only),
> or if it should be in the C++ gimplification hook (but then it is more
> costly because it would need to create a GENERIC IFN CALL only to
> immediately gimplify it).
I have the following questions regarding C++26:
1. Should all auto variables be zero-initialized by the compiler if they are
not explicitly
initialized in the source code per the language standard?
2. Should all temporaries be zero-initialized per the language standard?
3. Should the paddings of the auto variables or temporaries be zero-initialized
per the standard?
>From my understanding of your current patch (AUTO_INIT_CXX26), looks like that
> the answers
to the above are:
1. YES
2. YES
3. NO
Are the above understanding correct?
If all the auto variables are zero-initialized by the language standard, should
-Wuninitialized still
report warnings for uninitialized auto variables in the source code?
With the current patch, -Wunitialized still report warnings for uninitialized
auto variables in the source code.
Is this the expected behavior?
thanks.
Qing
>
> Also, I haven't added yet CLOBBER (bob) for -flifetime-dse=2 addition for
> new expressions before calling constructors (which is now desirable when
> the ctors no longer clobber it themselves).
>
> PARM_DECLs from function declarations (rather than definitions) are thrown
> away, so guess we need to remember those say in some custom attribute on
> the FUNCTION_DECLs (indexes of parameters with the attribute) and perhaps
> when the FE creates TARGET_EXPRs for those params, mark their
> TARGET_EXPR_SLOT with indeterminate attribute.
>
> And really no idea what should be done about the skipped vacuous
> initializations, I've mentioned some ideas in
> https://github.com/cplusplus/CWG/issues/758#issuecomment-3253963911
> but it all seems quite costly to me. For non-addressable gimple reg
> type ones perhaps just mark those vars specially so that at SSA construction
> time we don't use (D) SSA_NAMEs for the uninitialized paths but instead
> create .DEFERRED_INIT call somewhere dominating all the "uninitialized"
> uses and use that SSA_NAME instead (though, not sure about
> SSA_NAME_OCCURS_IN_ABNORMAL_PHIs). But for other vars (addressable or
> non-scalar)?
>
> --- gcc/gimplify.cc.jj 2025-08-06 10:41:32.359075693 +0200
> +++ gcc/gimplify.cc 2025-09-04 15:56:12.569285030 +0200
> @@ -2102,13 +2102,13 @@ gimple_add_padding_init_for_auto_var (tr
> /* Return true if the DECL need to be automaticly initialized by the
> compiler. */
> static bool
> -is_var_need_auto_init (tree decl)
> +var_needs_auto_init_p (tree decl)
> {
> if (auto_var_p (decl)
> - && (TREE_CODE (decl) != VAR_DECL
> - || !DECL_HARD_REGISTER (decl))
> - && (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
> - && (!lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl)))
> + && (TREE_CODE (decl) != VAR_DECL || !DECL_HARD_REGISTER (decl))
> + && flag_auto_var_init > AUTO_INIT_UNINITIALIZED
> + && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
> + && !lookup_attribute ("indeterminate", DECL_ATTRIBUTES (decl))
> && !OPAQUE_TYPE_P (TREE_TYPE (decl))
> && !is_empty_type (TREE_TYPE (decl)))
> return true;
> @@ -2221,7 +2221,7 @@ gimplify_decl_expr (tree *stmt_p, gimple
> /* When there is no explicit initializer, if the user requested,
> We should insert an artifical initializer for this automatic
> variable. */
> - else if (is_var_need_auto_init (decl)
> + else if (var_needs_auto_init_p (decl)
> && !decl_had_value_expr_p)
> {
> gimple_add_init_for_auto_var (decl,
> @@ -2315,14 +2315,14 @@ emit_warn_switch_unreachable (gimple *st
> /* Don't warn for compiler-generated gotos. These occur
> in Duff's devices, for example. */
> return NULL;
> - else if ((flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
> - && ((gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> - || (gimple_call_builtin_p (stmt, BUILT_IN_CLEAR_PADDING)
> - && (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)))
> - || (is_gimple_assign (stmt)
> - && gimple_assign_single_p (stmt)
> - && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
> - && gimple_call_internal_p (
> + else if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
> + && (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT)
> + || (gimple_call_builtin_p (stmt, BUILT_IN_CLEAR_PADDING)
> + && (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)))
> + || (is_gimple_assign (stmt)
> + && gimple_assign_single_p (stmt)
> + && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
> + && gimple_call_internal_p (
> SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)),
> IFN_DEFERRED_INIT))))
> /* Don't warn for compiler-generated initializations for
> @@ -6753,7 +6753,8 @@ gimplify_init_constructor (tree *expr_p,
> && clear_padding_type_may_have_padding_p (type)
> && ((AGGREGATE_TYPE_P (type) && !cleared && !is_empty_ctor)
> || !AGGREGATE_TYPE_P (type))
> - && is_var_need_auto_init (object))
> + && var_needs_auto_init_p (object)
> + && flag_auto_var_init != AUTO_INIT_CXX26)
> gimple_add_padding_init_for_auto_var (object, false, pre_p);
>
> return ret;
> --- gcc/cp/tree.cc.jj 2025-09-04 10:36:30.478109748 +0200
> +++ gcc/cp/tree.cc 2025-09-04 13:31:35.535889253 +0200
> @@ -5578,6 +5578,23 @@ handle_maybe_unused_attribute (tree *nod
> return ret;
> }
>
> +/* The C++26 [[indeterminate]] attribute. */
> +
> +static tree
> +handle_indeterminate_attribute (tree *node, tree name, tree, int,
> + bool *no_add_attrs)
> +{
> + if (TREE_CODE (*node) != PARM_DECL
> + && (!VAR_P (*node) || is_global_var (*node)))
> + {
> + pedwarn (input_location, OPT_Wattributes,
> + "%qE on declaration other than parameter or automatic variable",
> + name);
> + *no_add_attrs = true;
> + }
> + return NULL_TREE;
> +}
> +
> /* Table of valid C++ attributes. */
> static const attribute_spec cxx_gnu_attributes[] =
> {
> @@ -5617,6 +5634,8 @@ static const attribute_spec std_attribut
> handle_noreturn_attribute, attr_noreturn_exclusions },
> { "carries_dependency", 0, 0, true, false, false, false,
> handle_carries_dependency_attribute, NULL },
> + { "indeterminate", 0, 0, true, false, false, false,
> + handle_indeterminate_attribute, NULL },
> { "pre", 0, -1, false, false, false, false,
> handle_contract_attribute, NULL },
> { "post", 0, -1, false, false, false, false,
> --- gcc/cp/decl.cc.jj 2025-09-04 10:36:30.295112184 +0200
> +++ gcc/cp/decl.cc 2025-09-04 12:09:27.487617358 +0200
> @@ -19313,7 +19313,8 @@ start_preparsed_function (tree decl1, tr
> start_function_contracts (decl1);
>
> if (!processing_template_decl
> - && (flag_lifetime_dse > 1)
> + && flag_lifetime_dse > 1
> + && flag_auto_var_init == AUTO_INIT_UNINITIALIZED
> && DECL_CONSTRUCTOR_P (decl1)
> && !DECL_CLONED_FUNCTION_P (decl1)
> /* Clobbering an empty base is harmful if it overlays real data. */
> --- gcc/flag-types.h.jj 2025-08-23 15:00:04.410786022 +0200
> +++ gcc/flag-types.h 2025-09-04 11:40:25.872551977 +0200
> @@ -288,7 +288,8 @@ enum vect_cost_model {
> enum auto_init_type {
> AUTO_INIT_UNINITIALIZED = 0,
> AUTO_INIT_PATTERN = 1,
> - AUTO_INIT_ZERO = 2
> + AUTO_INIT_ZERO = 2,
> + AUTO_INIT_CXX26 = 3
> };
>
> /* Initialization of padding bits with zeros. */
> --- gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C.jj 2025-09-04
> 15:28:43.143684890 +0200
> +++ gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C 2025-09-04
> 15:50:32.883684485 +0200
> @@ -0,0 +1,154 @@
> +// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
> +// { dg-do compile { target c++11 } }
> +
> +int arr[2];
> +struct S { int a, b; };
> +S arr2[2];
> +
> +void
> +foo ([[indeterminate]] int n, int n2 [[indeterminate]], int n3
> [[indeterminate]] [2])
> +{
> + [[indeterminate]] int x1, x11, x12, x13;
> + int x14, x15 [[indeterminate]];
> + [[indeterminate ("foobar")]] int x2; // { dg-error "'indeterminate'
> attribute does not take any arguments" }
> + // { dg-error "expected primary-expression before 'int'" "" { target *-*-*
> } .-1 }
> + [[indeterminate (0)]] int x3; // { dg-error "'indeterminate' attribute
> does not take any arguments" }
> + // { dg-error "expected primary-expression before 'int'" "" { target *-*-*
> } .-1 }
> + [[indeterminate ("foo", "bar", "baz")]] int x4;// { dg-error
> "'indeterminate' attribute does not take any arguments" }
> + // { dg-error "expected primary-expression before 'int'" "" { target *-*-*
> } .-1 }
> + [[indeterminate (0, 1, 2)]] int x5; // { dg-error "'indeterminate'
> attribute does not take any arguments" }
> + // { dg-error "expected primary-expression before 'int'" "" { target *-*-*
> } .-1 }
> +
> + auto a = [] [[indeterminate]] () {}; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> + auto b = [] constexpr [[indeterminate]] {}; // { dg-warning
> "'indeterminate' attribute does not apply to types" }
> + // { dg-error "parameter declaration before lambda declaration specifiers
> only optional with" "" { target c++20_down } .-1 }
> + // { dg-error "'constexpr' lambda only available with" "" { target
> c++14_down } .-2 }
> + auto c = [] noexcept [[indeterminate]] {}; // { dg-warning
> "'indeterminate' attribute does not apply to types" }
> + // { dg-error "parameter declaration before lambda exception specification
> only optional with" "" { target c++20_down } .-1 }
> + auto d = [] () [[indeterminate]] {}; // { dg-warning "'indeterminate'
> attribute does not apply to types" }
> + auto e = new int [n] [[indeterminate]]; // { dg-warning "attributes
> ignored on outermost array type in new expression" }
> + auto e2 = new int [n] [[indeterminate]] [42]; // { dg-warning "attributes
> ignored on outermost array type in new expression" }
> + auto f = new int [n][42] [[indeterminate]]; // { dg-warning
> "'indeterminate' attribute does not apply to types" }
> + [[indeterminate]]; // { dg-warning "attributes at the beginning of
> statement are ignored" }
> + [[indeterminate]] {} // { dg-warning "attributes at the beginning of
> statement are ignored" }
> + [[indeterminate]] if (true) {} // { dg-warning "attributes at the
> beginning of statement are ignored" }
> + [[indeterminate]] while (false) {} // { dg-warning "attributes at the
> beginning of statement are ignored" }
> + [[indeterminate]] goto lab; // { dg-warning "attributes at the beginning
> of statement are ignored" }
> + [[indeterminate]] lab:; // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> + [[indeterminate]] try {} catch (int) {} // { dg-warning "attributes at the
> beginning of statement are ignored" }
> + if ([[indeterminate]] int x = 0) {}
> + switch (n)
> + {
> + [[indeterminate]] case 1: // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> + [[indeterminate]] break; // { dg-warning "attributes at the beginning of
> statement are ignored" }
> + [[indeterminate]] default: // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> + break;
> + }
> + for ([[indeterminate]] auto a : arr) {}
> + for ([[indeterminate]] auto [a, b] : arr2) {} // { dg-error "structured
> bindings only available with" "" { target c++14_down } }
> + [[indeterminate]] asm (""); // { dg-warning "attributes ignored on 'asm'
> declaration" }
> + try {} catch ([[indeterminate]] int x) {}
> + try {} catch ([[indeterminate]] int) {}
> + try {} catch (int [[indeterminate]] x) {} // { dg-warning "attribute
> ignored" }
> + try {} catch (int [[indeterminate]]) {} // { dg-warning "attribute
> ignored" }
> + try {} catch (int x [[indeterminate]]) {}
> +}
> +
> +[[indeterminate]] int bar (); // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> +using foobar [[indeterminate]] = int; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> +[[indeterminate]] int a; // { dg-error "'indeterminate' on declaration other
> than parameter or automatic variable" }
> +[[indeterminate]] auto [b, c] = arr; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> + // { dg-error "structured bindings only available with" "" { target
> c++14_down } .-1 }
> +[[indeterminate]]; // { dg-warning "attribute ignored" }
> +inline [[indeterminate]] void baz () {} // { dg-warning "attribute ignored" }
> + // { dg-error "standard attributes in middle of decl-specifiers" "" {
> target *-*-* } .-1 }
> +constexpr [[indeterminate]] int qux () { return 0; } // { dg-warning
> "attribute ignored" }
> + // { dg-error "standard attributes in middle of decl-specifiers" "" {
> target *-*-* } .-1 }
> +int [[indeterminate]] d; // { dg-warning "attribute ignored" }
> +int const [[indeterminate]] e = 1; // { dg-warning "attribute ignored" }
> +struct A {} [[indeterminate]]; // { dg-warning "attribute ignored in
> declaration of 'struct A'" }
> +struct A [[indeterminate]]; // { dg-warning "attribute ignored" }
> +struct A [[indeterminate]] a1; // { dg-warning "attribute ignored" }
> +A [[indeterminate]] a2; // { dg-warning "attribute ignored" }
> +enum B { B0 } [[indeterminate]]; // { dg-warning "attribute ignored in
> declaration of 'enum B'" }
> +enum B [[indeterminate]]; // { dg-warning "attribute ignored" }
> +enum B [[indeterminate]] b1; // { dg-warning "attribute ignored" }
> +B [[indeterminate]] b2; // { dg-warning "attribute ignored" }
> +struct [[indeterminate]] C {}; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +int f [[indeterminate]]; // { dg-error "'indeterminate' on declaration other
> than parameter or automatic variable" }
> +int g[2] [[indeterminate]]; // { dg-warning "'indeterminate' attribute does
> not apply to types" }
> +int g2 [[indeterminate]] [2]; // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> +int corge () [[indeterminate]]; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +int *[[indeterminate]] h; // { dg-warning "'indeterminate' attribute does
> not apply to types" }
> +int & [[indeterminate]] i = f; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +int && [[indeterminate]] j = 0; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +int S::* [[indeterminate]] k; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +auto l = sizeof (int [2] [[indeterminate]]); // { dg-warning
> "'indeterminate' attribute does not apply to types" }
> +int freddy ([[indeterminate]] int a,
> + [[indeterminate]] int,
> + [[indeterminate]] int c = 0,
> + [[indeterminate]] int = 0);
> +void
> +corge ([[indeterminate]] int a,
> + [[indeterminate]] int,
> + [[indeterminate]] int c = 0,
> + [[indeterminate]] int = 0)
> +{
> +}
> +[[indeterminate]] void
> +garply () // { dg-error "'indeterminate' on declaration other than parameter
> or automatic variable" }
> +{
> +}
> +int grault (int [[indeterminate]] a, // { dg-warning "attribute ignored" }
> + int [[indeterminate]], // { dg-warning "attribute ignored" }
> + int [[indeterminate]] c = 0, // { dg-warning "attribute ignored" }
> + int [[indeterminate]] = 0); // { dg-warning "attribute ignored" }
> +void
> +waldo (int [[indeterminate]] a, // { dg-warning "attribute ignored" }
> + int [[indeterminate]], // { dg-warning "attribute ignored" }
> + int [[indeterminate]] c = 0, // { dg-warning "attribute ignored" }
> + int [[indeterminate]] = 0) // { dg-warning "attribute ignored" }
> +{
> +}
> +int plugh (int a [[indeterminate]],
> + int b [[indeterminate]] = 0);
> +void
> +thud (int a [[indeterminate]],
> + int b [[indeterminate]] = 0)
> +{
> +}
> +enum [[indeterminate]] D { D0 }; // { dg-warning "'indeterminate' attribute
> does not apply to types" }
> +enum class [[indeterminate]] E { E0 }; // { dg-warning "'indeterminate'
> attribute does not apply to types" }
> +enum F {};
> +enum [[indeterminate]] F; // { dg-warning "'indeterminate' attribute does
> not apply to types" }
> +enum G {
> + G0 [[indeterminate]], // { dg-error "'indeterminate' on declaration other
> than parameter or automatic variable" }
> + G1 [[indeterminate]] = 2 // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> +};
> +namespace [[indeterminate]] H { using H0 = int; }// { dg-warning
> "'indeterminate' attribute directive ignored" }
> +namespace [[indeterminate]] {} // { dg-warning "'indeterminate' attribute
> directive ignored" }
> +[[indeterminate]] using namespace H; // { dg-warning "'indeterminate'
> attribute directive ignored" }
> +struct [[indeterminate]] I // { dg-warning "'indeterminate' attribute does
> not apply to types" }
> +{
> + [[indeterminate]]; // { dg-error "declaration does not declare anything" }
> + [[indeterminate]] int i; // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> + [[indeterminate]] int foo (); // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> + [[indeterminate]] int bar () { return 1; } // { dg-error "'indeterminate'
> on declaration other than parameter or automatic variable" }
> + [[indeterminate]] int : 0; // { dg-error "'indeterminate' on declaration
> other than parameter or automatic variable" }
> + [[indeterminate]] int i2 : 5; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> + [[indeterminate]] static int i3; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> + static int i4;
> +};
> +[[indeterminate]] int I::i4 = 0; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> +struct J : [[indeterminate]] C {}; // { dg-warning "attributes on base
> specifiers are ignored" }
> +#if __cpp_concepts >= 201907L
> +template <typename T>
> +concept K [[indeterminate]] = requires { true; };// { dg-error
> "'indeterminate' on declaration other than parameter or automatic variable"
> "" { target c++20 } }
> +#endif
> +typedef int L [[indeterminate]]; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> +template <typename T>
> +struct M {};
> +template <>
> +struct [[indeterminate]] M<int> { int m; }; // { dg-warning "'indeterminate'
> attribute does not apply to types" }
> +typedef int N[2] [[indeterminate]]; // { dg-warning "'indeterminate'
> attribute does not apply to types" }
> +typedef int O [[indeterminate]] [2]; // { dg-error "'indeterminate' on
> declaration other than parameter or automatic variable" }
> --- gcc/c-family/c-opts.cc.jj 2025-08-11 12:25:20.493002827 +0200
> +++ gcc/c-family/c-opts.cc 2025-09-04 12:23:40.373384906 +0200
> @@ -913,6 +913,10 @@ c_common_post_options (const char **pfil
> else
> flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_C11;
>
> + if (cxx_dialect >= cxx26)
> + SET_OPTION_IF_UNSET (&global_options, &global_options_set,
> + flag_auto_var_init, AUTO_INIT_CXX26);
> +
> /* C23 Annex F does not permit certain built-in functions to raise
> "inexact". */
> if (flag_isoc23)
>
>
> Jakub
>