c.opt: Add -fno-deduce-init-list.
authorJason Merrill <jason@redhat.com>
Fri, 18 Sep 2009 21:25:10 +0000 (17:25 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 18 Sep 2009 21:25:10 +0000 (17:25 -0400)
* c.opt: Add -fno-deduce-init-list.
* pt.c (get_pattern_parm): New.
(listify): Split out from...
(listify_autos): ...here.
(unify): Deduce std::initializer_list for T.
* call.c (build_over_call): Warn about it.

From-SVN: r151867

gcc/ChangeLog
gcc/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist-deduce.C [new file with mode: 0644]

index a3602abb810308fb74269a7cb21ccf0d3387a21c..16ee1d69a1f5ab812e4683b35ae6a29490cf904e 100644 (file)
@@ -1,3 +1,7 @@
+2009-09-18  Jason Merrill  <jason@redhat.com>
+
+       * c.opt: Add -fno-deduce-init-list.
+
 2009-09-18  Neil Vachharajani  <nvachhar@google.com>
 
        * value-prof.c (interesting_stringop_to_profile_p): Added output
index 5ee9a1348d448a47d9d832def6fad7efa5b6d4df..21f7ab7124694cb2374041fe0d81565c5a2fe720 100644 (file)
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -558,6 +558,10 @@ fconstant-string-class=
 ObjC ObjC++ Joined
 -fconst-string-class=<name>    Use class <name> for constant strings
 
+fdeduce-init-list
+C++ ObjC++ Var(flag_deduce_init_list) Init(1)
+-fno-deduce-init-list  disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list
+
 fdefault-inline
 C++ ObjC++
 Inline member functions by default
index 8bf0dde422651b3b2234b9e91697d45aa2e2cbd1..350aa3ee8cd62270fd7d38fba4c138ac736fdc77 100644 (file)
@@ -1,3 +1,11 @@
+2009-09-18  Jason Merrill  <jason@redhat.com>
+
+       * pt.c (get_pattern_parm): New.
+       (listify): Split out from...
+       (listify_autos): ...here.
+       (unify): Deduce std::initializer_list for T.
+       * call.c (build_over_call): Warn about it.
+
 2009-09-17  Andrew Pinski  <pinskia@gcc.gnu.org>
 
        PR c++/39365
@@ -67,7 +75,7 @@
        * decl.c (build_init_list_var_init): Check return value of
        perform_implicit_conversion.
 
-2009-09-03  Jason Merrill  <jason@redhat.com>
+2009-09-08  Jason Merrill  <jason@redhat.com>
 
        * class.c (currently_open_class): Make sure we're dealing with the
        main variant.
index f4b0497b7f95c61fc01fe0cc67f14d6dce2adc3d..8c1bb0edd47dc43c2e8d68d94b776ba8e2e91f6a 100644 (file)
@@ -5568,6 +5568,28 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
          && !TREE_ADDRESSABLE (type))
        conv = conv->u.next;
 
+      /* Warn about initializer_list deduction that isn't currently in the
+        working draft.  */
+      if (cxx_dialect > cxx98
+         && flag_deduce_init_list
+         && cand->template_decl
+         && is_std_init_list (non_reference (type)))
+       {
+         tree tmpl = TI_TEMPLATE (cand->template_decl);
+         tree realparm = chain_index (j, DECL_ARGUMENTS (cand->fn));
+         tree patparm = get_pattern_parm (realparm, tmpl);
+
+         if (!is_std_init_list (non_reference (TREE_TYPE (patparm))))
+           {
+             pedwarn (input_location, 0, "deducing %qT as %qT",
+                      non_reference (TREE_TYPE (patparm)),
+                      non_reference (type));
+             pedwarn (input_location, 0, "  in call to %q+D", cand->fn);
+             pedwarn (input_location, 0,
+                      "  (you can disable this with -fno-deduce-init-list)");
+           }
+       }
+
       val = convert_like_with_context
        (conv, VEC_index (tree, args, arg_index), fn, i - is_method,
         complain);
index e8db635fda7bb56e5546d07bbed7c07e922b819b..7801f987e5105bf03ae8f4dc3561df6027c2d0fd 100644 (file)
@@ -4646,6 +4646,7 @@ extern tree get_types_needing_access_check        (tree);
 extern int template_class_depth                        (tree);
 extern int is_specialization_of                        (tree, tree);
 extern bool is_specialization_of_friend                (tree, tree);
+extern tree get_pattern_parm                   (tree, tree);
 extern int comp_template_args                  (tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation     (tree);
index 9f094a3959ef61a4c4e11042153d48a60bd609d4..7e3a54540ec0ec7968d939812d6a0bebf6dd4610 100644 (file)
@@ -192,6 +192,8 @@ static void perform_typedefs_access_check (tree tmpl, tree targs);
 static void append_type_to_template_for_access_check_1 (tree, tree, tree);
 static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
 static bool primary_template_instantiation_p (const_tree);
+static tree listify (tree);
+static tree listify_autos (tree, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -8033,6 +8035,36 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   return result;
 }
 
+/* Given PARM_DECL PARM, find the corresponding PARM_DECL in the template
+   TMPL.  We do this using DECL_PARM_INDEX, which should work even with
+   parameter packs; all parms generated from a function parameter pack will
+   have the same DECL_PARM_INDEX.  */
+
+tree
+get_pattern_parm (tree parm, tree tmpl)
+{
+  tree pattern = DECL_TEMPLATE_RESULT (tmpl);
+  tree patparm;
+
+  if (DECL_ARTIFICIAL (parm))
+    {
+      for (patparm = DECL_ARGUMENTS (pattern);
+          patparm; patparm = TREE_CHAIN (patparm))
+       if (DECL_ARTIFICIAL (patparm)
+           && DECL_NAME (parm) == DECL_NAME (patparm))
+         break;
+    }
+  else
+    {
+      patparm = FUNCTION_FIRST_USER_PARM (DECL_TEMPLATE_RESULT (tmpl));
+      patparm = chain_index (DECL_PARM_INDEX (parm)-1, patparm);
+      gcc_assert (DECL_PARM_INDEX (patparm)
+                 == DECL_PARM_INDEX (parm));
+    }
+
+  return patparm;
+}
+
 /* Substitute ARGS into the vector or list of template arguments T.  */
 
 static tree
@@ -13727,6 +13759,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     {
       tree elt, elttype;
       unsigned i;
+      tree orig_parm = parm;
+
+      /* Replace T with std::initializer_list<T> for deduction.  */
+      if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+         && flag_deduce_init_list)
+       parm = listify (parm);
 
       if (!is_std_init_list (parm))
        /* We can only deduce from an initializer list argument if the
@@ -13752,6 +13790,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
          if (unify (tparms, targs, elttype, elt, elt_strict))
            return 1;
        }
+
+      /* If the std::initializer_list<T> deduction worked, replace the
+        deduced A with std::initializer_list<A>.  */
+      if (orig_parm != parm)
+       {
+         idx = TEMPLATE_TYPE_IDX (orig_parm);
+         targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
+         targ = listify (targ);
+         TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
+       }
       return 0;
     }
 
@@ -17446,26 +17494,33 @@ make_auto (void)
   return au;
 }
 
-/* Replace auto in TYPE with std::initializer_list<auto>.  */
+/* Given type ARG, return std::initializer_list<ARG>.  */
 
 static tree
-listify_autos (tree type, tree auto_node)
+listify (tree arg)
 {
   tree std_init_list = namespace_binding
     (get_identifier ("initializer_list"), std_node);
   tree argvec;
-  tree init_auto;
   if (!std_init_list || !DECL_CLASS_TEMPLATE_P (std_init_list))
     {    
-      error ("deducing auto from brace-enclosed initializer list requires "
+      error ("deducing from brace-enclosed initializer list requires "
             "#include <initializer_list>");
       return error_mark_node;
     }
   argvec = make_tree_vec (1);
-  TREE_VEC_ELT (argvec, 0) = auto_node;
-  init_auto = lookup_template_class (std_init_list, argvec, NULL_TREE,
-                                    NULL_TREE, 0, tf_warning_or_error);
+  TREE_VEC_ELT (argvec, 0) = arg;
+  return lookup_template_class (std_init_list, argvec, NULL_TREE,
+                               NULL_TREE, 0, tf_warning_or_error);
+}
+
+/* Replace auto in TYPE with std::initializer_list<auto>.  */
 
+static tree
+listify_autos (tree type, tree auto_node)
+{
+  tree init_auto = listify (auto_node);
+  tree argvec = make_tree_vec (1);
   TREE_VEC_ELT (argvec, 0) = init_auto;
   if (processing_template_decl)
     argvec = add_to_template_args (current_template_args (), argvec);
index 5a96820ba14d5ae2c28cf9ef22b5088025bac6a2..ad8e51cfe974c987b0f360974bedff69929c32f9 100644 (file)
@@ -1785,6 +1785,27 @@ two definitions were merged.
 This option is no longer useful on most targets, now that support has
 been added for putting variables into BSS without making them common.
 
+@item -fno-deduce-init-list
+@opindex fno-deduce-init-list
+Disable deduction of a template type parameter as
+std::initializer_list from a brace-enclosed initializer list, i.e.
+
+@smallexample
+template <class T> auto forward(T t) -> decltype (realfn (t))
+@{
+  return realfn (t);
+@}
+
+void f()
+@{
+  forward(@{1,2@}); // call forward<std::initializer_list<int>>
+@}
+@end smallexample
+
+This option is present because this deduction is an extension to the
+current specification in the C++0x working draft, and there was
+some concern about potential overload resolution problems.
+
 @item -ffriend-injection
 @opindex ffriend-injection
 Inject friend functions into the enclosing namespace, so that they are
index e4e7a21af78c4414386d1d8bb905850214d3247a..43f42b5e5fecf64114bf5b42118c92cf455094d6 100644 (file)
@@ -1,3 +1,7 @@
+2009-09-18  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/initlist-deduce.C: New.
+
 2009-09-18  Janis Johnson  <janis187@us.ibm.com>
 
        * gcc.dg/dfp/dfp.exp: Also run tests in c-c++-common/dfp.
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-deduce.C b/gcc/testsuite/g++.dg/cpp0x/initlist-deduce.C
new file mode 100644 (file)
index 0000000..e422132
--- /dev/null
@@ -0,0 +1,26 @@
+// Test for deduction of T as std::initializer_list.  This isn't currently
+// supported by the working draft, but is necessary for perfect forwarding
+// of initializer-lists to things that can take a std::initializer_list.
+
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+#include <initializer_list>
+
+struct A
+{
+  A(std::initializer_list<int>) { }
+};
+
+void f (A a) { }
+
+template <class T>
+auto g (T&& t) -> decltype (f(t)) // { dg-warning "call" }
+{
+  return f(t);
+}
+
+int main()
+{
+  g({1});                      // { dg-warning "deduc" }
+}