On 9/4/25 11:01 AM, Jakub Jelinek 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 guess doing it whenever flag_auto_var_init is set makes sense.

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.

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?

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

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 ();
}

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