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 >