diff --git a/gdb/NEWS b/gdb/NEWS
index 25e67e43c88..e721f3bde44 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -147,6 +147,10 @@ show print frame-info
   'frame', 'stepi'.  The python frame filtering also respect this setting.
   The 'backtrace' '-frame-info' option can override this global setting.
 
+info modules [-q] [REGEXP]
+  Return a list of Fortran modules matching REGEXP, or all modules if
+  no REGEXP is given.
+
 * Changed commands
 
 help
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1208e4f615e..3f97707c4c1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18784,6 +18784,16 @@
 is printed only if its name matches @var{regexp} and its type matches
 @var{type_regexp}.
 
+@kindex info modules
+@cindex modules
+@item info modules [-q] [@var{regexp}]
+List all Fortran modules in the program, or all modules matching the
+optional regular expression @var{regexp}.
+
+The optional flag @samp{-q}, which stands for @samp{quiet}, disables
+printing header information and messages explaining why no modules
+have been printed.
+
 @kindex info classes
 @cindex Objective-C, classes and selectors
 @item info classes
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index a78f818e0e8..b6225845935 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4021,6 +4021,10 @@ dw2_symtab_iter_next (struct dw2_symtab_iterator *iter)
 	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
 		continue;
 	      break;
+	    case MODULE_DOMAIN:
+	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
+		continue;
+	      break;
 	    default:
 	      break;
 	    }
@@ -5043,6 +5047,10 @@ dw2_expand_marked_cus
 	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE)
 		continue;
 	      break;
+	    case MODULES_DOMAIN:
+	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
+		continue;
+	      break;
 	    default:
 	      break;
 	    }
@@ -5949,6 +5957,15 @@ dw2_debug_names_iterator::next ()
 	  goto again;
 	}
       break;
+    case MODULE_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_module:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
     default:
       break;
     }
@@ -5985,6 +6002,14 @@ dw2_debug_names_iterator::next ()
 	  goto again;
 	}
       break;
+    case MODULES_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_module:
+	  break;
+	default:
+	  goto again;
+	}
     default:
       break;
     }
@@ -8712,7 +8737,8 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
 	      add_partial_namespace (pdi, lowpc, highpc, set_addrmap, cu);
 	      break;
 	    case DW_TAG_module:
-	      add_partial_module (pdi, lowpc, highpc, set_addrmap, cu);
+	      if (!pdi->is_declaration)
+		add_partial_module (pdi, lowpc, highpc, set_addrmap, cu);
 	      break;
 	    case DW_TAG_imported_unit:
 	      {
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 31b6d597773..44af8031fc4 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1272,6 +1272,8 @@ recursively_search_psymtabs
 	  QUIT;
 
 	  if ((domain == ALL_DOMAIN
+	       || (domain == MODULES_DOMAIN
+		   && (*psym)->domain == MODULE_DOMAIN)
 	       || (domain == VARIABLES_DOMAIN
 		   && (*psym)->aclass != LOC_TYPEDEF
 		   && (*psym)->aclass != LOC_BLOCK)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 8a551f1575a..f41ea3290df 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -297,6 +297,7 @@ search_domain_name (enum search_domain e)
     case VARIABLES_DOMAIN: return "VARIABLES_DOMAIN";
     case FUNCTIONS_DOMAIN: return "FUNCTIONS_DOMAIN";
     case TYPES_DOMAIN: return "TYPES_DOMAIN";
+    case MODULES_DOMAIN: return "MODULES_DOMAIN";
     case ALL_DOMAIN: return "ALL_DOMAIN";
     default: gdb_assert_not_reached ("bad search_domain");
     }
@@ -4474,7 +4475,7 @@ search_symbols (const char *regexp, enum search_domain kind,
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
-  gdb_assert (kind <= TYPES_DOMAIN);
+  gdb_assert (kind <= MODULES_DOMAIN);
 
   ourtype = types[kind];
   ourtype2 = types2[kind];
@@ -4648,7 +4649,10 @@ search_symbols (const char *regexp, enum search_domain kind,
 								     sym)))
 			      || (kind == TYPES_DOMAIN
 				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN))))
+				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+			      || (kind == MODULES_DOMAIN
+				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+				  && SYMBOL_LINE (sym) != 0))))
 		    {
 		      /* match */
 		      result.emplace_back (i, sym);
@@ -4779,6 +4783,11 @@ print_symbol_info (enum search_domain kind,
 
       printf_filtered (";\n");
     }
+  /* Printing of modules is currently done here, maybe at some future
+     point we might want a language specific method to print the module
+     symbol so that we can customise the output more.  */
+  else if (kind == MODULES_DOMAIN)
+    printf_filtered ("%s\n", SYMBOL_PRINT_NAME (sym));
 }
 
 /* This help function for symtab_symbol_info() prints information
@@ -4819,11 +4828,11 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
 		    const char *t_regexp, int from_tty)
 {
   static const char * const classnames[] =
-    {"variable", "function", "type"};
+    {"variable", "function", "type", "module"};
   const char *last_filename = "";
   int first = 1;
 
-  gdb_assert (kind <= TYPES_DOMAIN);
+  gdb_assert (kind <= MODULES_DOMAIN);
 
   if (regexp != nullptr && *regexp == '\0')
     regexp = nullptr;
@@ -5042,6 +5051,22 @@ info_types_command_completer (struct cmd_list_element *ignore,
   symbol_completer (ignore, tracker, text, word);
 }
 
+/* Implement the 'info modules' command.  */
+
+static void
+info_modules_command (const char *args, int from_tty)
+{
+  info_types_options opts;
+
+  auto grp = make_info_types_options_def_group (&opts);
+  gdb::option::process_options
+    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+  if (args != nullptr && *args == '\0')
+    args = nullptr;
+  symtab_symbol_info (opts.quiet, true, args, MODULES_DOMAIN, NULL,
+		      from_tty);
+}
+
 /* Breakpoint all functions matching regular expression.  */
 
 void
@@ -6365,6 +6390,10 @@ Options:\n\
   c = add_info ("sources", info_sources_command, info_sources_help.c_str ());
   set_cmd_completer_handle_brkchars (c, info_sources_command_completer);
 
+  c = add_info ("modules", info_modules_command,
+		_("All module names, or those matching REGEXP."));
+  set_cmd_completer_handle_brkchars (c, info_types_command_completer);
+
   add_com ("rbreak", class_breakpoint, rbreak_command,
 	   _("Set a breakpoint for all functions matching REGEXP."));
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dc65409dd24..ba8df9191ff 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -829,8 +829,11 @@ enum search_domain
   /* All defined types */
   TYPES_DOMAIN = 2,
 
+  /* All modules.  */
+  MODULES_DOMAIN = 3,
+
   /* Any type.  */
-  ALL_DOMAIN = 3
+  ALL_DOMAIN = 4
 };
 
 extern const char *search_domain_name (enum search_domain);
diff --git a/gdb/testsuite/gdb.fortran/info-modules.exp b/gdb/testsuite/gdb.fortran/info-modules.exp
new file mode 100644
index 00000000000..f961d28b000
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/info-modules.exp
@@ -0,0 +1,66 @@
+# 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/>.
+
+# This file tests 'info modules'.
+
+load_lib "fortran.exp"
+
+if { [skip_fortran_tests] } { continue }
+
+standard_testfile info-types.f90 info-types-2.f90
+
+if { [prepare_for_testing "failed to prepare" $testfile \
+	  [list $srcfile $srcfile2] {debug f90}] } {
+    return -1
+}
+
+if { ![runto MAIN__] } {
+    perror "Could not run to breakpoint `MAIN__'."
+    continue
+}
+
+gdb_test "info modules" \
+    [multi_line \
+	 "All defined modules:" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
+
+gdb_test "info modules 1" \
+    [multi_line \
+	 "All modules matching regular expression \"1\":" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
+
+gdb_test "info modules 2" \
+    [multi_line \
+	 "All modules matching regular expression \"2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" ]
+
+gdb_test "info modules mod" \
+    [multi_line \
+	 "All modules matching regular expression \"mod\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
diff --git a/gdb/testsuite/gdb.fortran/info-types-2.f90 b/gdb/testsuite/gdb.fortran/info-types-2.f90
new file mode 100644
index 00000000000..a4044184233
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/info-types-2.f90
@@ -0,0 +1,20 @@
+! 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 2 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/>.
+
+! Comment just to change the line number on which
+! mod2 is defined.
+module mod2
+  integer :: mod2_var_1 = 123
+end module mod2
diff --git a/gdb/testsuite/gdb.fortran/info-types.exp b/gdb/testsuite/gdb.fortran/info-types.exp
index 30646287ee9..1707de88bda 100644
--- a/gdb/testsuite/gdb.fortran/info-types.exp
+++ b/gdb/testsuite/gdb.fortran/info-types.exp
@@ -19,9 +19,10 @@ load_lib "fortran.exp"
 
 if { [skip_fortran_tests] } { continue }
 
-standard_testfile .f90
+standard_testfile info-types.f90 info-types-2.f90
 
-if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}] } {
+if { [prepare_for_testing "failed to prepare" $testfile \
+	  [list $srcfile $srcfile2] {debug f90}] } {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.fortran/info-types.f90 b/gdb/testsuite/gdb.fortran/info-types.f90
index 0e27e1ddf08..ec52ef98efc 100644
--- a/gdb/testsuite/gdb.fortran/info-types.f90
+++ b/gdb/testsuite/gdb.fortran/info-types.f90
@@ -21,6 +21,7 @@ end module mod1
 
 program info_types_test
   use mod1
+  use mod2
 
   type :: s1
      integer :: a
@@ -30,7 +31,7 @@ program info_types_test
   type (s1) :: var_a
   type (m1t1) :: var_b
 
-  var_a%a = 1
+  var_a%a = 1 + mod2_var_1
   var_b%b = 2
   l = .FALSE.
 end program info_types_test
