On 3/14/26 4:22 AM, Jakub Jelinek wrote:
Hi!

The following two testcases ICE during instantation.
Normally for the artificial var used for structured binding as condition
(which has NULL DECL_NAME) there is a DECL_EXPR which registers local
specialization and so tsubst_expr works fine.
But if there are errors while parsing the initializer, the VAR_DECL
has still NULL_TREE DECL_NAME, but error_mark_node TREE_TYPE and
when tsubst_expr is called on it, it falls back to calling lookup_name
(NULL_TREE) and ICEs on that.

The following patch fixes it by asserting it is error operand and
returning error_mark_node in that case.

There's a second fallback (to tsubst_decl) after name lookup, I would think that we just want to skip the lookup if DECL_NAME is null.

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

2026-03-14  Jakub Jelinek  <[email protected]>

        PR c++/120039
        PR c++/122559
        * pt.cc (tsubst_expr) <case VAR_DECL>: Don't call lookup_name on
        NULL_TREE, instead assert it is error_operand_p and seen_error
        and return error_mark_node.

        * g++.dg/cpp26/decomp28.C: New test.
        * g++.dg/cpp26/decomp29.C: New test.

--- gcc/cp/pt.cc.jj     2026-03-13 09:07:06.000000000 +0100
+++ gcc/cp/pt.cc        2026-03-13 12:37:20.004124157 +0100
@@ -22714,6 +22714,13 @@ tsubst_expr (tree t, tree args, tsubst_f
            }
          else if (r == NULL_TREE)
            {
+             if (DECL_NAME (t) == NULL_TREE)
+               {
+                 /* During error-recovery for e.g. structured bindings as
+                    condition artificial vars.  */
+                 gcc_assert (error_operand_p (t) && seen_error ());
+                 RETURN (error_mark_node);
+               }
              /* First try name lookup to find the instantiation.  */
              r = lookup_name (DECL_NAME (t));
              if (r)
--- gcc/testsuite/g++.dg/cpp26/decomp28.C.jj    2026-03-13 13:07:26.195745203 
+0100
+++ gcc/testsuite/g++.dg/cpp26/decomp28.C       2026-03-13 12:59:14.438020251 
+0100
@@ -0,0 +1,23 @@
+// PR c++/120039
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+  int a; long long b; short c;
+  explicit operator bool () const noexcept { return true; }
+};
+
+template <int N>
+void
+foo ()
+{
+  S s = S { 1, 2, 3 };
+  if (auto [sx, sy, sz] : s)   // { dg-warning "structured bindings in conditions only 
available with" "" { target c++23_down } }
+    ;                          // { dg-error "expected initializer before ':' token" 
"" { target *-*-* } .-1 }
+}                              // { dg-error "expected '\\\)' before ':' token" 
"" { target *-*-* } .-2 }
+
+int
+main ()
+{
+  foo <0> ();
+}
--- gcc/testsuite/g++.dg/cpp26/decomp29.C.jj    2026-03-13 13:07:30.841666996 
+0100
+++ gcc/testsuite/g++.dg/cpp26/decomp29.C       2026-03-13 13:05:15.808939648 
+0100
@@ -0,0 +1,19 @@
+// PR c++/122559
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+enum class A : bool { B, C };
+
+template <typename T>
+A type (T &&x)
+{
+  if (auto [value = x ()])     // { dg-warning "structured bindings in conditions only 
available with" "" { target c++23_down } }
+    return A::C;               // { dg-error "expected '\\\]' before '=' token" 
"" { target *-*-* } .-1 }
+  return A::B;                 // { dg-error "expected initializer before '\\\)' token" 
"" { target *-*-* } .-2 }
+}
+
+int
+main ()
+{
+  auto _ = type (A::B);
+}

        Jakub


Reply via email to