I wonder if it would work to use CONVERT_EXPR for reinterpret_cast.
On Tue, Apr 17, 2018, 9:45 PM Alexandre Oliva <[email protected]> wrote:
>
> A static_cast of a pointer to data member used to wrap the PTRMEM_CST
> in a NOP_EXPR, but the NOP_EXPR is taken, in constexpr, as evidence
> that there was a reinterpret_cast in the expression. While
> reinterpret_casts are to be rejected in constexprs, static_casts are
> ok.
>
> Thus, avoid introducing the NOP_EXPR in static_casts, folding the
> converted-to type into the PTRMEM_CST type.
>
> This requires PTRMEM_CST constant expansion to deal with such up and
> downcasts.
>
> ---
>
> I've tested this sucessfully with check-c++-all, but I'm not entirely
> happy with it, not just because the following testcase still fails
> (though the testcases in the patch pass), but also because the early
> folding and the extra work in cplus_expand_constant don't feel quite
> right.
>
>
> struct A { };
> struct B { int x; };
> struct C : A, B {};
> constexpr int C::*pci = &B::x;
> constexpr int A::*pai = static_cast<int A::*>(pci);
>
>
> I've experimented with an alternative of marking NOP_EXPRs introduced by
> static_casts and const_casts with a flag (static_flag), but that felt
> even more fragile, since we drop and rebuild NOP_EXPRs all the time,
> redundant ones used to be dropped safely, and so both positive and
> negative marks for constexpr compatibility could be lost, leading to
> false positives or missed errors.
>
> Still, it seems like we'd be better off with some reliable means to tell
> constexpr-compatible casts from other conversions. NOP_EXPRs alone just
> don't cut it.
>
> Anyway, at this point I'd appreciate some guidance as to how to proceed.
> At this stage of GCC8 development, I'm even considering dropping the
> incorrect complaint about reinterpret_cast, even if that would regress
> the rejection of casts that don't belong in constexprs.
>
> Thoughts? Suggestions?
>
> Thanks in advance,
>
> ---
>
> for gcc/cp/ChangeLog
>
> PR c++/85437
> * expr.c (cplus_expand_constant): Compute deltas for up and
> downcasts.
> * type.c (convert_ptrmem): Convert ptrmem type for static
> cast.
>
> for gcc/testsuite/ChangeLog
>
> PR c++/85437
> * g++.dg/cpp0x/pr85437.C: New.
> * g++.dg/cpp0x/pr85437-2.C: New.
> * g++.dg/cpp0x/pr85437-3.C: New.
> ---
> gcc/cp/expr.c | 25 +++++++++++++++++++++++++
> gcc/cp/typeck.c | 5 ++++-
> gcc/testsuite/g++.dg/cpp0x/pr85437-2.C | 7 +++++++
> gcc/testsuite/g++.dg/cpp0x/pr85437-3.C | 7 +++++++
> gcc/testsuite/g++.dg/cpp0x/pr85437.C | 16 ++++++++++++++++
> 5 files changed, 59 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437-2.C
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437-3.C
> create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr85437.C
>
> diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
> index 15894fc0b594..28fe2e83398d 100644
> --- a/gcc/cp/expr.c
> +++ b/gcc/cp/expr.c
> @@ -50,11 +50,36 @@ cplus_expand_constant (tree cst)
> while (!same_type_p (DECL_CONTEXT (member),
> TYPE_PTRMEM_CLASS_TYPE (type)))
> {
> + tree t1 = TYPE_MAIN_VARIANT (DECL_CONTEXT (member));
> + tree t2 = TYPE_MAIN_VARIANT (TYPE_PTRMEM_CLASS_TYPE
> (type));
> +
> + if (can_convert (t2, t1, 0))
> + {
> + base_kind kind;
> + tree binfo = lookup_base (t1, t2, ba_unique, &kind, 0);
> + if (binfo != error_mark_node
> + && kind != bk_via_virtual)
> + cst = size_binop (MINUS_EXPR, cst, BINFO_OFFSET
> (binfo));
> + break;
> + }
> +
> + if (can_convert (t1, t2, 0))
> + {
> + base_kind kind;
> + tree binfo = lookup_base (t2, t1, ba_unique, &kind, 0);
> + if (binfo != error_mark_node
> + && kind != bk_via_virtual)
> + cst = size_binop (PLUS_EXPR, cst, BINFO_OFFSET
> (binfo));
> + break;
> + }
> +
> /* The MEMBER must have been nestled within an
> anonymous aggregate contained in TYPE. Find the
> anonymous aggregate. */
> member = lookup_anon_field (TYPE_PTRMEM_CLASS_TYPE (type),
> DECL_CONTEXT (member));
> + if (!member)
> + break;
> cst = size_binop (PLUS_EXPR, cst, byte_position (member));
> }
> cst = fold (build_nop (type, cst));
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index b449b1f7f539..0b88181e9574 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -6871,7 +6871,10 @@ convert_ptrmem (tree type, tree expr, bool
> allow_inverse_p,
>
> }
>
> - return build_nop (type, expr);
> + if (c_cast_p)
> + return build_nop (type, expr);
> + else
> + return cp_fold_convert (type, expr);
> }
> else
> return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
> diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C
> b/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C
> new file mode 100644
> index 000000000000..57734a96b475
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C
> @@ -0,0 +1,7 @@
> +// { dg-do compile { target c++11 } }
> +
> +struct A { };
> +struct B : A { int x; };
> +
> +constexpr int A::*abx
> += reinterpret_cast<int(A::*)>(&B::x); // { dg-error
> "reinterpret.*constant" }
> diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C
> b/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C
> new file mode 100644
> index 000000000000..a956df6b05a1
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C
> @@ -0,0 +1,7 @@
> +// { dg-do compile { target c++11 } }
> +
> +struct A { int y; };
> +struct B { int x; };
> +struct C : A, B {};
> +constexpr int C::*pci = &B::x;
> +constexpr int A::*pai = static_cast<int A::*>(static_cast<int
> C::*>(&B::x));
> diff --git a/gcc/testsuite/g++.dg/cpp0x/pr85437.C
> b/gcc/testsuite/g++.dg/cpp0x/pr85437.C
> new file mode 100644
> index 000000000000..d02b1b600158
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/pr85437.C
> @@ -0,0 +1,16 @@
> +// { dg-do compile { target c++11 } }
> +
> +struct A { int a; constexpr A() : a(0) {} };
> +struct B : A { int x; constexpr B() : x(0) {} };
> +struct X { int z; constexpr X() : z(0) {} };
> +struct C : X, B {};
> +constexpr int C::*cbx = &B::x;
> +constexpr int B::*bx = &B::x;
> +constexpr int A::*abx = static_cast<int(A::*)>(&B::x);
> +
> +constexpr const C y;
> +constexpr const B& yb = y;
> +constexpr const A& ya = y;
> +constexpr int const *pcbx = &(y.*cbx);
> +constexpr int const *pbx = &(y.*bx);
> +constexpr int const *pabx = &(ya.*abx);
>
>
> --
> Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/
> You must be the change you wish to see in the world. -- Gandhi
> Be Free! -- http://FSFLA.org/ FSF Latin America board member
> Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer
>