]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix the remaining PR c++/24666 blockers (arrays decay to pointers too early)
authorPatrick Palka <ppalka@gcc.gnu.org>
Tue, 19 Jan 2016 00:19:16 +0000 (00:19 +0000)
committerPatrick Palka <ppalka@gcc.gnu.org>
Tue, 19 Jan 2016 00:19:16 +0000 (00:19 +0000)
gcc/cp/ChangeLog:

PR c++/11858
PR c++/24663
PR c++/24664
* decl.c (grokdeclarator): Don't decay array parameter type to
a pointer type if it's dependent.
(grokparms): Invoke strip_top_quals instead of directly invoking
cp_build_qualified_type.
* pt.c (decay_dependent_array_parm_type): New static function.
(type_unification_real): Call decay_dependent_array_parm_type
to decay a dependent array parameter type to its corresponding
pointer type before unification.
(more_specialized_fn): Likewise.
(get_bindings): Likewise.
* tree.c (cp_build_qualified_type): Trivial typofix in
documentation.

gcc/testsuite/ChangeLog:

PR c++/11858
PR c++/24663
PR c++/24664
* g++.dg/template/pr11858.C: New test.
* g++.dg/template/pr24663.C: New test.
* g++.dg/template/unify12.C: New test.
* g++.dg/template/unify13.C: New test.
* g++.dg/template/unify14.C: New test.
* g++.dg/template/unify15.C: New test.
* g++.dg/template/unify16.C: New test.
* g++.dg/template/unify17.C: New test.

From-SVN: r232547

13 files changed:
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/pr11858.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/pr24663.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify15.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify16.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/unify17.C [new file with mode: 0644]

index 9325bb0bf3c07313910c8701ae3b435ff817b2f6..87b4cca8468986ef8a8bb58d72b1e54a1fc5d9e5 100644 (file)
@@ -1,3 +1,21 @@
+2016-01-18  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       PR c++/11858
+       PR c++/24663
+       PR c++/24664
+       * decl.c (grokdeclarator): Don't decay array parameter type to
+       a pointer type if it's dependent.
+       (grokparms): Invoke strip_top_quals instead of directly invoking
+       cp_build_qualified_type.
+       * pt.c (decay_dependent_array_parm_type): New static function.
+       (type_unification_real): Call decay_dependent_array_parm_type
+       to decay a dependent array parameter type to its corresponding
+       pointer type before unification.
+       (more_specialized_fn): Likewise.
+       (get_bindings): Likewise.
+       * tree.c (cp_build_qualified_type): Trivial typofix in
+       documentation.
+
 2016-01-18  Jason Merrill  <jason@redhat.com>
 
        * cp-gimplify.c (cp_fold) [CONSTRUCTOR]: Don't clobber the input.
index df95133f25384829252adbdcb0434079333cd695..187390d2359fab199c7b8217519a4cb2b35695d5 100644 (file)
@@ -10898,8 +10898,13 @@ grokdeclarator (const cp_declarator *declarator,
 
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         /* Transfer const-ness of array into that of type pointed to.  */
-         type = build_pointer_type (TREE_TYPE (type));
+         /* Withhold decaying a dependent array type so that that during
+            instantiation we can detect type deduction failure cases such as
+            creating an array of void, creating a zero-size array, etc.  */
+         if (dependent_type_p (type))
+           ;
+         else
+           type = build_pointer_type (TREE_TYPE (type));
          type_quals = TYPE_UNQUALIFIED;
          array_parameter_p = true;
        }
@@ -11696,7 +11701,8 @@ grokparms (tree parmlist, tree *parms)
 
          /* Top-level qualifiers on the parameters are
             ignored for function types.  */
-         type = cp_build_qualified_type (type, 0);
+         type = strip_top_quals (type);
+
          if (TREE_CODE (type) == METHOD_TYPE)
            {
              error ("parameter %qD invalidly declared method type", decl);
index 403c5ac0bea813d7cc8c28b2362aac4aa5f8744d..866b4b1add86e0768c6de23e98dd219de0cb491b 100644 (file)
@@ -17729,6 +17729,23 @@ 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
@@ -18167,6 +18184,8 @@ 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;
@@ -20169,6 +20188,9 @@ 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;
@@ -20454,7 +20476,10 @@ 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] = TREE_VALUE (arg);
+      args[ix] = decay_dependent_array_parm_type (args[ix]);
+    }
 
   if (fn_type_unification (fn, explicit_args, targs,
                           args, ix,
index d4cf3102a03171b9d101ab26d34aa47fbb933ada..e2123ac5179ead033dfba82622535e8878b398ef 100644 (file)
@@ -1012,7 +1012,7 @@ c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */,
    arrays correctly.  In particular, if TYPE is an array of T's, and
    TYPE_QUALS is non-empty, returns an array of qualified T's.
 
-   FLAGS determines how to deal with ill-formed qualifications. If
+   COMPLAIN determines how to deal with ill-formed qualifications. If
    tf_ignore_bad_quals is set, then bad qualifications are dropped
    (this is permitted if TYPE was introduced via a typedef or template
    type parameter). If bad qualifications are dropped and tf_warning
index da5bfa931f1405a60a5c7ebd795e36e254d73b0d..9245b50b567e1b567230817773c38537fc5522fb 100644 (file)
@@ -1,3 +1,17 @@
+2016-01-18  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       PR c++/11858
+       PR c++/24663
+       PR c++/24664
+       * g++.dg/template/pr11858.C: New test.
+       * g++.dg/template/pr24663.C: New test.
+       * g++.dg/template/unify12.C: New test.
+       * g++.dg/template/unify13.C: New test.
+       * g++.dg/template/unify14.C: New test.
+       * g++.dg/template/unify15.C: New test.
+       * g++.dg/template/unify16.C: New test.
+       * g++.dg/template/unify17.C: New test.
+
 2016-01-18  David Malcolm  <dmalcolm@redhat.com>
 
        PR testsuite/69181
diff --git a/gcc/testsuite/g++.dg/template/pr11858.C b/gcc/testsuite/g++.dg/template/pr11858.C
new file mode 100644 (file)
index 0000000..dc0d688
--- /dev/null
@@ -0,0 +1,5 @@
+// PR c++/11858
+
+template <typename T> struct S { static typename T::x f (); }; // { dg-error "" }
+template <class T> int f (int [sizeof(T::f())]);
+int const i = f<S<int> >(0); // { dg-error "no matching function" }
diff --git a/gcc/testsuite/g++.dg/template/pr24663.C b/gcc/testsuite/g++.dg/template/pr24663.C
new file mode 100644 (file)
index 0000000..2dc68c2
--- /dev/null
@@ -0,0 +1,22 @@
+// PR c++/24663
+
+template<int I> int f1 (char[I]);
+template<int I> int f1 (char p1 = I);
+int i = f1<0>(0);
+
+template<typename T, int I> int f2 (T[I]); // { dg-error "" }
+int j = f2<int, 0>(0); // { dg-error "no matching function" }
+int k = f2<void, 1>(0); // { dg-error "no matching function" }
+
+int o[5];
+int l = f2<int[5], 1>(&o);
+
+template<int I> int f3 (char [][I]);
+template<int I> int f3 (char p1 = I);
+int x1 = f3<1>(0); // { dg-error "is ambiguous" }
+int x2 = f3<1>();
+
+template<typename T, int I> int f4 (T [][I]); // { dg-error "" }
+int y1 = f4<void, 1>(0); // { dg-error "no matching function" }
+int y2 = f4<int (void), 1>(0); // { dg-error "no matching function" }
+int y3 = f4<int&, 1>(0); // { dg-error "no matching function" }
diff --git a/gcc/testsuite/g++.dg/template/unify12.C b/gcc/testsuite/g++.dg/template/unify12.C
new file mode 100644 (file)
index 0000000..6e624e4
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-do run }
+#include <cassert>
+
+template<typename T, int I> int foo (T [I][I]) { return 0; }
+
+template int foo (char [][6]);
+
+template <typename T>
+int foo (T *)
+{
+  return -1;
+}
+
+template <typename T>
+int foo (T [3][3])
+{
+  return 1;
+}
+
+template <int I>
+int foo (bool [I][I])
+{
+  return 2;
+}
+
+template <>
+int foo (bool [3][2])
+{
+  return 3;
+}
+
+char x[3];
+bool y[4];
+bool z[3][2];
+
+int a = foo (&x);
+int b = foo (&y);
+int c = foo (z);
+
+int
+main ()
+{
+  assert (a == 1);
+  assert (b == 2);
+  assert (c == 3);
+}
diff --git a/gcc/testsuite/g++.dg/template/unify13.C b/gcc/testsuite/g++.dg/template/unify13.C
new file mode 100644 (file)
index 0000000..56a46df
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do run }
+#include <cassert>
+
+template<typename T, int I> int foo (T [I][I]) { return 0; }
+
+template<typename T>
+int foo (T [3][2])
+{
+  return 1;
+}
+
+template <>
+int foo (bool [3][2])
+{
+  return 2;
+}
+
+bool z[3][2];
+
+int a = foo (z);
+
+int
+main ()
+{
+  assert (a == 2);
+}
diff --git a/gcc/testsuite/g++.dg/template/unify14.C b/gcc/testsuite/g++.dg/template/unify14.C
new file mode 100644 (file)
index 0000000..7fda8fd
--- /dev/null
@@ -0,0 +1,5 @@
+template <typename T, int X>
+void bar (T [X]) { }
+
+template <typename T, int X>
+void bar (const T [X]) { }
diff --git a/gcc/testsuite/g++.dg/template/unify15.C b/gcc/testsuite/g++.dg/template/unify15.C
new file mode 100644 (file)
index 0000000..fe4848b
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do run }
+#include <cassert>
+
+template <typename T, int N>
+int bar (T (&) [N]) { return 0; }
+
+template <typename T, int N>
+int bar (const T (&) [N]) { return 1; }
+
+int
+main ()
+{
+  const int s[2] = { 0 };
+  assert (bar (s) == 1);
+}
diff --git a/gcc/testsuite/g++.dg/template/unify16.C b/gcc/testsuite/g++.dg/template/unify16.C
new file mode 100644 (file)
index 0000000..7b5a2aa
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do run }
+#include <cassert>
+
+template <typename T>
+struct Foo
+{
+  static int foo (T) { return 0; }
+};
+
+template <typename T, int I>
+struct Foo<T[I]>
+{
+  static int foo (T[I]) { return 1; }
+};
+
+template <int I>
+struct Foo<char[I]>
+{
+  static int foo (char[I]) { return 2; }
+};
+
+template <typename T>
+struct Foo<T[5]>
+{
+  static int foo (T[5]) { return 3; }
+};
+
+template <>
+struct Foo<char[5]>
+{
+  static int foo (char[5]) { return 4; }
+};
+
+template <>
+struct Foo<const char[5]>
+{
+  static int foo (const char[5]) { return 5; }
+};
+
+int a = Foo<const char[5]>::foo (0);
+int b = Foo<char[5]>::foo (0);
+int c = Foo<bool[5]>::foo (0);
+int d = Foo<char[4]>::foo (0);
+int e = Foo<bool[4]>::foo (0);
+int f = Foo<char[]>::foo (0);
+
+int
+main (void)
+{
+  assert (a == 5);
+  assert (b == 4);
+  assert (c == 3);
+  assert (d == 2);
+  assert (e == 1);
+  assert (f == 0);
+}
diff --git a/gcc/testsuite/g++.dg/template/unify17.C b/gcc/testsuite/g++.dg/template/unify17.C
new file mode 100644 (file)
index 0000000..2da8553
--- /dev/null
@@ -0,0 +1,11 @@
+void foo (int *);
+
+template <typename T>
+void bar (void (T[5])); // { dg-error "array of 'void'" }
+
+void
+baz (void)
+{
+  bar (foo); // { dg-bogus "" }
+  bar<void> (0); // { dg-error "no matching function" }
+}