> 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
> 

Reply via email to