Hi, Jakub,

Just briefly checked the v2, I have the following question:

There is no change to the routine expand_DEFERRED_INIT for the new “init_type 
== AUTO_INIT_CXX26”,
Is this intentional? 
If yes, then the new init_type AUTO_INIT_CXX26 will be treated as 
AUTO_INIT_ZERO when expanding
 the call to .DEFERRED_INIT (size, init_type, …), i.e, the variable will be 
zero-initialized. 

Is this expected behavior?

Thanks.

Qing



> On Sep 9, 2025, at 10:11, Jakub Jelinek <ja...@redhat.com> wrote:
> 
> On Fri, Sep 05, 2025 at 05:19:06PM +0200, Jason Merrill wrote:
>>> 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 guess doing it whenever flag_auto_var_init is set makes sense.
> 
> The following WIP patch does that (except for TARGET_EXPR_SLOTS created for
> [[indeterminate]] arguments.
> 
>>> 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).
>> 
>> I'll look at this.
> 
> Ok.  I wonder whether to keep adding CLOBBER (bob) as before to the start
> of some of the ctors for -std=c++23 and earlier (unless
> -ftrivial-auto-var-init= is specified).  The current patch does that.  If we
> stop doing that, we'd need to emit also CLOBBER (bob) before the calls to
> full object constructors for -flifetime-dse=2.
> 
>>> 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.
>> 
>> Doesn't the "Merge parameter attributes" code in duplicate_decls address
>> this?
> 
> You're right.  I thought DECL_ARGUMENTS is only set on FUNCTION_DECLs with
> definitions rather than declarations (I think that is the case for C FE),
> but clearly C++ FE has DECL_ARGUMENTS even for declarations.
> Added there diagnostics of [[indeterminate]] not specified on the first
> declaration.
> 
>> I guess we could change
>> 
>> {
>>  T t;
>>  do_stuff ();
>> label:
>>  do_more ();
>> }
>> 
>> to
>> 
>> {
>>  T t = ERR;
>>  do_stuff ();
>>  goto skip;
>> label:
>>  t = ERR;
>> skip:
>>  do_more ();
>> }
> 
> I'll try to work on this next, but it won't be trivial.  The forward gotos
> and switch cases are one thing and backward gotos another one, both need
> to be handled differently, plus make it work properly with [[fallthrough]]
> etc. (I'm contemplating on marking the if (0) { } around the extra labels
> and perhaps moved case labels with some flag so that gimplification can
> see it has been added artificially).
> 
> --- gcc/gimplify.cc.jj 2025-09-04 18:51:30.173760698 +0200
> +++ gcc/gimplify.cc 2025-09-09 10:42:34.436859935 +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;
> @@ -8458,6 +8459,7 @@ gimplify_target_expr (tree *expr_p, gimp
>   if (init)
>     {
>       gimple_seq init_pre_p = NULL;
> +      bool is_vla = false;
> 
>       /* TARGET_EXPR temps aren't part of the enclosing block, so add it
> to the temps list.  Handle also variable length TARGET_EXPRs.  */
> @@ -8468,6 +8470,7 @@ gimplify_target_expr (tree *expr_p, gimp
>  /* FIXME: this is correct only when the size of the type does
>     not depend on expressions evaluated in init.  */
>  gimplify_vla_decl (temp, &init_pre_p);
> +  is_vla = true;
> }
>       else
> {
> @@ -8479,6 +8482,15 @@ gimplify_target_expr (tree *expr_p, gimp
>  gimple_add_tmp_var (temp);
> }
> 
> +      if (var_needs_auto_init_p (temp))
> + {
> +  gimple_add_init_for_auto_var (temp, flag_auto_var_init, &init_pre_p);
> +  if (flag_auto_var_init == AUTO_INIT_PATTERN
> +      && !is_gimple_reg (temp)
> +      && clear_padding_type_may_have_padding_p (TREE_TYPE (temp)))
> +    gimple_add_padding_init_for_auto_var (temp, is_vla, &init_pre_p);
> + }
> +
>       /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
> expression is supposed to initialize the slot.  */
>       if (VOID_TYPE_P (TREE_TYPE (init)))
> --- gcc/cp/tree.cc.jj 2025-09-04 18:51:30.057762190 +0200
> +++ gcc/cp/tree.cc 2025-09-09 10:31:28.080908314 +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/call.cc.jj 2025-08-13 22:10:18.873791918 +0200
> +++ gcc/cp/call.cc 2025-09-09 15:36:13.419845002 +0200
> @@ -10474,6 +10474,7 @@ build_over_call (struct z_candidate *can
>   unsigned int arg_index = 0;
>   int conv_index = 0;
>   int param_index = 0;
> +  tree parmd = DECL_ARGUMENTS (fn);
> 
>   auto consume_object_arg = [&arg_index, &first_arg, args]()
>     {
> @@ -10491,6 +10492,8 @@ build_over_call (struct z_candidate *can
>       tree object_arg = consume_object_arg ();
>       argarray[argarray_size++] = build_this (object_arg);
>       parm = TREE_CHAIN (parm);
> +      if (parmd)
> + parmd = DECL_CHAIN (parmd);
>       /* We should never try to call the abstract constructor.  */
>       gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (fn));
> 
> @@ -10499,6 +10502,8 @@ build_over_call (struct z_candidate *can
>  argarray[argarray_size++] = (*args)[arg_index];
>  ++arg_index;
>  parm = TREE_CHAIN (parm);
> +  if (parmd)
> +    parmd = DECL_CHAIN (parmd);
> }
>     }
>   /* Bypass access control for 'this' parameter.  */
> @@ -10586,6 +10591,8 @@ build_over_call (struct z_candidate *can
> 
>       argarray[argarray_size++] = converted_arg;
>       parm = TREE_CHAIN (parm);
> +      if (parmd)
> + parmd = DECL_CHAIN (parmd);
>     }
> 
>   auto handle_arg = [fn, flags](tree type,
> @@ -10609,6 +10616,27 @@ build_over_call (struct z_candidate *can
>       return val;
>     };
> 
> +  auto handle_indeterminate_arg = [](tree parmd, tree val)
> +    {
> +      if (parmd
> +  && lookup_attribute (NULL, "indeterminate", DECL_ATTRIBUTES (parmd)))
> + {
> +  STRIP_NOPS (val);
> +  if (TREE_CODE (val) == ADDR_EXPR
> +      && TREE_CODE (TREE_OPERAND (val, 0)) == TARGET_EXPR)
> +    {
> +      val = TARGET_EXPR_SLOT (TREE_OPERAND (val, 0));
> +      if (auto_var_p (val) && DECL_ARTIFICIAL (val))
> + {
> +  tree id = get_identifier ("indeterminate");
> +  DECL_ATTRIBUTES (val)
> +    = tree_cons (build_tree_list (NULL_TREE, id), NULL_TREE,
> + DECL_ATTRIBUTES (val));
> + }
> +    }
> + }
> +    };
> +
>   if (DECL_XOBJ_MEMBER_FUNCTION_P (fn))
>     {
>       gcc_assert (cand->num_convs > 0);
> @@ -10622,8 +10650,13 @@ build_over_call (struct z_candidate *can
>       if (val == error_mark_node)
> return error_mark_node;
>       else
> - argarray[argarray_size++] = val;
> + {
> +  argarray[argarray_size++] = val;
> +  handle_indeterminate_arg (parmd, val);
> + }
>       parm = TREE_CHAIN (parm);
> +      if (parmd)
> + parmd = DECL_CHAIN (parmd);
>     }
> 
>   gcc_assert (first_arg == NULL_TREE);
> @@ -10669,7 +10702,12 @@ build_over_call (struct z_candidate *can
>       if (val == error_mark_node)
> return error_mark_node;
>       else
> - argarray[argarray_size++] = val;
> + {
> +  argarray[argarray_size++] = val;
> +  handle_indeterminate_arg (parmd, val);
> + }
> +      if (parmd)
> + parmd = DECL_CHAIN (parmd);
>     }
> 
>   /* Default arguments */
> @@ -10685,6 +10723,9 @@ build_over_call (struct z_candidate *can
>       if (val == error_mark_node)
> return error_mark_node;
>       argarray[argarray_size++] = val;
> +      handle_indeterminate_arg (parmd, val);
> +      if (parmd)
> + parmd = DECL_CHAIN (parmd);
>     }
> 
>   /* Ellipsis */
> --- gcc/cp/decl.cc.jj 2025-09-08 11:45:23.324029341 +0200
> +++ gcc/cp/decl.cc 2025-09-09 14:00:46.506872041 +0200
> @@ -2930,6 +2930,19 @@ duplicate_decls (tree newdecl, tree oldd
> {
>           DECL_ATTRIBUTES (newarg)
>    = (*targetm.merge_decl_attributes) (oldarg, newarg);
> +  if (lookup_attribute (NULL, "indeterminate",
> + DECL_ATTRIBUTES (newarg))
> +      && !lookup_attribute (NULL, "indeterminate",
> +    DECL_ATTRIBUTES (oldarg)))
> +    {
> +      auto_diagnostic_group d;
> +      error_at (DECL_SOURCE_LOCATION (newarg),
> + "%<indeterminate%> attribute not specified "
> +        "for parameter %qD on the first declaration of "
> + "its function", newarg);
> +      inform (DECL_SOURCE_LOCATION (oldarg),
> +      "earlier declaration");
> +    }
>           DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
> }
> 
> @@ -19316,7 +19329,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-09-04 18:51:30.122761354 +0200
> +++ gcc/flag-types.h 2025-09-09 10:31:28.086908233 +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-indeterminate3.C.jj 2025-09-09 
> 15:48:02.540320387 +0200
> +++ gcc/testsuite/g++.dg/cpp26/attr-indeterminate3.C 2025-09-09 
> 15:55:44.010150054 +0200
> @@ -0,0 +1,21 @@
> +// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
> +// { dg-do compile { target c++11 } }
> +// { dg-skip-if "" { c++26 } { "-ftrivial-auto-var-init=*" } { "" } }
> +
> +struct S { S (); S (const S &); ~S (); int s; };
> +void foo (S u, S v [[indeterminate]], int);
> +void foo (S a, S b, S c = S ()); // { dg-message "earlier declaration" }
> +void foo (S d, S e, S f [[indeterminate]]); // { dg-error "'indeterminate' 
> attribute not specified for parameter 'f' on the first declaration of its 
> function" }
> +
> +void
> +foo (S i [[indeterminate]], S j, S k) // { dg-error "'indeterminate' 
> attribute not specified for parameter 'i' on the first declaration of its 
> function" }
> +{
> +}
> +
> +void
> +bar (S l, S m, S n = S ()) // { dg-message "earlier declaration" }
> +{
> +}
> +
> +void bar (S o [[indeterminate]], S p, [[indeterminate]]S q); // { dg-error 
> "'indeterminate' attribute not specified for parameter 'o' on the first 
> declaration of its function" }
> + // { dg-error "'indeterminate' attribute not specified for parameter 'q' on 
> the first declaration of its function" "" { target *-*-* } .-1 }
> --- gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C.jj 2025-09-09 
> 15:51:54.689216319 +0200
> +++ gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C 2025-09-09 
> 15:52:27.164782082 +0200
> @@ -0,0 +1,36 @@
> +// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
> +// { dg-do compile { target c++11 } }
> +// { dg-additional-options "-ftrivial-auto-var-init=uninitialized 
> -fdump-tree-gimple" }
> +// { dg-final { scan-tree-dump-not " = \\.DEFERRED_INIT \\\(" "gimple" } }
> +
> +struct S { S (); S (const S &); ~S (); int s; };
> +void foo (S a [[indeterminate]], S b, S c [[indeterminate]] = S ());
> +void foo (S d, S e, S f [[indeterminate]]);
> +
> +void
> +bar ()
> +{
> +  S g [[indeterminate]], h;
> +  foo (g, h, S ());
> +  foo (g, h);
> +}
> +
> +void
> +foo (S i [[indeterminate]], S j, S k)
> +{
> +}
> +
> +void
> +baz ([[indeterminate]] S l, S m, [[indeterminate]] S n = S ())
> +{
> +}
> +
> +void baz (S o, S p, S q);
> +
> +void
> +qux ()
> +{
> +  S r, s;
> +  baz (r, s, s);
> +  baz (r, s);
> +}
> --- gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C.jj 2025-09-09 
> 10:31:28.096908097 +0200
> +++ gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C 2025-09-09 
> 10:31:28.096908097 +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/testsuite/g++.dg/cpp26/attr-indeterminate2.C.jj 2025-09-09 
> 15:42:05.219115549 +0200
> +++ gcc/testsuite/g++.dg/cpp26/attr-indeterminate2.C 2025-09-09 
> 15:51:33.316502091 +0200
> @@ -0,0 +1,39 @@
> +// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
> +// { dg-do compile { target c++11 } }
> +// { dg-additional-options "-fdump-tree-gimple" }
> +// { dg-skip-if "" { c++26 } { "-ftrivial-auto-var-init=*" } { "" } }
> +// Expect .DEFERRED_INIT calls for the h, r and s variables (3) and
> +// temporaries for the second arguments to foo and baz calls (4).
> +// { dg-final { scan-tree-dump-times " = \\.DEFERRED_INIT \\\(" 7 "gimple" { 
> target c++26 } } }
> +
> +struct S { S (); S (const S &); ~S (); int s; };
> +void foo (S a [[indeterminate]], S b, S c [[indeterminate]] = S ());
> +void foo (S d, S e, S f [[indeterminate]]);
> +
> +void
> +bar ()
> +{
> +  S g [[indeterminate]], h;
> +  foo (g, h, S ());
> +  foo (g, h);
> +}
> +
> +void
> +foo (S i [[indeterminate]], S j, S k)
> +{
> +}
> +
> +void
> +baz ([[indeterminate]] S l, S m, [[indeterminate]] S n = S ())
> +{
> +}
> +
> +void baz (S o, S p, S q);
> +
> +void
> +qux ()
> +{
> +  S r, s;
> +  baz (r, s, s);
> +  baz (r, s);
> +}
> --- gcc/c-family/c-opts.cc.jj 2025-09-04 18:51:30.032762512 +0200
> +++ gcc/c-family/c-opts.cc 2025-09-09 10:31:28.097908083 +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)
> --- gcc/doc/invoke.texi.jj 2025-09-09 10:22:39.813089294 +0200
> +++ gcc/doc/invoke.texi 2025-09-09 13:27:24.432827931 +0200
> @@ -14696,27 +14696,25 @@ and @option{-fauto-profile}.
> 
> @opindex ftrivial-auto-var-init
> @item -ftrivial-auto-var-init=@var{choice}
> -Initialize automatic variables with either a pattern or with zeroes to 
> increase
> -the security and predictability of a program by preventing uninitialized 
> memory
> -disclosure and use.
> +Initialize automatic variables or temporary objects with either a pattern or 
> with
> +zeroes to increase the security and predictability of a program by preventing
> +uninitialized memory disclosure and use.
> GCC still considers an automatic variable that doesn't have an explicit
> initializer as uninitialized, @option{-Wuninitialized} and
> @option{-Wanalyzer-use-of-uninitialized-value} will still report
> -warning messages on such automatic variables and the compiler will
> -perform optimization as if the variable were uninitialized.
> +warning messages on such automatic variables or temporary objects and the
> +compiler will perform optimization as if the variable were uninitialized.
> With this option, GCC will also initialize any padding of automatic variables
> -that have structure or union types to zeroes.
> -However, the current implementation cannot initialize automatic variables 
> that
> -are declared between the controlling expression and the first case of a
> -@code{switch} statement.  Using @option{-Wtrivial-auto-var-init} to report 
> all
> -such cases.
> +or temporary objects that have structure or union types to zeroes.
> +However, the current implementation cannot initialize automatic variables
> +whose initialization is bypassed through @code{switch} or @code{goto}
> +statement.  Using @option{-Wtrivial-auto-var-init} to report all such cases.
> 
> The three values of @var{choice} are:
> 
> @itemize @bullet
> @item
> @samp{uninitialized} doesn't initialize any automatic variables.
> -This is C and C++'s default.
> 
> @item
> @samp{pattern} Initialize automatic variables with values which will likely
> @@ -14730,7 +14728,10 @@ The values used for pattern initializati
> @samp{zero} Initialize automatic variables with zeroes.
> @end itemize
> 
> -The default is @samp{uninitialized}.
> +The default is @samp{uninitialized} except for C++26, in which case
> +if @option{-ftrivial-auto-var-init=} is not specified at all automatic
> +variables or temporary objects are zero initialized, but zero initialization
> +of padding bits does not happen.
> 
> Note that the initializer values, whether @samp{zero} or @samp{pattern},
> refer to data representation (in memory or machine registers), rather
> @@ -14743,7 +14744,7 @@ with the bit patterns @code{0x00} or @co
> @var{choice}, whether or not these representations stand for values in
> that range, and even if they do, the interpretation of the value held by
> the variable will depend on the bias.  A @samp{hardbool} variable that
> -uses say @code{0X5A} and @code{0xA5} for @code{false} and @code{true},
> +uses say @code{0x5A} and @code{0xA5} for @code{false} and @code{true},
> respectively, will trap with either @samp{choice} of trivial
> initializer, i.e., @samp{zero} initialization will not convert to the
> representation for @code{false}, even if it would for a @code{static}
> @@ -14754,7 +14755,8 @@ are initialized with @code{false} (zero)
> requested.
> 
> You can control this behavior for a specific variable by using the variable
> -attribute @code{uninitialized} (@pxref{Variable Attributes}).
> +attribute @code{uninitialized} standard attribute (@pxref{Variable 
> Attributes})
> +or the C++26 @code{[[indeterminate]]}.
> 
> @opindex fvect-cost-model
> @item -fvect-cost-model=@var{model}
> 
> 
> Jakub
> 

Reply via email to