diff --git a/gdb/symtab.c b/gdb/symtab.c
index 16861e2bc92..ba0d5eed6b3 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4339,13 +4339,13 @@ search_symbols (const char *regexp, enum search_domain kind,
   struct symbol *sym;
   int found_misc = 0;
   static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_abs};
+    = {mst_data, mst_text, mst_unknown};
   static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_abs};
+    = {mst_bss, mst_file_text, mst_unknown};
   static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_abs};
+    = {mst_file_data, mst_solib_trampoline, mst_unknown};
   static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_abs};
+    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
   enum minimal_symbol_type ourtype;
   enum minimal_symbol_type ourtype2;
   enum minimal_symbol_type ourtype3;
@@ -4628,7 +4628,23 @@ print_symbol_info (enum search_domain kind,
   /* Typedef that is not a C++ class.  */
   if (kind == TYPES_DOMAIN
       && SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN)
-    typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
+    {
+      /* FIXME: For C (and C++) we end up with a difference in output here
+	 between how a typedef is printed, and non-typedefs are printed.
+	 The TYPEDEF_PRINT code places a ";" at the end in an attempt to
+	 appear C-like, while TYPE_PRINT doesn't.
+
+	 For the struct printing case below, things are worse, we force
+	 printing of the ";" in this function, which is going to be wrong
+	 for languages that don't require a ";" between statements.  */
+      if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF)
+	typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
+      else
+	{
+	  type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
+	  printf_filtered ("\n");
+	}
+    }
   /* variable, func, or typedef-that-is-c++-class.  */
   else if (kind < TYPES_DOMAIN
 	   || (kind == TYPES_DOMAIN
@@ -6080,14 +6096,6 @@ Prints the functions.\n"),
 				  _("functions")));
   set_cmd_completer_handle_brkchars (c, info_print_command_completer);
 
-  /* FIXME:  This command has at least the following problems:
-     1.  It prints builtin types (in a very strange and confusing fashion).
-     2.  It doesn't print right, e.g. with
-     typedef struct foo *FOO
-     type_print prints "FOO" when we want to make it (in this situation)
-     print "struct foo *".
-     I also think "ptype" or "whatis" is more likely to be useful (but if
-     there is much disagreement "info types" can be fixed).  */
   c = add_info ("types", info_types_command, _("\
 All type names, or those matching REGEXP.\n\
 Usage: info types [-q] [REGEXP]\n\
diff --git a/gdb/testsuite/gdb.base/info-types.c b/gdb/testsuite/gdb.base/info-types.c
new file mode 100644
index 00000000000..6746238801d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-types.c
@@ -0,0 +1,78 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+typedef int my_int_t;
+typedef float my_float_t;
+typedef my_int_t nested_int_t;
+typedef my_float_t nested_float_t;
+
+struct baz_t
+{
+  float f;
+  double d;
+};
+
+typedef struct baz_t baz_t;
+typedef struct baz_t baz;
+typedef baz_t nested_baz_t;
+typedef baz nested_baz;
+typedef struct baz_t *baz_ptr;
+
+enum enum_t
+{
+ AA, BB, CC
+};
+
+typedef enum enum_t my_enum_t;
+typedef my_enum_t nested_enum_t;
+
+volatile int var_a;
+volatile float var_b;
+volatile my_int_t var_c;
+volatile my_float_t var_d;
+volatile nested_int_t var_e;
+volatile nested_float_t var_f;
+volatile struct baz_t var_g;
+volatile baz_t var_h;
+volatile baz var_i;
+volatile nested_baz_t var_j;
+volatile nested_baz var_k;
+volatile baz_ptr var_l;
+volatile enum enum_t var_m;
+volatile my_enum_t var_n;
+volatile nested_enum_t var_o;
+
+#ifdef __cplusplus
+
+class CL
+{
+  int a;
+};
+
+typedef CL my_cl;
+typedef CL *my_ptr;
+
+volatile CL var_cpp_a;
+volatile my_cl var_cpp_b;
+volatile my_ptr var_cpp_c;
+
+#endif /* __cplusplus */
+
+int
+main ()
+{
+  asm ("" ::: "memory");
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-types.exp b/gdb/testsuite/gdb.base/info-types.exp
new file mode 100644
index 00000000000..a5808425398
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-types.exp
@@ -0,0 +1,109 @@
+# Copyright 2019 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check that 'info types' produces the expected output for an inferior
+# containing a number of different types.
+
+# Only test C++ if we are able.  Always use C.
+if { [skip_cplus_tests] || [get_compiler_info "c++"] } {
+    set lang {c}
+} else {
+    set lang {c c++}
+}
+
+foreach l $lang {
+    set dir "$l"
+    remote_exec host "rm -rf [standard_output_file ${dir}]"
+    remote_exec host "mkdir -p [standard_output_file ${dir}]"
+}
+
+# Run 'info types' test, compiling the test file for language LANG,
+# which should be either 'c' or 'c++'.
+proc run_test { lang } {
+    global testfile
+    global srcfile
+    global binfile
+    global subdir
+    global srcdir
+    global compile_flags
+
+    standard_testfile .c
+
+    if {[prepare_for_testing "failed to prepare" \
+	     "${lang}/${testfile}" $srcfile "debug $lang"]} {
+	return -1
+    }
+
+    if ![runto_main] then {
+	fail "can't run to main"
+	return 0
+    }
+
+    if { $lang == "c++" } {
+	set output_re \
+	    [multi_line \
+		 "All defined types:" \
+		 "" \
+		 "File .*:" \
+		 "59:\[\t \]+CL;" \
+		 "21:\[\t \]+baz_t;" \
+		 "33:\[\t \]+enum_t;" \
+		 "28:\[\t \]+typedef baz_t baz;" \
+		 "31:\[\t \]+typedef baz_t \\* baz_ptr;" \
+		 "27:\[\t \]+typedef baz_t baz_t;" \
+		 "\[\t \]+double" \
+		 "\[\t \]+float" \
+		 "\[\t \]+int" \
+		 "64:\[\t \]+typedef CL my_cl;" \
+		 "38:\[\t \]+typedef enum_t my_enum_t;" \
+		 "17:\[\t \]+typedef float my_float_t;" \
+		 "16:\[\t \]+typedef int my_int_t;" \
+		 "65:\[\t \]+typedef CL \\* my_ptr;" \
+		 "30:\[\t \]+typedef baz_t nested_baz;" \
+		 "29:\[\t \]+typedef baz_t nested_baz_t;" \
+		 "39:\[\t \]+typedef enum_t nested_enum_t;" \
+		 "19:\[\t \]+typedef float nested_float_t;" \
+		 "18:\[\t \]+typedef int nested_int_t;" \
+		 "\[\t \]+unsigned int"]
+    } else {
+	set output_re \
+	    [multi_line \
+		 "All defined types:" \
+		 "" \
+		 "File .*:" \
+		 "28:\[\t \]+typedef struct baz_t baz;" \
+		 "31:\[\t \]+typedef struct baz_t \\* baz_ptr;" \
+		 "21:\[\t \]+struct baz_t;" \
+		 "\[\t \]+double" \
+		 "33:\[\t \]+enum enum_t;" \
+		 "\[\t \]+float" \
+		 "\[\t \]+int" \
+		 "38:\[\t \]+typedef enum enum_t my_enum_t;" \
+		 "17:\[\t \]+typedef float my_float_t;" \
+		 "16:\[\t \]+typedef int my_int_t;" \
+		 "30:\[\t \]+typedef struct baz_t nested_baz;" \
+		 "29:\[\t \]+typedef struct baz_t nested_baz_t;" \
+		 "39:\[\t \]+typedef enum enum_t nested_enum_t;" \
+		 "19:\[\t \]+typedef float nested_float_t;" \
+		 "18:\[\t \]+typedef int nested_int_t;" \
+		 "\[\t \]+unsigned int" ]
+    }
+
+    gdb_test "info types" $output_re
+}
+
+foreach_with_prefix l $lang {
+    run_test $l
+}
