On Tue, 19 Jan 2016, Patrick Palka wrote:

On Mon, Jan 18, 2016 at 4:04 PM, Jason Merrill <ja...@redhat.com> wrote:
On 01/18/2016 02:12 PM, Patrick Palka wrote:

On Mon, Jan 18, 2016 at 10:34 AM, Jason Merrill <ja...@redhat.com> wrote:

On 12/25/2015 12:37 PM, Patrick Palka wrote:


That alone would not be sufficient because more_specialized_fn()
doesn't call maybe_adjust_types_for_deduction() beforehand, yet we
have to do the decaying there too (and on both types, not just one of
them).

And maybe_adjust_types_for_deduction() seems to operate on the
presumption that one type is the parameter type and one is the
argument type. But in more_specialized_fn() and in get_bindings() we
are really working with two parameter types and have to decay them
both. So sometimes we have to decay one of the types that are
eventually going to get passed to unify(), and other times we want to
decay both types that are going to get passed to unify().
maybe_adjust_types_for_deduction() seems to only expect the former
case.

Finally, maybe_adjust_types_for_deduction() is not called when
unifying a nested function declarator (because it is guarded by the
subr flag in unify_one_argument), so doing it there we would also
regress in the following test case:



Ah, that makes sense.

How about keeping the un-decayed type in the PARM_DECLs, so that we get
the
substitution failure in instantiate_template, but having the decayed type
in
the TYPE_ARG_TYPES, probably by doing the decay in grokparms, so it's
already decayed when we're doing unification?


I just tried this, and it works well! With this approach, all but one
of the test cases pass.  The failing test case is unify17.C:

-- 8< --

void foo (int *);

template <typename T>
void bar (void (T[5])); // { dg-error "array of 'void'" }

void
baz (void)
{
   bar<void> (0); // { dg-error "no matching function" }
}

-- 8< --

Here, we don't get a substitution failure because we don't have a
corresponding FUNCTION_DECL for the nested function specifier, only a
FUNCTION_TYPE. So there is no PARM_DECL to recurse into during
substitution, that retains the un-decayed argument type "T[5]" of the
nested function specifier.


Then your original patch is OK.  Thanks for indulging me.

I have committed the original patch, but I just noticed that it has
the unintended effect of changing whether certain template
declarations are considered duplicates or not.  For instance, in the
following test case we no longer consider the three declarations of
"foo" to be duplicates and we instead register three overloads for
foo, so that when we go to use foo later on we now get an ambiguity
error:

$ cat hmmmmm.cc
template <typename T>
int foo (T [4]);

template <typename T>
int foo (T [3]);

template <typename T>
int foo (T *);

int x = foo<int> (0);
$ g++ hmmmmm.cc
hmmmmm.cc:10:20: error: call of overloaded ‘foo(int)’ is ambiguous
int x = foo<int> (0);
                   ^
hmmmmm.cc:2:5: note: candidate: int foo(T [4]) [with T = int]
int foo (T [4]);
    ^~~
hmmmmm.cc:5:5: note: candidate: int foo(T [3]) [with T = int]
int foo (T [3]);
    ^~~
hmmmmm.cc:8:5: note: candidate: int foo(T*) [with T = int]
int foo (T *);
    ^~~


Before the patch, this test case would have compiled cleanly because
each subsequent declaration of foo would have been considered a
duplicate of the first one (since we would have decayed the array
parameter types early on).

I am not sure whether the previous or current behavior is correct, or
if maybe the first two decls ought to be considered duplicates and the
last one not.  What do you think?


A much more significant side effect of this patch is that it changes the
mangling of function templates that have dependent array parameters.
For the following test case:

    template <typename T, int I>
    int foo (T [I]);

    int x = foo<int, 5> (0);

We now output

  _Z3fooIiLi5EEiAT0__T_ (aka "int foo<int, 5>(int [5])")

instead of

  _Z3fooIiLi5EEiPT_ (aka "int foo<int, 5>(int*)")

because when mangling a specialized FUNCTION_DECL the mangler uses the
undecayed TYPE_ARG_TYPES (TREE_TYPE (...)) of the corresponding
TEMPLATE_DECL instead of using the decayed
TYPE_ARG_TYPES (TREE_TYPE (...)) of that FUNCTION_DECL.

In light of this, I am inclined to instead use your suggested approach
(to decay the parameter types in grokparms, which become the
FUNCTION_TYPE's TYPE_ARG_TYPES, while retaining the un-decayed types in
the PARM_DECLs) since that approach does not exhibit this mangling issue
or the above mentioned overloading issue.  Here is a patch for that.

-- 8< --

Subject: [PATCH] Use a different approach for avoiding to decay array
 parameters too early

gcc/cp/ChangeLog:

        PR c++/11858
        PR c++/24663
        PR c++/24664
        * decl.c (grokparms): Decay each parameter type after stripping
        its qualifiers.
        * pt.c (tsubst_decl) [FUNCTION_DECL]: Return error_mark_node if
        substition of the DECL_ARGUMENTS fails.
        (decay_dependent_array_parm_type): Delete.
        (type_unification_real): Remove calls to
        decay_dependent_array_parm_type.
        (more_specialized_fn): Likewise.
        (get_bindings): Likewise.

gcc/testsuite/ChangeLog:

        PR c++/11858
        PR c++/24663
        PR c++/24664
        * g++.dg/template/mangle2.C: New test.
        * g++.dg/template/unify17.C: XFAIL.
---
 gcc/cp/decl.c                           |  1 +
 gcc/cp/pt.c                             | 31 +++++--------------------------
 gcc/testsuite/g++.dg/template/mangle2.C | 22 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/template/unify17.C |  4 ++--
 4 files changed, 30 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/mangle2.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ceeef60..d681281 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11702,6 +11702,7 @@ grokparms (tree parmlist, tree *parms)
          /* Top-level qualifiers on the parameters are
             ignored for function types.  */
          type = strip_top_quals (type);
+         type = type_decays_to (type);

          if (TREE_CODE (type) == METHOD_TYPE)
            {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index fdef601..a7084a1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11740,6 +11740,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
                                     complain, t);
        DECL_RESULT (r) = NULL_TREE;

+       for (tree parm = DECL_ARGUMENTS (r); parm; parm = DECL_CHAIN (parm))
+         if (TREE_TYPE (parm) == error_mark_node)
+           RETURN (error_mark_node);
+
        TREE_STATIC (r) = 0;
        TREE_PUBLIC (r) = TREE_PUBLIC (t);
        DECL_EXTERNAL (r) = 1;
@@ -17742,23 +17746,6 @@ fn_type_unification (tree fn,
   return r;
 }

-/* TYPE is the type of a function parameter.  If TYPE is a (dependent)
-   ARRAY_TYPE, return the corresponding POINTER_TYPE to which it decays.
-   Otherwise return TYPE.  (We shouldn't see non-dependent ARRAY_TYPE
-   parameters because they get decayed as soon as they are declared.)  */
-
-static tree
-decay_dependent_array_parm_type (tree type)
-{
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      gcc_assert (uses_template_parms (type));
-      return type_decays_to (type);
-    }
-
-  return type;
-}
-
 /* Adjust types before performing type deduction, as described in
    [temp.deduct.call] and [temp.deduct.conv].  The rules in these two
    sections are symmetric.  PARM is the type of a function parameter
@@ -18197,8 +18184,6 @@ type_unification_real (tree tparms,
       arg = args[ia];
       ++ia;

-      parm = decay_dependent_array_parm_type (parm);
-
       if (unify_one_argument (tparms, targs, parm, arg, subr, strict,
                              explain_p))
        return 1;
@@ -20232,9 +20217,6 @@ more_specialized_fn (tree pat1, tree pat2, int len)
           len = 0;
         }

-      arg1 = decay_dependent_array_parm_type (arg1);
-      arg2 = decay_dependent_array_parm_type (arg2);
-
       if (TREE_CODE (arg1) == REFERENCE_TYPE)
        {
          ref1 = TYPE_REF_IS_RVALUE (arg1) + 1;
@@ -20520,10 +20502,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, 
bool check_rettype)
   for (arg = decl_arg_types, ix = 0;
        arg != NULL_TREE && arg != void_list_node;
        arg = TREE_CHAIN (arg), ++ix)
-    {
-      args[ix] = TREE_VALUE (arg);
-      args[ix] = decay_dependent_array_parm_type (args[ix]);
-    }
+    args[ix] = TREE_VALUE (arg);

   if (fn_type_unification (fn, explicit_args, targs,
                           args, ix,
diff --git a/gcc/testsuite/g++.dg/template/mangle2.C 
b/gcc/testsuite/g++.dg/template/mangle2.C
new file mode 100644
index 0000000..f9ea040
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/mangle2.C
@@ -0,0 +1,22 @@
+template <typename T, int I>
+int foo (T [I]);
+
+template <typename T>
+int bar (T [7]);
+
+template <int I>
+int baz (int [I]);
+
+extern int x, y, z;
+
+int
+main ()
+{
+  x = foo<int, 5> (0);
+  y = bar<char> (0);
+  z = baz<9> (0);
+}
+
+// { dg-final { scan-assembler "_Z3fooIiLi5EEiPT_" } }
+// { dg-final { scan-assembler "_Z3barIcEiPT_" } }
+// { dg-final { scan-assembler "_Z3bazILi9EEiPi" } }
diff --git a/gcc/testsuite/g++.dg/template/unify17.C 
b/gcc/testsuite/g++.dg/template/unify17.C
index 2da8553..3ae7699 100644
--- a/gcc/testsuite/g++.dg/template/unify17.C
+++ b/gcc/testsuite/g++.dg/template/unify17.C
@@ -1,11 +1,11 @@
 void foo (int *);

 template <typename T>
-void bar (void (T[5])); // { dg-error "array of 'void'" }
+void bar (void (T[5])); // { dg-error "array of 'void'" "" { xfail *-*-* } }

 void
 baz (void)
 {
   bar (foo); // { dg-bogus "" }
-  bar<void> (0); // { dg-error "no matching function" }
+  bar<void> (0); // { dg-error "no matching function" "" { xfail *-*-* } }
 }
--
2.7.0.83.gdfccd77.dirty

Reply via email to