Core 1591
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Oct 2013 21:58:19 +0000 (21:58 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Oct 2013 21:58:19 +0000 (21:58 +0000)
* pt.c (unify_array_domain): Split out from unify.
(unify): Use it for list deduction, too.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@203725 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/initlist74.C [new file with mode: 0644]

index a325988..2852f1f 100644 (file)
@@ -1,5 +1,9 @@
 2013-10-16  Jason Merrill  <jason@redhat.com>
 
+       Core 1591
+       * pt.c (unify_array_domain): Split out from unify.
+       (unify): Use it for list deduction, too.
+
        PR c++/57850
        * decl2.c (dump_tu): Split out from...
        (cp_write_global_declarations): ...here.  Call it in PCH mode.
index eed648a..a1eb7a2 100644 (file)
@@ -17007,6 +17007,72 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
   return unify_success (explain_p);
 }
 
+/* Handle unification of the domain of an array.  PARM_DOM and ARG_DOM are
+   INTEGER_TYPEs representing the TYPE_DOMAIN of ARRAY_TYPEs.  The other
+   parameters and return value are as for unify.  */
+
+static int
+unify_array_domain (tree tparms, tree targs,
+                   tree parm_dom, tree arg_dom,
+                   bool explain_p)
+{
+  tree parm_max;
+  tree arg_max;
+  bool parm_cst;
+  bool arg_cst;
+
+  /* Our representation of array types uses "N - 1" as the
+     TYPE_MAX_VALUE for an array with "N" elements, if "N" is
+     not an integer constant.  We cannot unify arbitrarily
+     complex expressions, so we eliminate the MINUS_EXPRs
+     here.  */
+  parm_max = TYPE_MAX_VALUE (parm_dom);
+  parm_cst = TREE_CODE (parm_max) == INTEGER_CST;
+  if (!parm_cst)
+    {
+      gcc_assert (TREE_CODE (parm_max) == MINUS_EXPR);
+      parm_max = TREE_OPERAND (parm_max, 0);
+    }
+  arg_max = TYPE_MAX_VALUE (arg_dom);
+  arg_cst = TREE_CODE (arg_max) == INTEGER_CST;
+  if (!arg_cst)
+    {
+      /* The ARG_MAX may not be a simple MINUS_EXPR, if we are
+        trying to unify the type of a variable with the type
+        of a template parameter.  For example:
+
+          template <unsigned int N>
+          void f (char (&) [N]);
+          int g();
+          void h(int i) {
+            char a[g(i)];
+            f(a);
+          }
+
+        Here, the type of the ARG will be "int [g(i)]", and
+        may be a SAVE_EXPR, etc.  */
+      if (TREE_CODE (arg_max) != MINUS_EXPR)
+       return unify_vla_arg (explain_p, arg_dom);
+      arg_max = TREE_OPERAND (arg_max, 0);
+    }
+
+  /* If only one of the bounds used a MINUS_EXPR, compensate
+     by adding one to the other bound.  */
+  if (parm_cst && !arg_cst)
+    parm_max = fold_build2_loc (input_location, PLUS_EXPR,
+                               integer_type_node,
+                               parm_max,
+                               integer_one_node);
+  else if (arg_cst && !parm_cst)
+    arg_max = fold_build2_loc (input_location, PLUS_EXPR,
+                              integer_type_node,
+                              arg_max,
+                              integer_one_node);
+
+  return unify (tparms, targs, parm_max, arg_max,
+               UNIFY_ALLOW_INTEGER, explain_p);
+}
+
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
    set of template parameters to a template.  TARGS is the bindings
    for those template parameters, as determined thus far; TARGS may
@@ -17092,13 +17158,17 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
          && flag_deduce_init_list)
        parm = listify (parm);
 
-      if (!is_std_init_list (parm))
+      if (!is_std_init_list (parm)
+         && TREE_CODE (parm) != ARRAY_TYPE)
        /* We can only deduce from an initializer list argument if the
-          parameter is std::initializer_list; otherwise this is a
-          non-deduced context. */
+          parameter is std::initializer_list or an array; otherwise this
+          is a non-deduced context. */
        return unify_success (explain_p);
 
-      elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
+      if (TREE_CODE (parm) == ARRAY_TYPE)
+       elttype = TREE_TYPE (parm);
+      else
+       elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
 
       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (arg), i, elt)
        {
@@ -17121,6 +17191,15 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
                                   explain_p);
        }
 
+      if (TREE_CODE (parm) == ARRAY_TYPE)
+       {
+         /* Also deduce from the length of the initializer list.  */
+         tree max = size_int (CONSTRUCTOR_NELTS (arg));
+         tree idx = compute_array_index_type (NULL_TREE, max, tf_none);
+         return unify_array_domain (tparms, targs, TYPE_DOMAIN (parm),
+                                    idx, explain_p);
+       }
+
       /* If the std::initializer_list<T> deduction worked, replace the
         deduced A with std::initializer_list<A>.  */
       if (orig_parm != parm)
@@ -17494,63 +17573,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
       RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
                               strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
       if (TYPE_DOMAIN (parm) != NULL_TREE)
-       {
-         tree parm_max;
-         tree arg_max;
-         bool parm_cst;
-         bool arg_cst;
-
-         /* Our representation of array types uses "N - 1" as the
-            TYPE_MAX_VALUE for an array with "N" elements, if "N" is
-            not an integer constant.  We cannot unify arbitrarily
-            complex expressions, so we eliminate the MINUS_EXPRs
-            here.  */
-         parm_max = TYPE_MAX_VALUE (TYPE_DOMAIN (parm));
-         parm_cst = TREE_CODE (parm_max) == INTEGER_CST;
-         if (!parm_cst)
-           {
-             gcc_assert (TREE_CODE (parm_max) == MINUS_EXPR);
-             parm_max = TREE_OPERAND (parm_max, 0);
-           }
-         arg_max = TYPE_MAX_VALUE (TYPE_DOMAIN (arg));
-         arg_cst = TREE_CODE (arg_max) == INTEGER_CST;
-         if (!arg_cst)
-           {
-             /* The ARG_MAX may not be a simple MINUS_EXPR, if we are
-                trying to unify the type of a variable with the type
-                of a template parameter.  For example:
-
-                   template <unsigned int N>
-                  void f (char (&) [N]);
-                  int g(); 
-                  void h(int i) {
-                     char a[g(i)];
-                    f(a); 
-                   }
-
-                Here, the type of the ARG will be "int [g(i)]", and
-                may be a SAVE_EXPR, etc.  */
-             if (TREE_CODE (arg_max) != MINUS_EXPR)
-               return unify_vla_arg (explain_p, arg);
-             arg_max = TREE_OPERAND (arg_max, 0);
-           }
-
-         /* If only one of the bounds used a MINUS_EXPR, compensate
-            by adding one to the other bound.  */
-         if (parm_cst && !arg_cst)
-           parm_max = fold_build2_loc (input_location, PLUS_EXPR,
-                                   integer_type_node,
-                                   parm_max,
-                                   integer_one_node);
-         else if (arg_cst && !parm_cst)
-           arg_max = fold_build2_loc (input_location, PLUS_EXPR,
-                                  integer_type_node,
-                                  arg_max,
-                                  integer_one_node);
-
-         RECUR_AND_CHECK_FAILURE (tparms, targs, parm_max, arg_max,
-                                  UNIFY_ALLOW_INTEGER, explain_p);
-       }
+       return unify_array_domain (tparms, targs, TYPE_DOMAIN (parm),
+                                  TYPE_DOMAIN (arg), explain_p);
       return unify_success (explain_p);
 
     case REAL_TYPE:
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist74.C b/gcc/testsuite/g++.dg/cpp0x/initlist74.C
new file mode 100644 (file)
index 0000000..4305b59
--- /dev/null
@@ -0,0 +1,7 @@
+// Core 1591
+// { dg-require-effective-target c++11 }
+
+template<class T, int N> void g(T const (&)[N]);
+void f() {
+  g( { 1, 2, 3, 4 } );
+}