Use find_opt instead of linear search through options in
handle_pragma_diagnostic (PR 49654) and reject non-warning options and
options not valid for the current language (PR 49655).

Boot&tested on x86_64-linux-gnu.

OK?

gcc/testsuite/ChangeLog:

2015-09-22  Manuel López-Ibáñez  <m...@gcc.gnu.org>

    PR c/49655
    * gcc.dg/pragma-diag-6.c: New test.

gcc/ChangeLog:

2015-09-22  Manuel López-Ibáñez  <m...@gcc.gnu.org>

    PR c/49655
    * opts.h (write_langs): Declare.
    * opts-global.c (write_langs): Make it extern.

gcc/c-family/ChangeLog:

2015-09-22  Manuel López-Ibáñez  <m...@gcc.gnu.org>

    PR c/49654
    PR c/49655
    * c-pragma.c (handle_pragma_diagnostic): Detect non-warning
    options and options not valid for the current language.
Index: gcc/c-family/c-pragma.c
===================================================================
--- gcc/c-family/c-pragma.c     (revision 227965)
+++ gcc/c-family/c-pragma.c     (working copy)
@@ -747,26 +747,44 @@ handle_pragma_diagnostic(cpp_reader *ARG
       warning_at (loc, OPT_Wpragmas,
                  "missing option after %<#pragma GCC diagnostic%> kind");
       return;
     }
 
+  const char *option_string = TREE_STRING_POINTER (x);
+  /* option_string + 1 to skip the initial '-' */
+  unsigned int lang_mask = c_common_option_lang_mask () | CL_COMMON;
+  unsigned int option_index = find_opt (option_string + 1, lang_mask);
+  if (option_index == OPT_SPECIAL_unknown)
+    {
+      warning_at (loc, OPT_Wpragmas,
+                 "unknown option after %<#pragma GCC diagnostic%> kind");
+      return;
+    }
+  else if (!(cl_options[option_index].flags & CL_WARNING))
+    {
+      warning_at (loc, OPT_Wpragmas,
+                 "%qs is not an option that controls warnings", option_string);
+      return;
+    }
+  else if (!(cl_options[option_index].flags & lang_mask))
+    {
+      char * ok_langs = write_langs (cl_options[option_index].flags);
+      char * bad_lang = write_langs (c_common_option_lang_mask ());
+      warning_at (loc, OPT_Wpragmas,
+                 "option %qs is valid for %s but not for %s",
+                 option_string, ok_langs, bad_lang);
+      free (ok_langs);
+      free (bad_lang);
+      return;
+    }
+
   struct cl_option_handlers handlers;
   set_default_handlers (&handlers);
-
-  unsigned int option_index;
-  const char *option_string = TREE_STRING_POINTER (x);
-  for (option_index = 0; option_index < cl_options_count; option_index++)
-    if (strcmp (cl_options[option_index].opt_text, option_string) == 0)
-      {
-       control_warning_option (option_index, (int) kind, kind != DK_IGNORED,
-                               input_location, c_family_lang_mask, &handlers,
-                               &global_options, &global_options_set,
-                               global_dc);
-       return;
-      }
-  warning_at (loc, OPT_Wpragmas,
-             "unknown option after %<#pragma GCC diagnostic%> kind");
+  control_warning_option (option_index, (int) kind, kind != DK_IGNORED,
+                         loc, lang_mask, &handlers,
+                         &global_options, &global_options_set,
+                         global_dc);
 }
 
 /*  Parse #pragma GCC target (xxx) to set target specific options.  */
 static void
 handle_pragma_target(cpp_reader *ARG_UNUSED(dummy))
Index: gcc/testsuite/gcc.dg/pragma-diag-6.c
===================================================================
--- gcc/testsuite/gcc.dg/pragma-diag-6.c        (revision 0)
+++ gcc/testsuite/gcc.dg/pragma-diag-6.c        (revision 0)
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+#pragma GCC diagnostic error "-Wnoexcept" /* { dg-warning "is valid for 
C../ObjC.. but not for C" } */
+#pragma GCC diagnostic error "-fstrict-aliasing" /* { dg-warning "not an 
option that controls warnings" } */
+#pragma GCC diagnostic error "-Werror" /* { dg-warning "not an option that 
controls warnings" } */
+int i;
Index: gcc/opts.h
===================================================================
--- gcc/opts.h  (revision 227965)
+++ gcc/opts.h  (working copy)
@@ -366,10 +366,11 @@ extern void control_warning_option (unsi
                                    unsigned int lang_mask,
                                    const struct cl_option_handlers *handlers,
                                    struct gcc_options *opts,
                                    struct gcc_options *opts_set,
                                    diagnostic_context *dc);
+extern char *write_langs (unsigned int mask);
 extern void print_ignored_options (void);
 extern void handle_common_deferred_options (void);
 extern bool common_handle_option (struct gcc_options *opts,
                                  struct gcc_options *opts_set,
                                  const struct cl_decoded_option *decoded,
Index: gcc/opts-global.c
===================================================================
--- gcc/opts-global.c   (revision 227965)
+++ gcc/opts-global.c   (working copy)
@@ -52,11 +52,11 @@ static vec<const_char_p> ignored_options
 const char **in_fnames;
 unsigned num_in_fnames;
 
 /* Return a malloced slash-separated list of languages in MASK.  */
 
-static char *
+char *
 write_langs (unsigned int mask)
 {
   unsigned int n = 0, len = 0;
   const char *lang_name;
   char *result;

Reply via email to