diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index fdb5be7b2b7..69ec47cd215 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -941,6 +941,12 @@ class cplus_language : public language_defn
 		   const struct type_print_options *flags) const override
   {
     c_print_type (type, varstring, stream, show, level, la_language, flags);
+
+    /* Print target type or template arguments if TYPE it is a function
+       template.  */
+    if (type->code () == TYPE_CODE_FUNC)
+      c_type_print_template_args (flags, type, stream, la_language);
+
   }
 
   /* See language.h.  */
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index 7d9eaf8571b..538d007e2e6 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -134,4 +134,14 @@ extern int c_textual_element_type (struct type *, char);
 
 extern gdb::unique_xmalloc_ptr<char> c_canonicalize_name (const char *name);
 
+/* Display template arguments of TYPE in the style [with T = ..., U = ...]
+   based on FLAGS and LANGUAGE on STREAM.
+   TYPE is the type whose template arguments are being displayed.
+   It can be a struct/class/union or a function.  */
+
+extern void c_type_print_template_args (const type_print_options *flags,
+					type *type,
+					ui_file *stream,
+					language language);
+
 #endif /* GDB_C_LANG_H */
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 821b78becf4..a4a3914909b 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -786,22 +786,26 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
-/* A helper for c_type_print_base_struct_union that displays template
-   parameters.
-
-   TYPE is the type whose template arguments are being displayed.
-
-   STREAM is the stream on which to print.  */
+/* See c-lang.h.  */
 
-static void
-c_type_print_template_args (const struct type_print_options *flags,
-			    struct type *type, struct ui_file *stream,
-			    enum language language)
+void
+c_type_print_template_args (const type_print_options *flags, type *type,
+			    ui_file *stream, language language)
 {
+  gdb_assert (type->code () == TYPE_CODE_STRUCT
+	      || type->code () == TYPE_CODE_UNION
+	      || type->code () == TYPE_CODE_FUNC);
+
   if (flags->raw || TYPE_N_TEMPLATE_ARGUMENTS (type) == 0)
     return;
 
   stream->wrap_here (4);
+
+  /* For functions we have to add a space here, for struct/class/unions
+     this is already taken care of in c_type_print_base_struct_union.  */
+  if (type->code () == TYPE_CODE_FUNC)
+    gdb_puts (" ", stream);
+
   gdb_printf (stream, _("[with "));
 
   for (int i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
@@ -823,7 +827,12 @@ c_type_print_template_args (const struct type_print_options *flags,
 	print_variable_value (sym, {}, stream, 0, language_def (language));
     }
 
-  gdb_puts (_("] "), stream);
+  gdb_puts (_("]"), stream);
+
+  /* For struct/class/unions printing of the type is not complete yet, so
+     we have to add a space here.  */
+  if (type->code () != TYPE_CODE_FUNC)
+    gdb_puts (" ", stream);
 }
 
 /* Use 'print_spaces', but take into consideration the
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 8b87d58dd9c..1eff94de246 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -7915,7 +7915,25 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
   /* If we've finished processing a top-level function, subsequent
      symbols go in the file symbol list.  */
   if (cu->get_builder ()->outermost_context_p ())
-    cu->list_in_scope = &cu->get_builder ()->get_file_symbols ();
+    cu->list_in_scope =  &cu->get_builder ()->get_file_symbols ();
+
+  /* In case of C++ functions, add template parameters to the type, similar
+     to class/struct/union types handled in process_structure_scope.  */
+  if (!template_args.empty () && cu->lang () == language_cplus)
+    {
+      struct type *type =  get_die_type (die, cu);
+      gdb_assert (type != nullptr && type->code () == TYPE_CODE_FUNC);
+
+      ALLOCATE_CPLUS_STRUCT_TYPE (type);
+      TYPE_N_TEMPLATE_ARGUMENTS (type) = template_args.size ();
+      TYPE_TEMPLATE_ARGUMENTS (type)
+	= XOBNEWVEC (&objfile->objfile_obstack,
+		     struct symbol *,
+		     TYPE_N_TEMPLATE_ARGUMENTS (type));
+      memcpy (TYPE_TEMPLATE_ARGUMENTS (type),
+	      template_args.data (),
+	      (TYPE_N_TEMPLATE_ARGUMENTS (type) * sizeof (struct symbol *)));
+    }
 }
 
 /* Process all the DIES contained within a lexical block scope.  Start
diff --git a/gdb/testsuite/gdb.cp/cp-relocate.exp b/gdb/testsuite/gdb.cp/cp-relocate.exp
index fb45313466b..81f03ce64e8 100644
--- a/gdb/testsuite/gdb.cp/cp-relocate.exp
+++ b/gdb/testsuite/gdb.cp/cp-relocate.exp
@@ -54,11 +54,11 @@ gdb_file_cmd ${binfile}
 set func1_name ""
 set func2_name ""
 gdb_test_multiple "info functions func<.>" "info functions" {
-    -re "\tint (\[^\r\]*func<1>\[^\r]*);" {
+    -re "\tint (\[^\r\]*func<1>\[^\r]*) \\\[with X = 1\\\];" {
 	set func1_name $expect_out(1,string)
 	exp_continue
     }
-    -re "\tint (\[^\r\]*func<2>\[^\r]*);" {
+    -re "\tint (\[^\r\]*func<2>\[^\r]*) \\\[with X = 2\\\];" {
 	set func2_name $expect_out(1,string)
 	exp_continue
     }
diff --git a/gdb/testsuite/gdb.cp/cpexprs.exp.tcl b/gdb/testsuite/gdb.cp/cpexprs.exp.tcl
index 085dfdd0678..a6c6df959fc 100644
--- a/gdb/testsuite/gdb.cp/cpexprs.exp.tcl
+++ b/gdb/testsuite/gdb.cp/cpexprs.exp.tcl
@@ -449,95 +449,95 @@ add {tclass<base>::do_something} \
     - \
     -
 add {flubber<int, int, int, int, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = int, E = int]} \
     - \
     flubber
 add {flubber<int, int, int, int, short>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = int, E = short]} \
     - \
     flubber
 add {flubber<int, int, int, int, long>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = int, E = long]} \
     - \
     flubber
 add {flubber<int, int, int, int, char>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = int, E = char]} \
     - \
     flubber
 add {flubber<int, int, int, short, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = short, E = int]} \
     - \
     flubber
 add {flubber<int, int, int, short, short>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = short, E = short]} \
     - \
     flubber
 add {flubber<int, int, int, short, long>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = short, E = long]} \
     - \
     flubber
 add {flubber<int, int, int, short, char>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = short, E = char]} \
     - \
     flubber
 add {flubber<int, int, int, long, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = long, E = int]} \
     - \
     flubber
 add {flubber<int, int, int, long, short>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = long, E = short]} \
     - \
     flubber
 add {flubber<int, int, int, long, long>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = long, E = long]} \
     - \
     flubber
 add {flubber<int, int, int, long, char>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = long, E = char]} \
     - \
     flubber
 add {flubber<int, int, int, char, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = char, E = int]} \
     - \
     flubber
 add {flubber<int, int, int, char, short>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = char, E = short]} \
     - \
     flubber
 add {flubber<int, int, int, char, long>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = char, E = long]} \
     - \
     flubber
 add {flubber<int, int, int, char, char>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = int, D = char, E = char]} \
     - \
     flubber
 add {flubber<int, int, short, int, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = short, D = int, E = int]} \
     - \
     flubber
 add {flubber<int, int, short, int, short>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = short, D = int, E = short]} \
     - \
     flubber
 add {flubber<int, int, short, int, long>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = short, D = int, E = long]} \
     - \
     flubber
 add {flubber<int, int, short, int, char>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = short, D = int, E = char]} \
     - \
     flubber
 add {flubber<int, int, short, short, int>} \
-    {void (void)} \
+    {void (void) [with A = int, B = int, C = short, D = short, E = int]} \
     - \
     flubber
 add {flubber<short, int, short, int, short>} \
-    {void (void)} \
+    {void (void) [with A = short, B = int, C = short, D = int, E = short]} \
     - \
     flubber
 add {flubber<long, short, long, short, long>} \
-    {void (void)} \
+    {void (void) [with A = long, B = short, C = long, D = short, E = long]} \
     - \
     flubber
 add {tclass<base>::do_something} \
diff --git a/gdb/testsuite/gdb.dwarf2/template-specification-full-name.exp b/gdb/testsuite/gdb.dwarf2/template-specification-full-name.exp
index eea7106d701..714a59f3568 100644
--- a/gdb/testsuite/gdb.dwarf2/template-specification-full-name.exp
+++ b/gdb/testsuite/gdb.dwarf2/template-specification-full-name.exp
@@ -81,4 +81,5 @@ if {![runto_main]} {
 }
 
 # Just a sanity check to make sure GDB slurped the symbols correctly.
-gdb_test "print apply<int>" " = {void \\(void\\)} $hex <apply<int>\\(\\)>"
+gdb_test "print apply<int>" \
+    " = {void \\(void\\) \\\[with T = int\\\]} $hex <apply<int>\\(\\)>"
