On 3/3/21 7:55 PM, Marek Polacek wrote:
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.

This again, sigh.  Let me take a step back.

So basically, the output of convert_like_real in a template is a mix of template and non-template trees, and thus unsuitable for consumption by anything other than grabbing its type and throwing it away, as most callers do.

The problem here is that cp_build_function_call_vec calls check_function_arguments with these trees. build_over_call, however, does not call check_function_arguments in a template. Preventing that call in a template also fixes the testcase, though it regresses diagnostic location in Wnonnull5.C (which it shouldn't, that's a separate bug).

IMPLICIT_CONV_EXPR is a way to represent the conversion so that the result is still a template tree, and therefore suitable for fold_for_warn, which allows us to warn when parsing the template, which is generally desirable.

I think the approach of expanding IMPLICIT_CONV_EXPR is probably the right choice, but perhaps we should expand it to all non-trivial conversions, not just those that would use problematic tree codes.

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

(I'm not sure why tsubst* also doesn't crash on a FLOAT_EXPR; it'd
make sense to me to also create an IMPLICIT_CONV_EXPR for integer
to real convs and add "case FLOAT_EXPR" just under FIX_TRUNC_EXPR.
But perhaps that's too risky to do now.)

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?

gcc/cp/ChangeLog:

        PR c++/97973
        * call.c (convert_like): When converting real to integer in
        a template, use IMPLICIT_CONV_EXPR.

gcc/testsuite/ChangeLog:

        PR c++/97973
        * g++.dg/conversion/real-to-int1.C: New test.
---
  gcc/cp/call.c                                  |  7 ++++++-
  gcc/testsuite/g++.dg/conversion/real-to-int1.C | 17 +++++++++++++++++
  2 files changed, 23 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/conversion/real-to-int1.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 123f06b1f2b..8074d8fdba8 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8062,7 +8062,12 @@ 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))))
+      && (CLASS_TYPE_P (convs->type)
+         || CLASS_TYPE_P (TREE_TYPE (expr))
+         /* Converting real to integer produces FIX_TRUNC_EXPR which
+            tsubst also doesn't grok.  */
+         || (SCALAR_FLOAT_TYPE_P (TREE_TYPE (expr))
+             && INTEGRAL_OR_ENUMERATION_TYPE_P (convs->type))))
      {
        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
index 00000000000..f7b990b3f4b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/real-to-int1.C
@@ -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> ();
+}

base-commit: 8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4


Reply via email to