On Mon, Jan 25, 2016 at 10:08:34AM -0500, Jason Merrill wrote: > On 01/22/2016 05:07 PM, Marek Polacek wrote: > >On Fri, Jan 22, 2016 at 03:38:26PM -0500, Jason Merrill wrote: > >>If we have a NOP_EXPR to the same type, we should strip it here. > > > >This helps for the unreduced testcases in the PR, but not for the reduced > >one, > >because for the reduced one, the types are not the same. One type is > >struct > >{ > > void Dict::<T461> (struct Dict *, T) * __pfn; > > long int __delta; > >} > >and the second one > >struct > >{ > > void Dict::<T442> (struct Dict *) * __pfn; > > long int __delta; > >} > > > >The NOP_EXPR in this case originated in build_reinterpret_cast_1: > >7070 else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype)) > >7071 || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) > >7072 return build_nop (type, expr); > > Well, a reinterpret_cast makes the expression non-constant, so we can > recognize that case (when the types are unrelated) and bail out. After that > we probably still need to deal with the case of conversion to a > pointer-to-member-of-base type; for functions it looks like we can just copy > the PTRMEM_CST and give it a different type, but for data members I think > we'll need to add support for the type not matching the member in > expand_ptrmem_cst.
It appears that handling the case when the types don't match is sufficient, at least all the tests pass, thus the following should be enough. If you want me to take care of the rest then please let me know, though without a testcase it might be harder to get right. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2016-01-25 Marek Polacek <pola...@redhat.com> PR c++/69379 * constexpr.c (cxx_eval_constant_expression): Handle PTRMEM_CSTs wrapped in NOP_EXPRs. * g++.dg/pr69379.C: New test. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 6b0e5a8..4b952d1 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -3619,6 +3619,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, 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 (same_type_ignoring_top_level_qualifiers_p (type, + TREE_TYPE (op))) + STRIP_NOPS (t); + else + { + if (!ctx->quiet) + error_at (EXPR_LOC_OR_LOC (t, input_location), + "reinterpret_cast has different types"); + *non_constant_p = true; + return t; + } + } if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST && !integer_zerop (op)) diff --git gcc/testsuite/g++.dg/pr69379.C gcc/testsuite/g++.dg/pr69379.C index e69de29..249ad00 100644 --- gcc/testsuite/g++.dg/pr69379.C +++ gcc/testsuite/g++.dg/pr69379.C @@ -0,0 +1,20 @@ +// PR c++/69379 +// { dg-do compile } +// { dg-options "-Wformat" } + +typedef int T; +class A { +public: + template <class D> A(const char *, D); + template <class Fn, class A1, class A2> + void m_fn1(const char *, Fn, A1 const &, A2); +}; +struct Dict { + void m_fn2(); +}; +void fn1() { + A a("", ""); + typedef void *Get; + typedef void (Dict::*d)(T); + a.m_fn1("", Get(), d(&Dict::m_fn2), ""); +} Marek