From ae1b211b581dd1f39476e726394d52d9685bc561 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 20 Dec 2019 18:33:13 +0100 Subject: [PATCH] backport: re PR c++/92695 (P1064R0 - virtual constexpr fails if object taken from array) Backported from mainline 2019-12-03 Jakub Jelinek 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. From-SVN: r279664 --- gcc/cp/ChangeLog | 7 +++++ gcc/cp/constexpr.c | 22 +++++++++++++++ gcc/testsuite/ChangeLog | 5 ++++ .../g++.dg/cpp2a/constexpr-virtual14.C | 27 +++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2e47b485d54..b727db680e7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6 +1,13 @@ 2019-12-20 Jakub Jelinek Backported from mainline + 2019-12-03 Jakub Jelinek + + 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. + 2019-12-02 Jakub Jelinek PR c++/92695 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 13d8a17c3e0..e2ca305aaca 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1419,6 +1419,28 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, 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)); + } + } + *p = build_tree_list (parms, arg); p = &TREE_CHAIN (*p); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d50e9836b83..b8f1c54098d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,11 @@ 2019-12-20 Jakub Jelinek Backported from mainline + 2019-12-03 Jakub Jelinek + + PR c++/92695 + * g++.dg/cpp2a/constexpr-virtual14.C: New test. + 2019-12-02 Jakub Jelinek PR c++/92695 diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C new file mode 100644 index 00000000000..b29d3f6aefb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual14.C @@ -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 +constexpr int get () { T f; return f.add (); } +static_assert (get () == 20); +static_assert (get () == 20);