Hi!

The extra handling of jumps across vacuous inits for -std=c++26
or -ftrivial-auto-var-init={zero,pattern} added for P2795R5 is undesirable
when processing_template_decl, because it creates labels without DECL_NAME
and GOTO_EXPRs to those and those can't be tsubsted.
I was afraid the pop_labels and check_goto_1 and check_previous_goto_1
handling might not happen again during instantiation, but clearly it does
happen fully (and has to, because whether some declaration has vacuous
initialization or not can't be decided in some cases when parsing the
template, if dependent types are involved).

So, this patch just restricts the P2795R5 PR114457 r16-4212 changes
to !processing_template_decl and adds 2 copies of the erroneous2.C testcase,
one changing the function into a function template where nothing is
dependent and another one where most of the declarations are dependent.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 

2025-11-20  Jakub Jelinek  <[email protected]>

        PR c++/122758
        * decl.cc (pop_labels): Don't call adjust_backward_gotos if
        processing_template_decl.
        (decl_instrument_init_bypass_p): Always return false if
        processing_template_decl.
        (check_goto_1): Don't push anything to direct_goto vector
        if processing_template_decl.

        * g++.dg/cpp26/erroneous5.C: New test.
        * g++.dg/cpp26/erroneous6.C: New test.

--- gcc/cp/decl.cc.jj   2025-11-19 09:28:25.185134232 +0100
+++ gcc/cp/decl.cc      2025-11-19 13:05:19.044034172 +0100
@@ -517,7 +517,8 @@ pop_labels (tree block)
   auto_vec<tree, 32> labels (named_labels->elements ());
   hash_table<named_label_hash>::iterator end (named_labels->end ());
 
-  if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+  if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+      && !processing_template_decl)
     {
       for (decltype (end) iter (named_labels->begin ()); iter != end; ++iter)
        {
@@ -3875,6 +3876,7 @@ decl_instrument_init_bypass_p (tree decl
   tree type = TREE_TYPE (decl);
 
   return (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+         && !processing_template_decl
          && type != error_mark_node
          && VAR_P (decl)
          && !TREE_STATIC (decl)
@@ -4357,7 +4359,9 @@ check_goto_1 (named_label_entry *ent, tr
          && ent->uses->binding_level == current_binding_level
          && ent->uses->names_in_scope == current_binding_level->names)
        {
-         if (declp && flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+         if (declp
+             && flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+             && !processing_template_decl)
            vec_safe_push (ent->uses->direct_goto,
                           named_label_fwd_direct_goto { declp });
          return;
@@ -4371,7 +4375,9 @@ check_goto_1 (named_label_entry *ent, tr
       new_use->in_omp_scope = false;
       new_use->computed_goto = computed ? make_tree_vector () : nullptr;
       new_use->direct_goto = nullptr;
-      if (declp && flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+      if (declp
+         && flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+         && !processing_template_decl)
        vec_safe_push (new_use->direct_goto,
                       named_label_fwd_direct_goto { declp });
 
--- gcc/testsuite/g++.dg/cpp26/erroneous5.C.jj  2025-11-19 13:11:49.280473452 
+0100
+++ gcc/testsuite/g++.dg/cpp26/erroneous5.C     2025-11-19 13:12:28.956909687 
+0100
@@ -0,0 +1,241 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* } { "-ftrivial-auto-var-init=*" } { "" } }
+// { dg-options "-O2 -fdump-tree-gimple" }
+// All the s1..s24 variables and i1 need .DEFERRED_INIT call on their
+// declarations.
+// Plus, forward gotos to l1 & l2 labels need up to s1-s4 and s6-s9 vars to
+// be .DEFERRED_INITed (and backward gotos up to that minus the first two).
+// switch to case 15 skips over s12, switch to case 16/17 skip
+// over s12 and s13 but the adjacent l3 label needs to also skip over s3-s4
+// and s6-s9 and s11.  switch to case 18 skips over s12-s14 and switch to
+// default in the same switch skips over s12-s15.
+// goto l4; skips over s19 initialization.
+// goto l5; skips over s20-s22 initialization.
+// switch to case 32/33 skips over s23 but goto to adjacent l6 skips also
+// over s20-s22.  switch to default in that switch skips over s23-s24.
+// { dg-final { scan-tree-dump-times "  s1 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s2 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s3 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s4 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s5 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s6 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s7 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s8 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s9 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s10 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s11 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s12 = \.DEFERRED_INIT \\\(" 5 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s13 = \.DEFERRED_INIT \\\(" 4 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s14 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s15 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s16 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s17 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s18 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s19 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s20 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s21 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s22 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s23 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s24 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  i1 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+
+struct S { int a, b, c; };
+
+template <int N>
+int
+foo (int x)
+{
+  int r = 0;
+  if (x == 1)
+    goto l1;
+  S s1;
+  if (x == 2)
+    goto l1;
+  S s2;
+  {
+    S s10;
+    if (x == 12)
+      goto l1;
+    s10.a = 1;
+    r += s10.a;
+    int i1;
+    if (x == 13)
+      goto l1;
+    i1 = 2;
+    r += i1;
+  }
+  if (x == 3)
+    goto l2;
+  if (x == 4)
+    goto l1;
+  {
+    S s3;
+    if (x == 5)
+      goto l2;
+    S s4;
+    if (x == 6)
+      goto l1;
+    {
+      S s5;
+      if (x == 7)
+       goto l1;
+      s5.a = 5;
+      r += s5.a;
+    }
+    S s6;
+    {
+      S s7;
+      S s8;
+      if (x == 8)
+       goto l1;
+      S s9;
+      if (x == 9)
+       goto l2;
+      if (x == 10)
+       goto l2;
+      if (x == 11)
+       goto l2;
+      l1:
+      l2:
+      s1.a = 1;
+      s2.b = 2;
+      s3.c = 3;
+      s4.a = 4;
+      s6.b = 6;
+      s7.c = 7;
+      s8.a = 8;
+      s9.b = 9;
+      r += s1.a + s2.b + s3.c;
+      r += s4.a + s6.b + s7.c;
+      r += s8.a + s9.b;
+      if (x == 14)
+       goto l3;
+      S s11;
+      switch (x)
+       {
+         S s12;
+       case 15:
+         S s13;
+         // FALLTHRU
+       l3:
+       case 16:
+       case 17:
+         S s14;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a;
+         return r;
+       case 18:
+         S s15;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         s15.b = 5;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a + s15.b;
+         return r;
+       default:
+         if (x != 19 && x != 20)
+           break;
+         S s16;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         s15.b = 5;
+         s16.c = 6;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a + s15.b + s16.c;
+         return r;
+       }
+      if (x == 21)
+       goto l3;
+    }
+    S s17;
+    if (x == 22)
+      goto l3;
+    if (x == 23)
+      goto l1;
+    if (x == 24)
+      goto l2;
+    s17.a = 1;
+    r += s17.a;
+  }
+  S s18;
+  if (x == 25)
+    {
+      S s19;
+      s19.c = 2;
+      r += s19.c;
+      if (x == 29)
+       l4:;
+      goto l3;
+    }
+  if (x == 26)
+    goto l1;
+  if (x == 27)
+    goto l2;
+  s18.b = 1;
+  r += s18.b;
+  if (x == 28)
+    goto l4;
+  {
+    S s20;
+    {
+      S s21;
+      if (x == 29)
+       goto l1;
+      S s22;
+      if (x == 30)
+       goto l2;
+      l5:
+      s20.a = 1;
+      s21.b = 2;
+      s22.c = 3;
+      r += s20.a + s21.b + s22.c;
+      switch (x)
+       {
+       case 31:
+         S s23;
+         // FALLTHRU
+       l6:
+       case 32:
+       case 33:
+         S s24;
+         s23.a = 1;
+         s24.b = 2;
+         r += s23.a + s24.b;
+         return r;
+       default:
+         if (x >= 34 && x <= 35)
+           return r;
+         break;
+       }
+      if (x == 34)
+       goto l5;
+      if (x == 35)
+       goto l6;
+      return r;
+    }
+    if (x == 36)
+      goto l5;
+    if (x == 37)
+      goto l6;
+  }
+  if (x == 38)
+    goto l5;
+  if (x == 39)
+    goto l6;
+  return r;
+}
+
+int
+bar (int x)
+{
+  return foo <42> (x);
+}
--- gcc/testsuite/g++.dg/cpp26/erroneous6.C.jj  2025-11-19 13:13:02.794428890 
+0100
+++ gcc/testsuite/g++.dg/cpp26/erroneous6.C     2025-11-19 13:13:33.318995159 
+0100
@@ -0,0 +1,241 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* } { "-ftrivial-auto-var-init=*" } { "" } }
+// { dg-options "-O2 -fdump-tree-gimple" }
+// All the s1..s24 variables and i1 need .DEFERRED_INIT call on their
+// declarations.
+// Plus, forward gotos to l1 & l2 labels need up to s1-s4 and s6-s9 vars to
+// be .DEFERRED_INITed (and backward gotos up to that minus the first two).
+// switch to case 15 skips over s12, switch to case 16/17 skip
+// over s12 and s13 but the adjacent l3 label needs to also skip over s3-s4
+// and s6-s9 and s11.  switch to case 18 skips over s12-s14 and switch to
+// default in the same switch skips over s12-s15.
+// goto l4; skips over s19 initialization.
+// goto l5; skips over s20-s22 initialization.
+// switch to case 32/33 skips over s23 but goto to adjacent l6 skips also
+// over s20-s22.  switch to default in that switch skips over s23-s24.
+// { dg-final { scan-tree-dump-times "  s1 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s2 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s3 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s4 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s5 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s6 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s7 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s8 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s9 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s10 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s11 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s12 = \.DEFERRED_INIT \\\(" 5 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s13 = \.DEFERRED_INIT \\\(" 4 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s14 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s15 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s16 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s17 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s18 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s19 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s20 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s21 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s22 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s23 = \.DEFERRED_INIT \\\(" 3 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  s24 = \.DEFERRED_INIT \\\(" 2 "gimple" 
{ target c++26 } } }
+// { dg-final { scan-tree-dump-times "  i1 = \.DEFERRED_INIT \\\(" 1 "gimple" 
{ target c++26 } } }
+
+struct S { int a, b, c; };
+
+template <typename S>
+int
+foo (int x)
+{
+  int r = 0;
+  if (x == 1)
+    goto l1;
+  S s1;
+  if (x == 2)
+    goto l1;
+  S s2;
+  {
+    S s10;
+    if (x == 12)
+      goto l1;
+    s10.a = 1;
+    r += s10.a;
+    int i1;
+    if (x == 13)
+      goto l1;
+    i1 = 2;
+    r += i1;
+  }
+  if (x == 3)
+    goto l2;
+  if (x == 4)
+    goto l1;
+  {
+    S s3;
+    if (x == 5)
+      goto l2;
+    S s4;
+    if (x == 6)
+      goto l1;
+    {
+      S s5;
+      if (x == 7)
+       goto l1;
+      s5.a = 5;
+      r += s5.a;
+    }
+    S s6;
+    {
+      S s7;
+      S s8;
+      if (x == 8)
+       goto l1;
+      S s9;
+      if (x == 9)
+       goto l2;
+      if (x == 10)
+       goto l2;
+      if (x == 11)
+       goto l2;
+      l1:
+      l2:
+      s1.a = 1;
+      s2.b = 2;
+      s3.c = 3;
+      s4.a = 4;
+      s6.b = 6;
+      s7.c = 7;
+      s8.a = 8;
+      s9.b = 9;
+      r += s1.a + s2.b + s3.c;
+      r += s4.a + s6.b + s7.c;
+      r += s8.a + s9.b;
+      if (x == 14)
+       goto l3;
+      S s11;
+      switch (x)
+       {
+         S s12;
+       case 15:
+         S s13;
+         // FALLTHRU
+       l3:
+       case 16:
+       case 17:
+         S s14;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a;
+         return r;
+       case 18:
+         S s15;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         s15.b = 5;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a + s15.b;
+         return r;
+       default:
+         if (x != 19 && x != 20)
+           break;
+         S s16;
+         s11.a = 1;
+         s12.b = 2;
+         s13.c = 3;
+         s14.a = 4;
+         s15.b = 5;
+         s16.c = 6;
+         r += s11.a + s12.b + s13.c;
+         r += s14.a + s15.b + s16.c;
+         return r;
+       }
+      if (x == 21)
+       goto l3;
+    }
+    S s17;
+    if (x == 22)
+      goto l3;
+    if (x == 23)
+      goto l1;
+    if (x == 24)
+      goto l2;
+    s17.a = 1;
+    r += s17.a;
+  }
+  S s18;
+  if (x == 25)
+    {
+      S s19;
+      s19.c = 2;
+      r += s19.c;
+      if (x == 29)
+       l4:;
+      goto l3;
+    }
+  if (x == 26)
+    goto l1;
+  if (x == 27)
+    goto l2;
+  s18.b = 1;
+  r += s18.b;
+  if (x == 28)
+    goto l4;
+  {
+    S s20;
+    {
+      S s21;
+      if (x == 29)
+       goto l1;
+      S s22;
+      if (x == 30)
+       goto l2;
+      l5:
+      s20.a = 1;
+      s21.b = 2;
+      s22.c = 3;
+      r += s20.a + s21.b + s22.c;
+      switch (x)
+       {
+       case 31:
+         S s23;
+         // FALLTHRU
+       l6:
+       case 32:
+       case 33:
+         S s24;
+         s23.a = 1;
+         s24.b = 2;
+         r += s23.a + s24.b;
+         return r;
+       default:
+         if (x >= 34 && x <= 35)
+           return r;
+         break;
+       }
+      if (x == 34)
+       goto l5;
+      if (x == 35)
+       goto l6;
+      return r;
+    }
+    if (x == 36)
+      goto l5;
+    if (x == 37)
+      goto l6;
+  }
+  if (x == 38)
+    goto l5;
+  if (x == 39)
+    goto l6;
+  return r;
+}
+
+int
+bar (int x)
+{
+  return foo <S> (x);
+}

        Jakub

Reply via email to