Class template argument deduction refinements
authorJason Merrill <jason@redhat.com>
Tue, 28 Feb 2017 23:57:09 +0000 (18:57 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 28 Feb 2017 23:57:09 +0000 (18:57 -0500)
* call.c (joust): Move deduction guide tiebreaker down.
* decl.c (start_decl_1, cp_finish_decl, grokdeclarator): Allow class
deduction with no initializer.
* pt.c (build_deduction_guide): Handle implicit default/copy ctor.
(do_class_deduction): Use that rather than special case.
(do_auto_deduction): Handle null initializer.

From-SVN: r245796

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/class-deduction17.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction25.C
gcc/testsuite/g++.dg/cpp1z/class-deduction30.C
gcc/testsuite/g++.dg/cpp1z/class-deduction31.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/class-deduction32.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/error15.C
gcc/testsuite/g++.dg/template/error52.C

index e62bdb3420c04ef651a9b7cf7662c467154dd6a1..b0e589c812db5f76305862cbe2264e4dbcdd07a2 100644 (file)
@@ -1,3 +1,13 @@
+2017-02-28  Jason Merrill  <jason@redhat.com>
+
+       Class template argument deduction refinements
+       * call.c (joust): Move deduction guide tiebreaker down.
+       * decl.c (start_decl_1, cp_finish_decl, grokdeclarator): Allow class
+       deduction with no initializer.
+       * pt.c (build_deduction_guide): Handle implicit default/copy ctor.
+       (do_class_deduction): Use that rather than special case.
+       (do_auto_deduction): Handle null initializer.
+
 2017-02-28  Jakub Jelinek  <jakub@redhat.com>
 
        * decl.c (find_decomp_class_base): Use cond ? G_("...") : G_("...")
index 560804ab2d548422604cfd8a1e9cddc231c30fdf..babab00158db18fa43e9fa7c02afcd1b3f8a75e4 100644 (file)
@@ -9670,18 +9670,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
        return winner;
     }
 
-  /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
-  if (deduction_guide_p (cand1->fn))
-    {
-      gcc_assert (deduction_guide_p (cand2->fn));
-      /* We distinguish between candidates from an explicit deduction guide and
-        candidates built from a constructor based on DECL_ARTIFICIAL.  */
-      int art1 = DECL_ARTIFICIAL (cand1->fn);
-      int art2 = DECL_ARTIFICIAL (cand2->fn);
-      if (art1 != art2)
-       return art2 - art1;
-    }
-
   /* or, if not that,
      F1 is a non-template function and F2 is a template function
      specialization.  */
@@ -9719,6 +9707,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
        return winner;
     }
 
+  /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
+  if (deduction_guide_p (cand1->fn))
+    {
+      gcc_assert (deduction_guide_p (cand2->fn));
+      /* We distinguish between candidates from an explicit deduction guide and
+        candidates built from a constructor based on DECL_ARTIFICIAL.  */
+      int art1 = DECL_ARTIFICIAL (cand1->fn);
+      int art2 = DECL_ARTIFICIAL (cand2->fn);
+      if (art1 != art2)
+       return art2 - art1;
+    }
+
   /* or, if not that, F2 is from a using-declaration, F1 is not, and the
      conversion sequences are equivalent.
      (proposed in http://lists.isocpp.org/core/2016/10/1142.php) */
index 54cbbb70c01c4db6cd3d8e507103a1047e82c0a8..3e7316f3e0b739df02354e025769ad68eb1da8f6 100644 (file)
@@ -5238,13 +5238,15 @@ start_decl_1 (tree decl, bool initialized)
   else if (aggregate_definition_p && !complete_p)
     {
       if (type_uses_auto (type))
-       gcc_unreachable ();
+       gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (type));
       else
-       error ("aggregate %q#D has incomplete type and cannot be defined",
-              decl);
-      /* Change the type so that assemble_variable will give
-        DECL an rtl we can live with: (mem (const_int 0)).  */
-      type = TREE_TYPE (decl) = error_mark_node;
+       {
+         error ("aggregate %q#D has incomplete type and cannot be defined",
+                decl);
+         /* Change the type so that assemble_variable will give
+            DECL an rtl we can live with: (mem (const_int 0)).  */
+         type = TREE_TYPE (decl) = error_mark_node;
+       }
     }
 
   /* Create a new scope to hold this declaration if necessary.
@@ -6816,14 +6818,17 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
              return;
            }
 
-         gcc_unreachable ();
+         gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node));
        }
       d_init = init;
-      if (TREE_CODE (d_init) == TREE_LIST
-         && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
-       d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
-                                                 tf_warning_or_error);
-      d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
+      if (d_init)
+       {
+         if (TREE_CODE (d_init) == TREE_LIST
+             && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+           d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
+                                                     tf_warning_or_error);
+         d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
+       }
       enum auto_deduction_context adc = adc_variable_type;
       if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
        adc = adc_decomp_type;
@@ -12323,19 +12328,12 @@ grokdeclarator (const cp_declarator *declarator,
 
     if (VAR_P (decl) && !initialized)
       if (tree auto_node = type_uses_auto (type))
-       {
-         location_t loc = declspecs->locations[ds_type_spec];
-         if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
-           {
-             error_at (loc, "invalid use of template-name %qE without an "
-                       "argument list", tmpl);
-             inform (loc, "class template argument deduction "
-                     "requires an initializer");
-           }
-         else
+       if (!CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+         {
+           location_t loc = declspecs->locations[ds_type_spec];
            error_at (loc, "declaration of %q#D has no initializer", decl);
-         TREE_TYPE (decl) = error_mark_node;
-       }
+           TREE_TYPE (decl) = error_mark_node;
+         }
 
     if (storage_class == sc_extern && initialized && !funcdef_flag)
       {
index d5428ed9feb27a21e7f82912ac5dc40542cb158f..ec9d53a83ee2fadba023a01dac3e82f79a18a60b 100644 (file)
@@ -24941,103 +24941,137 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
 }
 
 /* Returns a C++17 class deduction guide template based on the constructor
-   CTOR.  */
+   CTOR.  As a special case, CTOR can be a RECORD_TYPE for an implicit default
+   guide, or REFERENCE_TYPE for an implicit copy/move guide.  */
 
 static tree
 build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
 {
-  if (outer_args)
-    ctor = tsubst (ctor, outer_args, complain, ctor);
-  tree type = DECL_CONTEXT (ctor);
-  tree fn_tmpl;
-  if (TREE_CODE (ctor) == TEMPLATE_DECL)
+  tree type, tparms, targs, fparms, fargs, ci;
+  bool memtmpl = false;
+  bool explicit_p;
+  location_t loc;
+
+  if (TYPE_P (ctor))
     {
-      fn_tmpl = ctor;
-      ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
+      type = ctor;
+      bool copy_p = TREE_CODE (type) == REFERENCE_TYPE;
+      if (copy_p)
+       {
+         type = TREE_TYPE (type);
+         fparms = tree_cons (NULL_TREE, type, void_list_node);
+       }
+      else
+       fparms = void_list_node;
+
+      tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
+      tparms = DECL_TEMPLATE_PARMS (ctmpl);
+      targs = CLASSTYPE_TI_ARGS (type);
+      ci = NULL_TREE;
+      fargs = NULL_TREE;
+      loc = DECL_SOURCE_LOCATION (ctmpl);
+      explicit_p = false;
     }
   else
-    fn_tmpl = DECL_TI_TEMPLATE (ctor);
-
-  tree tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
-  /* If type is a member class template, DECL_TI_ARGS (ctor) will have fully
-     specialized args for the enclosing class.  Strip those off, as the
-     deduction guide won't have those template parameters.  */
-  tree targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
-                                           TMPL_PARMS_DEPTH (tparms));
-  /* Discard the 'this' parameter.  */
-  tree fparms = FUNCTION_ARG_CHAIN (ctor);
-  tree fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
-  tree ci = get_constraints (ctor);
-
-  if (PRIMARY_TEMPLATE_P (fn_tmpl))
-    {
-      /* For a member template constructor, we need to flatten the two template
-        parameter lists into one, and then adjust the function signature
-        accordingly.  This gets...complicated.  */
-      ++processing_template_decl;
-      tree save_parms = current_template_parms;
-
-      /* For a member template we should have two levels of parms/args, one for
-        the class and one for the constructor.  We stripped specialized args
-        for further enclosing classes above.  */
-      const int depth = 2;
-      gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
-
-      /* Template args for translating references to the two-level template
-        parameters into references to the one-level template parameters we are
-        creating.  */
-      tree tsubst_args = copy_node (targs);
-      TMPL_ARGS_LEVEL (tsubst_args, depth)
-       = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
-
-      /* Template parms for the constructor template.  */
-      tree ftparms = TREE_VALUE (tparms);
-      unsigned flen = TREE_VEC_LENGTH (ftparms);
-      /* Template parms for the class template.  */
-      tparms = TREE_CHAIN (tparms);
-      tree ctparms = TREE_VALUE (tparms);
-      unsigned clen = TREE_VEC_LENGTH (ctparms);
-      /* Template parms for the deduction guide start as a copy of the template
-        parms for the class.  We set current_template_parms for
-        lookup_template_class_1.  */
-      current_template_parms = tparms = copy_node (tparms);
-      tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
-      for (unsigned i = 0; i < clen; ++i)
-       TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
-
-      /* Now we need to rewrite the constructor parms to append them to the
-        class parms.  */
-      for (unsigned i = 0; i < flen; ++i)
+    {
+      if (outer_args)
+       ctor = tsubst (ctor, outer_args, complain, ctor);
+      type = DECL_CONTEXT (ctor);
+      tree fn_tmpl;
+      if (TREE_CODE (ctor) == TEMPLATE_DECL)
        {
-         unsigned index = i + clen;
-         unsigned level = 1;
-         tree oldelt = TREE_VEC_ELT (ftparms, i);
-         tree olddecl = TREE_VALUE (oldelt);
-         tree newdecl = rewrite_template_parm (olddecl, index, level,
-                                               tsubst_args, complain);
-         tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
-                                            tsubst_args, complain, ctor);
-         tree list = build_tree_list (newdef, newdecl);
-         TEMPLATE_PARM_CONSTRAINTS (list)
-           = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
-                                     tsubst_args, complain, ctor);
-         TREE_VEC_ELT (new_vec, index) = list;
-         TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+         fn_tmpl = ctor;
+         ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
        }
+      else
+       fn_tmpl = DECL_TI_TEMPLATE (ctor);
+
+      tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
+      /* If type is a member class template, DECL_TI_ARGS (ctor) will have
+        fully specialized args for the enclosing class.  Strip those off, as
+        the deduction guide won't have those template parameters.  */
+      targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
+                                               TMPL_PARMS_DEPTH (tparms));
+      /* Discard the 'this' parameter.  */
+      fparms = FUNCTION_ARG_CHAIN (ctor);
+      fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
+      ci = get_constraints (ctor);
+      loc = DECL_SOURCE_LOCATION (ctor);
+      explicit_p = DECL_NONCONVERTING_P (ctor);
+
+      if (PRIMARY_TEMPLATE_P (fn_tmpl))
+       {
+         memtmpl = true;
+
+         /* For a member template constructor, we need to flatten the two
+            template parameter lists into one, and then adjust the function
+            signature accordingly.  This gets...complicated.  */
+         ++processing_template_decl;
+         tree save_parms = current_template_parms;
+
+         /* For a member template we should have two levels of parms/args, one
+            for the class and one for the constructor.  We stripped
+            specialized args for further enclosing classes above.  */
+         const int depth = 2;
+         gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
+
+         /* Template args for translating references to the two-level template
+            parameters into references to the one-level template parameters we
+            are creating.  */
+         tree tsubst_args = copy_node (targs);
+         TMPL_ARGS_LEVEL (tsubst_args, depth)
+           = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
+
+         /* Template parms for the constructor template.  */
+         tree ftparms = TREE_VALUE (tparms);
+         unsigned flen = TREE_VEC_LENGTH (ftparms);
+         /* Template parms for the class template.  */
+         tparms = TREE_CHAIN (tparms);
+         tree ctparms = TREE_VALUE (tparms);
+         unsigned clen = TREE_VEC_LENGTH (ctparms);
+         /* Template parms for the deduction guide start as a copy of the
+            template parms for the class.  We set current_template_parms for
+            lookup_template_class_1.  */
+         current_template_parms = tparms = copy_node (tparms);
+         tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
+         for (unsigned i = 0; i < clen; ++i)
+           TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
+
+         /* Now we need to rewrite the constructor parms to append them to the
+            class parms.  */
+         for (unsigned i = 0; i < flen; ++i)
+           {
+             unsigned index = i + clen;
+             unsigned level = 1;
+             tree oldelt = TREE_VEC_ELT (ftparms, i);
+             tree olddecl = TREE_VALUE (oldelt);
+             tree newdecl = rewrite_template_parm (olddecl, index, level,
+                                                   tsubst_args, complain);
+             tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
+                                                tsubst_args, complain, ctor);
+             tree list = build_tree_list (newdef, newdecl);
+             TEMPLATE_PARM_CONSTRAINTS (list)
+               = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
+                                         tsubst_args, complain, ctor);
+             TREE_VEC_ELT (new_vec, index) = list;
+             TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+           }
 
-      /* Now we have a final set of template parms to substitute into the
-        function signature.  */
-      targs = template_parms_to_args (tparms);
-      fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE,
-                                complain, ctor);
-      fargs = tsubst (fargs, tsubst_args, complain, ctor);
-      if (ci)
-       ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
+         /* Now we have a final set of template parms to substitute into the
+            function signature.  */
+         targs = template_parms_to_args (tparms);
+         fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE,
+                                    complain, ctor);
+         fargs = tsubst (fargs, tsubst_args, complain, ctor);
+         if (ci)
+           ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
 
-      current_template_parms = save_parms;
-      --processing_template_decl;
+         current_template_parms = save_parms;
+         --processing_template_decl;
+       }
     }
-  else
+
+  if (!memtmpl)
     {
       /* Copy the parms so we can set DECL_PRIMARY_TEMPLATE.  */
       tparms = copy_node (tparms);
@@ -25046,12 +25080,12 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
     }
 
   tree fntype = build_function_type (type, fparms);
-  tree ded_fn = build_lang_decl_loc (DECL_SOURCE_LOCATION (ctor),
+  tree ded_fn = build_lang_decl_loc (loc,
                                     FUNCTION_DECL,
                                     dguide_name (type), fntype);
   DECL_ARGUMENTS (ded_fn) = fargs;
   DECL_ARTIFICIAL (ded_fn) = true;
-  DECL_NONCONVERTING_P (ded_fn) = DECL_NONCONVERTING_P (ctor);
+  DECL_NONCONVERTING_P (ded_fn) = explicit_p;
   tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
   DECL_ARTIFICIAL (ded_tmpl) = true;
   DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
@@ -25085,27 +25119,16 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
   tree type = TREE_TYPE (tmpl);
 
   vec<tree,va_gc> *args;
-  if (TREE_CODE (init) == TREE_LIST)
+  if (init == NULL_TREE
+      || TREE_CODE (init) == TREE_LIST)
     args = make_tree_vector_from_list (init);
-  else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+  else if (BRACE_ENCLOSED_INITIALIZER_P (init)
+          && !TYPE_HAS_LIST_CTOR (type)
+          && !is_std_init_list (type))
     args = make_tree_vector_from_ctor (init);
   else
     args = make_tree_vector_single (init);
 
-  if (args->length() == 1)
-    {
-      /* First try to deduce directly, since we don't have implicitly-declared
-        constructors yet.  */
-      tree parms = build_tree_list (NULL_TREE, type);
-      tree tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
-      tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
-      int err = type_unification_real (tparms, targs, parms, &(*args)[0],
-                                      1, /*subr*/false, DEDUCE_CALL,
-                                      LOOKUP_NORMAL, NULL, /*explain*/false);
-      if (err == 0)
-       return tsubst (type, targs, complain, tmpl);
-    }
-
   tree dname = dguide_name (tmpl);
   tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
                                      /*type*/false, /*complain*/false,
@@ -25121,6 +25144,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
       type = TREE_TYPE (most_general_template (tmpl));
     }
 
+  bool saw_default = false;
+  bool saw_copy = false;
   if (CLASSTYPE_METHOD_VEC (type))
     // FIXME cache artificial deduction guides
     for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
@@ -25128,21 +25153,30 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
        tree fn = OVL_CURRENT (fns);
        tree guide = build_deduction_guide (fn, outer_args, complain);
        cands = ovl_cons (guide, cands);
+
+       tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn);
+       if (sufficient_parms_p (parms))
+         saw_default = true;
+       if (parms && sufficient_parms_p (TREE_CHAIN (parms)))
+         {
+           tree pt = TREE_VALUE (parms);
+           if (TREE_CODE (pt) == REFERENCE_TYPE
+               && (same_type_ignoring_top_level_qualifiers_p
+                   (TREE_TYPE (pt), type)))
+             saw_copy = true;
+         }
       }
 
-  if (cands == NULL_TREE)
+  if (!saw_default && args->length() == 0)
     {
-      if (args->length() == 0)
-       {
-         /* Try tmpl<>.  */
-         tree t = lookup_template_class (tmpl, NULL_TREE, NULL_TREE,
-                                         NULL_TREE, false, tf_none);
-         if (t != error_mark_node)
-           return t;
-       }
-      error ("cannot deduce template arguments for %qT, as it has "
-            "no deduction guides or user-declared constructors", type);
-      return error_mark_node;
+      tree guide = build_deduction_guide (type, outer_args, complain);
+      cands = ovl_cons (guide, cands);
+    }
+  if (!saw_copy && args->length() == 1)
+    {
+      tree guide = build_deduction_guide (build_reference_type (type),
+                                         outer_args, complain);
+      cands = ovl_cons (guide, cands);
     }
 
   /* Prune explicit deduction guides in copy-initialization context.  */
@@ -25225,7 +25259,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
   if (init == error_mark_node)
     return error_mark_node;
 
-  if (type_dependent_expression_p (init)
+  if (init && type_dependent_expression_p (init)
       && context != adc_unify)
     /* Defining a subset of type-dependent expressions that we can deduce
        from ahead of time isn't worth the trouble.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction17.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction17.C
new file mode 100644 (file)
index 0000000..7f2be00
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+template <class T>
+struct A
+{
+  A (std::initializer_list<T>);
+};
+
+A a{1,2};
+
index 07ab5f5738cf47c2b4d72c4e7fed03e172d13d0b..0e496e62d85a5e10f5febd481f32604b1be479c4 100644 (file)
@@ -15,10 +15,10 @@ template<class T> struct A {
 template<class T, int N = remove_ref_t<T>::value> A(T&&, int*) -> A<T>; //#3
 
 A a{1,0}; // uses #1 to deduce A<int> and initializes with #1
-A b{a,0}; // uses #3 (not #2) to deduce A<A<int>&> and initializes with #1
+A b{a,0}; // uses #2 to deduce A<int> and initializes with #2
 
 template <class,class> struct same;
 template <class T> struct same<T,T> {};
 
 same<decltype(a),A<int>> s1;
-same<decltype(b),A<A<int>&>> s2;
+same<decltype(b),A<int>> s2;
index e182803ae7945b9cc12863be621f696d4e17bcb2..f50e87819ea8ef85f33dae1e91ef09ce48fb7e46 100644 (file)
@@ -3,4 +3,4 @@
 template <class T = void> struct A { };
 
 A a{};
-
+A a2;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction31.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction31.C
new file mode 100644 (file)
index 0000000..4423157
--- /dev/null
@@ -0,0 +1,22 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+  A(T); // #1
+  A(const A&); // #2
+};
+
+template <class T> A(T) -> A<T>;  // #3
+
+A a (42); // uses #3 to deduce A<int> and initializes with #1
+A b = a;  // uses #2 (not #3) to deduce A<int> and initializes with #2; #2 is more specialized
+
+template <class T> A(A<T>) -> A<A<T>>;  // #4
+
+A b2 = a;  // uses #4 to deduce A<A<int>> and initializes with #1; #4 is as specialized as #2
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+same<decltype(a),A<int>> s1;
+same<decltype(b),A<int>> s2;
+same<decltype(b2),A<A<int>>> s3;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction32.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction32.C
new file mode 100644 (file)
index 0000000..4c3824f
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+
+std::initializer_list l { 1, 2, 3 };
index be002412efb8e4d84a29e00574156467d2bd8ee7..c32b5d421ffa004394b709c3446277038f158b41 100644 (file)
@@ -10,12 +10,13 @@ namespace N
   int K;
 }
 
-N::A f2;              // { dg-error "1:invalid use of template-name 'N::A' without an argument list" }
+N::A f2;              // { dg-error "1:invalid use of template-name 'N::A' without an argument list" "" { target c++14_down } }
+                               // { dg-error "deduction|no match" "" { target c++1z } .-1 }
 N::INVALID f3;        // { dg-error "4:'INVALID' in namespace 'N' does not name a type" }
 N::C::INVALID f4;     // { dg-error "7:'INVALID' in 'struct N::C' does not name a type" }
 N::K f6;              // { dg-error "4:'K' in namespace 'N' does not name a type" }
 typename N::A f7;
-// { dg-error "13:invalid use of template-name 'N::A' without an argument list" "13" { target *-*-* } 17 }
+// { dg-error "13:invalid use of template-name 'N::A' without an argument list" "13" { target *-*-* } .-1 }
 
 struct B
 {
@@ -24,7 +25,7 @@ struct B
   N::C::INVALID f4;   // { dg-error "9:'INVALID' in 'struct N::C' does not name a type" }
   N::K f6;            // { dg-error "6:'K' in namespace 'N' does not name a type" }
   typename N::A f7;
-// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } 26 }
+// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } .-1 }
 };
 
 template <int>
@@ -36,5 +37,3 @@ struct C
   N::K f6;            // { dg-error "6:'K' in namespace 'N' does not name a type" }
   typename N::A f7;   // { dg-error "15:invalid use of template-name 'N::A' without an argument list" }
 };
-
-// { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { target *-*-* } 17 }
index 3350c8e6a787397eecfbde578e00fabc81b13fb6..03068bbf440ce4806cec86b21b3775d0178a42c5 100644 (file)
@@ -9,11 +9,11 @@ namespace H {
     struct B {};
     }
 
-A a;             // { dg-error "template" }
-H::B b;          // { dg-error "template" }
+A a;             // { dg-error "template|no match" }
+H::B b;          // { dg-error "template|no match" }
 
 int main() {
-    A a;         // { dg-error "template" }
-    H::B b;      // { dg-error "template" }
+    A a;         // { dg-error "template|no match" }
+    H::B b;      // { dg-error "template|no match" }
     return 0;
     }