On Fri, Jul 24, 2026 at 07:02:06PM +0200, Jakub Jelinek wrote:
> On Fri, Jul 24, 2026 at 05:36:01PM +0200, Jakub Jelinek wrote:
> > Or do you mean I should always unconditionally try
> > cxx_fold_indirect_ref, if that succeeds, nothing to report, we're done,
> > if it fails, and tree_strip_nop_conversions (op) is an ADDR_EXPR,
> > use a loop to skip over all DECL_FIELD_IS_BASE (because those shouldn't
> > be then matching) and just use it to find out what the dynamic
> > type is?
> 
> I've tried that, but that regresses a few tests:
> 
> --- gcc/cp/constexpr.cc.jj    2026-07-24 18:38:54.332025326 +0200
> +++ gcc/cp/constexpr.cc       2026-07-24 18:46:44.785857777 +0200
> @@ -10259,6 +10259,44 @@ cxx_eval_constant_expression (const cons
>             }
>         }
>  
> +     /* [expr.static.cast]/10: A prvalue of type "pointer to cv1 B", where
> +        B is a class type, can be converted to a prvalue of type
> +        "pointer to cv2 D", where D is a complete class derived from B, ...
> +        If the prvalue of type "pointer to cv1 B" points to a B that is
> +        actually a base class subobject of an object of type D, the
> +        resulting pointer points to the enclosing object of type D.
> +        Otherwise, the behavior is undefined.
> +        Similarly [expr.static.cast]/2 for references. */
> +     if (INDIRECT_TYPE_P (type)
> +         && INDIRECT_TYPE_P (TREE_TYPE (op))
> +         && COMPLETE_TYPE_P (TREE_TYPE (type))
> +         && !integer_zerop (op)
> +         && is_properly_derived_from (TREE_TYPE (type),
> +                                      TREE_TYPE (TREE_TYPE (op)))
> +         && cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), op,
> +                                   NULL, jump_target) == NULL_TREE)

And calling it on sop instead of op doesn't help either.

One case that fails is the last line of
struct A { int a; };
struct D { int d; };
struct E { int e; };
struct F : A, D, E { int f; };
constexpr F p = {};
constexpr auto &q = static_cast <const A &> (p);
constexpr auto &r = static_cast <const F &> (q);
constexpr auto &s = static_cast <const D &> (r);
constexpr auto &t = static_cast <const F &> (s);
Here, sop is &p.D.3015 where p is a VAR_DECL with
const F type and D.3015 is FIELD_DECL of the D base.
As two lines earlier shows, if it is &p.D.3014
where D.3014 is FIELD_DECL of the A base (i.e. primary base),
it works fine.
So maybe cxx_fold_indirect_ref isn't the right function to call?

Though, on the other side, it works fine with the pointers instead of
references case.
constexpr auto q2 = static_cast <const A *> (&p);
constexpr auto r2 = static_cast <const F *> (q2);
constexpr auto s2 = static_cast <const D *> (r2);
constexpr auto t2 = static_cast <const F *> (s2);
Here, the difference is that we don't see sop being &p.D.3014, but
&p.D.3014 + 18446744073709551612 and that is what ccxx_fold_indirect_ref
handles.

Also note, in the earlier version of the patch, I had there for the case
where I didn't emit diagnostics setting of op to
op = build_fold_addr_expr_loc (loc, sop);
and just left the rest of the later code perform a cast if the type
wasn't the right one (e.g. due to cv quals).  This worked fine for
the pointer cases, but didn't work for references.  So there must be
something I'm missing about references.

        Jakub

Reply via email to