public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC PATCH] parse #pragma GCC diagnostic in libcpp
@ 2015-07-29  4:43 Manuel López-Ibáñez
  2015-08-21 17:44 ` Manuel López-Ibáñez
  2015-09-25 15:58 ` Dodji Seketeli
  0 siblings, 2 replies; 7+ messages in thread
From: Manuel López-Ibáñez @ 2015-07-29  4:43 UTC (permalink / raw)
  To: Gcc Patch List
  Cc: Joseph S. Myers, Jason Merrill, Dodji Seketeli, Marek Polacek

[-- Attachment #1: Type: text/plain, Size: 1088 bytes --]

Currently, #pragma GCC diagnostic is handled entirely by the FE. This
has several drawbacks:

* PR c++/53431 - C++ preprocessor ignores #pragma GCC diagnostic: The
C++ parser lexes (and preprocesses) before handling the pragmas.

* PR 53920 - "gcc -E" does not honor #pragma GCC diagnostic ignored
"-Wunused-macro": Because -E does not invoke the FE code that parses
the FE pragmas.

* PR 64698 - preprocessor ignores #pragma GCC diagnostic when using
-save-temps. Same issue as above.

The following patch moves the handling of #pragma GCC diagnostic to
libcpp but keeps the interface with the diagnostic machinery in the FE
by using a call-back function.

One serious problem with this approach is that the preprocessor will
delete the pragmas from the preprocessed output, thus '-E',
'-save-temps'  will not contain the pragmas and compiling the
preprocessed file will trigger the warnings that they were meant to
suppress.  Any ideas how to prevent libcpp from deleting the #pragmas?

No Changelog since this is not a request for approval, but comments are welcome.

Cheers,

Manuel.

[-- Attachment #2: cpp_pragma.diff --]
[-- Type: text/plain, Size: 12672 bytes --]

Index: gcc/c-family/c-opts.c
===================================================================
--- gcc/c-family/c-opts.c	(revision 226219)
+++ gcc/c-family/c-opts.c	(working copy)
@@ -969,10 +969,11 @@ c_common_post_options (const char **pfil
     }
 
   cb = cpp_get_callbacks (parse_in);
   cb->file_change = cb_file_change;
   cb->dir_change = cb_dir_change;
+  cb->handle_pragma_diagnostic = cb_handle_pragma_diagnostic;
   cpp_post_options (parse_in);
   init_global_opts_from_cpp (&global_options, cpp_get_options (parse_in));
 
   input_location = UNKNOWN_LOCATION;
 
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 226219)
+++ gcc/c-family/c-common.h	(working copy)
@@ -769,10 +769,12 @@ extern void check_function_arguments_rec
 					      unsigned HOST_WIDE_INT);
 extern bool check_builtin_function_arguments (tree, int, tree *);
 extern void check_function_format (tree, int, tree *);
 extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
 extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
+extern void cb_handle_pragma_diagnostic (location_t, const char *,
+					 location_t, const char *);
 extern bool attribute_takes_identifier_p (const_tree);
 extern bool c_common_handle_option (size_t, const char *, int, int, location_t,
 				    const struct cl_option_handlers *);
 extern bool default_handle_c_option (size_t, const char *, int);
 extern tree c_common_type_for_mode (machine_mode, int);
Index: gcc/c-family/c-pragma.c
===================================================================
--- gcc/c-family/c-pragma.c	(revision 226219)
+++ gcc/c-family/c-pragma.c	(working copy)
@@ -699,58 +699,75 @@ handle_pragma_visibility (cpp_reader *du
     }
   if (pragma_lex (&x) != CPP_EOF)
     warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>");
 }
 
-static void
-handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
-{
-  const char *kind_string, *option_string;
-  unsigned int option_index;
-  enum cpp_ttype token;
+/* CPP call-back to handle "#pragma GCC diagnostic KIND_STRING
+   OPTION_STRING", where KIND_STRING is error, warning, ignored, push
+   or pop. LOC_KIND is the location of the KIND_STRING. LOC_OPTION is
+   the location of the warning option string.  */
+
+extern void
+cb_handle_pragma_diagnostic (location_t loc_kind, const char * kind_string,
+			     location_t loc_option, const char * option_string)
+{
+  if (!kind_string)
+    {
+      warning_at (loc_kind, OPT_Wpragmas,
+		  "missing [error|warning|ignored|push|pop]"
+		  " after %<#pragma GCC diagnostic%>");
+      return;
+    }
+
   diagnostic_t kind;
-  tree x;
-  struct cl_option_handlers handlers;
 
-  token = pragma_lex (&x);
-  if (token != CPP_NAME)
-    GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
-  kind_string = IDENTIFIER_POINTER (x);
   if (strcmp (kind_string, "error") == 0)
     kind = DK_ERROR;
   else if (strcmp (kind_string, "warning") == 0)
     kind = DK_WARNING;
   else if (strcmp (kind_string, "ignored") == 0)
     kind = DK_IGNORED;
   else if (strcmp (kind_string, "push") == 0)
     {
-      diagnostic_push_diagnostics (global_dc, input_location);
+      diagnostic_push_diagnostics (global_dc, loc_kind);
       return;
     }
   else if (strcmp (kind_string, "pop") == 0)
     {
-      diagnostic_pop_diagnostics (global_dc, input_location);
+      diagnostic_pop_diagnostics (global_dc, loc_kind);
       return;
     }
   else
-    GCC_BAD ("expected [error|warning|ignored|push|pop] after %<#pragma GCC diagnostic%>");
+    {
+      warning_at (loc_kind, OPT_Wpragmas,
+		  "expected [error|warning|ignored|push|pop]"
+		  " after %<#pragma GCC diagnostic%>");
+      return;
+    }
 
-  token = pragma_lex (&x);
-  if (token != CPP_STRING)
-    GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
-  option_string = TREE_STRING_POINTER (x);
+  if (!option_string)
+    {
+      warning_at (loc_option, OPT_Wpragmas, "missing option"
+		  " after %<#pragma GCC diagnostic%> kind");
+      return;
+    }
+  /* option_string + 1 to skip the initial '-' */
+  unsigned int option_index =  find_opt (option_string + 1, c_family_lang_mask);
+  if (option_index == OPT_SPECIAL_unknown
+      || !(cl_options[option_index].flags & CL_WARNING))
+    {
+      warning_at (loc_option, OPT_Wpragmas, "unknown warning option"
+		  " after %<#pragma GCC diagnostic%> kind");
+      return;
+    }
+
+  struct cl_option_handlers handlers;
   set_default_handlers (&handlers);
-  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;
-      }
-  GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
+  control_warning_option (option_index, (int) kind, kind != DK_IGNORED,
+			  loc_kind, c_family_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))
@@ -1451,11 +1468,10 @@ init_pragma (void)
   c_register_pragma (0, "pack", handle_pragma_pack);
 #endif
   c_register_pragma (0, "weak", handle_pragma_weak);
   c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
 
-  c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
   c_register_pragma ("GCC", "target", handle_pragma_target);
   c_register_pragma ("GCC", "optimize", handle_pragma_optimize);
   c_register_pragma ("GCC", "push_options", handle_pragma_push_options);
   c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options);
   c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options);
Index: gcc/testsuite/c-c++-common/cpp/pragma-gcc-diag.c
===================================================================
--- gcc/testsuite/c-c++-common/cpp/pragma-gcc-diag.c	(revision 0)
+++ gcc/testsuite/c-c++-common/cpp/pragma-gcc-diag.c	(revision 0)
@@ -0,0 +1,5 @@
+/* { dg-do preprocess } */
+/* { dg-options "-Wunused-macros -E" } */
+/* PR preprocessor/53920 */
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#define FOO
Index: gcc/testsuite/c-c++-common/pragma-diag-5.c
===================================================================
--- gcc/testsuite/c-c++-common/pragma-diag-5.c	(revision 0)
+++ gcc/testsuite/c-c++-common/pragma-diag-5.c	(revision 0)
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-Wundef" } */
+#pragma GCC diagnostic ignored "-Wundef"
+#if FOO
+#endif
+int main (void) { return 42; }
Index: gcc/testsuite/c-c++-common/pragma-diag-3.c
===================================================================
--- gcc/testsuite/c-c++-common/pragma-diag-3.c	(revision 0)
+++ gcc/testsuite/c-c++-common/pragma-diag-3.c	(revision 0)
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+#pragma GCC diagnostic /* { dg-warning "missing" "missing" } */
+#pragma GCC diagnostic warn /* { dg-warning "24:expected" } */
+#pragma GCC diagnostic ignored "-Wfoo" /* { dg-warning "32:unknown" } */
Index: gcc/testsuite/c-c++-common/pragma-diag-4.c
===================================================================
--- gcc/testsuite/c-c++-common/pragma-diag-4.c	(revision 0)
+++ gcc/testsuite/c-c++-common/pragma-diag-4.c	(revision 0)
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+#pragma GCC diagnostic error "-fstrict-aliasing" /* { dg-warning "unknown" } */
+#pragma GCC diagnostic error "-Werror" /* { dg-warning "unknown" } */
+
Index: libcpp/directives.c
===================================================================
--- libcpp/directives.c	(revision 226219)
+++ libcpp/directives.c	(working copy)
@@ -42,12 +42,11 @@ typedef void (*pragma_cb) (cpp_reader *)
 struct pragma_entry
 {
   struct pragma_entry *next;
   const cpp_hashnode *pragma;	/* Name and length.  */
   bool is_nspace;
-  bool is_internal;
-  bool is_deferred;
+  bool is_deferred; /* !is_deferred means that it is internal.  */
   bool allow_expansion;
   union {
     pragma_cb handler;
     struct pragma_entry *space;
     unsigned int ident;
@@ -114,10 +113,11 @@ static char ** restore_registered_pragma
                                            char **);
 static void do_pragma_once (cpp_reader *);
 static void do_pragma_poison (cpp_reader *);
 static void do_pragma_system_header (cpp_reader *);
 static void do_pragma_dependency (cpp_reader *);
+static void do_pragma_diagnostic (cpp_reader *pfile);
 static void do_pragma_warning_or_error (cpp_reader *, bool error);
 static void do_pragma_warning (cpp_reader *);
 static void do_pragma_error (cpp_reader *);
 static void do_linemarker (cpp_reader *);
 static const cpp_token *get_token_no_padding (cpp_reader *);
@@ -1234,11 +1234,11 @@ register_pragma_internal (cpp_reader *pf
 			  const char *name, pragma_cb handler)
 {
   struct pragma_entry *entry;
 
   entry = register_pragma_1 (pfile, space, name, false);
-  entry->is_internal = true;
+  entry->is_deferred = false; /* it is internal.  */
   entry->u.handler = handler;
 }
 
 /* Register a pragma NAME in namespace SPACE.  If SPACE is null, it
    goes in the global namespace.  HANDLER is the handler it will call,
@@ -1264,11 +1264,11 @@ cpp_register_pragma (cpp_reader *pfile, 
       entry->u.handler = handler;
     }
 }
 
 /* Similarly, but create mark the pragma for deferred processing.
-   When found, a CPP_PRAGMA token will be insertted into the stream
+   When found, a CPP_PRAGMA token will be inserted into the stream
    with IDENT in the token->u.pragma slot.  */
 void
 cpp_register_deferred_pragma (cpp_reader *pfile, const char *space,
 			      const char *name, unsigned int ident,
 			      bool allow_expansion, bool allow_name_expansion)
@@ -1298,10 +1298,11 @@ _cpp_init_internal_pragmas (cpp_reader *
   register_pragma_internal (pfile, "GCC", "system_header",
 			    do_pragma_system_header);
   register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency);
   register_pragma_internal (pfile, "GCC", "warning", do_pragma_warning);
   register_pragma_internal (pfile, "GCC", "error", do_pragma_error);
+  register_pragma_internal (pfile, "GCC", "diagnostic", do_pragma_diagnostic);
 }
 
 /* Return the number of registered pragmas in PE.  */
 
 static int
@@ -1669,10 +1670,46 @@ do_pragma_dependency (cpp_reader *pfile)
     }
 
   free ((void *) fname);
 }
 
+/* Handle a "#pragma GCC diagnostic".  We parse the #pragma here to
+   set up the classification as early as possible, but we let the FEs
+   handle the actual implementation because CPP does not have access
+   to the diagnostic interfaces.  */
+static void
+do_pragma_diagnostic (cpp_reader *pfile)
+{
+  const cpp_token *tok = _cpp_lex_token (pfile);
+  source_location loc_kind = tok->src_loc;
+  const unsigned char * kind_string = 
+    (tok->type == CPP_NAME || tok->type == CPP_KEYWORD) 
+    ? cpp_token_as_text (pfile, tok)
+    : NULL;
+
+  const unsigned char * option_string = NULL;
+  source_location loc_option = loc_kind;
+  if (kind_string)
+    {
+      tok = _cpp_lex_token (pfile);
+      loc_option = tok->src_loc;
+      cpp_string str;
+      if (tok->type == CPP_STRING
+	  && cpp_interpret_string_notranslate (pfile, &tok->val.str, 1, &str,
+						CPP_STRING)
+	  && str.len > 0)
+	{
+	  option_string = str.text;
+	}
+    }
+  if (pfile->cb.handle_pragma_diagnostic)
+    pfile->cb.handle_pragma_diagnostic (loc_kind, (const char *) kind_string,
+					loc_option, (const char *) option_string);
+  if (option_string)
+    free ((void *) option_string);
+}
+
 /* Issue a diagnostic with the message taken from the pragma.  If
    ERROR is true, the diagnostic is a warning, otherwise, it is an
    error.  */
 static void
 do_pragma_warning_or_error (cpp_reader *pfile, bool error)
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 226219)
+++ libcpp/include/cpplib.h	(working copy)
@@ -591,10 +591,13 @@ struct cpp_callbacks
   /* Callback to identify whether an attribute exists.  */
   int (*has_attribute) (cpp_reader *);
 
   /* Callback that can change a user builtin into normal macro.  */
   bool (*user_builtin_macro) (cpp_reader *, cpp_hashnode *);
+
+  void (*handle_pragma_diagnostic) (source_location, const char*,
+				    source_location, const char*);
 };
 
 #ifdef VMS
 #define INO_T_CPP ino_t ino[3]
 #else

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-09-27  1:29 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-29  4:43 [RFC PATCH] parse #pragma GCC diagnostic in libcpp Manuel López-Ibáñez
2015-08-21 17:44 ` Manuel López-Ibáñez
2015-09-20 18:23   ` Manuel López-Ibáñez
2015-09-23 23:43     ` Joseph Myers
2015-09-25 15:58 ` Dodji Seketeli
2015-09-27 12:03   ` Manuel López-Ibáñez
2015-09-27 14:45     ` Dodji Seketeli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).