I wonder if it would work to use CONVERT_EXPR for reinterpret_cast.

On Tue, Apr 17, 2018, 9:45 PM Alexandre Oliva <aol...@redhat.com> 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
>

Reply via email to