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