> Does this also fix PR116385 and PR68604? Yes, both, confirmed with the reproducers from those PRs: - for PR116385 all four cases (lambda, local class, and the two default-argument uses) now compile; - for PR68604, typeid(A::i) compiles in C++11+.
One thing I caught while testing: typeid(A::i) must remain ill-formed in C++98 (DR613 only applies from C++11), so I'm gating the unevaluated parse on cxx_dialect >= cxx11 to avoid changing the C++98 behavior. I'll send a v3 to gcc-patches that also handles the template operand in tsubst and factors the polymorphic-glvalue check into a shared helper, as you suggested. > ...actually, why do we need C++11 here? For the declval tests, C++11 is required because std::declval is a C++11 feature. For typeid(A::i) (PR68604), it's required semantically: that case is only valid from C++11 onwards per DR613 - in C++98 it must stay ill-formed - https://godbolt.org/z/WfG1xhsz1 Also, final is keyword introduced in C++11, but can be used with extension as here: https://godbolt.org/z/G6bzToE5b пт, 26 июн. 2026 г. в 22:32, Marek Polacek <[email protected]>: > On Fri, Jun 26, 2026 at 09:23:15PM +0300, Vladislav Semykin wrote: > > This v2 handles the non-template case via reparse. Two cases are left for > > follow-up, and I'd appreciate your guidance on whether they belong in > this > > PR or separately: > > A few random comments. > > The new patch doesn't seem to have a ChangeLog entry (or I missed it). > > The subject should be something like > > c++: fix unevaluated operand context for typeid [PR125886] > > > 1. Template-dependent operand: the decision needs to happen at > instantiation > > time in tsubst (TYPEID_EXPR). My first attempt with an unconditional > > cp_unevaluated there regressed typeid10.C (PR c++/25466), so it needs the > > same type-dependent two-pass logic. > > I personally would require this to be handled in this patch... > > > 2. Polymorphic glvalue inside a lambda: should be odr-used and captured, > > but currently isn't. > > ...but not this. > > > For completeness: the template case is broken on current trunk in the > same > > way - wrongly triggers static_assert, just like the non-template case did > > before this patch, here is the link: https://godbolt.org/z/Thnf6Mrx1 > > Does this also fix PR116385 and PR68604? > > > From aed304a308a9d33191285b0f23a45a2ad7070b75 Mon Sep 17 00:00:00 2001 > > From: Vladislav Semykin <[email protected]> > > Date: Fri, 26 Jun 2026 20:50:15 +0300 > > Subject: [PATCH] cp: fix unevaluated operand context for typeid [PR > > c++/125886] > > > > Signed-off-by: Vladislav Semykin <[email protected]> > > --- > > gcc/cp/cp-tree.h | 4 ++- > > gcc/cp/parser.cc | 41 ++++++++++++++++++++++--- > > gcc/testsuite/g++.dg/cpp0x/pr125886-2.C | 10 ++++++ > > gcc/testsuite/g++.dg/cpp0x/pr125886.C | 21 +++++++++++++ > > 4 files changed, 71 insertions(+), 5 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr125886-2.C > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr125886.C > > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > > index 132139f9d..ccf2a5f5b 100644 > > --- a/gcc/cp/cp-tree.h > > +++ b/gcc/cp/cp-tree.h > > @@ -6340,7 +6340,9 @@ extern bool cp_preserve_using_decl; > > > > /* Nonzero if we are parsing an unevaluated operand: an operand to > > sizeof, typeof, or alignof. This is a count since operands to > > - sizeof can be nested. */ > > + sizeof can be nested. For typeid, the unevaluated/evaluated > > + decision depends on the operand type ([expr.typeid]/4-5) and is > > + taken in cp_parser_postfix_expression (RID_TYPEID) via reparse. */ > > > > extern int cp_unevaluated_operand; > > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > > index 8194106c6..08793e470 100644 > > --- a/gcc/cp/parser.cc > > +++ b/gcc/cp/parser.cc > > @@ -292,7 +292,10 @@ static void missing_template_diag > > static FILE *cp_lexer_debug_stream; > > > > /* Nonzero if we are parsing an unevaluated operand: an operand to > > - sizeof, typeof, or alignof. */ > > + sizeof, typeof, or alignof. This is a count since operands to > > + sizeof can be nested. For typeid, the unevaluated/evaluated > > + decision depends on the operand type ([expr.typeid]/4-5) and is > > + taken in cp_parser_postfix_expression (RID_TYPEID) via reparse. */ > > int cp_unevaluated_operand; > > I'm not sure we need to talk about cp_parser_postfix_expression in > this comment. > > > /* Nonzero if we are parsing a reflect-expression and shouldn't strip > > @@ -8569,10 +8572,40 @@ cp_parser_postfix_expression (cp_parser *parser, > bool address_p, bool cast_p, > > /* Otherwise, fall back to the expression variant. */ > > else > > { > > - tree expression; > > + cp_lexer_save_tokens (parser->lexer); > > + ++cp_unevaluated_operand; > > + ++c_inhibit_evaluation_warnings; > > + tree expression = cp_parser_expression(parser, &idk); > > Missing space before ). > > > + --c_inhibit_evaluation_warnings; > > + --cp_unevaluated_operand; > > + > > + bool need_eval = false; > > + if (expression != error_mark_node > > + && processing_template_decl == 0) > > + { > > + /* Reuse the same predicate as build_typeid (rtti.cc) so > > + there is a single source of truth for the [expr.typeid]/4 > > + condition. */ > > + int nonnull = 0; > > + tree t = TREE_TYPE (expression); > > + need_eval = (CLASS_TYPE_P (t) > > + && TYPE_POLYMORPHIC_P (t) > > + && !resolves_to_fixed_type_p (expression, > &nonnull) > > + && !nonnull > > + /* Only glvalues are evaluated. */ > > + /* prvalues are unevaluated even for > > + polymorphic types. */ > > + && glvalue_p (expression)); > > This should be a new routine otherwise they will get out of sync at > some point. > > > + } > > + if (need_eval) > > + { > > + /* Roll back to unevaluated parse. */ > > I'm not sure I understand this comment. There should be a comment before > the first cp_parser_expression explaining what's going on here. > > > + cp_lexer_rollback_tokens (parser->lexer); > > + expression = cp_parser_expression (parser, &idk); > > + } > > + else > > + cp_lexer_commit_tokens (parser->lexer); > > > > - /* Look for an expression. */ > > - expression = cp_parser_expression (parser, & idk); > > /* Compute its typeid. */ > > postfix_expression = build_typeid (expression, > tf_warning_or_error); > > /* Look for the `)' token. */ > > diff --git a/gcc/testsuite/g++.dg/cpp0x/pr125886-2.C > b/gcc/testsuite/g++.dg/cpp0x/pr125886-2.C > > new file mode 100644 > > index 000000000..f5e565fc0 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp0x/pr125886-2.C > > Let's call the test typeid14.C and put it into rtti/. > > > @@ -0,0 +1,10 @@ > > Add > // PR c++/125886 > as the first line. > > > +/* { dg-do compile } */ > > +/* { dg-options "-std=c++11" } */ > > Make this > // { dg-do compile { target c++11 } } > ... actually, why do we need C++11 here? > > > + > > +#include <typeinfo> > > +#include <utility> > > + > > +// Polymorphic glvalue: [expr.typeid]/4 evaluated -> declval<B>() is > > +// instantiated and __declval_protector's static_assert fires. > > +class B { virtual ~B(); }; > > +void bar() { char const *b = typeid(std::declval<B>()).name(); } // { > dg-error "static assertion failed: declval" "" { target *-*-* } 0 } > > diff --git a/gcc/testsuite/g++.dg/cpp0x/pr125886.C > b/gcc/testsuite/g++.dg/cpp0x/pr125886.C > > new file mode 100644 > > index 000000000..9e9673d02 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/cpp0x/pr125886.C > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-std=c++11" } */ > > Same as above. > > > +#include <typeinfo> > > +#include <utility> > > + > > +// 1. Non-polymorphic: [expr.typeid]/5 unevaluated -> declval<A>() is > ok. > > +class A {}; > > +void foo() { char const *a = typeid(std::declval<A>()).name(); } > > + > > +// 2. Non-polymorphic lambda operand: unevaluated, no capture needed. > > +void qux(int n) { [&]{ typeid(n); }; } > > + > > +// 3. final-class polymorphic glvalue: resolves_to_fixed_type_p -> > static > > +// typeid, unevaluated (no vtable lookup, no odr-use). > > +class F final { virtual ~F(); }; > > +void fin(F& f) { typeid(f); } > > + > > +// TODO: The template-dependent operand and polymorphic > > +// lambda-capture cases are not yet handled and > > +// will be addressed in a follow-up. > > -- > > 2.43.0 > > > > Thanks, > > Marek > >
