On Mon, Dec 02, 2019 at 02:29:56PM -0500, Jason Merrill wrote:
> On 11/27/19 6:38 PM, Jakub Jelinek wrote:
> > +     if (i == 0 && DECL_VIRTUAL_P (fun))
> > +       {
> > +         tree addr = arg;
> > +         STRIP_NOPS (addr);
> > +         if (TREE_CODE (addr) == ADDR_EXPR)
> > +           {
> > +             tree obj = TREE_OPERAND (addr, 0);
> > +             while (TREE_CODE (obj) == COMPONENT_REF
> > +                    && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1)))
> > +               obj = TREE_OPERAND (obj, 0);
> 
> Shouldn't this loop stop when we reach DECL_CONTEXT (fun)?

I guess it can, patch I can test tonight attached.  I thought it doesn't matter
much, because cxx_eval_indirect_ref would be able to go from further derived
class to the base if we want too far, but maybe that is not the case
with multiple inheritance.

> Relatedly, I notice that the OBJ_TYPE_REF code breaks with multiple
> inheritance: Adding a virtual function to Y in constexpr-virtual6.C leads to

I'm afraid I'd be lost with that.  There is another bug in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92695#c12 about constexpr
defaulted virtual destructors not being synthetized until end of TU.

2019-12-02  Jakub Jelinek  <ja...@redhat.com>

        PR c++/92695
        * constexpr.c (cxx_bind_parameters_in_call): For virtual calls,
        adjust the first argument to point to the derived object rather
        than its base.

        * g++.dg/cpp2a/constexpr-virtual14.C: New test.

--- gcc/cp/constexpr.c.jj       2019-12-02 22:30:31.608306270 +0100
+++ gcc/cp/constexpr.c  2019-12-02 22:35:42.374501609 +0100
@@ -1441,6 +1441,26 @@ cxx_bind_parameters_in_call (const const
            arg = adjust_temp_type (type, arg);
          if (!TREE_CONSTANT (arg))
            *non_constant_args = true;
+         /* For virtual calls, adjust the this argument, so that it is
+            the object on which the method is called, rather than
+            one of its bases.  */
+         if (i == 0 && DECL_VIRTUAL_P (fun))
+           {
+             tree addr = arg;
+             STRIP_NOPS (addr);
+             if (TREE_CODE (addr) == ADDR_EXPR)
+               {
+                 tree obj = TREE_OPERAND (addr, 0);
+                 while (TREE_CODE (obj) == COMPONENT_REF
+                        && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1))
+                        && !same_type_ignoring_top_level_qualifiers_p
+                                       (TREE_TYPE (obj), DECL_CONTEXT (fun)))
+                   obj = TREE_OPERAND (obj, 0);
+                 if (obj != TREE_OPERAND (addr, 0))
+                   arg = build_fold_addr_expr_with_type (obj,
+                                                         TREE_TYPE (arg));
+               }
+           }
          TREE_VEC_ELT (binds, i) = arg;
        }
       parms = TREE_CHAIN (parms);
--- gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C.jj 2019-12-02 
22:34:05.554998508 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C    2019-12-02 
22:34:05.554998508 +0100
@@ -0,0 +1,27 @@
+// PR c++/92695
+// { dg-do compile { target c++2a } }
+
+struct A {
+  virtual int get () = 0;
+  virtual int set (A *o) = 0;
+};
+struct B : A {
+  constexpr int get () override { return 10; }
+  constexpr int set (A *o) override { a = o; return 20; }
+  A *a {};
+};
+constexpr auto addressof = [] (A &n) { return &n; };
+struct C {
+  B b;
+  A *c { addressof (b) };
+  constexpr int add () { return c->set (addressof (b)); }
+};
+struct D {
+  B b[2];
+  A *c { addressof (b[0]) };
+  constexpr int add () { return c->set (addressof (b[0])); }
+};
+template <typename T>
+constexpr int get () { T f; return f.add (); }
+static_assert (get<C> () == 20);
+static_assert (get<D> () == 20);


        Jakub

Reply via email to