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