See 093ae9b50968f04eafc9d64cc654b48e234f1bc0

gcc-verify and gcc-style are ok.
Test sweep for: [
  cpp0x/pr125886.C
  coroutines/unevaluated.C
  rtti/*.C
  cpp0x/constexpr-typeid*.C
  cpp2a/constexpr-typeid*.C
  template/typeid*.C
  cpp0x/lambda/*.C
  cpp1y/*lambda*.C
  cpp2a/*lambda*.C
  pr127132.C
] is clean.

Tested on full CI (via `make -k check-c++-all`):
    expected passes: 619076
    unexpected failures: 9
    unexpected successes: 1
    expected failures: 6012
    unresolved testcases: 2
    unsupported tests: 23071
Seems like noise on failed tests.
From 093ae9b50968f04eafc9d64cc654b48e234f1bc0 Mon Sep 17 00:00:00 2001
From: Vladislav Semykin <[email protected]>
Date: Fri, 4 Sep 2026 09:25:58 +0300
Subject: [PATCH v3] c++: fix typeid capture in generic lambdas [PR c++/127132]
To: [email protected]

[expr.prim.lambda.capture]/7 (P0588R1 / CWG1468) requires a lambda to
capture a local entity if the expression would be potentially evaluated
were the effect of any enclosing typeid expressions ignored.  Capture
must not depend on whether the typeid operand is itself evaluated.

The PR125886 two-pass parse gated the capture-triggering evaluated
re-parse on processing_template_decl == 0.  A generic lambda's own auto
parameter makes that nonzero regardless of the operand, so capture of
an outer polymorphic glvalue was skipped and the resulting uncaptured
decl ICEd at RTL expand (PR127132).

Do not teach typeid_evaluated_p to treat a template context as
evaluated: mark_used must still suppress instantiation while the
operand is genuinely unevaluated (declval<T>()), and
resolves_to_fixed_type_p already returns "fixed" whenever
in_template_context.

Instead, add cp_unevaluated_typeid_cutoff: process_outer_var_ref
suppresses capture only when cp_unevaluated_operand exceeds that
cutoff.  A typeid probe uses a new RAII class that raises the cutoff
only when operand == cutoff at probe start, so sizeof (typeid (b))
stays suppressed while typeid (typeid (x)) looks through every
enclosing typeid.  The look-through applies only inside a lambda
(LAMBDA_FUNCTION_P); a local class or default argument still sees the
operand as unevaluated.  The same cutoff is used for this-capture.
Force-reset sites that clear cp_unevaluated_operand also
save/reset/restore the cutoff, including cp_evaluated.

The evaluated re-parse is still gated on
!instantiation_dependent_expression_p so mark_used runs for a
non-dependent polymorphic operand inside a generic lambda.

Changes since v2:
- Jason: capture must ignore enclosing typeid entirely
  ([expr.prim.lambda.capture]/7).  Do not change typeid_evaluated_p or
  mark_used.
- New cutoff + cp_unevaluated_typeid_operand RAII on the probe (parser
  and tsubst_expr).  process_outer_var_ref looks through typeid only
  for lambdas; local classes keep the unevaluated early-return
  (pr125886.C params).
- this-capture and every force-reset of cp_unevaluated_operand follow
  the cutoff, including cp_evaluated.
- Tests: pr127132.C plus /7 cases on pr125886.C, including 10-deep
  nested typeid and the same nest inside sizeof.

Changes since v1:
- Jason: typeid_evaluated_p should err on the side of "evaluated" when
  it can't tell, not try to compute a precise answer.  That v2 approach
  is superseded: capture no longer depends on typeid_evaluated_p.

Tested on x86_64-pc-linux-gnu.  Targeted g++.dg sweep (rtti,
constexpr-typeid, template/typeid, lambda dirs, pr125886.C,
pr127132.C, coroutines/unevaluated.C).  No FAIL/XPASS/UNRESOLVED after
restricting the look-through to lambdas.
Tested full CI (via make -k check-c++-all):

  make -k check-c++-all  (8313.7s)  10 to review
    expected passes: 619076
    unexpected failures: 9
    unexpected successes: 1
    expected failures: 6012
    unresolved testcases: 2
    unsupported tests: 23071
    FAIL: c-c++-common/analyzer/flex-without-call-summaries.c  -std=c++11  at line 886 (test for warnings, line 885)
    XPASS: c-c++-common/analyzer/flex-without-call-summaries.c  -std=c++11 PR analyzer/103546 (test for bogus messages, line 893)
    FAIL: c-c++-common/analyzer/flex-without-call-summaries.c  -std=c++11 (test for excess errors)
    FAIL: g++.dg/gomp/bad-array-section-10.C  -std=c++26 (test for excess errors)
    FAIL: g++.dg/gomp/bad-array-section-10.C  -std=c++26 -fimplicit-constexpr (test for excess errors)
    FAIL: g++.dg/guality/pr55665.C   -O2 -flto -fno-use-linker-plugin -flto-partition=none  line 23 p == 40
    FAIL: g++.dg/modules/xtreme-header-2_a.H -std=c++26 -fimplicit-constexpr (test for excess errors)
    FAIL: g++.dg/modules/xtreme-header-2_c.C -std=c++26 -fimplicit-constexpr (test for excess errors)
    FAIL: g++.dg/modules/xtreme-header-7_a.H -std=c++26 -fimplicit-constexpr (test for excess errors)
    FAIL: g++.dg/modules/xtreme-header_a.H -std=c++26 -fimplicit-constexpr (test for excess errors)

------------------------------------------------------------------------
Total expected passes: 619076 = 619076
10 FAIL/XPASS/UNRESOLVED across 1 sweep(s) - see above

gcc/cp/ChangeLog:

	PR c++/127132
	* cp-tree.h (saved_scope): Save unevaluated_typeid_cutoff.
	(cp_unevaluated_typeid_cutoff): Declare.
	(cp_unevaluated_typeid_operand): New RAII class.
	(cp_evaluated): Save, reset, and restore the cutoff.
	* parser.cc (cp_unevaluated_typeid_cutoff): Define.
	(cp_unevaluated_typeid_operand): Implement.
	(cp_parser_postfix_expression): Use the new RAII for the typeid
	probe.  Gate the evaluated re-parse on operand dependence, not
	processing_template_decl.
	* pt.cc (instantiate_class_template): Save/reset/restore the
	cutoff around NSDMI / lambda capture substitution.
	(tsubst_expr): Use the new RAII for TYPEID_EXPR's probe.
	* semantics.cc (process_outer_var_ref): Allow lambda capture
	through a typeid probe per [expr.prim.lambda.capture]/7.
	* lambda.cc (lambda_expr_this_capture): Same cutoff for this.
	* constraint.cc (tsubst_constraint_variables): Save/reset/restore
	the cutoff with cp_unevaluated_operand.
	* name-lookup.cc (push_to_top_level, pop_from_top_level): Same.
	(local_state_t): Same.

gcc/testsuite/ChangeLog:

	PR c++/127132
	* g++.dg/rtti/pr127132.C: New test.
	* g++.dg/cpp0x/pr125886.C: Test capture regardless of typeid
	evaluated-ness, missing capture-default, nested sizeof (typeid),
	nested typeid, and a 10-deep nest (plain and inside sizeof).

Signed-off-by: Vladislav Semykin <[email protected]>
---
 gcc/cp/constraint.cc                  |  3 ++
 gcc/cp/cp-tree.h                      | 34 ++++++++++++--
 gcc/cp/lambda.cc                      |  6 ++-
 gcc/cp/name-lookup.cc                 |  7 +++
 gcc/cp/parser.cc                      | 34 +++++++++++---
 gcc/cp/pt.cc                          |  5 +-
 gcc/cp/semantics.cc                   | 20 +++++++-
 gcc/testsuite/g++.dg/cpp0x/pr125886.C | 66 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/rtti/pr127132.C  | 53 +++++++++++++++++++++
 9 files changed, 214 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/rtti/pr127132.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index fa271a96282..d0d39da7979 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1703,9 +1703,12 @@ tsubst_constraint_variables (tree t, tree args, subst_info info)
   /* Clear cp_unevaluated_operand across tsubst so that we get a proper chain
      of PARM_DECLs.  */
   int saved_unevaluated_operand = cp_unevaluated_operand;
+  int saved_unevaluated_typeid_cutoff = cp_unevaluated_typeid_cutoff;
   cp_unevaluated_operand = 0;
+  cp_unevaluated_typeid_cutoff = 0;
   tree vars = tsubst (t, args, info.complain, info.in_decl);
   cp_unevaluated_operand = saved_unevaluated_operand;
+  cp_unevaluated_typeid_cutoff = saved_unevaluated_typeid_cutoff;
   if (vars == error_mark_node)
     return error_mark_node;
   return declare_constraint_vars (t, vars);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 369d2a9119d..1897e977099 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2133,6 +2133,7 @@ struct GTY(()) saved_scope {
   bool expansion_stmt : 1;
 
   int unevaluated_operand;
+  int unevaluated_typeid_cutoff;
   int inhibit_evaluation_warnings;
   int noexcept_operand;
   int ref_temp_count;
@@ -6303,6 +6304,13 @@ extern bool cp_preserve_using_decl;
 
 extern int cp_unevaluated_operand;
 
+/* cp_unevaluated_operand depth up to which lambda capture is still
+   allowed.  A typeid operand's own unevaluated probe raises this so
+   that probe does not by itself suppress capture
+   ([expr.prim.lambda.capture]/7).  */
+
+extern int cp_unevaluated_typeid_cutoff;
+
 /* RAII class used to inhibit the evaluation of operands during parsing
    and template instantiation.  Evaluation warnings are also inhibited.  */
 
@@ -6313,6 +6321,20 @@ public:
   ~cp_unevaluated ();
 };
 
+/* Like cp_unevaluated, but for a typeid operand's own unevaluated
+   probe: also conditionally raises cp_unevaluated_typeid_cutoff so
+   this probe does not by itself suppress lambda capture
+   ([expr.prim.lambda.capture]/7), unless something else already
+   makes the context unevaluated.  */
+
+class cp_unevaluated_typeid_operand
+{
+public:
+  int saved_cutoff;
+  cp_unevaluated_typeid_operand ();
+  ~cp_unevaluated_typeid_operand ();
+};
+
 /* The reverse: an RAII class used for nested contexts that are evaluated even
    if the enclosing context is not.  */
 
@@ -6321,13 +6343,19 @@ class cp_evaluated
 public:
   int uneval;
   int inhibit;
+  int typeid_cutoff;
   cp_evaluated (bool reset = true)
-    : uneval(cp_unevaluated_operand), inhibit(c_inhibit_evaluation_warnings)
+    : uneval (cp_unevaluated_operand), inhibit (c_inhibit_evaluation_warnings),
+      typeid_cutoff (cp_unevaluated_typeid_cutoff)
   { if (reset)
-      cp_unevaluated_operand = c_inhibit_evaluation_warnings = 0; }
+      {
+	cp_unevaluated_operand = c_inhibit_evaluation_warnings = 0;
+	cp_unevaluated_typeid_cutoff = 0;
+      } }
   ~cp_evaluated ()
   { cp_unevaluated_operand = uneval;
-    c_inhibit_evaluation_warnings = inhibit; }
+    c_inhibit_evaluation_warnings = inhibit;
+    cp_unevaluated_typeid_cutoff = typeid_cutoff; }
 };
 
 /* in pt.cc  */
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index e0d676cae81..ff76b98d6e7 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -847,8 +847,10 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
 	this_capture = spec;
       }
 
-  /* In unevaluated context this isn't an odr-use, so don't capture.  */
-  if (cp_unevaluated_operand)
+  /* In unevaluated context this isn't an odr-use, so don't capture.
+     A typeid operand's own probe is capture-transparent
+     ([expr.prim.lambda.capture]/7).  */
+  if (cp_unevaluated_operand > cp_unevaluated_typeid_cutoff)
     add_capture_p = false;
 
   /* If we captured 'this' but don't have a capture proxy yet, look up the
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 60a6e6f4430..13cee628faa 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -9069,6 +9069,7 @@ push_to_top_level (void)
   s->need_pop_function_context = need_pop;
   s->function_decl = current_function_decl;
   s->unevaluated_operand = cp_unevaluated_operand;
+  s->unevaluated_typeid_cutoff = cp_unevaluated_typeid_cutoff;
   s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
   s->suppress_location_wrappers = suppress_location_wrappers;
   s->x_stmt_tree.stmts_are_full_exprs_p = true;
@@ -9080,6 +9081,7 @@ push_to_top_level (void)
   current_namespace = global_namespace;
   push_class_stack ();
   cp_unevaluated_operand = 0;
+  cp_unevaluated_typeid_cutoff = 0;
   c_inhibit_evaluation_warnings = 0;
   suppress_location_wrappers = 0;
 }
@@ -9112,6 +9114,7 @@ pop_from_top_level (void)
     pop_function_context ();
   current_function_decl = s->function_decl;
   cp_unevaluated_operand = s->unevaluated_operand;
+  cp_unevaluated_typeid_cutoff = s->unevaluated_typeid_cutoff;
   c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
   suppress_location_wrappers = s->suppress_location_wrappers;
 
@@ -9129,6 +9132,7 @@ namespace {
 struct local_state_t
 {
   int cp_unevaluated_operand;
+  int cp_unevaluated_typeid_cutoff;
   int c_inhibit_evaluation_warnings;
   int cp_noexcept_operand_;
   bool has_cfun;
@@ -9139,6 +9143,8 @@ struct local_state_t
     local_state_t s;
     s.cp_unevaluated_operand = ::cp_unevaluated_operand;
     ::cp_unevaluated_operand = 0;
+    s.cp_unevaluated_typeid_cutoff = ::cp_unevaluated_typeid_cutoff;
+    ::cp_unevaluated_typeid_cutoff = 0;
     s.c_inhibit_evaluation_warnings = ::c_inhibit_evaluation_warnings;
     ::c_inhibit_evaluation_warnings = 0;
     s.cp_noexcept_operand_ = ::cp_noexcept_operand;
@@ -9153,6 +9159,7 @@ struct local_state_t
   restore () const
   {
     ::cp_unevaluated_operand = this->cp_unevaluated_operand;
+    ::cp_unevaluated_typeid_cutoff = this->cp_unevaluated_typeid_cutoff;
     ::c_inhibit_evaluation_warnings = this->c_inhibit_evaluation_warnings;
     ::cp_noexcept_operand = this->cp_noexcept_operand_;
     if (this->has_cfun)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 967ba3fd542..4567e239a00 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -296,6 +296,12 @@ static FILE *cp_lexer_debug_stream;
    sizeof can be nested.  */
 int cp_unevaluated_operand;
 
+/* cp_unevaluated_operand depth up to which lambda capture is still
+   allowed; raised by a typeid operand's own unevaluated probe so that
+   probe does not by itself suppress capture
+   ([expr.prim.lambda.capture]/7).  */
+int cp_unevaluated_typeid_cutoff;
+
 /* Nonzero if we are parsing a reflect-expression and shouldn't strip
    using-declarations.  */
 bool cp_preserve_using_decl;
@@ -3253,6 +3259,23 @@ cp_unevaluated::~cp_unevaluated ()
   --cp_unevaluated_operand;
 }
 
+cp_unevaluated_typeid_operand::cp_unevaluated_typeid_operand ()
+  : saved_cutoff (cp_unevaluated_typeid_cutoff)
+{
+  bool transparent = (cp_unevaluated_operand == cp_unevaluated_typeid_cutoff);
+  ++cp_unevaluated_operand;
+  ++c_inhibit_evaluation_warnings;
+  if (transparent)
+    cp_unevaluated_typeid_cutoff = cp_unevaluated_operand;
+}
+
+cp_unevaluated_typeid_operand::~cp_unevaluated_typeid_operand ()
+{
+  --c_inhibit_evaluation_warnings;
+  --cp_unevaluated_operand;
+  cp_unevaluated_typeid_cutoff = saved_cutoff;
+}
+
 // -------------------------------------------------------------------------- //
 // Tentative Parsing
 
@@ -8579,16 +8602,15 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	       (mark_used -> instantiation; lambda capture).  */
 	    cp_lexer_save_tokens (parser->lexer);
 	    {
-	      cp_unevaluated u;
+	      cp_unevaluated_typeid_operand u;
 	      expression = cp_parser_expression (parser, &idk);
 	    }
-	    /* If we're already within an unevaluated operand, everything
-	       in the subtree stays not potentially evaluated regardless
-	       of [expr.typeid]/4 ([basic.def.odr]/3), so the evaluated
-	       re-parse below can have nothing to do; skip it.  */
+	    /* Skip the evaluated re-parse if something else already makes
+	       the context unevaluated, or if the operand is still
+	       instantiation-dependent (tsubst_expr will re-check).  */
 	    if (expression != error_mark_node
-		&& processing_template_decl == 0
 		&& !cp_unevaluated_operand
+		&& !instantiation_dependent_expression_p (expression)
 		&& typeid_evaluated_p (expression))
 	      {
 		/* Re-parse the operand evaluated so the /4 side-effects occur.
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dd0efa54112..8f7e74bea51 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12962,6 +12962,7 @@ instantiate_class_template (tree type)
   maybe_diagnose_erroneous_template (t ? TI_TEMPLATE (t) : templ);
 
   int saved_unevaluated_operand = cp_unevaluated_operand;
+  int saved_unevaluated_typeid_cutoff = cp_unevaluated_typeid_cutoff;
   int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
 
   fn_context = decl_function_context (TYPE_MAIN_DECL (type));
@@ -12973,6 +12974,7 @@ instantiate_class_template (tree type)
   else
     {
       cp_unevaluated_operand = 0;
+      cp_unevaluated_typeid_cutoff = 0;
       c_inhibit_evaluation_warnings = 0;
     }
 
@@ -13390,6 +13392,7 @@ instantiate_class_template (tree type)
       /* Restore these before substituting into the lambda capture
 	 initializers.  */
       cp_unevaluated_operand = saved_unevaluated_operand;
+      cp_unevaluated_typeid_cutoff = saved_unevaluated_typeid_cutoff;
       c_inhibit_evaluation_warnings = saved_inhibit_evaluation_warnings;
     }
 
@@ -23098,7 +23101,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    tree operand;
 	    tree uneval;
 	    {
-	      cp_unevaluated u;
+	      cp_unevaluated_typeid_operand u;
 	      uneval = RECUR (operand_0);
 	    }
 	    /* If we're already within an unevaluated operand, everything
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bb952e2f62c..df9b0da6094 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4682,15 +4682,26 @@ tree
 process_outer_var_ref (tree decl, tsubst_flags_t complain,
 		       bool odr_use/*=false*/)
 {
+  bool in_typeid_probe = false;
   if (cp_unevaluated_operand)
     {
       tree type = TREE_TYPE (decl);
       if (!dependent_type_p (type)
 	  && variably_modified_type_p (type, NULL_TREE))
 	/* VLAs are used even in unevaluated context.  */;
-      else
-	/* It's not a use (3.2) if we're in an unevaluated context.  */
+      else if (cp_unevaluated_operand > cp_unevaluated_typeid_cutoff
+	       || !current_function_decl
+	       || !LAMBDA_FUNCTION_P (current_function_decl))
+	/* It's not a use (3.2) if we're in an unevaluated context.
+	   [expr.prim.lambda.capture]/7 looks through typeid only for
+	   lambda capture, so a local class or default argument still
+	   sees the operand as unevaluated.  */
 	return decl;
+      else
+	/* Inside a typeid operand's own probe in a lambda: capture is
+	   still required, but a missing capture-default must not be
+	   diagnosed until a later evaluated pass, if any.  */
+	in_typeid_probe = true;
     }
   if (decl == error_mark_node)
     return decl;
@@ -4788,6 +4799,11 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain,
     return var;
   else if (lambda_expr)
     {
+      if (in_typeid_probe)
+	/* Don't know yet whether the operand is really evaluated.  A
+	   real (non-probe) pass will diagnose it if so; if it stays
+	   unevaluated there is nothing to diagnose.  */
+	return var;
       if (complain & tf_error)
 	{
 	  auto_diagnostic_group d;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr125886.C b/gcc/testsuite/g++.dg/cpp0x/pr125886.C
index 96a7ec3cff1..3cd2a7df5b8 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr125886.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr125886.C
@@ -48,6 +48,35 @@ params (int n)
   void g (const std::type_info& = typeid (n));
 }
 
+// [expr.prim.lambda.capture]/7 (P0588R1 / CWG1468): capture must ignore
+// the effect of enclosing typeid expressions.  n is not a polymorphic
+// glvalue, so the operand is unevaluated ([expr.typeid]/5), but n is
+// still captured.
+void
+capture_regardless_of_evaluated (int n)
+{
+  auto lam = [=] { (void) typeid (n); };
+  static_assert (sizeof (lam) == sizeof (int), "");
+}
+
+#if __cplusplus >= 201402L
+void
+capture_regardless_of_evaluated_generic (int n)
+{
+  auto lam = [=](auto a) { (void) typeid (n); };
+  lam (0);
+  static_assert (sizeof (lam) == sizeof (int), "");
+}
+#endif
+
+// No capture-default and a genuinely unevaluated operand: must not
+// diagnose "not captured".
+void
+no_capture_default_non_poly (int n)
+{
+  [] { (void) typeid (n); };
+}
+
 // A final-class polymorphic glvalue resolves to a fixed (static) type,
 // so typeid is unevaluated: no vtable lookup, no odr-use.
 struct F final { virtual ~F (); };
@@ -80,3 +109,40 @@ nested_unevaluated_lambda(B &b)
 {
   [] { (void) sizeof (typeid (b)); }; // OK: no capture required
 }
+
+// sizeof (typeid (b)) is a genuinely unevaluated context wrapping
+// typeid, so the cutoff stays unraised and b is not captured.
+void
+nested_unevaluated_lambda_size (B &b)
+{
+  auto lam = [=] { (void) sizeof (typeid (b)); };
+  static_assert (sizeof (lam) == 1, "");
+}
+
+// Nested typeid looks through every enclosing typeid
+// ([expr.prim.lambda.capture]/7, "any enclosing typeid expressions").
+void
+nested_typeid_capture (int x)
+{
+  auto lam = [=] { (void) typeid (typeid (x)); };
+  static_assert (sizeof (lam) == sizeof (int), "");
+}
+
+// Extremely nested typeid: look-through on each probe
+// (operand == cutoff -> cutoff += 1)
+void
+nested_typeid_capture_extreme(int x)
+{
+  auto lam = [=] {
+    (void) typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (x)))))))))));
+  };
+  static_assert (sizeof (lam) == sizeof (int), "");
+}
+
+// sizeof does not cutoff, all 10 typeid-probe see
+// operand != cutoff and not captured.
+void nested_typeid_capture_extreme_v2(int x)
+{
+  auto lam = [=] { (void) sizeof (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (typeid (x))))))))))); };
+  static_assert (sizeof (lam) == 1, "");
+}
diff --git a/gcc/testsuite/g++.dg/rtti/pr127132.C b/gcc/testsuite/g++.dg/rtti/pr127132.C
new file mode 100644
index 00000000000..dd984cfc822
--- /dev/null
+++ b/gcc/testsuite/g++.dg/rtti/pr127132.C
@@ -0,0 +1,53 @@
+// PR c++/127132 - regression against the PR c++/125886 fix
+// (r17-2200-g621661f7d2e9).
+// { dg-do compile { target c++14 } }
+// c++14 target: the lambda's generic parameter (auto a) is only valid
+// from C++14 on.
+
+// [expr.typeid]/4: *c is a polymorphic glvalue, so typeid's operand is
+// evaluated, and the generic lambda's by-copy capture-default must
+// capture c for that use.  On trunk this capture is currently missing,
+// leaving a decl reference with nothing behind it once the lambda's
+// call operator is expanded - crashing at RTL expand time instead of
+// compiling cleanly.
+
+namespace std {
+class type_info;
+}
+
+class C {
+  virtual ~C();
+};
+
+void foo(const std::type_info &type);
+
+void
+bar (C *c)
+{
+  [=](auto a) { foo(typeid(*c)); }(1);
+}
+
+// [expr.prim.lambda.capture]/7: capture must not depend on whether the
+// typeid operand is evaluated.  F is final, so [expr.typeid]/4 would
+// leave typeid (f) unevaluated, but f is still captured.  Generic-lambda
+// variant of typeid14.C's final_glvalue.
+
+struct F final { virtual ~F (); };
+
+void
+final_glvalue_generic (F &f)
+{
+  [=](auto a) { (void) typeid (f); }(1);
+}
+
+// D::i names no local entity, so [expr.prim.lambda.capture]/7 does not
+// apply and a DR613 non-static member id-expression stays unevaluated
+// (no capture).  Generic-lambda variant of typeid14.C's nsm.
+
+struct D { int i; };
+
+void
+nsm_generic ()
+{
+  [=](auto a) { (void) typeid (D::i); }(1);
+}

base-commit: 71fe685aaadf6cfae13ec46a38fb76a26562823b
-- 
2.43.0

Reply via email to