From 4445af6433ca974376ec64e2a808a527654afccf Mon Sep 17 00:00:00 2001
From: Odysseas Georgoudis <odygrd@hotmail.com>
Date: Mon, 27 Jul 2026 13:36:01 +0100
Subject: [PATCH] c++: Fix lambda scope cleanup after class error [PR125343]

cp_parser_class_head opens a lambda mangling scope for a valid class
head.  If begin_class_definition rejects that type, it replaces it with
error_mark_node.  The old cleanup condition consequently leaves the
scope open, and lambda error recovery reaches
record_lambda_scope_sig_discriminator with the wrong active scope.

Remember whether the class head opened a lambda scope and use that
state for cleanup independently of whether the definition succeeds.

PR c++/125343

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_class_specifier): Preserve whether the
	class head opened a lambda scope and use it for cleanup.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/pr125343.C: New test.

Signed-off-by: Odysseas Georgoudis <odygrd@hotmail.com>
---
 gcc/cp/parser.cc                      | 11 ++++++---
 gcc/testsuite/g++.dg/cpp2a/pr125343.C | 35 +++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr125343.C

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a4cfcfa480e..b7dc2beace0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -29784,6 +29784,10 @@ cp_parser_class_specifier (cp_parser* parser)
       return error_mark_node;
     }
 
+  /* Remember whether cp_parser_class_head opened a lambda scope;
+     begin_class_definition can replace TYPE with error_mark_node.  */
+  bool has_lambda_scope = type != error_mark_node;
+
   cp_ensure_no_omp_declare_simd (parser);
   cp_ensure_no_oacc_routine (parser);
 
@@ -29867,10 +29871,9 @@ cp_parser_class_specifier (cp_parser* parser)
   if (cp_parser_allow_gnu_extensions_p (parser))
     attributes = cp_parser_gnu_attributes_opt (parser);
   if (type != error_mark_node)
-    {
-      type = finish_struct (type, attributes);
-      finish_lambda_scope ();
-    }
+    type = finish_struct (type, attributes);
+  if (has_lambda_scope)
+    finish_lambda_scope ();
   if (nested_name_specifier_p)
     pop_inner_scope (old_scope, scope);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/pr125343.C b/gcc/testsuite/g++.dg/cpp2a/pr125343.C
new file mode 100644
index 00000000000..33b88c21472
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/pr125343.C
@@ -0,0 +1,35 @@
+// PR c++/125343
+// { dg-do compile { target c++20 } }
+
+void f1()
+{
+  []<struct S {}>() {}; // { dg-error "types may not be defined in parameter types" }
+  // { dg-error "definition of .struct f1..::<lambda>::S. inside template parameter list" "" { target *-*-* } .-1 }
+  [] {};
+}
+
+void f2()
+{
+  []<struct {}>() {}; // { dg-error "types may not be defined in parameter types" }
+  // { dg-error "definition of .struct f2..::<lambda>::<unnamed>. inside template parameter list" "" { target *-*-* } .-1 }
+}
+
+void f3()
+{
+  []<class T = struct S {}>() {};
+  // { dg-error "definition of .struct f3..::<lambda>::S. inside template parameter list" "" { target *-*-* } .-1 }
+}
+
+void f4()
+{
+  []<template <union U {}> class T>() {}; // { dg-error "types may not be defined in parameter types" }
+  // { dg-error "definition of .union f4..::<lambda>::U. inside template parameter list" "" { target *-*-* } .-1 }
+}
+
+void f5()
+{
+  []<struct S {}; // { dg-error "types may not be defined in parameter types" }
+  // { dg-error "definition of .struct f5..::<lambda>::S. inside template parameter list" "" { target *-*-* } .-1 }
+  // { dg-error "expected .>. before .;. token" "" { target *-*-* } .-2 }
+  // { dg-error "expected '\\\{' before ';' token" "" { target *-*-* } .-3 }
+}
-- 
2.43.5

