diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2896efdd7f2..17dce107491 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2890,10 +2890,11 @@ get_mapped_args (tree map)
       tree level = make_tree_vec (list.length ());
       for (unsigned j = 0; j < list.length(); ++j)
 	TREE_VEC_ELT (level, j) = list[j];
+      /* None of the args at any level are defaulted.  */
+      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (level, list.length());
       SET_TMPL_ARGS_LEVEL (args, i + 1, level);
       list.release ();
     }
-  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);
 
   return args;
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f387b5036d2..b5350bb8409 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3684,25 +3684,29 @@ struct GTY(()) lang_decl {
   ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->args
 #define TI_PENDING_TEMPLATE_FLAG(NODE) \
   TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE))
-/* For a given TREE_VEC containing a template argument list,
-   this property contains the number of arguments that are not
-   defaulted.  */
+/* For a given TREE_VEC containing a template argument list (but not multiple
+   levels of arguments), this property contains the number of arguments that are
+   not defaulted and optionally the number of explicitly specified template
+   arguments. It is either a INT_CST denoting the number of non-default
+   arguments, or a TREE_LIST with TREE_PURPOSE denoting the number of explicitly
+   given template arguments of a function template, and TREE_VALUE denoting the
+   number of non-default arguments.  */
 #define NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \
   TREE_CHAIN (TREE_VEC_CHECK (NODE))
 
 /* Below are the setter and getter of the NON_DEFAULT_TEMPLATE_ARGS_COUNT
    property.  */
 #define SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE, INT_VALUE) \
-  NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) = build_int_cst (NULL_TREE, INT_VALUE)
-#if CHECKING_P
-#define GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \
-    int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE))
-#else
+  set_non_default_template_args_count (TREE_VEC_CHECK (NODE), INT_VALUE)
+
 #define GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \
-  NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE) \
-  ? int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) \
-  : TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (NODE))
-#endif
+  get_non_default_template_args_count (TREE_VEC_CHECK (NODE))
+
+#define EXPLICIT_TEMPLATE_ARGS_P(NODE) \
+  (get_explicit_template_args_count (TREE_VEC_CHECK (NODE)) > 0)
+
+#define SET_EXPLICIT_TEMPLATE_ARGS_COUNT(NODE, INT_VALUE) \
+  set_explicit_template_args_count (TREE_VEC_CHECK (NODE), INT_VALUE)
 
 /* The list of access checks that were deferred during parsing
    which need to be performed at template instantiation time.
@@ -5938,7 +5942,8 @@ enum auto_deduction_context
        identical to their defaults.
    TFF_NO_TEMPLATE_BINDINGS: do not print information about the template
        arguments for a function template specialization.
-   TFF_POINTER: we are printing a pointer type.  */
+   TFF_POINTER: we are printing a pointer type.
+   TFF_AS_PRIMARY: show the template like a primary template.  */
 
 #define TFF_PLAIN_IDENTIFIER			(0)
 #define TFF_SCOPE				(1)
@@ -5956,6 +5961,7 @@ enum auto_deduction_context
 #define TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS	(1 << 12)
 #define TFF_NO_TEMPLATE_BINDINGS		(1 << 13)
 #define TFF_POINTER		                (1 << 14)
+#define TFF_AS_PRIMARY		                (1 << 15)
 
 /* These constants can be used as bit flags to control strip_typedefs.
 
@@ -7153,6 +7159,10 @@ extern void pop_access_scope			(tree);
 extern bool check_template_shadow		(tree);
 extern bool check_auto_in_tmpl_args             (tree, tree);
 extern tree get_innermost_template_args		(tree, int);
+extern void set_non_default_template_args_count (tree args, int count);
+extern int  get_non_default_template_args_count (tree args);
+extern void set_explicit_template_args_count (tree args, int count);
+extern bool get_explicit_template_args_count (tree args);
 extern void maybe_begin_member_template_processing (tree);
 extern void maybe_end_member_template_processing (void);
 extern tree finish_member_template_decl		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7c2a134e406..74b0cac0f2f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -9985,6 +9985,10 @@ grokfndecl (tree ctype,
 	  /* A friend declaration of the form friend void f<>().  Record
 	     the information in the TEMPLATE_ID_EXPR.  */
 	  SET_DECL_IMPLICIT_INSTANTIATION (decl);
+	  /* Set the template args as explicitly specified - they were certainly
+	     not deduced from function arguments.  */
+	  if (args)
+	    SET_EXPLICIT_TEMPLATE_ARGS_COUNT (args, NUM_TMPL_ARGS (args));
 
 	  gcc_assert (identifier_p (fns) || OVL_P (fns));
 	  DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 012a4ecddf4..fb62adbeb0b 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -86,11 +86,11 @@ static void dump_exception_spec (cxx_pretty_printer *, tree, int);
 static void dump_template_argument (cxx_pretty_printer *, tree, int);
 static void dump_template_argument_list (cxx_pretty_printer *, tree, int);
 static void dump_template_parameter (cxx_pretty_printer *, tree, int);
-static void dump_template_bindings (cxx_pretty_printer *, tree, tree,
-                                    vec<tree, va_gc> *);
+static void dump_template_bindings (cxx_pretty_printer *, tree, tree, tree,
+                                    vec<tree, va_gc> *, int);
 static void dump_scope (cxx_pretty_printer *, tree, int);
 static void dump_template_parms (cxx_pretty_printer *, tree, int, int);
-static int get_non_default_template_args_count (tree, int);
+static int args_or_non_default_template_args_count (tree, int);
 static const char *function_category (tree);
 static void maybe_print_constexpr_context (diagnostic_context *);
 static void maybe_print_instantiation_context (diagnostic_context *);
@@ -272,24 +272,23 @@ dump_template_argument (cxx_pretty_printer *pp, tree arg, int flags)
     }
 }
 
-/* Count the number of template arguments ARGS whose value does not
-   match the (optional) default template parameter in PARAMS  */
+/* Returns GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (ARGS) unless FLAGS requests the
+   full count of template args.  */
 
 static int
-get_non_default_template_args_count (tree args, int flags)
+args_or_non_default_template_args_count (tree args, int flags)
 {
-  int n = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (args));
+  gcc_assert (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args));
 
   if (/* We use this flag when generating debug information.  We don't
 	 want to expand templates at this point, for this may generate
 	 new decls, which gets decl counts out of sync, which may in
 	 turn cause codegen differences between compilations with and
 	 without -g.  */
-      (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0
-      || !flag_pretty_templates)
-    return n;
+      (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0)
+    return NUM_TMPL_ARGS (args);
 
-  return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (INNERMOST_TEMPLATE_ARGS (args));
+  return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args);
 }
 
 /* Dump a template-argument-list ARGS (always a TREE_VEC) under control
@@ -298,7 +297,7 @@ get_non_default_template_args_count (tree args, int flags)
 static void
 dump_template_argument_list (cxx_pretty_printer *pp, tree args, int flags)
 {
-  int n = get_non_default_template_args_count (args, flags);
+  int n = args_or_non_default_template_args_count (args, flags);
   int need_comma = 0;
   int i;
 
@@ -369,7 +368,7 @@ dump_template_parameter (cxx_pretty_printer *pp, tree parm, int flags)
 
 static void
 dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
-                        vec<tree, va_gc> *typenames)
+			tree used_parms, vec<tree, va_gc> *typenames, int flags)
 {
   /* Print "[with" and ']', conditional on whether anything is printed at all.
      This is tied to whether a semicolon is needed to separate multiple template
@@ -414,23 +413,47 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
       /* Don't crash if we had an invalid argument list.  */
       if (TMPL_ARGS_DEPTH (args) >= lvl)
 	lvl_args = TMPL_ARGS_LEVEL (args, lvl);
+      const int len = TREE_VEC_LENGTH (p);
+      const int non_default_len
+	= lvl_args ? args_or_non_default_template_args_count (lvl_args, flags)
+		   : len;
 
-      for (i = 0; i < TREE_VEC_LENGTH (p); ++i)
+      for (i = 0; i < len; ++i, ++arg_idx)
 	{
+	  const tree parm_i = TREE_VEC_ELT (p, i);
+	  gcc_assert (TREE_CODE (parm_i) == TREE_LIST);
+	  const tree parm_val = TREE_VALUE (parm_i);
+	  const tree parm_type = TREE_CODE (parm_val) == TYPE_DECL
+				   || TREE_CODE (parm_val) == TEMPLATE_DECL
+				   ? TREE_TYPE (parm_val)
+				   : TREE_CODE (parm_val) == PARM_DECL
+				       ? DECL_ARG_TYPE (parm_val)
+				       : NULL_TREE;
+
+	  /* If the template parameter is defaulted and does not appear in
+	     used_parms (function arguments, return type, or exception
+	     specifier), skip the parameter.  */
+	  if (i >= non_default_len)
+	    {
+	      tree it;
+	      for (it = used_parms; it && TREE_VALUE (it) != parm_type;
+		   it = TREE_CHAIN (it))
+		;
+	      if (!it)
+		continue;
+	    }
+
 	  tree arg = NULL_TREE;
 
 	  /* Don't crash if we had an invalid argument list.  */
 	  if (lvl_args && NUM_TMPL_ARGS (lvl_args) > arg_idx)
 	    arg = TREE_VEC_ELT (lvl_args, arg_idx);
 
-	  tree parm_i = TREE_VEC_ELT (p, i);
 	  /* If the template argument repeats the template parameter (T = T),
 	     skip the parameter.*/
 	  if (arg && TREE_CODE (arg) == TEMPLATE_TYPE_PARM
-		&& TREE_CODE (parm_i) == TREE_LIST
-		&& TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL
-		&& TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i)))
-		     == TEMPLATE_TYPE_PARM
+		&& TREE_CODE (parm_val) == TYPE_DECL
+		&& TREE_CODE (TREE_TYPE (parm_val)) == TEMPLATE_TYPE_PARM
 		&& DECL_NAME (TREE_VALUE (parm_i))
 		     == DECL_NAME (TREE_CHAIN (arg)))
 	    continue;
@@ -450,8 +473,6 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
 	    }
 	  else
 	    pp_string (pp, M_("<missing>"));
-
-	  ++arg_idx;
 	}
 
       parms = TREE_CHAIN (parms);
@@ -1634,8 +1655,16 @@ dump_substitution (cxx_pretty_printer *pp,
   if (template_parms != NULL_TREE && template_args != NULL_TREE
       && !(flags & TFF_NO_TEMPLATE_BINDINGS))
     {
-      vec<tree, va_gc> *typenames = t ? find_typenames (t) : NULL;
-      dump_template_bindings (pp, template_parms, template_args, typenames);
+      vec<tree, va_gc> *typenames = nullptr;
+      tree used_parms = NULL_TREE;
+      if (t)
+	{
+	  typenames = find_typenames (t);
+	  const tree fn = TREE_TYPE (DECL_TEMPLATE_RESULT (t));
+	  used_parms = find_template_parameters (fn, template_parms);
+	}
+      dump_template_bindings (pp, template_parms, template_args, used_parms,
+			      typenames, flags);
     }
 }
 
@@ -1688,8 +1717,15 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   /* Likewise for the constexpr specifier, in case t is a specialization.  */
   constexpr_p = DECL_DECLARED_CONSTEXPR_P (t);
 
-  /* Pretty print template instantiations only.  */
-  if (DECL_USE_TEMPLATE (t) && DECL_TEMPLATE_INFO (t)
+  /* Keep t before the following branch makes t point to a more general
+     template. Without the specialized template, the information about defaulted
+     template arguments is lost.  */
+  tree specialized_t = t;
+  int specialized_flags = 0;
+
+  /* Pretty print only template instantiations. Don't pretty print explicit
+     specializations like 'template <> void fun<int> (int)'.  */
+  if (DECL_TEMPLATE_INSTANTIATION (t) && DECL_TEMPLATE_INFO (t)
       && !(flags & TFF_NO_TEMPLATE_BINDINGS)
       && flag_pretty_templates)
     {
@@ -1701,6 +1737,9 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 	{
 	  template_parms = DECL_TEMPLATE_PARMS (tmpl);
 	  t = tmpl;
+	  /* The "[with ...]" clause is printed, thus dump functions printing
+	     SPECIALIZED_T need to add TFF_AS_PRIMARY to their flags.  */
+	  specialized_flags = TFF_AS_PRIMARY;
 	}
     }
 
@@ -1710,8 +1749,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   fntype = TREE_TYPE (t);
   parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t);
 
-  if (DECL_CLASS_SCOPE_P (t))
-    cname = DECL_CONTEXT (t);
+  if (DECL_CLASS_SCOPE_P (specialized_t))
+    cname = DECL_CONTEXT (specialized_t);
   /* This is for partially instantiated template methods.  */
   else if (TREE_CODE (fntype) == METHOD_TYPE)
     cname = TREE_TYPE (TREE_VALUE (parmtypes));
@@ -1749,13 +1788,14 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
     /* Nothing.  */;
   else if (cname)
     {
-      dump_type (pp, cname, flags);
+      dump_type (pp, cname, flags | specialized_flags);
       pp_cxx_colon_colon (pp);
     }
   else
     dump_scope (pp, CP_DECL_CONTEXT (t), flags);
 
-  dump_function_name (pp, t, dump_function_name_flags);
+  dump_function_name (pp, specialized_t,
+		      dump_function_name_flags | specialized_flags);
 
   if (!(flags & TFF_NO_FUNCTION_ARGUMENTS))
     {
@@ -1802,26 +1842,6 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 	  pp_character (pp, ']');
 	}
     }
-  else if (template_args)
-    {
-      bool need_comma = false;
-      int i;
-      pp_cxx_begin_template_argument_list (pp);
-      template_args = INNERMOST_TEMPLATE_ARGS (template_args);
-      for (i = 0; i < TREE_VEC_LENGTH (template_args); ++i)
-	{
-	  tree arg = TREE_VEC_ELT (template_args, i);
-	  if (need_comma)
-	    pp_separate_with_comma (pp);
-	  if (ARGUMENT_PACK_P (arg))
-	    pp_cxx_left_brace (pp);
-	  dump_template_argument (pp, arg, TFF_PLAIN_IDENTIFIER);
-	  if (ARGUMENT_PACK_P (arg))
-	    pp_cxx_right_brace (pp);
-	  need_comma = true;
-	}
-      pp_cxx_end_template_argument_list (pp);
-    }
 }
 
 /* Print a parameter list. If this is for a member function, the
@@ -1968,13 +1988,35 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
 
   dump_module_suffix (pp, t);
 
+/* Print function template parameters if:
+   1. t is template, and
+   2. the caller didn't request to only print the template-name, and
+   3. t actually has template parameters that are not indirect parameters from
+      enclosing scopes, i.e. either
+      - t is a friend template specialization
+	(eg. template<class T> struct X { friend void foo<T>(int); }; since
+	PRIMARY_TEMPLATE_P requires a TEMPLATE_DECL, this case must be checked
+	before PRIMARY_TEMPLATE_P is safe to call), or
+      - t is a primary template (own template header),
+      and
+   4. either
+      - flags requests to show no function arguments, in which case deduced
+	types could be hidden and thus need to be printed, or
+      - at least one function template argument was given explicitly and the
+	diagnostics output should reflect the code as it was written,
+
+  Whether t is a specialization of a template informs the PRIMARY parameter of
+  dump_template_parms.
+ */
   if (DECL_TEMPLATE_INFO (t)
       && !(flags & TFF_TEMPLATE_NAME)
-      && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)
       && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL
-	  || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))))
-    dump_template_parms (pp, DECL_TEMPLATE_INFO (t), !DECL_USE_TEMPLATE (t),
-                         flags);
+	    || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
+      && ((flags & TFF_NO_FUNCTION_ARGUMENTS)
+	    || (DECL_TI_ARGS (t)
+		  && EXPLICIT_TEMPLATE_ARGS_P (INNERMOST_TEMPLATE_ARGS
+						 (DECL_TI_ARGS (t))))))
+    dump_template_parms (pp, DECL_TEMPLATE_INFO (t), !DECL_USE_TEMPLATE (t), flags);
 }
 
 /* Dump the template parameters from the template info INFO under control of
@@ -1989,6 +2031,8 @@ dump_template_parms (cxx_pretty_printer *pp, tree info,
 {
   tree args = info ? TI_ARGS (info) : NULL_TREE;
 
+  if (flags & TFF_AS_PRIMARY)
+    primary = true;
   if (primary && flags & TFF_TEMPLATE_NAME)
     return;
   flags &= ~(TFF_CLASS_KEY_OR_ENUM | TFF_TEMPLATE_NAME);
@@ -1998,10 +2042,11 @@ dump_template_parms (cxx_pretty_printer *pp, tree info,
      to crash producing error messages.  */
   if (args && !primary)
     {
-      int len, ix;
-      len = get_non_default_template_args_count (args, flags);
+      int ix;
 
       args = INNERMOST_TEMPLATE_ARGS (args);
+      int len = args_or_non_default_template_args_count (args, flags);
+      gcc_assert (len <= NUM_TMPL_ARGS (args));
       for (ix = 0; ix != len; ix++)
 	{
 	  tree arg = TREE_VEC_ELT (args, ix);
@@ -2026,25 +2071,35 @@ dump_template_parms (cxx_pretty_printer *pp, tree info,
       tree parms = DECL_TEMPLATE_PARMS (tpl);
       int len, ix;
 
-      parms = TREE_CODE (parms) == TREE_LIST ? TREE_VALUE (parms) : NULL_TREE;
-      len = parms ? TREE_VEC_LENGTH (parms) : 0;
-
-      for (ix = 0; ix != len; ix++)
+      if (TREE_CODE (parms) == TREE_LIST)
 	{
-	  tree parm;
+	  parms = INNERMOST_TEMPLATE_PARMS (parms);
+	  if (args)
+	    {
+	      len = args_or_non_default_template_args_count
+		      (INNERMOST_TEMPLATE_ARGS (args), flags);
+	      gcc_assert (len <= TREE_VEC_LENGTH (parms));
+	    }
+	  else
+	    len = TREE_VEC_LENGTH (parms);
 
-          if (TREE_VEC_ELT (parms, ix) == error_mark_node)
-            {
-              pp_string (pp, M_("<template parameter error>"));
-              continue;
-            }
+	  for (ix = 0; ix != len; ix++)
+	    {
+	      tree parm;
 
-          parm = TREE_VALUE (TREE_VEC_ELT (parms, ix));
+	      if (TREE_VEC_ELT (parms, ix) == error_mark_node)
+		{
+		  pp_string (pp, M_("<template parameter error>"));
+		  continue;
+		}
 
-	  if (ix)
-	    pp_separate_with_comma (pp);
+	      parm = TREE_VALUE (TREE_VEC_ELT (parms, ix));
 
-	  dump_decl (pp, parm, flags & ~TFF_DECL_SPECIFIERS);
+	      if (ix)
+		pp_separate_with_comma (pp);
+
+	      dump_decl (pp, parm, flags & ~TFF_DECL_SPECIFIERS);
+	    }
 	}
     }
   pp_cxx_end_template_argument_list (pp);
@@ -3163,7 +3218,8 @@ lang_decl_name (tree decl, int v, bool translate)
     }
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
-    dump_function_name (cxx_pp, decl, TFF_PLAIN_IDENTIFIER);
+    dump_function_name (cxx_pp, decl,
+			TFF_PLAIN_IDENTIFIER | TFF_NO_FUNCTION_ARGUMENTS);
   else if ((DECL_NAME (decl) == NULL_TREE)
            && TREE_CODE (decl) == NAMESPACE_DECL)
     dump_decl (cxx_pp, decl, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME);
@@ -4060,10 +4116,10 @@ print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
   gcc_assert (TREE_CODE (args_a) == TREE_VEC);
   gcc_assert (TREE_CODE (args_b) == TREE_VEC);
   int flags = 0;
-  int len_a = get_non_default_template_args_count (args_a, flags);
   args_a = INNERMOST_TEMPLATE_ARGS (args_a);
-  int len_b = get_non_default_template_args_count (args_b, flags);
+  int len_a = args_or_non_default_template_args_count (args_a, flags);
   args_b = INNERMOST_TEMPLATE_ARGS (args_b);
+  int len_b = args_or_non_default_template_args_count (args_b, flags);
   /* Determine the maximum range of args for which non-default template args
      were used; beyond this, only default args (if any) were used, and so
      they will be equal from this point onwards.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 66040035b2f..2460bdc0fe4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -689,6 +689,63 @@ strip_innermost_template_args (tree args, int extra_levels)
   return new_args;
 }
 
+/* Let ARGS know that there are COUNT entries which are not defaulted. ARGS must
+ * be a single level of arguments.  */
+
+void
+set_non_default_template_args_count (tree args, int count)
+{
+  gcc_assert (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args));
+  gcc_assert (count <= NUM_TMPL_ARGS (args));
+  tree cst = build_int_cst (integer_type_node, count);
+  if (TREE_CHAIN (args) && TREE_CODE (TREE_CHAIN (args)) == TREE_LIST)
+    TREE_VALUE (TREE_CHAIN (args)) = cst;
+  else
+    TREE_CHAIN (args) = cst;
+}
+
+/* Query the number of non-defaulted template arguments in a single level of
+   template ARGS.  */
+
+int
+get_non_default_template_args_count (tree args)
+{
+  gcc_assert (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args));
+  tree node = TREE_CHAIN (args);
+  if (!node)
+    return NUM_TMPL_ARGS (args);
+  if (TREE_CODE (node) == TREE_LIST)
+    node = TREE_VALUE (node);
+  const int count = int_cst_value (node);
+  gcc_assert (count <= NUM_TMPL_ARGS (args));
+  return count;
+}
+
+/* Set the COUNT of explicitly specified function template ARGS.  */
+
+void
+set_explicit_template_args_count (tree args, int count)
+{
+  args = INNERMOST_TEMPLATE_ARGS (args);
+  tree non_default
+    = TREE_CHAIN (args)
+	? INTEGER_CST_CHECK (TREE_CHAIN (args))
+	: build_int_cst (integer_type_node, TREE_VEC_LENGTH (args));
+  TREE_CHAIN (args) = build_tree_list (build_int_cst (integer_type_node, count),
+				       non_default);
+}
+
+/* Query the number of explicity specified function template ARGS.  */
+
+bool
+get_explicit_template_args_count (tree args)
+{
+  tree node = TREE_CHAIN (INNERMOST_TEMPLATE_ARGS (args));
+  return node && TREE_CODE (node) == TREE_LIST
+	   ? int_cst_value (TREE_PURPOSE (node))
+	   : 0;
+}
+
 /* We've got a template header coming up; push to a new level for storing
    the parms.  */
 
@@ -2504,7 +2561,7 @@ determine_specialization (tree template_id,
   if (candidates)
     {
       tree fn = TREE_VALUE (candidates);
-      *targs_out = copy_node (DECL_TI_ARGS (fn));
+      *targs_out = copy_template_args (DECL_TI_ARGS (fn));
 
       /* Propagate the candidate's constraints to the declaration.  */
       if (tsk != tsk_template)
@@ -4334,7 +4391,6 @@ expand_template_argument_pack (tree args)
   tree result_args = NULL_TREE;
   int in_arg, out_arg = 0, nargs = args ? TREE_VEC_LENGTH (args) : 0;
   int num_result_args = -1;
-  int non_default_args_count = -1;
 
   /* First, determine if we need to expand anything, and the number of
      slots we'll need.  */
@@ -4364,9 +4420,7 @@ expand_template_argument_pack (tree args)
 
   /* Expand arguments.  */
   result_args = make_tree_vec (num_result_args);
-  if (NON_DEFAULT_TEMPLATE_ARGS_COUNT (args))
-    non_default_args_count =
-      GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args);
+  int non_default_args_count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args);
   for (in_arg = 0; in_arg < nargs; ++in_arg)
     {
       tree arg = TREE_VEC_ELT (args, in_arg);
@@ -4376,8 +4430,7 @@ expand_template_argument_pack (tree args)
           int i, num_packed = TREE_VEC_LENGTH (packed);
           for (i = 0; i < num_packed; ++i, ++out_arg)
             TREE_VEC_ELT (result_args, out_arg) = TREE_VEC_ELT(packed, i);
-	  if (non_default_args_count > 0)
-	    non_default_args_count += num_packed - 1;
+	  non_default_args_count += num_packed - 1;
         }
       else
         {
@@ -4385,8 +4438,7 @@ expand_template_argument_pack (tree args)
           ++out_arg;
         }
     }
-  if (non_default_args_count >= 0)
-    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (result_args, non_default_args_count);
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (result_args, non_default_args_count);
   return result_args;
 }
 
@@ -4789,8 +4841,7 @@ template_parm_to_arg (tree t)
 	  /* Turn this argument into a TYPE_ARGUMENT_PACK
 	     with a single element, which expands T.  */
 	  tree vec = make_tree_vec (1);
-	  if (CHECKING_P)
-	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
+	  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
 
 	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
 
@@ -4805,8 +4856,7 @@ template_parm_to_arg (tree t)
 	  /* Turn this argument into a NONTYPE_ARGUMENT_PACK
 	     with a single element, which expands T.  */
 	  tree vec = make_tree_vec (1);
-	  if (CHECKING_P)
-	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
+	  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (vec, TREE_VEC_LENGTH (vec));
 
 	  t = convert_from_reference (t);
 	  TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
@@ -4828,11 +4878,16 @@ template_parms_level_to_args (tree parms)
 {
   tree a = copy_node (parms);
   TREE_TYPE (a) = NULL_TREE;
+  int nondefault = 0;
   for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)
-    TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i));
+    {
+      tree elt = TREE_VEC_ELT (a, i);
+      TREE_VEC_ELT (a, i) = template_parm_to_arg (elt);
+      if (!elt || elt == error_mark_node || !TREE_PURPOSE (elt))
+	++nondefault;
+    }
 
-  if (CHECKING_P)
-    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, nondefault);
 
   return a;
 }
@@ -8721,9 +8776,8 @@ coerce_template_parameter_pack (tree parms,
     }
 
   SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
-  if (CHECKING_P)
-    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (packed_args,
-					 TREE_VEC_LENGTH (packed_args));
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (packed_args,
+				       TREE_VEC_LENGTH (packed_args));
   return argument_pack;
 }
 
@@ -9087,7 +9141,7 @@ coerce_template_parms (tree parms,
       return error_mark_node;
     }
 
-  if (CHECKING_P && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args))
+  if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args))
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args,
 					 TREE_VEC_LENGTH (new_inner_args));
 
@@ -13332,8 +13386,9 @@ copy_template_args (tree t)
       TREE_VEC_ELT (new_vec, i) = elt;
     }
 
-  NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec)
-    = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t);
+  if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (t))
+    NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec)
+      = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t);
 
   return new_vec;
 }
@@ -13373,13 +13428,33 @@ tree
 tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
   tree orig_t = t;
-  int len, need_new = 0, i, expanded_len_adjust = 0, out;
+  int need_new = 0, i, expanded_len_adjust = 0, out;
   tree *elts;
 
   if (t == error_mark_node)
     return error_mark_node;
 
-  len = TREE_VEC_LENGTH (t);
+  const int len = TREE_VEC_LENGTH (t);
+  if (len == 0)
+    return t;
+
+  /* Shortcut if T has multiple levels. All elts must be TREE_VECs and we simply
+     recurse. The remainder of this function doesn't apply to multi-level
+     args.  */
+  if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (t))
+    {
+      tree r = make_tree_vec (len);
+      for (i = 0; i < len; i++)
+	{
+	  tree new_arg = tsubst_template_args (TREE_VEC_ELT (t, i), args,
+					       complain, in_decl);
+	  if (new_arg == error_mark_node)
+	    return error_mark_node;
+	  TREE_VEC_ELT (r, i) = new_arg;
+	}
+      return r;
+    }
+
   elts = XALLOCAVEC (tree, len);
 
   for (i = 0; i < len; i++)
@@ -13389,8 +13464,6 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
       if (!orig_arg)
 	new_arg = NULL_TREE;
-      else if (TREE_CODE (orig_arg) == TREE_VEC)
-	new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
       else if (PACK_EXPANSION_P (orig_arg))
         {
           /* Substitute into an expansion expression.  */
@@ -13424,19 +13497,6 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   /* Make space for the expanded arguments coming from template
      argument packs.  */
   t = make_tree_vec (len + expanded_len_adjust);
-  /* ORIG_T can contain TREE_VECs. That happens if ORIG_T contains the
-     arguments for a member template.
-     In that case each TREE_VEC in ORIG_T represents a level of template
-     arguments, and ORIG_T won't carry any non defaulted argument count.
-     It will rather be the nested TREE_VECs that will carry one.
-     In other words, ORIG_T carries a non defaulted argument count only
-     if it doesn't contain any nested TREE_VEC.  */
-  if (NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t))
-    {
-      int count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t);
-      count += expanded_len_adjust;
-      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (t, count);
-    }
   for (i = 0, out = 0; i < len; i++)
     {
       tree orig_arg = TREE_VEC_ELT (orig_t, i);
@@ -13457,6 +13517,65 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
         }
     }
 
+  /* The non-default template count can only be copied from ARGS if ORIG_T
+     requests a substitution of a complete level from ARGS. If the resulting T
+     contains the same entries as ARGS, then simply return the relevant level
+     from ARGS, which already has the correct non-default count.  */
+  int non_default_count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t)
+			    + expanded_len_adjust;
+  if (expanded_len_adjust == 0)
+    {
+      auto level_of_parm = [](tree vec, int i) -> int {
+	tree parm = TREE_VEC_ELT (vec, i);
+	while (ARGUMENT_PACK_P (parm) || PACK_EXPANSION_P (parm))
+	  {
+	    if (ARGUMENT_PACK_P (parm))
+	      parm = ARGUMENT_PACK_ARGS (parm);
+	    if (PACK_EXPANSION_P (parm))
+	      parm = PACK_EXPANSION_PATTERN (parm);
+	    if (TREE_CODE (parm) == TREE_VEC && TREE_VEC_LENGTH (parm) == 1)
+	      parm = TREE_VEC_ELT (parm, 0);
+	  }
+	if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+	       || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+	       || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+	      && i == TEMPLATE_TYPE_IDX (parm))
+	  return TEMPLATE_TYPE_LEVEL (parm);
+	else if (TREE_CODE (parm) == TEMPLATE_PARM_INDEX
+		   && i == TEMPLATE_PARM_IDX (parm))
+	  return TEMPLATE_PARM_LEVEL (parm);
+	return -1;
+      };
+
+      const int level = level_of_parm (orig_t, 0);
+      if (level > 0 && level <= TMPL_ARGS_DEPTH (args))
+	{
+	  args = TMPL_ARGS_LEVEL (args, level);
+	  if (len == NUM_TMPL_ARGS (args))
+	    {
+	      bool t_equals_args
+		= TREE_VEC_ELT (args, 0) == TREE_VEC_ELT (t, 0);
+	      int i;
+	      for (i = 1; i < len; ++i)
+		{
+		  if (level_of_parm (orig_t, i) == level)
+		    t_equals_args = t_equals_args && TREE_VEC_ELT (args, i)
+						       == TREE_VEC_ELT (t, i);
+		  else
+		    break;
+		}
+	      if (i == len && t_equals_args)
+		{
+		  ggc_free (t);
+		  return args;
+		}
+	      if (i == len && NON_DEFAULT_TEMPLATE_ARGS_COUNT (args))
+		non_default_count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args);
+	    }
+	}
+    }
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (t, non_default_count);
+
   return t;
 }
 
@@ -21687,8 +21806,7 @@ fn_type_unification (tree fn,
       explicit_targs = INNERMOST_TEMPLATE_ARGS (explicit_targs);
       for (i = NUM_TMPL_ARGS (explicit_targs); i--;)
 	TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (explicit_targs, i);
-      if (!incomplete && CHECKING_P
-	  && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+      if (!incomplete && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
 	SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT
 	  (targs, NUM_TMPL_ARGS (explicit_targs));
     }
@@ -21874,6 +21992,11 @@ fn_type_unification (tree fn,
 	excessive_deduction_depth = false;
     }
 
+  /* If all template parameters were explicitly given, treat them like default
+     template arguments for diagnostics.  */
+  if (explicit_targs && explicit_targs != error_mark_node)
+    SET_EXPLICIT_TEMPLATE_ARGS_COUNT (targs, NUM_TMPL_ARGS (explicit_targs));
+
   return r;
 }
 
@@ -22516,9 +22639,17 @@ type_unification_real (tree tparms,
 	     be NULL_TREE or ERROR_MARK_NODE, so we do not need
 	     to explicitly check cxx_dialect here.  */
 	  if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
-	    /* OK, there is a default argument.  Wait until after the
-	       conversion check to do substitution.  */
-	    continue;
+	    {
+	      /* The position of the first default template argument,
+		 is also the number of non-defaulted arguments in TARGS.
+		 Record that.  */
+	      if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+		SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, i);
+
+	      /* OK, there is a default argument.  Wait until after the
+		 conversion check to do substitution.  */
+	      continue;
+	    }
 
 	  /* If the type parameter is a parameter pack, then it will
 	     be deduced to an empty parameter pack.  */
@@ -22621,21 +22752,14 @@ type_unification_real (tree tparms,
 	  if (arg == error_mark_node)
 	    return 1;
 	  else if (arg)
-	    {
-	      TREE_VEC_ELT (targs, i) = arg;
-	      /* The position of the first default template argument,
-		 is also the number of non-defaulted arguments in TARGS.
-		 Record that.  */
-	      if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
-		SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, i);
-	    }
+	    TREE_VEC_ELT (targs, i) = arg;
 	}
 
       if (saw_undeduced++ == 1)
 	goto again;
     }
 
-  if (CHECKING_P && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+  if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
 
   return unify_success (explain_p);
@@ -24998,6 +25122,8 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
   if (!template_template_parm_bindings_ok_p (tparms, deduced_args))
     return NULL_TREE;
 
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (deduced_args, ntparms);
+
   return deduced_args;
 }
 
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C
index d3c1f589f87..b88bf7d4b34 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C
@@ -1,6 +1,6 @@
 // { dg-options "-gdwarf-2 -dA" }
 // { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param" 1 } }
-// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param\[^\n\]*\n\[^\n\]* DW_AT_name\n\[^\n\]* DW_AT_type\n\[^\n\]* DW_AT_const_value" 1 } }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param\[^\n\]*\n\[^\n\]* DW_AT_name\n\[^\n\]* DW_AT_type\n(?:\[^\n\]* DW_AT_default_value\n)?\[^\n\]* DW_AT_const_value" 1 } }
 #include "template-params-12.H"
 /* We get const_value for NULL pointers to member functions.  */
 #if __cplusplus > 199711L // Ugh, C++98 barfs at both the cast and the overload.
diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C
new file mode 100644
index 00000000000..6481798a69b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C
@@ -0,0 +1,61 @@
+// { dg-options "-fpretty-templates" }
+// { dg-do compile { target c++11 } }
+
+template <int a = 1>
+  [[deprecated]] void f0(); // { dg-message "'template<int a> void f0\\(\\)'" }
+
+template <int a>
+  [[deprecated]] void f1(); // { dg-message "'template<int a> void f1\\(\\)'" }
+
+template <class a, int b = 1>
+  [[deprecated]] void f2(); // { dg-message "'template<class a, int b> void f2\\(\\)'" }
+
+template <class a, int b = 1>
+  [[deprecated]] void f3(a); // { dg-message "'template<class a, int b> void f3\\(a\\)'" }
+
+template <class a>
+  [[deprecated]] void f4(a); // { dg-message "'template<class a> void f4\\(a\\)'" }
+
+template <>
+  [[deprecated]] void f4<int>(int);
+
+template <>
+  [[deprecated]] void f4(float);
+
+template <class a, class b = int>
+  [[deprecated]] void f5(a);
+
+template void f5<float>(float); // { dg-error "'void f5<a>\\(a\\) .with a = float.'" }
+
+template <class a, class b = int>
+  struct c
+  {
+    template <class d, class e = int>
+      [[deprecated]] static void f(d);
+  };
+
+int main()
+{
+  f0();            // { dg-warning "'void f0\\(\\)'" }
+  f1<1>();         // { dg-warning "'void f1<a>\\(\\) .with int a = 1.'" }
+  f2<int>();       // { dg-warning "'void f2<a>\\(\\) .with a = int.'" }
+  f3(1);           // { dg-warning "'void f3\\(a\\) .with a = int.'" }
+  f3<float>(1);    // { dg-warning "'void f3<a>\\(a\\) .with a = float.'" }
+  f3<float, 2>(1); // { dg-warning "'void f3<a, b>\\(a\\) .with a = float; int b = 2.'" }
+  f4(1.);          // { dg-warning "'void f4\\(a\\) .with a = double.'" }
+  f4(1);           // { dg-warning "'void f4<int>\\(int\\)'" }
+  f4(1.f);         // { dg-warning "'void f4\\(float\\)'" }
+
+  f0(0); // { dg-error "" }
+  f1(0); // { dg-error "" }
+  f2(0); // { dg-error "" }
+  f3();  // { dg-error "" }
+  f4();  // { dg-error "" }
+
+  c<int>::f(1.);    // { dg-warning "'static void c<a>::f\\(d\\) .with d = double; a = int.'" }
+  c<int>::f<int>(1);    // { dg-warning "'static void c<a>::f<d>\\(d\\) .with d = int; a = int.'" }
+  c<int>::f<float, int>(1.f);    // { dg-warning "'static void c<a>::f<d, e>\\(d\\) .with d = float; e = int; a = int.'" }
+  c<float, int>::f(1.);    // { dg-warning "'static void c<a, b>::f\\(d\\) .with d = double; a = float; b = int.'" }
+  c<float, int>::f<int>(1);    // { dg-warning "'static void c<a, b>::f<d>\\(d\\) .with d = int; a = float; b = int.'" }
+  c<float, int>::f<float, int>(1.f);    // { dg-warning "'static void c<a, b>::f<d, e>\\(d\\) .with d = float; e = int; a = float; b = int.'" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C
new file mode 100644
index 00000000000..a82709f5785
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C
@@ -0,0 +1,37 @@
+// { dg-options "-fno-pretty-templates" }
+// { dg-do compile { target c++11 } }
+
+template <int a = 1>
+  [[deprecated]] void f0();
+
+template <int a>
+  [[deprecated]] void f1();
+
+template <class a, int b = 1>
+  [[deprecated]] void f2();
+
+template <class a, int b = 1>
+  [[deprecated]] void f3(a);
+
+template <class a>
+  [[deprecated]] void f4(a);
+
+template <>
+  [[deprecated]] void f4<int>(int);
+
+template <class a, class b = int>
+  [[deprecated]] void f5(a);
+
+template void f5<float>(float); // { dg-error "'void f5<float>\\(float\\)'" }
+
+int main()
+{
+  f0();            // { dg-warning "'void f0\\(\\)'" }
+  f1<1>();         // { dg-warning "'void f1<1>\\(\\)'" }
+  f2<int>();       // { dg-warning "'void f2<int>\\(\\)'" }
+  f3(1);           // { dg-warning "'void f3\\(int\\)'" }
+  f3<float>(1);    // { dg-warning "'void f3<float>\\(float\\)'" }
+  f3<float, 2>(1); // { dg-warning "'void f3<float, 2>\\(float\\)'" }
+  f4(1.);          // { dg-warning "'void f4\\(double\\)'" }
+  f4(1);           // { dg-warning "'void f4<int>\\(int\\)'" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-3.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-3.C
new file mode 100644
index 00000000000..c5dceafca29
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-3.C
@@ -0,0 +1,29 @@
+// { dg-options "-fpretty-templates" }
+// { dg-do compile { target c++11 } }
+
+template <class T>
+  struct id
+  { using type = T; };
+
+template <class T0, class T1 = int, template <class> class foo = id>
+  struct A
+  {
+    template <class U0 = const T1&>
+      [[deprecated]] static void
+      f(typename foo<U0>::type);
+  };
+
+template <int> struct B;
+
+template <> struct B<1> 
+  { using type = int; };
+
+template <class T, int x = 1>
+  [[deprecated]] typename B<x>::type
+  f0(T);
+
+int main()
+{
+  A<int>::f(0); // { dg-warning "'static void A<T0>::f\\(typename foo<U0>::type\\) .with U0 = const int&; T0 = int; foo = id; typename foo<U0>::type = const int&.'" }
+  f0(0); // { dg-warning "'typename B<x>::type f0\\(T\\) .with T = int; int x = 1; typename B<x>::type = int.'" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-4.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-4.C
new file mode 100644
index 00000000000..14704b6a29e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-4.C
@@ -0,0 +1,19 @@
+// { dg-options "-fpretty-templates" }
+// { dg-do compile { target c++11 } }
+
+template <class T> struct X {};
+template <class... T> struct Y {};
+
+template <template <class> class Tpl, template <class...> class VTpl,
+	  class T0 = float, class U0 = VTpl<Tpl<T0>>, int x0 = 2>
+  struct S
+  {
+    template <class T, class... Ps, class U = int, int x = 1>
+      [[deprecated]] static U0
+      f(T, Ps&&...);
+  };
+
+void g()
+{
+  S<X, Y>::f(1, '2', 3, 4.); // { dg-warning "'static U0 S<Tpl, VTpl>::f\\(T, Ps&& ...\\) .with T = int; Ps = {char, int, double}; Tpl = X; VTpl = Y; U0 = Y<X<float> >.'" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-5.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-5.C
new file mode 100644
index 00000000000..0f13466fb27
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-5.C
@@ -0,0 +1,12 @@
+// { dg-options "-fpretty-templates" }
+// { dg-do compile { target c++11 } }
+//
+// Tests the case where DECL_TI_TEMPLATE doesn't return a TEMPLATE_DECL for the
+// FUNCTION_DECL of foo<U>(int).
+
+template <class T0, class T1 = int, int x = 1> void foo (int);
+
+template <class U, int y = 2>
+class Q {
+  friend void foo<U> (int = 3); // { dg-error "'void foo<U>\\(int\\)'" }
+};
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index de7570a6efa..0aa45404283 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -141,7 +141,7 @@ int test_7 (int first, const char *second, float third)
                                          |
                                          const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "initializing argument 2 of 'int test_7\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl }
+  // { dg-message "initializing argument 2 of 'int test_7<T>\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl }
   /* { dg-begin-multiline-output "" }
  int test_7 (int one, T two, float three);
                       ~~^~~
diff --git a/gcc/testsuite/g++.dg/ext/pretty1.C b/gcc/testsuite/g++.dg/ext/pretty1.C
index 06608ae30eb..c5bfd6082a7 100644
--- a/gcc/testsuite/g++.dg/ext/pretty1.C
+++ b/gcc/testsuite/g++.dg/ext/pretty1.C
@@ -60,7 +60,7 @@ __assert_fail (const char *cond, const char *file, unsigned int line,
   abort ();
 }
 
-// { dg-final { scan-assembler "int bar\\(T\\).*with T = int" } }
+// { dg-final { scan-assembler "int bar<int>\\(int\\)" } }
 // { dg-final { scan-assembler "top level" } }
 // { dg-final { scan-assembler "int main\\(\\)" } }
 // { dg-final { scan-assembler "int bar\\(T\\).*with T = double" } }
diff --git a/gcc/testsuite/g++.dg/goacc/template.C b/gcc/testsuite/g++.dg/goacc/template.C
index 10d3f446da7..4fcd88bfc56 100644
--- a/gcc/testsuite/g++.dg/goacc/template.C
+++ b/gcc/testsuite/g++.dg/goacc/template.C
@@ -157,12 +157,12 @@ main ()
 }
 
 /* { dg-final { scan-tree-dump-times {(?n)^OpenACC routine '[^']+' has 'nohost' clause\.$} 4 oaccloops } }
-   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = char\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
+   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble<T>\(int\) \[with T = char\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
    { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble<char>\(int\)char' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } }
-   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = int\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
+   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble<T>\(int\) \[with T = int\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
    { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble<int>\(int\)int' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } }
-   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = float\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
+   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble<T>\(int\) \[with T = float\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
    { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble<float>\(int\)float' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } }
-   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = double\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
+   { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble<T>\(int\) \[with T = double\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } }
    { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble<double>\(int\)double' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } }
    TODO See PR101551 for 'offloading_enabled' differences.  */
diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-7.C b/gcc/testsuite/g++.dg/gomp/declare-variant-7.C
index 7dda899578a..9cb654cb5e6 100644
--- a/gcc/testsuite/g++.dg/gomp/declare-variant-7.C
+++ b/gcc/testsuite/g++.dg/gomp/declare-variant-7.C
@@ -70,6 +70,6 @@ test ()
   s.f12 (0.0);		// { dg-final { scan-tree-dump-times "S<1>::f11<double> \\\(&s, 0.0\\\);" 1 "gimple" } }
   s.f14 (0LL);		// { dg-final { scan-tree-dump-times "S<1>::f13<long long int> \\\(&s, 0\\\);" 1 "gimple" } }
   T<0> t;
-  t.f16 (s);		// { dg-final { scan-tree-dump-times "T<0>::f16<S<1> > \\\(&t, s\\\);" 1 "gimple" } }
-  t.f18 (s);		// { dg-final { scan-tree-dump-times "T<0>::f18<S<1> > \\\(&t, s\\\);" 1 "gimple" } }
+  t.f16 (s);		// { dg-final { scan-tree-dump-times "T<0>::f16 \\\(&t, s\\\);" 1 "gimple" } }
+  t.f18 (s);		// { dg-final { scan-tree-dump-times "T<0>::f18 \\\(&t, s\\\);" 1 "gimple" } }
 }
diff --git a/gcc/testsuite/g++.dg/template/error40.C b/gcc/testsuite/g++.dg/template/error40.C
index c5df56fc1be..16a44d1819f 100644
--- a/gcc/testsuite/g++.dg/template/error40.C
+++ b/gcc/testsuite/g++.dg/template/error40.C
@@ -8,11 +8,11 @@ struct A
 
 void foo(void)
 {
-  A<void> a = 0;		// { dg-error "A<void, 0, 1>" }
+  A<void> a = 0;		// { dg-error "A<void>" }
 }
 
-template <class T> T f(T);	    // { dg-message "int f<int>.int." }
-template <class T> T f(T, int = 0); // { dg-message "" }
+template <class T> T f(T);	    // { dg-message "int f.int." }
+template <class T> T f(T, int = 0); // { dg-message "int f.int, int." }
 
 template <class T>
 struct B
diff --git a/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C b/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C
index 6348ae1ee67..30c7ecd5065 100644
--- a/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C
+++ b/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C
@@ -35,7 +35,7 @@ template<> void f1<int> (int)
   
   if (strcmp (function, "f1<int>"))
     bad = true;
-  if (strcmp (pretty, "void f1(T) [with T = int]"))
+  if (strcmp (pretty, "void f1<int>(int)"))
     bad = true;
 }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C
index 6dd4b546c0c..93dbf4b489f 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C
@@ -19,7 +19,7 @@ const char* S3<char>::h(int) { return __PRETTY_FUNCTION__; }
 int main()
 {
   if (strcmp (S3<double>::h(7), 
-	      "static const char* S3<T>::h(U) [with U = int; T = double]") == 0)
+	      "static const char* S3<double>::h(int)") == 0)
     return 0;
   else 
     return 1;
