diff mbox

Introduce #pragma GCC diagnostic off

Message ID 9905781.8p9cTLN4od@polaris
State New
Headers show

Commit Message

Eric Botcazou April 19, 2013, 4:34 p.m. UTC
Hi,

this patch implements the new "#pragma GCC diagnostic off" for the C family of 
compilers as well as for the Ada compiler.  In fact the subject is slightly 
misleading as the main goal of the patch is to wire the diagnostic circuitry 
of the Ada front-end to that of the middle-end, thus enabling the former to 
drive the latter; but the former has the equivalent of "diagnostic off" so it 
needs middle-end support for it, which in turn could be reused by the C family 
of compilers.

The implementation in diagnostic.c is a bit kludgy in that it overloads the 
option index 0.  But this index has been disabled since day #1 and I couldn't 
figure out a more elegant approach... Of course I'm ready to implement what 
the maintainers would suggest as alternative implementation.

Tested on x86_64-suse-linux, OK for the mainline?


2013-04-19  Eric Botcazou  <ebotcazou@adacore.com>

	* doc/extend.texi (Diagnostic Pragmas): Document diagnostic off.
	* diagnostic.c (diagnostic_classify_diagnostic): Accept zero index and
	document its semantics.
	(diagnostic_report_diagnostic): Adjust accordingly.
c-family/
	* c-pragma.c (ALL_KINDS_STRING): Define.
	(handle_pragma_diagnostic): Use it and accept diagnostic off.
ada/
	* gcc-interface/trans.c: Include diagnostic.h and opts.h.
	(Pragma_to_gnu) <Pragma_Warnings>: New case.
	* gcc-interface/Make-lang.in (ada/trans.o): Adjust.


2013-04-19  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc.dg/pragma-diag-3.c: New test.
diff mbox

Patch

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 198047)
+++ doc/extend.texi	(working copy)
@@ -14807,6 +14807,10 @@  track of the location of each pragma, an
 to the state as of that point in the source file.  Thus, pragmas occurring
 after a line do not affect diagnostics caused by that line.
 
+@item #pragma GCC diagnostic off
+Causes GCC to ignore all the diagnostics. This is equivalent to specifying
+@samp{ignored} for all the diagnostics with the previous form of the pragma.
+
 @item #pragma GCC diagnostic push
 @itemx #pragma GCC diagnostic pop
 
Index: c-family/c-pragma.c
===================================================================
--- c-family/c-pragma.c	(revision 198047)
+++ c-family/c-pragma.c	(working copy)
@@ -684,19 +684,22 @@  handle_pragma_visibility (cpp_reader *du
     warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>");
 }
 
+#define ALL_KINDS_STRING "[error|warning|ignored|off|push|pop]"
+
 static void
 handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
 {
-  const char *kind_string, *option_string;
+  const char *kind_string;
   unsigned int option_index;
   enum cpp_ttype token;
   diagnostic_t kind;
   tree x;
   struct cl_option_handlers handlers;
+  bool no_option = false;
 
   token = pragma_lex (&x);
   if (token != CPP_NAME)
-    GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
+    GCC_BAD ("missing "ALL_KINDS_STRING" after %<#pragma GCC diagnostic%>");
   kind_string = IDENTIFIER_POINTER (x);
   if (strcmp (kind_string, "error") == 0)
     kind = DK_ERROR;
@@ -704,6 +707,11 @@  handle_pragma_diagnostic(cpp_reader *ARG
     kind = DK_WARNING;
   else if (strcmp (kind_string, "ignored") == 0)
     kind = DK_IGNORED;
+  else if (strcmp (kind_string, "off") == 0)
+    {
+      kind = DK_IGNORED;
+      no_option = true;
+    }
   else if (strcmp (kind_string, "push") == 0)
     {
       diagnostic_push_diagnostics (global_dc, input_location);
@@ -715,23 +723,27 @@  handle_pragma_diagnostic(cpp_reader *ARG
       return;
     }
   else
-    GCC_BAD ("expected [error|warning|ignored|push|pop] after %<#pragma GCC diagnostic%>");
+    GCC_BAD ("expected "ALL_KINDS_STRING" after %<#pragma GCC diagnostic%>");
+
+  if (no_option)
+    option_index = 0;
+  else
+    {
+      token = pragma_lex (&x);
+      if (token != CPP_STRING)
+	GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
+      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)
+	  break;
+      if (option_index == cl_options_count)
+	GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
+    }
 
-  token = pragma_lex (&x);
-  if (token != CPP_STRING)
-    GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
-  option_string = TREE_STRING_POINTER (x);
   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,
+			  input_location, c_family_lang_mask, &handlers,
+			  &global_options, &global_options_set, global_dc);
 }
 
 /*  Parse #pragma GCC target (xxx) to set target specific options.  */
Index: diagnostic.c
===================================================================
--- diagnostic.c	(revision 198047)
+++ diagnostic.c	(working copy)
@@ -551,7 +551,8 @@  default_diagnostic_finalizer (diagnostic
 
 /* Interface to specify diagnostic kind overrides.  Returns the
    previous setting, or DK_UNSPECIFIED if the parameters are out of
-   range.  */
+   range.  If OPTION_INDEX is zero, the new setting is for all the
+   diagnostics.  */
 diagnostic_t
 diagnostic_classify_diagnostic (diagnostic_context *context,
 				int option_index,
@@ -560,7 +561,7 @@  diagnostic_classify_diagnostic (diagnost
 {
   diagnostic_t old_kind;
 
-  if (option_index <= 0
+  if (option_index < 0
       || option_index >= context->n_opts
       || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
     return DK_UNSPECIFIED;
@@ -692,9 +693,8 @@  diagnostic_report_diagnostic (diagnostic
       /* This tests for #pragma diagnostic changes.  */
       if (context->n_classification_history > 0)
 	{
-	  int i;
 	  /* FIXME: Stupid search.  Optimize later. */
-	  for (i = context->n_classification_history - 1; i >= 0; i --)
+	  for (int i = context->n_classification_history - 1; i >= 0; i --)
 	    {
 	      if (linemap_location_before_p
 		  (line_table,
@@ -706,7 +706,9 @@  diagnostic_report_diagnostic (diagnostic
 		      i = context->classification_history[i].option;
 		      continue;
 		    }
-		  if (context->classification_history[i].option == diagnostic->option_index)
+		  int option = context->classification_history[i].option;
+		  /* The option 0 is for all the diagnostics.  */
+		  if (option == 0 || option == diagnostic->option_index)
 		    {
 		      diag_class = context->classification_history[i].kind;
 		      if (diag_class != DK_UNSPECIFIED)
Index: testsuite/gcc.dg/pragma-diag-3.c
===================================================================
--- testsuite/gcc.dg/pragma-diag-3.c	(revision 0)
+++ testsuite/gcc.dg/pragma-diag-3.c	(revision 0)
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized" } */
+
+#pragma GCC diagnostic push
+
+int foo1 (void)
+{
+  int i;
+#pragma GCC diagnostic off
+  return i;         /* { dg-bogus "is used uninitialized" } */
+}
+
+#pragma GCC diagnostic pop
+
+int foo2 (void)
+{
+  int i;
+  return i;         /* { dg-warning "is used uninitialized" } */
+}
Index: ada/gcc-interface/trans.c
===================================================================
--- ada/gcc-interface/trans.c	(revision 198047)
+++ ada/gcc-interface/trans.c	(working copy)
@@ -36,6 +36,8 @@ 
 #include "gimple.h"
 #include "bitmap.h"
 #include "cgraph.h"
+#include "diagnostic.h"
+#include "opts.h"
 #include "target.h"
 #include "common/common-target.h"
 
@@ -1184,8 +1186,8 @@  Identifier_to_gnu (Node_Id gnat_node, tr
 static tree
 Pragma_to_gnu (Node_Id gnat_node)
 {
-  Node_Id gnat_temp;
   tree gnu_result = alloc_stmt_list ();
+  Node_Id gnat_temp;
 
   /* Check for (and ignore) unrecognized pragma and do nothing if we are just
      annotating types.  */
@@ -1278,6 +1280,89 @@  Pragma_to_gnu (Node_Id gnat_node)
       if (write_symbols == NO_DEBUG)
 	post_error ("must specify -g?", gnat_node);
       break;
+
+    case Pragma_Warnings:
+      {
+	Node_Id gnat_expr;
+	/* Preserve the location of the pragma.  */
+	const location_t location = input_location;
+	struct cl_option_handlers handlers;
+	unsigned int option_index;
+	diagnostic_t kind;
+	bool imply;
+
+	gnat_temp = First (Pragma_Argument_Associations (gnat_node));
+
+	/* This is the String form: pragma Warnings (String).  */
+	if (Nkind (Expression (gnat_temp)) == N_String_Literal)
+	  {
+	    kind = DK_WARNING;
+	    gnat_expr = Expression (gnat_temp);
+	    imply = true;
+	  }
+
+	/* This is the On/Off form: pragma Warnings (On | Off [,String]).  */
+	else if (Nkind (Expression (gnat_temp)) == N_Identifier)
+	  {
+	    switch (Chars (Expression (gnat_temp)))
+	      {
+		case Name_Off:
+		  kind = DK_IGNORED;
+		  break;
+
+		case Name_On:
+		  kind = DK_WARNING;
+		  break;
+
+		default:
+		  gcc_unreachable ();
+	      }
+
+	    if (Present (Next (gnat_temp)))
+	      {
+		/* pragma Warnings (On | Off, Name) is handled differently.  */
+		if (Nkind (Expression (Next (gnat_temp))) != N_String_Literal)
+		  break;
+
+	        gnat_expr = Expression (Next (gnat_temp));
+	      }
+	    else
+	      gnat_expr = Empty;
+
+	    imply = false;
+	  }
+
+	else
+	  gcc_unreachable ();
+
+	/* This is the same implementation as in the C family of compilers.  */
+	if (Present (gnat_expr))
+	  {
+	    tree gnu_expr = gnat_to_gnu (gnat_expr);
+	    const char *opt_string = TREE_STRING_POINTER (gnu_expr);
+	    const int len = TREE_STRING_LENGTH (gnu_expr);
+	    if (len < 3 || opt_string[0] != '-' || opt_string[1] != 'W')
+	      break;
+	    for (option_index = 0;
+		 option_index < cl_options_count;
+		 option_index++)
+	      if (strcmp (cl_options[option_index].opt_text, opt_string) == 0)
+		break;
+	    if (option_index == cl_options_count)
+	      {
+		post_error ("unknown -W switch", gnat_node);
+		break;
+	      }
+	  }
+	else
+	  option_index = 0;
+
+	set_default_handlers (&handlers);
+	control_warning_option (option_index, (int) kind, imply, location,
+				CL_Ada, &handlers, &global_options,
+				&global_options_set, global_dc);
+      }
+      break;
     }
 
   return gnu_result;