This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] [PR c++/85437] accept static_casted ptrmem in constexpr


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]