On 1/21/26 5:04 PM, Jakub Jelinek wrote:
Hi!

The move of the resolves_to_fixed_type_p call earlier in build_base_path
for constexpr virtual inheritance caused the following ICE.
What changed is that in an unevaluated context expr can be a CALL_EXPR with
class type and when it is not a ctor,
resolves_to_fixed_type_p -> fixed_type_or_null
ICEs on it:
       if (CLASS_TYPE_P (TREE_TYPE (instance)))
         {
           /* We missed a build_cplus_new somewhere, likely due to tf_decltype
              mishandling.  */
           gcc_checking_assert (false);
Now, the reason why that worked fine when resolves_to_fixed_type_p was
later in the function is that there was
       /* This must happen before the call to save_expr.  */
       expr = cp_build_addr_expr (expr, complain);
in between the new and old calls to resolves_to_fixed_type_p, and for the
uneval case like that
cp_build_addr_expr -> unary_complex_lvalue -> build_cplus_new
wraps the CALL_EXPR into a TARGET_EXPR already, so the later call
was happy.

Now, none of fixed_type_p, virtual_access or nonnull values are ever
used in the build_base_path uneval path.
   if (code == PLUS_EXPR
       && !want_pointer
       && !has_empty
       && !uneval
       && !virtual_access)
     return build_simple_base_path (expr, binfo);
doesn't look at it,
   if (!want_pointer)
     {
       rvalue = !lvalue_p (expr);
       /* This must happen before the call to save_expr.  */
       expr = cp_build_addr_expr (expr, complain);
     }
   else
     expr = mark_rvalue_use (expr);
neither, nothing soon after it either and very soon we
   if (uneval)
     {
       expr = build_nop (ptr_target_type, expr);
       goto indout;
     }
and indout: doesn't use it either.

So, if only uneval expressions have problems with moving the
resolves_to_fixed_type_p call earlier, the following patch fixes
it by just not calling that function at all in the uneval case
because we will not care about the result anyway.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-01-21  Jakub Jelinek  <[email protected]>

        PR c++/123692
        * class.cc (build_base_path): Don't call resolves_to_fixed_type_p if
        !uneval.

Drop the ! here.

OK with that tweak.


        * g++.dg/cpp0x/pr123692.C: New test.

--- gcc/cp/class.cc.jj  2026-01-17 14:35:11.439781766 +0100
+++ gcc/cp/class.cc     2026-01-20 13:36:45.018109244 +0100
@@ -347,7 +347,10 @@ build_base_path (enum tree_code code,
                 || processing_template_decl
                 || in_template_context);
- fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
+  if (!uneval)
+    fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
+  else
+    fixed_type_p = 0;
/* Do we need to look in the vtable for the real offset? */
    virtual_access = (v_binfo && fixed_type_p <= 0);
--- gcc/testsuite/g++.dg/cpp0x/pr123692.C.jj    2026-01-20 13:42:39.763057828 
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr123692.C       2026-01-20 13:42:18.298423983 
+0100
@@ -0,0 +1,9 @@
+// PR c++/123692
+// { dg-do compile { target c++11 } }
+
+struct A { A (int); bool operator == (A); };
+struct B : A { using A::A; };
+B operator - (B, B);
+extern B c;
+extern A d;
+decltype (d == c - 1) x;

        Jakub


Reply via email to