On 9/4/26 2:37 AM, Vladislav Semykin wrote:

Looking good, just a few small issues left.

  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)

Yes, these failures are unrelated. In general any unresolved testcases should also be checked, but they are also unrelated (vect/pr36648.cc doesn't like -fimplicit-constexpr, I'm adjusting the testcase now). I generally filter these out by comparing to an earlier baseline testrun of my own, but you can also check gcc-testresults.

        * g++.dg/rtti/pr127132.C: New test.
        * g++.dg/cpp0x/pr125886.C: Test capture regardless of typeid

Please name testcases by what they test, not only their PR number, to enable testing like

  cpp0x/constexpr-typeid*.C
  cpp2a/constexpr-typeid*.C
  template/typeid*.C
  cpp0x/lambda/*.C
  cpp1y/*lambda*.C
  cpp2a/*lambda*.C

that you mention doing. The PR number can come at the end (our usual convention of a sequence number often causes rebase issues).

+/* 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

Instead of a new class, how about making this case a defaulted parameter to the cp_unevaluated constructor?

@@ -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;

This function seems to be missing the in_typeid_probe error case handling from process_outer_var_ref.

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.

Are there any tests that depend on this? In general mark_used doesn't do much in a template.

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

These || are suprising.  They seem to be needed in this patch because...

@@ -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;

...the in_typeid_probe check is limited to the lambda_expr case. If we instead check it immediately after the capture case, i.e. before

  else if (!odr_use && decl_constant_var_p (var))

then we don't need the || above.

+// [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), "");
+}

This test isn't reliable; the compiler is allowed to optimize away the capture if n it isn't actually odr-used, as in
https://eel.is/c++draft/expr.prim#lambda.capture-example-4

I'd actually consider this comparison succeeding to be a (minor) missed-optimization bug. But let's not mess with that in this patch, since the assert passed in GCC 16 so fixing the optimization would be a lambda ABI change that we'd need to control with -fabi-version.

So I guess let's keep this test as it is for now, but add a comment

// If this starts to fail that's OK, the compiler is allowed to optimize
// away the capture, but we need to control it with -fabi-version.

+// [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);
+}

This could also call foo(), and/or check the size?

+// 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);
+}

This could also check the size.

It would also be good to also have tests of 'this' capture, such as if typeid(D::i) were in a member function of D.

Also the typeid14.C references seem stale, the current patch no longer modifies that file.

Jason

Reply via email to