This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] [PR c++/85437] accept static_casted ptrmem in constexpr
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: Alexandre Oliva <aoliva at redhat dot com>, gcc-patches List <gcc-patches at gcc dot gnu dot org>, Nathan Sidwell <nathan at acm dot org>
- Date: Wed, 18 Apr 2018 14:59:34 +0200
- Subject: Re: [PATCH] [PR c++/85437] accept static_casted ptrmem in constexpr
- References: <or604puqhd.fsf@lxoliva.fsfla.org> <CADzB+2mcor+rs3WgC-tdbcy+9mao+ugK-DTgbDfZT3sjvs-eqw@mail.gmail.com>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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