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 >