c++: ICE with real-to-int conversion in template [PR97973]
authorMarek Polacek <polacek@redhat.com>
Wed, 3 Mar 2021 23:37:49 +0000 (18:37 -0500)
committerMarek Polacek <polacek@redhat.com>
Wed, 17 Mar 2021 23:26:25 +0000 (19:26 -0400)
In this test we are building a call in a template, but since neither
the function nor any of its arguments are dependent, we go down the
normal path in finish_call_expr.  convert_arguments sees that we're
binding a reference to int to double and therein convert_to_integer
creates a FIX_TRUNC_EXPR.  Later, we call check_function_arguments
which folds the arguments, and, in a template, fold_for_warn calls
fold_non_dependent_expr.  But tsubst_copy_and_build should not see
a FIX_TRUNC_EXPR (see the patch discussed in
<https://gcc.gnu.org/pipermail/gcc-patches/2018-March/496183.html>)
or we crash.

So let's not create a FIX_TRUNC_EXPR in a template in the first place
and instead use IMPLICIT_CONV_EXPR.

gcc/cp/ChangeLog:

PR c++/97973
* call.c (conv_unsafe_in_template_p): New.
(convert_like): Use it.

gcc/testsuite/ChangeLog:

PR c++/97973
* g++.dg/conversion/real-to-int1.C: New test.

gcc/cp/call.c
gcc/testsuite/g++.dg/conversion/real-to-int1.C [new file with mode: 0644]

index 29f4b50..390b8aa 100644 (file)
@@ -8048,6 +8048,27 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
   return expr;
 }
 
+/* Return true if converting FROM to TO is unsafe in a template.  */
+
+static bool
+conv_unsafe_in_template_p (tree to, tree from)
+{
+  /* Converting classes involves TARGET_EXPR.  */
+  if (CLASS_TYPE_P (to) || CLASS_TYPE_P (from))
+    return true;
+
+  /* Converting real to integer produces FIX_TRUNC_EXPR which tsubst
+     doesn't handle.  */
+  if (SCALAR_FLOAT_TYPE_P (from) && INTEGRAL_OR_ENUMERATION_TYPE_P (to))
+    return true;
+
+  /* Converting integer to real isn't a trivial conversion, either.  */
+  if (INTEGRAL_OR_ENUMERATION_TYPE_P (from) && SCALAR_FLOAT_TYPE_P (to))
+    return true;
+
+  return false;
+}
+
 /* Wrapper for convert_like_internal that handles creating
    IMPLICIT_CONV_EXPR.  */
 
@@ -8064,7 +8085,7 @@ convert_like (conversion *convs, tree expr, tree fn, int argnum,
   tree conv_expr = NULL_TREE;
   if (processing_template_decl
       && convs->kind != ck_identity
-      && (CLASS_TYPE_P (convs->type) || CLASS_TYPE_P (TREE_TYPE (expr))))
+      && conv_unsafe_in_template_p (convs->type, TREE_TYPE (expr)))
     {
       conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr);
       if (convs->kind != ck_ref_bind)
diff --git a/gcc/testsuite/g++.dg/conversion/real-to-int1.C b/gcc/testsuite/g++.dg/conversion/real-to-int1.C
new file mode 100644 (file)
index 0000000..f7b990b
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/97973
+
+void (*foo[1])(const int &);
+void (*foo2[1])(const double &);
+
+template<typename>
+void f ()
+{
+  (foo[0])(1.1);
+  (foo2[0])(1);
+}
+
+void
+g ()
+{
+  f<char> ();
+}