Hi!

The OBJ_TYPE_REF constexpr handling looks through DECL_FIELD_IS_BASE
COMPONENT_REFs to find the actual object on which the method is called,
but as the following testcase shows, we need to do the similar thing also
for the argument passed as this, because cxx_eval_indirect_ref otherwise
fails to fold it.  It can handle going from derived to base, not not vice
versa.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

2019-11-27  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-11-27 17:26:57.229014008 +0100
+++ gcc/cp/constexpr.c  2019-11-27 17:53:37.477566346 +0100
@@ -1441,6 +1441,24 @@ 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)))
+                   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-11-27 
18:01:17.181532622 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C    2019-11-27 
18:00:49.620954471 +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