https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127132
--- Comment #6 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The trunk branch has been updated by Jason Merrill <[email protected]>: https://gcc.gnu.org/g:a310db3ba39dbf8bd4db94ee5de7acce5e1cca69 commit r17-3993-ga310db3ba39dbf8bd4db94ee5de7acce5e1cca69 Author: Vladislav Semykin <[email protected]> Date: Sat Sep 5 00:19:35 2026 +0300 c++: fix typeid capture in generic lambdas [PR c++/127132] [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 and lambda_expr_this_capture suppress capture only when cp_unevaluated_operand exceeds that cutoff. A typeid probe passes typeid_operand=true to cp_unevaluated, which 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. Inside the cutoff, capture is attempted as usual, but a missing capture-default is not diagnosed there - the real evaluated-ness isn't known yet, and a later, non-probe pass will diagnose it if the operand turns out evaluated. Outside a lambda (a local class, a default argument) the capture attempt has nothing to attach to and falls through unchanged, so params() in pr125886.C still sees an unevaluated operand with no extra special-casing. Every force-reset site that clears cp_unevaluated_operand also save/reset/restores the cutoff, including cp_evaluated. processing_template_decl == 0 turned out to still be the right gate for the evaluated re-parse itself: mark_used and build_typeid both already no-op unconditionally in any template context, independent of which pass hits them, so the two-pass parse needs no extra gate there either. gcc/cp/ChangeLog: PR c++/127132 * cp-tree.h (saved_scope): Save unevaluated_typeid_cutoff. (cp_unevaluated_typeid_cutoff): Declare. (cp_unevaluated): Add a defaulted TYPEID_OPERAND parameter; save and restore the cutoff. (cp_evaluated): Save, reset, and restore the cutoff. * parser.cc (cp_unevaluated_typeid_cutoff): Define. (cp_unevaluated::cp_unevaluated, cp_unevaluated::~cp_unevaluated): Implement TYPEID_OPERAND cutoff handling. (cp_parser_postfix_expression): Pass typeid_operand=true for the typeid probe. * pt.cc (instantiate_class_template): Save/reset/restore the cutoff around NSDMI / lambda capture substitution. (tsubst_expr): Pass typeid_operand=true for TYPEID_EXPR's probe. * semantics.cc (process_outer_var_ref): Allow lambda capture through a typeid probe per [expr.prim.lambda.capture]/7; defer the "not captured" diagnostic to a later, non-probe pass. * lambda.cc (lambda_expr_this_capture): Same cutoff and deferral 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/typeid-lambda-capture-pr127132.C: New test, consolidating the original PR127132 reproducer with the /7 cases previously added to pr125886.C, plus this-capture coverage and closure-size checks. Signed-off-by: Vladislav Semykin <[email protected]> Reviewed-by: Jason Merrill <[email protected]>
