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