Short version:
* -Wno-missing-include-dirs  had no effect as the warning was always on
* For CPP-only options like -idirafter, no warning was shown.

This patch tries to address both, i.e. cpp's include-dir diagnostics are
shown as well – and silencing the diagnostic works as well.

OK for mainline?

Tobias

PS:  BACKGROUND and LONG DESCRIPTION

C/C++ by default have disabled the -Wmissing-include-dirs warning.
Fortran by default has that warning enabled.

The value is actually stored at two places (cf. c-family/c.opt):
  Wmissing-include-dirs
  ... CPP(warn_missing_include_dirs) Var(cpp_warn_missing_include_dirs) Init(0)

For CPP, that value always needs to initialized – and it is used
in gcc/incpath.c as
              cpp_options *opts = cpp_get_options (pfile);
              if (opts->warn_missing_include_dirs && cur->user_supplied_p)
                cpp_warning (pfile, CPP_W_MISSING_INCLUDE_DIRS, "%s: %s",

Additionally, there is cpp_warn_missing_include_dirs which is used by
Fortran – and which consists of
  global_options.x_cpp_warn_missing_include_dirs
  global_options_set._cpp_warn_missing_include_dirs

The flag processing happens as described in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55534#c11
in short:
  - First gfc_init_options is called
  - Then for reach command-line option gfc_handle_option
  - Finally gfc_post_options

Currently:
- gfc_init_options: Sets cpp_warn_missing_include_dirs
  (unconditionally as unset)
- gfc_handle_option: Always warns about the missing include dir
- before gfc_post_options: set_option is called, which sets
  cpp_warn_missing_include_dirs – but that's too late.

Additionally, as mentioned above – pfile's warn_missing_include_dirs
is never properly set.

 * * *

This patch fixes those issues:
* Now -Wno-missing-include-dirs does silence the warnings
* CPP now also properly does warn.

Example (initial version):
$ gfortran-trunk ../empty.f90 -c -cpp -idirafter /fdaf/ -I bar/ 
-Wmissing-include-dirs
f951: Warning: Nonexistent include directory ‘bar//’ [-Wmissing-include-dirs]
<built-in>: Warning: /fdaf/: No such file or directory
<built-in>: Warning: bar/: No such file or directory

In order to avoid the double output for -I, I disabled the Fortran output if
CPP is enabled. Additionally, I had to use the cpp_reason_option_codes to
print the flag in brackets.
Fixed/final output is:

<built-in>: Warning: /fdaf/: No such file or directory [-Wmissing-include-dirs]
<built-in>: Warning: bar/: No such file or directory [-Wmissing-include-dirs]

-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 
München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas 
Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht 
München, HRB 106955
Fortran: Fix -Wno-missing-include-dirs handling [PR55534]

gcc/fortran/ChangeLog:

	PR fortran/55534
	* cpp.c: Define GCC_C_COMMON_C for #include "options.h" to make
	cpp_reason_option_codes available.
	(gfc_cpp_register_include_paths): Make static, set pfile's
	warn_missing_include_dirs and move before caller.
	(gfc_cpp_init_cb): New, cb code moved from ...
	(gfc_cpp_init_0): ... here.
	(gfc_cpp_post_options): Call gfc_cpp_init_cb.
	(cb_cpp_diagnostic_cpp_option): New. As implemented in c-family
	to match CppReason flags to -W... names.
	(cb_cpp_diagnostic): Use it to replace single special case.
	* cpp.h (gfc_cpp_register_include_paths): Remove as now static.
	* gfortran.h (gfc_check_include_dirs): New prototype.
	* options.c (gfc_init_options): Don't set -Wmissing-include-dirs.
	(gfc_post_options): Set it here after commandline processing.
	* scanner.c (gfc_do_check_include_dirs, gfc_check_include_dirs):
	New. Diagnostic moved from ...
	(add_path_to_list): ... here, which came before cmdline processing.
	* scanner.h (struct gfc_directorylist): Reorder for alignment issues,
	add new 'bool warn'.

 gcc/fortran/cpp.c      | 106 ++++++++++++++++++++++++++++++-------------------
 gcc/fortran/cpp.h      |   2 -
 gcc/fortran/gfortran.h |   1 +
 gcc/fortran/options.c  |  14 +++----
 gcc/fortran/scanner.c  |  58 +++++++++++++++++++--------
 gcc/fortran/scanner.h  |   2 +-
 6 files changed, 116 insertions(+), 67 deletions(-)

diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
index 83c4517acdb..3ff895455e9 100644
--- a/gcc/fortran/cpp.c
+++ b/gcc/fortran/cpp.c
@@ -19,11 +19,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+
+#define GCC_C_COMMON_C
+#include "options.h"  /* For cpp_reason_option_codes. */
+#undef GCC_C_COMMON_C
+
 #include "target.h"
 #include "gfortran.h"
 #include "diagnostic.h"
 
-
 #include "toplev.h"
 
 #include "../../libcpp/internal.h"
@@ -240,6 +244,18 @@ gfc_cpp_temporary_file (void)
   return gfc_cpp_option.temporary_filename;
 }
 
+static void
+gfc_cpp_register_include_paths (void)
+{
+  int cxx_stdinc = 0;
+  cpp_get_options (cpp_in)->warn_missing_include_dirs
+    = global_options.x_cpp_warn_missing_include_dirs;
+  register_include_chains (cpp_in, gfc_cpp_option.sysroot,
+			   gfc_cpp_option.prefix, gfc_cpp_option.multilib,
+			   gfc_cpp_option.standard_include_paths, cxx_stdinc,
+			   gfc_cpp_option.verbose);
+}
+
 void
 gfc_cpp_init_options (unsigned int decoded_options_count,
 		      struct cl_decoded_option *decoded_options ATTRIBUTE_UNUSED)
@@ -435,6 +451,37 @@ gfc_cpp_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED
   return result;
 }
 
+/* This function needs to be called before gfc_cpp_register_include_paths
+   as the latter may diagnose missing include directories.  */
+static void
+gfc_cpp_init_cb (void)
+{
+  struct cpp_callbacks *cb;
+
+  cb = cpp_get_callbacks (cpp_in);
+  cb->file_change = cb_file_change;
+  cb->line_change = cb_line_change;
+  cb->ident = cb_ident;
+  cb->def_pragma = cb_def_pragma;
+  cb->diagnostic = cb_cpp_diagnostic;
+
+  if (gfc_cpp_option.dump_includes)
+    cb->include = cb_include;
+
+  if ((gfc_cpp_option.dump_macros == 'D')
+      || (gfc_cpp_option.dump_macros == 'N'))
+    {
+      cb->define = cb_define;
+      cb->undef  = cb_undef;
+    }
+
+  if (gfc_cpp_option.dump_macros == 'U')
+    {
+      cb->before_define = dump_queued_macros;
+      cb->used_define = cb_used_define;
+      cb->used_undef = cb_used_undef;
+    }
+}
 
 void
 gfc_cpp_post_options (void)
@@ -498,6 +545,7 @@ gfc_cpp_post_options (void)
      way libcpp will do it, namely, with no charset conversion but with
      skipping of a UTF-8 BOM if present.  */
   diagnostic_initialize_input_context (global_dc, nullptr, true);
+  gfc_cpp_init_cb ();
 
   gfc_cpp_register_include_paths ();
 }
@@ -506,32 +554,6 @@ gfc_cpp_post_options (void)
 void
 gfc_cpp_init_0 (void)
 {
-  struct cpp_callbacks *cb;
-
-  cb = cpp_get_callbacks (cpp_in);
-  cb->file_change = cb_file_change;
-  cb->line_change = cb_line_change;
-  cb->ident = cb_ident;
-  cb->def_pragma = cb_def_pragma;
-  cb->diagnostic = cb_cpp_diagnostic;
-
-  if (gfc_cpp_option.dump_includes)
-    cb->include = cb_include;
-
-  if ((gfc_cpp_option.dump_macros == 'D')
-      || (gfc_cpp_option.dump_macros == 'N'))
-    {
-      cb->define = cb_define;
-      cb->undef  = cb_undef;
-    }
-
-  if (gfc_cpp_option.dump_macros == 'U')
-    {
-      cb->before_define = dump_queued_macros;
-      cb->used_define = cb_used_define;
-      cb->used_undef = cb_used_undef;
-    }
-
   /* Initialize the print structure.  Setting print.src_line to -1 here is
      a trick to guarantee that the first token of the file will cause
      a linemarker to be output by maybe_print_line.  */
@@ -723,17 +745,6 @@ gfc_cpp_add_include_path_after (char *path, bool user_supplied)
   add_path (path, INC_AFTER, cxx_aware, user_supplied);
 }
 
-void
-gfc_cpp_register_include_paths (void)
-{
-  int cxx_stdinc = 0;
-  register_include_chains (cpp_in, gfc_cpp_option.sysroot,
-			   gfc_cpp_option.prefix, gfc_cpp_option.multilib,
-			   gfc_cpp_option.standard_include_paths, cxx_stdinc,
-			   gfc_cpp_option.verbose);
-}
-
-
 
 static void scan_translation_unit_trad (cpp_reader *);
 static void account_for_newlines (const unsigned char *, size_t);
@@ -1043,6 +1054,21 @@ cb_used_define (cpp_reader *pfile, location_t line ATTRIBUTE_UNUSED,
   cpp_define_queue = q;
 }
 
+/* Return the gcc option code associated with the reason for a cpp
+   message, or 0 if none.  */
+
+static int
+cb_cpp_diagnostic_cpp_option (enum cpp_warning_reason reason)
+{
+  const struct cpp_reason_option_codes_t *entry;
+
+  for (entry = cpp_reason_option_codes; entry->reason != CPP_W_NONE; entry++)
+    if (entry->reason == reason)
+      return entry->option_code;
+  return 0;
+}
+
+
 /* Callback from cpp_error for PFILE to print diagnostics from the
    preprocessor.  The diagnostic is of type LEVEL, with REASON set
    to the reason code if LEVEL is represents a warning, at location
@@ -1089,8 +1115,8 @@ cb_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
     }
   diagnostic_set_info_translated (&diagnostic, msg, ap,
 				  richloc, dlevel);
-  if (reason == CPP_W_WARNING_DIRECTIVE)
-    diagnostic_override_option_index (&diagnostic, OPT_Wcpp);
+  diagnostic_override_option_index (&diagnostic,
+				    cb_cpp_diagnostic_cpp_option (reason));
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
   if (level == CPP_DL_WARNING_SYSHDR)
     global_dc->dc_warn_system_headers = save_warn_system_headers;
diff --git a/gcc/fortran/cpp.h b/gcc/fortran/cpp.h
index f642c7745f7..5cb7e5a9c34 100644
--- a/gcc/fortran/cpp.h
+++ b/gcc/fortran/cpp.h
@@ -50,6 +50,4 @@ void gfc_cpp_done (void);
 void gfc_cpp_add_include_path (char *path, bool user_supplied);
 void gfc_cpp_add_include_path_after (char *path, bool user_supplied);
 
-void gfc_cpp_register_include_paths (void);
-
 #endif /* GFC_CPP_H */
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index fdf556eef3d..b02c434295c 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3031,6 +3031,7 @@ void gfc_scanner_init_1 (void);
 void gfc_add_include_path (const char *, bool, bool, bool);
 void gfc_add_intrinsic_modules_path (const char *);
 void gfc_release_include_path (void);
+void gfc_check_include_dirs (void);
 FILE *gfc_open_included_file (const char *, bool, bool);
 
 int gfc_at_end (void);
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 847e20e8829..a1ac760dd96 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -159,14 +159,7 @@ gfc_init_options (unsigned int decoded_options_count,
 			   | GFC_FPE_UNDERFLOW;
   gfc_option.rtcheck = 0;
 
-  /* ??? Wmissing-include-dirs is disabled by default in C/C++ but
-     enabled by default in Fortran.  Ideally, we should express this
-     in .opt, but that is not supported yet.  */
-  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
-		       cpp_warn_missing_include_dirs, 1);
-
   set_dec_flags (0);
-
   set_default_std_flags ();
 
   /* Initialize cpp-related options.  */
@@ -260,6 +253,13 @@ gfc_post_options (const char **pfilename)
   char *source_path;
   int i;
 
+  /* This needs to be after the commandline has been processed.
+     In Fortran, the options is by default enabled, in C/C++
+     by default disabled.  */
+  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+		       cpp_warn_missing_include_dirs, 1);
+  gfc_check_include_dirs ();
+
   /* Finalize DEC flags.  */
   post_dec_flags (flag_dec);
 
diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c
index 39db0994b62..93446c90b0e 100644
--- a/gcc/fortran/scanner.c
+++ b/gcc/fortran/scanner.c
@@ -298,6 +298,46 @@ gfc_scanner_done_1 (void)
     }
 }
 
+/* In order that -W(no-)missing-include-dirs works, the diagnostic can only be
+   run after processing the commandline.  */
+static void
+gfc_do_check_include_dirs (gfc_directorylist **list)
+{
+  struct stat st;
+  gfc_directorylist *prev, *q, *n;
+  prev = NULL;
+  n = *list;
+  while (n)
+    {
+      q = n; n = n->next;
+      if (stat (q->path, &st))
+	{
+	  if (errno != ENOENT)
+	    gfc_warning_now (0, "Include directory %qs: %s", q->path,
+			     xstrerror(errno));
+	  else if (q->warn && !gfc_cpp_enabled ())
+	    gfc_warning_now (OPT_Wmissing_include_dirs,
+			     "Nonexistent include directory %qs", q->path);
+	}
+      else if (!S_ISDIR (st.st_mode))
+	gfc_fatal_error ("%qs is not a directory", q->path);
+      else
+	continue;
+      if (prev == NULL)
+	*list = n;
+      else
+	prev->next = n;
+      free (q->path);
+      free (q);
+    }
+}
+
+void
+gfc_check_include_dirs ()
+{
+  gfc_do_check_include_dirs (&include_dirs);
+  gfc_do_check_include_dirs (&intrinsic_modules_dirs);
+}
 
 /* Adds path to the list pointed to by list.  */
 
@@ -308,7 +348,6 @@ add_path_to_list (gfc_directorylist **list, const char *path,
   gfc_directorylist *dir;
   const char *p;
   char *q;
-  struct stat st;
   size_t len;
   int i;
   
@@ -326,22 +365,6 @@ add_path_to_list (gfc_directorylist **list, const char *path,
   while (i >=0 && IS_DIR_SEPARATOR (q[i]))
     q[i--] = '\0';
 
-  if (stat (q, &st))
-    {
-      if (errno != ENOENT)
-	gfc_warning_now (0, "Include directory %qs: %s", path,
-			 xstrerror(errno));
-      else if (warn)
-	gfc_warning_now (OPT_Wmissing_include_dirs,
-			 "Nonexistent include directory %qs", path);
-      return;
-    }
-  else if (!S_ISDIR (st.st_mode))
-    {
-      gfc_fatal_error ("%qs is not a directory", path);
-      return;
-    }
-
   if (head || *list == NULL)
     {
       dir = XCNEW (gfc_directorylist);
@@ -362,6 +385,7 @@ add_path_to_list (gfc_directorylist **list, const char *path,
   if (head)
     *list = dir;
   dir->use_for_modules = use_for_modules;
+  dir->warn = warn;
   dir->path = XCNEWVEC (char, strlen (p) + 2);
   strcpy (dir->path, p);
   strcat (dir->path, "/");	/* make '/' last character */
diff --git a/gcc/fortran/scanner.h b/gcc/fortran/scanner.h
index 0bad63f4ffb..8782fe6ccc5 100644
--- a/gcc/fortran/scanner.h
+++ b/gcc/fortran/scanner.h
@@ -23,8 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 typedef struct gfc_directorylist
 {
   char *path;
-  bool use_for_modules;
   struct gfc_directorylist *next;
+  bool use_for_modules, warn;
 }
 gfc_directorylist;
 

Reply via email to