diff mbox

C++ PATCH for C++17 class template argument deduction issues

Message ID CADzB+2ky3hxWhm-JMf8+RAj0hPn0uchY=gv1NwyKQDQ7auirrQ@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Feb. 28, 2017, 11:56 p.m. UTC
This patch implements some proposed resolutions to open issues with
C++17 class template argument deduction.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 5486547c53bf6e83bcdd822b2f9cdce171d115b0
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 28 07:45:04 2017 -1000

            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.
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 560804a..babab00 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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) */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 54cbbb7..3e7316f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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)
       {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d5428ed..ec9d53a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
+    {
+      if (outer_args)
+	ctor = tsubst (ctor, outer_args, complain, ctor);
+      type = DECL_CONTEXT (ctor);
+      tree fn_tmpl;
+      if (TREE_CODE (ctor) == TEMPLATE_DECL)
+	{
+	  fn_tmpl = ctor;
+	  ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
+	}
+      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);
+      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))
-    {
-      /* 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;
+      if (PRIMARY_TEMPLATE_P (fn_tmpl))
+	{
+	  memtmpl = true;
 
-      /* 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);
+	  /* 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;
 
-      /* 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));
+	  /* 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 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);
+	  /* 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));
 
-      /* 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);
-	}
+	  /* 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
index 0000000..7f2be00
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction17.C
@@ -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};
+
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C
index 07ab5f5..0e496e6 100644
--- a/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction25.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction30.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction30.C
index e182803..f50e878 100644
--- a/gcc/testsuite/g++.dg/cpp1z/class-deduction30.C
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction30.C
@@ -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
index 0000000..4423157
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction31.C
@@ -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
index 0000000..4c3824f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction32.C
@@ -0,0 +1,5 @@ 
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+
+std::initializer_list l { 1, 2, 3 };
diff --git a/gcc/testsuite/g++.dg/parse/error15.C b/gcc/testsuite/g++.dg/parse/error15.C
index be00241..c32b5d4 100644
--- a/gcc/testsuite/g++.dg/parse/error15.C
+++ b/gcc/testsuite/g++.dg/parse/error15.C
@@ -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 }
diff --git a/gcc/testsuite/g++.dg/template/error52.C b/gcc/testsuite/g++.dg/template/error52.C
index 3350c8e..03068bb 100644
--- a/gcc/testsuite/g++.dg/template/error52.C
+++ b/gcc/testsuite/g++.dg/template/error52.C
@@ -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;
     }