On 12/2/19 4:43 PM, Jakub Jelinek wrote:
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.
OK after testing.
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