Add a __nowarn__ keyword

DJ Delorie dj@redhat.com
Tue Aug 21 03:24:00 GMT 2007


Patch so far.  I added some code to fill in the origin array in the
global_dc to what the switch "means" before we go and change it, so
that using the table results in the same effect as if we had never
changed the switch.

I haven't tried to do anything with the mapped-location in the source.
Recording the location is easy (I think), but to take advantage of it
we'd probably have to restructure the classification tree some so that
we can search it.  Plus, there may be minor changes to the diagnostic
API to pass the current location to the diagnostics module.  Unless we
already think the location information we have access to is reliable?
The diagnostics do print the file and line with each message...



Index: diagnostic.c
===================================================================
--- diagnostic.c	(revision 127658)
+++ diagnostic.c	(working copy)
@@ -53,12 +53,13 @@ static void default_diagnostic_finalizer
 static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
 static bool diagnostic_count_diagnostic (diagnostic_context *,
 					 diagnostic_info *);
 static void diagnostic_action_after_output (diagnostic_context *,
 					    diagnostic_info *);
 static void real_abort (void) ATTRIBUTE_NORETURN;
+static int lookup_classification (diagnostic_context *, int);
 
 /* A diagnostic_context surrogate for stderr.  */
 static diagnostic_context global_diagnostic_context;
 diagnostic_context *global_dc = &global_diagnostic_context;
 
 
@@ -325,17 +326,75 @@ diagnostic_classify_diagnostic (diagnost
 
   if (option_index <= 0
       || option_index >= N_OPTS
       || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
     return DK_UNSPECIFIED;
 
+  if (context->classification_state)
+    {
+      diagnostic_classification_state_t *state;
+
+      old_kind = lookup_classification (context, option_index);
+      state = (diagnostic_classification_state_t *)
+	xmalloc (sizeof (diagnostic_classification_state_t));
+
+      state->previous = context->classification_state;
+      state->option_index = option_index;
+      state->kind = new_kind;
+      context->classification_state = state;
+
+      return old_kind;
+    }
+
   old_kind = context->classify_diagnostic[option_index];
   context->classify_diagnostic[option_index] = new_kind;
   return old_kind;
 }
 
+static int
+lookup_classification (diagnostic_context * context, int option_index)
+{
+  if (option_index <= 0
+      || option_index >= N_OPTS)
+    return DK_UNSPECIFIED;
+
+  if (context->classification_state)
+    {
+      diagnostic_classification_state_t *s;
+      for (s = context->classification_state;
+	   s; s = s->previous)
+	{
+	  if (s->option_index == option_index)
+	    return s->kind;
+	}
+    }
+  return context->classify_diagnostic[option_index];
+}
+
+diagnostic_classification_state_t *
+diagnostic_save_classifications (diagnostic_context *context)
+{
+  if (context->classification_state == NULL)
+    {
+      /* Create the head of the chain.  */
+      context->classification_state = (diagnostic_classification_state_t *)
+	xmalloc (sizeof (diagnostic_classification_state_t));
+      context->classification_state->previous = NULL;
+      context->classification_state->option_index = 0;
+      context->classification_state->kind = context->classify_diagnostic[0];
+    }
+  return context->classification_state;
+}
+
+void
+diagnostic_restore_classifications (diagnostic_context *context,
+				    diagnostic_classification_state_t *state)
+{
+  context->classification_state = state;
+}
+
 /* Report a diagnostic message (an error or a warning) as specified by
    DC.  This function is *the* subroutine in terms of which front-ends
    should implement their specific diagnostic handling modules.  The
    front-end independent format specifiers are exactly those described
    in the documentation of output_format.  */
 
@@ -372,21 +431,23 @@ diagnostic_report_diagnostic (diagnostic
       diagnostic->kind = DK_ERROR;
       maybe_print_warnings_as_errors_message = true;
     }
   
   if (diagnostic->option_index)
     {
+      int kind;
       /* This tests if the user provided the appropriate -Wfoo or
 	 -Wno-foo option.  */
       if (! option_enabled (diagnostic->option_index))
 	return;
       /* This tests if the user provided the appropriate -Werror=foo
 	 option.  */
-      if (context->classify_diagnostic[diagnostic->option_index] != DK_UNSPECIFIED)
+      kind = lookup_classification (context, diagnostic->option_index);
+      if (kind != DK_UNSPECIFIED)
 	{
-	  diagnostic->kind = context->classify_diagnostic[diagnostic->option_index];
+	  diagnostic->kind = kind;
 	  maybe_print_warnings_as_errors_message = false;
 	}
       /* This allows for future extensions, like temporarily disabling
 	 warnings for ranges of source code.  */
       if (diagnostic->kind == DK_IGNORED)
 	return;
Index: diagnostic.h
===================================================================
--- diagnostic.h	(revision 127658)
+++ diagnostic.h	(working copy)
@@ -53,12 +53,19 @@ typedef struct
 /*  Forward declarations.  */
 typedef struct diagnostic_context diagnostic_context;
 typedef void (*diagnostic_starter_fn) (diagnostic_context *,
 				       diagnostic_info *);
 typedef diagnostic_starter_fn diagnostic_finalizer_fn;
 
+/* The diagnostic state is an opaque pointer.  */
+typedef struct diagnostic_classification_state_t {
+  struct diagnostic_classification_state_t *previous;
+  int option_index;
+  int kind;
+} diagnostic_classification_state_t;
+
 /* This data structure bundles altogether any information relevant to
    the context of a diagnostic message.  */
 struct diagnostic_context
 {
   /* Where most of the diagnostic formatting work is done.  */
   pretty_printer *printer;
@@ -77,12 +84,15 @@ struct diagnostic_context
      (OPT_* from options.h), this array may contain a new kind that
      the diagnostic should be changed to before reporting, or
      DK_UNSPECIFIED to leave it as the reported kind, or DK_IGNORED to
      not report it at all.  N_OPTS is from <options.h>.  */
   char classify_diagnostic[N_OPTS];
 
+  /* If non-NULL, this is the current state of changes to the above.  */
+  diagnostic_classification_state_t *classification_state;
+
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
   bool show_option_requested;
 
   /* True if we should raise a SIGABRT on errors.  */
   bool abort_on_error;
@@ -188,12 +198,24 @@ extern void diagnostic_report_current_mo
 extern void diagnostic_report_current_function (diagnostic_context *);
 
 /* Force diagnostics controlled by OPTIDX to be kind KIND.  */
 extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *,
 						    int /* optidx */,
 						    diagnostic_t /* kind */);
+
+/* This returns a token which represents the current state of the
+   diagnostic classifications.  */
+extern diagnostic_classification_state_t *
+  diagnostic_save_classifications (diagnostic_context *context);
+
+/* This returns the classifications to some previous point.  Further
+   changes to the classifications will be relative to this previous
+   point.  */
+extern void diagnostic_restore_classifications (diagnostic_context *context,
+						diagnostic_classification_state_t *);
+
 extern void diagnostic_report_diagnostic (diagnostic_context *,
 					  diagnostic_info *);
 #ifdef ATTRIBUTE_GCC_DIAG
 extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
 				 location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
 extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
Index: c-pragma.c
===================================================================
--- c-pragma.c	(revision 127658)
+++ c-pragma.c	(working copy)
@@ -814,39 +814,91 @@ handle_pragma_visibility (cpp_reader *du
   if (pragma_lex (&x) != CPP_EOF)
     warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>");
 }
 
 #endif
 
+typedef struct diagnostic_stack_entry_t {
+  struct diagnostic_stack_entry_t *previous;
+  struct diagnostic_classification_state_t *state;
+} diagnostic_stack_entry_t;
+
+static diagnostic_stack_entry_t *diagnostic_stack = 0;
+
 static void
 handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
 {
   const char *kind_string, *option_string;
   unsigned int option_index;
   enum cpp_ttype token;
   diagnostic_t kind;
   tree x;
+  diagnostic_stack_entry_t *stack;
 
   if (cfun)
     {
       error ("#pragma GCC diagnostic not allowed inside functions");
       return;
     }
 
   token = pragma_lex (&x);
   if (token != CPP_NAME)
-    GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
+    GCC_BAD ("missing [push|pop|error|warning|ignored] after %<#pragma GCC diagnostic%>");
   kind_string = IDENTIFIER_POINTER (x);
+
+  if (strcmp (kind_string, "push") == 0)
+    {
+      stack = (diagnostic_stack_entry_t *) xmalloc (sizeof (diagnostic_stack_entry_t));
+      stack->previous = diagnostic_stack;
+      stack->state = diagnostic_save_classifications (global_dc);
+      diagnostic_stack = stack;
+ 
+      token = pragma_lex (&x);
+      if (token != CPP_NAME)
+	return;
+      kind_string = IDENTIFIER_POINTER (x);
+    }
+  else if (strcmp (kind_string, "pop") == 0)
+    {
+      stack = diagnostic_stack;
+      if (!stack)
+	{
+	  error ("$pragma GCC diagnostic pop with no matching push");
+	  return;
+	}
+      diagnostic_stack = stack->previous;
+      diagnostic_restore_classifications (global_dc, stack->state);
+      free (stack);
+      return;
+    }
+#if 0
+  /* This is an example of how to do this, in case we decide to need
+     this functionality in the future.  "undo" moves one state up the
+     tree, effectively undoing the previous pragma.  It relies on
+     every pragma being in the state tree (which may be expensive), so
+     we must force the tree to exist somehow.  */
+  else if (strcmp (kind_string, "undo") == 0)
+    {
+      diagnostic_classification_state_t *state;
+      state = diagnostic_save_classifications (global_dc);
+      state = state->previous;
+      diagnostic_restore_classifications (global_dc, state);
+      return;
+    }
+  /* Here we force the state tree to exist for any change-type pragma.  */
+  diagnostic_save_classifications (global_dc);
+#endif
+
   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
-    GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>");
+    GCC_BAD ("expected [push|pop|error|warning|ignored] after %<#pragma GCC diagnostic%>");
 
   token = pragma_lex (&x);
   if (token != CPP_STRING)
     GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
   option_string = TREE_STRING_POINTER (x);
   for (option_index = 0; option_index < cl_options_count; option_index++)
@@ -855,13 +907,29 @@ handle_pragma_diagnostic(cpp_reader *ARG
 	/* This overrides -Werror, for example.  */
 	diagnostic_classify_diagnostic (global_dc, option_index, kind);
 	/* This makes sure the option is enabled, like -Wfoo would do.  */
 	if (cl_options[option_index].var_type == CLVC_BOOLEAN
 	    && cl_options[option_index].flag_var
 	    && kind != DK_IGNORED)
+	  {
+	    /* Make the default setting explicit, in case we pop.  */
+	    if (global_dc->classify_diagnostic[option_index] == DK_UNSPECIFIED)
+	      {
+		if (*(int *) cl_options[option_index].flag_var)
+		  {
+		    if (global_dc->warning_as_error_requested)
+		      global_dc->classify_diagnostic[option_index] = DK_ERROR;
+		    else
+		      global_dc->classify_diagnostic[option_index] = DK_WARNING;
+		  }
+		else
+		  global_dc->classify_diagnostic[option_index] = DK_IGNORED;
+	      }
+	    /* And turn the option on.  */
 	    *(int *) cl_options[option_index].flag_var = 1;
+	  }
 	return;
       }
   GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
 }
 
 /* A vector of registered pragma callbacks.  */



More information about the Gcc-patches mailing list