On Wed, Apr 18, 2018 at 05:07:33AM +0000, Jason Merrill wrote:
> I wonder if it would work to use CONVERT_EXPR for reinterpret_cast.

I have tried following (still need Alex' expr.c changes, otherwise it ICEs),
on the bright side it fixes the new pr85437-4.C testcase,
but it causes Excess errors:
/usr/src/gcc/gcc/testsuite/g++.dg/Wcast-function-type.C:15:19: error: invalid 
conversion to type 'void (S::*)(int)' from type 'void (S::*)(int*)'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrmem4.C:23:41:   in 
'constexpr' expansion of 'Bar(&Foo::test)'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-ptrmem4.C:23:41: error: a 
reinterpret_cast is not a constant expression
/usr/src/gcc/gcc/testsuite/g++.dg/cpp0x/pr68116.C:12:1: error: invalid 
conversion to type 'void (C::*)(int)' from type 'void (C::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/template/ptrmem19.C:19:23: error: invalid 
conversion to type 'void (C::*)(F)' from type 'void (C::*)(B*)'
/usr/src/gcc/gcc/testsuite/g++.dg/template/ptrmem19.C:19:23: error: invalid 
conversion to type 'void (C::*)(B*)' from type 'void (C::*)(F)'
/usr/src/gcc/gcc/testsuite/g++.dg/init/static2.C:20:1: error: invalid 
conversion to type 'void (A::*)()' from type 'void (B::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/init/static2.C:20:1: error: type 'B' is not a 
base type for type 'A'
/usr/src/gcc/gcc/testsuite/g++.dg/init/static2.C:20:1: error:    in pointer to 
member conversion
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem4.C:39:33: error: type 'D' 
is not a base type for type 'B'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem4.C:39:33: error:    in 
pointer to member conversion
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem4.C:43:29: error: type 'D' 
is not a base type for type 'X'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem4.C:43:29: error:    in 
pointer to member conversion
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:31:41: error: invalid 
conversion to type 'float (B::*)()' from type 'int (D::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:31:41: error: type 'D' 
is not a base type for type 'B'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:31:41: error:    in 
pointer to member conversion
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:32:41: error: invalid 
conversion to type 'float (D::*)()' from type 'int (B::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:35:37: error: invalid 
conversion to type 'int (X::*)()' from type 'int (D::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:35:37: error: type 'D' 
is not a base type for type 'X'
/usr/src/gcc/gcc/testsuite/g++.dg/conversion/ptrmem5.C:35:37: error:    in 
pointer to member conversion
/usr/src/gcc/gcc/testsuite/g++.dg/init/ptrmem3.C:8:66: error: invalid 
conversion to type 'void (foo::*)()' from type 'int (foo::*)(int)'
/usr/src/gcc/gcc/testsuite/g++.dg/pr69379.C:20:1: error: invalid conversion to 
type 'void (Dict::*)(T)' {aka 'void (Dict::*)(int)'} from type 'void 
(Dict::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/other/default6.C:13:33: error: invalid 
conversion to type 'void (BaseRobot::*)()' from type 'int (BaseRobot::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/other/default6.C:17:33: error: invalid 
conversion to type 'void (BaseRobot::*)()' from type 'int (BaseRobot::*)()'
/usr/src/gcc/gcc/testsuite/g++.dg/torture/pr37354.C:13:1: error: invalid 
conversion to type 'void (GenericClass::*)()' from type 'int 
(AlsaDriver::*)(unsigned int)'
/usr/src/gcc/gcc/testsuite/g++.dg/torture/pr37354.C:13:1: error: type 
'AlsaDriver' is not a base type for type 'GenericClass'
/usr/src/gcc/gcc/testsuite/g++.dg/torture/pr37354.C:13:1: error:    in pointer 
to member conversion
etc.

--- gcc/cp/constexpr.c.jj       2018-04-13 10:33:03.078658240 +0200
+++ gcc/cp/constexpr.c  2018-04-18 13:42:54.097312535 +0200
@@ -4595,10 +4595,12 @@ cxx_eval_constant_expression (const cons
        if (TREE_CODE (op) == PTRMEM_CST
            && !TYPE_PTRMEM_P (type))
          op = cplus_expand_constant (op);
-       if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR)
+       if (TREE_CODE (op) == PTRMEM_CST
+           && (tcode == NOP_EXPR || tcode == CONVERT_EXPR))
          {
-           if (same_type_ignoring_top_level_qualifiers_p (type,
-                                                          TREE_TYPE (op))
+           if (tcode == NOP_EXPR
+               || same_type_ignoring_top_level_qualifiers_p (type,
+                                                             TREE_TYPE (op))
                || can_convert_qual (type, op))
              return cp_fold_convert (type, op);
            else
--- gcc/cp/typeck.c.jj  2018-04-18 08:57:09.555612419 +0200
+++ gcc/cp/typeck.c     2018-04-18 13:50:14.278498305 +0200
@@ -5758,6 +5758,16 @@ build_nop (tree type, tree expr)
   return build1_loc (EXPR_LOCATION (expr), NOP_EXPR, type, expr);
 }
 
+/* Similarly, but build CONVERT_EXPR instead.  */
+
+static tree
+build_convert_expr (tree type, tree expr)
+{
+  if (type == error_mark_node || error_operand_p (expr))
+    return expr;
+  return build1_loc (EXPR_LOCATION (expr), CONVERT_EXPR, type, expr);
+}
+
 /* Take the address of ARG, whatever that means under C++ semantics.
    If STRICT_LVALUE is true, require an lvalue; otherwise, allow xvalues
    and class rvalues as well.
@@ -7409,7 +7419,7 @@ build_reinterpret_cast_1 (tree type, tre
        warning (OPT_Wcast_function_type,
                 "cast between incompatible function types"
                 " from %qH to %qI", intype, type);
-      return build_nop (type, expr);
+      return build_convert_expr (type, expr);
     }
   else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
     {
@@ -7420,7 +7430,7 @@ build_reinterpret_cast_1 (tree type, tre
        warning (OPT_Wcast_function_type,
                 "cast between incompatible pointer to member types"
                 " from %qH to %qI", intype, type);
-      return build_nop (type, expr);
+      return build_convert_expr (type, expr);
     }
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
           || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
@@ -7446,7 +7456,7 @@ build_reinterpret_cast_1 (tree type, tre
        /* strict_aliasing_warning STRIP_NOPs its expr.  */
        strict_aliasing_warning (EXPR_LOCATION (expr), type, expr);
 
-      return build_nop (type, expr);
+      return build_convert_expr (type, expr);
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
           || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7457,7 +7467,7 @@ build_reinterpret_cast_1 (tree type, tre
        warning (OPT_Wconditionally_supported,
                 "casting between pointer-to-function and pointer-to-object "
                 "is conditionally-supported");
-      return build_nop (type, expr);
+      return build_convert_expr (type, expr);
     }
   else if (VECTOR_TYPE_P (type))
     return convert_to_vector (type, expr);
--- gcc/cp/expr.c.jj    2018-03-09 23:22:23.682236182 +0100
+++ gcc/cp/expr.c       2018-04-18 14:24:52.692310448 +0200
@@ -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));
--- gcc/testsuite/g++.dg/cpp0x/pr85437.C.jj     2018-04-18 14:25:50.655332890 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/pr85437.C        2018-04-18 14:28:34.234396893 
+0200
@@ -0,0 +1,17 @@
+// PR c++/85437
+// { 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); // { dg-bogus "not a 
constant expression" }
+
+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);
--- gcc/testsuite/g++.dg/cpp0x/pr85437-2.C.jj   2018-04-18 14:25:50.654332889 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/pr85437-2.C      2018-04-18 14:28:45.613401350 
+0200
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { 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" }
--- gcc/testsuite/g++.dg/cpp0x/pr85437-3.C.jj   2018-04-18 14:25:50.655332890 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/pr85437-3.C      2018-04-18 14:29:57.691429562 
+0200
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { 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)); 
// { dg-bogus "not a constant expression" }
--- gcc/testsuite/g++.dg/cpp0x/pr85437-4.C.jj   2018-04-18 14:29:29.028418341 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/pr85437-4.C      2018-04-18 14:29:39.829422569 
+0200
@@ -0,0 +1,8 @@
+// PR c++/85437
+// { dg-do compile { target c++11 } }
+
+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);    // { dg-bogus "not a 
constant expression" }


        Jakub

Reply via email to