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