The problem in this PR is that we have a PTRMEM_CST wrapped in NOP_EXPR and fold_convert can't digest that.
For the unreduced test in the PR, this occurs since rev 230508: we force a NOP_EXPR when converting to the same type in build_static_cast_1: if (result == expr && SCALAR_TYPE_P (type)) /* Leave some record of the cast. */ result = build_nop (type, expr); For the reduced test in the PR, this happens since the C++ delayed folding merge, and we wrap a PTRMEM_CST in NOP_EXPR in build_reinterpret_cast: else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype)) || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))) return build_nop (type, expr); This patch <https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00679.html> prevented cp_fold_convert to wrap a PTRMEM_CST in NOP_EXPR, but in this case cp_fold_convert gets a PTRMEM_CST already wrapped in NOP_EXPR. I think we can fix this by extending the fix to also handle nested PTRMEM_CSTs. I've verified that this fixes the ICE with the unreduced testcase too. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2016-01-21 Marek Polacek <pola...@redhat.com> PR c++/69379 * cvt.c (cp_fold_convert): Handle PTRMEM_CSTs wrapped in NOP_EXPRs. * g++.dg/pr69379.C: New test. diff --git gcc/cp/cvt.c gcc/cp/cvt.c index f381f9b..667307a 100644 --- gcc/cp/cvt.c +++ gcc/cp/cvt.c @@ -592,12 +592,14 @@ tree cp_fold_convert (tree type, tree expr) { tree conv; + tree sexpr = tree_strip_nop_conversions (expr); + if (TREE_TYPE (expr) == type) conv = expr; - else if (TREE_CODE (expr) == PTRMEM_CST) + else if (TREE_CODE (sexpr) == PTRMEM_CST) { /* Avoid wrapping a PTRMEM_CST in NOP_EXPR. */ - conv = copy_node (expr); + conv = copy_node (sexpr); TREE_TYPE (conv) = type; } else 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