Hi!

For middle-end pointer conversions are useless, which means the gimplifier
can change the type of the value being gimplified.
gimplify_call_expr is careful about this and remembers the fnptrtype early
before gimplification and
  else
    /* Remember the original function type.  */
    CALL_EXPR_FN (*expr_p) = build1 (NOP_EXPR, fnptrtype,
                                     CALL_EXPR_FN (*expr_p));
it at the end if needed, but my cp_gimplify_expr changes didn't do that
(and unfortunately got backported to 9.x already).

The following patch fixes it similarly to what gimplify_call_expr uses.
I haven't changed gimplify_to_rvalue to do that, as it is quite specific to
the CALL_EXPR_FN, while there is just one caller right now, if more are
added, most likely they won't need such behavior or it might be even
harmful, because the NOP_EXPR then is not is_gimple_val.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 9.3?

2019-10-23  Jakub Jelinek  <ja...@redhat.com>

        PR c++/92201
        * cp-gimplify.c (cp_gimplify_expr): If gimplify_to_rvalue changes the
        function pointer type, re-add cast to the original one.

        * g++.dg/other/pr92201.C: New test.

--- gcc/cp/cp-gimplify.c.jj     2019-10-18 00:16:09.905545389 +0200
+++ gcc/cp/cp-gimplify.c        2019-10-23 20:49:30.255410883 +0200
@@ -838,11 +838,17 @@ cp_gimplify_expr (tree *expr_p, gimple_s
          && CALL_EXPR_FN (*expr_p)
          && cp_get_callee_fndecl_nofold (*expr_p) == NULL_TREE)
        {
+         tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
          enum gimplify_status t
            = gimplify_to_rvalue (&CALL_EXPR_FN (*expr_p), pre_p, NULL,
                                  is_gimple_call_addr);
          if (t == GS_ERROR)
            ret = GS_ERROR;
+         /* GIMPLE considers most pointer conversion useless, but for
+            calls we actually care about the exact function pointer type.  */
+         else if (TREE_TYPE (CALL_EXPR_FN (*expr_p)) != fnptrtype)
+           CALL_EXPR_FN (*expr_p)
+             = build1 (NOP_EXPR, fnptrtype, CALL_EXPR_FN (*expr_p));
        }
       if (!CALL_EXPR_FN (*expr_p))
        /* Internal function call.  */;
--- gcc/testsuite/g++.dg/other/pr92201.C.jj     2019-10-23 20:59:41.375139038 
+0200
+++ gcc/testsuite/g++.dg/other/pr92201.C        2019-10-23 20:58:33.068175381 
+0200
@@ -0,0 +1,7 @@
+// PR c++/92201
+
+int
+foo (void (*p) ())
+{
+  return (*reinterpret_cast<int (*)()> (p)) ();
+}

        Jakub

Reply via email to