diff gcc/opts.c @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children 3bfb6c00c1e0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/opts.c	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,2327 @@
+/* Command line option handling.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+   Contributed by Neil Booth.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "expr.h"
+#include "ggc.h"
+#include "output.h"
+#include "langhooks.h"
+#include "opts.h"
+#include "options.h"
+#include "flags.h"
+#include "toplev.h"
+#include "params.h"
+#include "diagnostic.h"
+#include "tm_p.h"		/* For OPTIMIZATION_OPTIONS.  */
+#include "insn-attr.h"		/* For INSN_SCHEDULING.  */
+#include "target.h"
+#include "tree-pass.h"
+#include "dbgcnt.h"
+#include "debug.h"
+
+/* Value of the -G xx switch, and whether it was passed or not.  */
+unsigned HOST_WIDE_INT g_switch_value;
+bool g_switch_set;
+
+/* Same for selective scheduling.  */
+bool sel_sched_switch_set;
+
+/* True if we should exit after parsing options.  */
+bool exit_after_options;
+
+/* Print various extra warnings.  -W/-Wextra.  */
+bool extra_warnings;
+
+/* True to warn about any objects definitions whose size is larger
+   than N bytes.  Also want about function definitions whose returned
+   values are larger than N bytes, where N is `larger_than_size'.  */
+bool warn_larger_than;
+HOST_WIDE_INT larger_than_size;
+
+/* True to warn about any function whose frame size is larger
+ * than N bytes. */
+bool warn_frame_larger_than;
+HOST_WIDE_INT frame_larger_than_size;
+
+/* Type(s) of debugging information we are producing (if any).  See
+   flags.h for the definitions of the different possible types of
+   debugging information.  */
+enum debug_info_type write_symbols = NO_DEBUG;
+
+/* Level of debugging information we are producing.  See flags.h for
+   the definitions of the different possible levels.  */
+enum debug_info_level debug_info_level = DINFO_LEVEL_NONE;
+
+/* A major contribution to object and executable size is debug
+   information size.  A major contribution to debug information size
+   is struct descriptions replicated in several object files. The
+   following flags attempt to reduce this information.  The basic
+   idea is to not emit struct debugging information in the current
+   compilation unit when that information will be generated by
+   another compilation unit.
+
+   Debug information for a struct defined in the current source
+   file should be generated in the object file.  Likewise the
+   debug information for a struct defined in a header should be
+   generated in the object file of the corresponding source file.
+   Both of these case are handled when the base name of the file of
+   the struct definition matches the base name of the source file
+   of the current compilation unit.  This matching emits minimal
+   struct debugging information.
+
+   The base file name matching rule above will fail to emit debug
+   information for structs defined in system headers.  So a second
+   category of files includes system headers in addition to files
+   with matching bases.
+
+   The remaining types of files are library headers and application
+   headers.  We cannot currently distinguish these two types.  */
+
+enum debug_struct_file
+{
+  DINFO_STRUCT_FILE_NONE,   /* Debug no structs. */
+  DINFO_STRUCT_FILE_BASE,   /* Debug structs defined in files with the
+                               same base name as the compilation unit. */
+  DINFO_STRUCT_FILE_SYS,    /* Also debug structs defined in system
+                               header files.  */
+  DINFO_STRUCT_FILE_ANY     /* Debug structs defined in all files. */
+};
+
+/* Generic structs (e.g. templates not explicitly specialized)
+   may not have a compilation unit associated with them, and so
+   may need to be treated differently from ordinary structs.
+
+   Structs only handled by reference (indirectly), will also usually
+   not need as much debugging information.  */
+
+static enum debug_struct_file debug_struct_ordinary[DINFO_USAGE_NUM_ENUMS]
+  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
+static enum debug_struct_file debug_struct_generic[DINFO_USAGE_NUM_ENUMS]
+  = { DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY, DINFO_STRUCT_FILE_ANY };
+
+/* Parse the -femit-struct-debug-detailed option value
+   and set the flag variables. */
+
+#define MATCH( prefix, string ) \
+  ((strncmp (prefix, string, sizeof prefix - 1) == 0) \
+   ? ((string += sizeof prefix - 1), 1) : 0)
+
+void
+set_struct_debug_option (const char *spec)
+{
+  /* various labels for comparison */
+  static char dfn_lbl[] = "dfn:", dir_lbl[] = "dir:", ind_lbl[] = "ind:";
+  static char ord_lbl[] = "ord:", gen_lbl[] = "gen:";
+  static char none_lbl[] = "none", any_lbl[] = "any";
+  static char base_lbl[] = "base", sys_lbl[] = "sys";
+
+  enum debug_struct_file files = DINFO_STRUCT_FILE_ANY;
+  /* Default is to apply to as much as possible. */
+  enum debug_info_usage usage = DINFO_USAGE_NUM_ENUMS;
+  int ord = 1, gen = 1;
+
+  /* What usage? */
+  if (MATCH (dfn_lbl, spec))
+    usage = DINFO_USAGE_DFN;
+  else if (MATCH (dir_lbl, spec))
+    usage = DINFO_USAGE_DIR_USE;
+  else if (MATCH (ind_lbl, spec))
+    usage = DINFO_USAGE_IND_USE;
+
+  /* Generics or not? */
+  if (MATCH (ord_lbl, spec))
+    gen = 0;
+  else if (MATCH (gen_lbl, spec))
+    ord = 0;
+
+  /* What allowable environment? */
+  if (MATCH (none_lbl, spec))
+    files = DINFO_STRUCT_FILE_NONE;
+  else if (MATCH (any_lbl, spec))
+    files = DINFO_STRUCT_FILE_ANY;
+  else if (MATCH (sys_lbl, spec))
+    files = DINFO_STRUCT_FILE_SYS;
+  else if (MATCH (base_lbl, spec))
+    files = DINFO_STRUCT_FILE_BASE;
+  else
+    error ("argument %qs to %<-femit-struct-debug-detailed%> not recognized",
+           spec);
+
+  /* Effect the specification. */
+  if (usage == DINFO_USAGE_NUM_ENUMS)
+    {
+      if (ord)
+        {
+          debug_struct_ordinary[DINFO_USAGE_DFN] = files;
+          debug_struct_ordinary[DINFO_USAGE_DIR_USE] = files;
+          debug_struct_ordinary[DINFO_USAGE_IND_USE] = files;
+        }
+      if (gen)
+        {
+          debug_struct_generic[DINFO_USAGE_DFN] = files;
+          debug_struct_generic[DINFO_USAGE_DIR_USE] = files;
+          debug_struct_generic[DINFO_USAGE_IND_USE] = files;
+        }
+    }
+  else
+    {
+      if (ord)
+        debug_struct_ordinary[usage] = files;
+      if (gen)
+        debug_struct_generic[usage] = files;
+    }
+
+  if (*spec == ',')
+    set_struct_debug_option (spec+1);
+  else
+    {
+      /* No more -femit-struct-debug-detailed specifications.
+         Do final checks. */
+      if (*spec != '\0')
+	error ("argument %qs to %<-femit-struct-debug-detailed%> unknown",
+               spec);
+      if (debug_struct_ordinary[DINFO_USAGE_DIR_USE]
+		< debug_struct_ordinary[DINFO_USAGE_IND_USE]
+	  || debug_struct_generic[DINFO_USAGE_DIR_USE]
+		< debug_struct_generic[DINFO_USAGE_IND_USE])
+	error ("%<-femit-struct-debug-detailed=dir:...%> must allow at least"
+               " as much as %<-femit-struct-debug-detailed=ind:...%>");
+    }
+}
+
+/* Find the base name of a path, stripping off both directories and
+   a single final extension. */
+static int
+base_of_path (const char *path, const char **base_out)
+{
+  const char *base = path;
+  const char *dot = 0;
+  const char *p = path;
+  char c = *p;
+  while (c)
+    {
+      if (IS_DIR_SEPARATOR(c))
+        {
+          base = p + 1;
+          dot = 0;
+        }
+      else if (c == '.')
+        dot = p;
+      c = *++p;
+    }
+  if (!dot)
+    dot = p;
+  *base_out = base;
+  return dot - base;
+}
+
+/* Match the base name of a file to the base name of a compilation unit. */
+
+static const char *main_input_basename;
+static int main_input_baselength;
+
+static int
+matches_main_base (const char *path)
+{
+  /* Cache the last query. */
+  static const char *last_path = NULL;
+  static int last_match = 0;
+  if (path != last_path)
+    {
+      const char *base;
+      int length = base_of_path (path, &base);
+      last_path = path;
+      last_match = (length == main_input_baselength
+                    && memcmp (base, main_input_basename, length) == 0);
+    }
+  return last_match;
+}
+
+#ifdef DEBUG_DEBUG_STRUCT
+
+static int
+dump_struct_debug (tree type, enum debug_info_usage usage,
+		   enum debug_struct_file criterion, int generic,
+		   int matches, int result)
+{
+  /* Find the type name. */
+  tree type_decl = TYPE_STUB_DECL (type);
+  tree t = type_decl;
+  const char *name = 0;
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = DECL_NAME (t);
+  if (t)
+    name = IDENTIFIER_POINTER (t);
+
+  fprintf (stderr, "	struct %d %s %s %s %s %d %p %s\n",
+	   criterion,
+           DECL_IN_SYSTEM_HEADER (type_decl) ? "sys" : "usr",
+           matches ? "bas" : "hdr",
+           generic ? "gen" : "ord",
+           usage == DINFO_USAGE_DFN ? ";" :
+             usage == DINFO_USAGE_DIR_USE ? "." : "*",
+           result,
+           (void*) type_decl, name);
+  return result;
+}
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  dump_struct_debug (type, usage, criterion, generic, matches, result)
+
+#else
+
+#define DUMP_GSTRUCT(type, usage, criterion, generic, matches, result) \
+  (result)
+
+#endif
+
+
+bool
+should_emit_struct_debug (tree type, enum debug_info_usage usage)
+{
+  enum debug_struct_file criterion;
+  tree type_decl;
+  bool generic = lang_hooks.types.generic_p (type);
+
+  if (generic)
+    criterion = debug_struct_generic[usage];
+  else
+    criterion = debug_struct_ordinary[usage];
+
+  if (criterion == DINFO_STRUCT_FILE_NONE)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+  if (criterion == DINFO_STRUCT_FILE_ANY)
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  type_decl = TYPE_STUB_DECL (type);
+
+  if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, false, true);
+
+  if (matches_main_base (DECL_SOURCE_FILE (type_decl)))
+    return DUMP_GSTRUCT (type, usage, criterion, generic, true, true);
+  return DUMP_GSTRUCT (type, usage, criterion, generic, false, false);
+}
+
+/* Nonzero means use GNU-only extensions in the generated symbolic
+   debugging information.  Currently, this only has an effect when
+   write_symbols is set to DBX_DEBUG, XCOFF_DEBUG, or DWARF_DEBUG.  */
+bool use_gnu_debug_info_extensions;
+
+/* The default visibility for all symbols (unless overridden) */
+enum symbol_visibility default_visibility = VISIBILITY_DEFAULT;
+
+/* Global visibility options.  */
+struct visibility_flags visibility_options;
+
+/* What to print when a switch has no documentation.  */
+#ifdef ENABLE_CHECKING
+static const char undocumented_msg[] = N_("This switch lacks documentation");
+#else
+static const char undocumented_msg[] = "";
+#endif
+
+/* Used for bookkeeping on whether user set these flags so
+   -fprofile-use/-fprofile-generate does not use them.  */
+static bool profile_arc_flag_set, flag_profile_values_set;
+static bool flag_unroll_loops_set, flag_tracer_set;
+static bool flag_value_profile_transformations_set;
+static bool flag_peel_loops_set, flag_branch_probabilities_set;
+static bool flag_inline_functions_set, flag_ipa_cp_set, flag_ipa_cp_clone_set;
+static bool flag_predictive_commoning_set, flag_unswitch_loops_set, flag_gcse_after_reload_set;
+
+/* Functions excluded from profiling.  */
+
+typedef char *char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(char_p);
+DEF_VEC_ALLOC_P(char_p,heap);
+
+static VEC(char_p,heap) *flag_instrument_functions_exclude_functions;
+static VEC(char_p,heap) *flag_instrument_functions_exclude_files;
+
+typedef const char *const_char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p,heap);
+
+static VEC(const_char_p,heap) *ignored_options;
+
+/* Input file names.  */
+const char **in_fnames;
+unsigned num_in_fnames;
+
+static int common_handle_option (size_t scode, const char *arg, int value,
+				 unsigned int lang_mask);
+static void handle_param (const char *);
+static void set_Wextra (int);
+static unsigned int handle_option (const char **argv, unsigned int lang_mask);
+static char *write_langs (unsigned int lang_mask);
+static void complain_wrong_lang (const char *, const struct cl_option *,
+				 unsigned int lang_mask);
+static void handle_options (unsigned int, const char **, unsigned int);
+static void set_debug_level (enum debug_info_type type, int extended,
+			     const char *arg);
+
+/* If ARG is a non-negative integer made up solely of digits, return its
+   value, otherwise return -1.  */
+static int
+integral_argument (const char *arg)
+{
+  const char *p = arg;
+
+  while (*p && ISDIGIT (*p))
+    p++;
+
+  if (*p == '\0')
+    return atoi (arg);
+
+  return -1;
+}
+
+/* Return a malloced slash-separated list of languages in MASK.  */
+static char *
+write_langs (unsigned int mask)
+{
+  unsigned int n = 0, len = 0;
+  const char *lang_name;
+  char *result;
+
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      len += strlen (lang_name) + 1;
+
+  result = XNEWVEC (char, len);
+  len = 0;
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      {
+	if (len)
+	  result[len++] = '/';
+	strcpy (result + len, lang_name);
+	len += strlen (lang_name);
+      }
+
+  result[len] = 0;
+
+  return result;
+}
+
+/* Complain that switch OPT_INDEX does not apply to this front end.  */
+static void
+complain_wrong_lang (const char *text, const struct cl_option *option,
+		     unsigned int lang_mask)
+{
+  char *ok_langs, *bad_lang;
+
+  ok_langs = write_langs (option->flags);
+  bad_lang = write_langs (lang_mask);
+
+  /* Eventually this should become a hard error IMO.  */
+  warning (0, "command line option \"%s\" is valid for %s but not for %s",
+	   text, ok_langs, bad_lang);
+
+  free (ok_langs);
+  free (bad_lang);
+}
+
+/* Buffer the unknown option described by the string OPT.  Currently,
+   we only complain about unknown -Wno-* options if they may have
+   prevented a diagnostic. Otherwise, we just ignore them.
+   Note that if we do complain, it is only as a warning, not an error;
+   passing the compiler an unrecognised -Wno-* option should never
+   change whether the compilation succeeds or fails.  */
+
+static void postpone_unknown_option_warning(const char *opt)
+{
+  VEC_safe_push (const_char_p, heap, ignored_options, opt);
+}
+
+/* Produce a warning for each option previously buffered.  */
+
+void print_ignored_options (void)
+{
+  location_t saved_loc = input_location;
+
+  input_location = 0;
+
+  while (!VEC_empty (const_char_p, ignored_options))
+    {
+      const char *opt;
+      opt = VEC_pop (const_char_p, ignored_options);
+      warning (0, "unrecognized command line option \"%s\"", opt);
+    }
+
+  input_location = saved_loc;
+}
+
+/* Handle the switch beginning at ARGV for the language indicated by
+   LANG_MASK.  Returns the number of switches consumed.  */
+static unsigned int
+handle_option (const char **argv, unsigned int lang_mask)
+{
+  size_t opt_index;
+  const char *opt, *arg = 0;
+  char *dup = 0;
+  int value = 1;
+  unsigned int result = 0;
+  const struct cl_option *option;
+
+  opt = argv[0];
+
+  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+  if (opt_index == cl_options_count
+      && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
+      && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
+    {
+      /* Drop the "no-" from negative switches.  */
+      size_t len = strlen (opt) - 3;
+
+      dup = XNEWVEC (char, len + 1);
+      dup[0] = '-';
+      dup[1] = opt[1];
+      memcpy (dup + 2, opt + 5, len - 2 + 1);
+      opt = dup;
+      value = 0;
+      opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+      if (opt_index == cl_options_count && opt[1] == 'W')
+	{
+	  /* We don't generate warnings for unknown -Wno-* options
+             unless we issue diagnostics.  */
+	  postpone_unknown_option_warning (argv[0]);
+	  result = 1;
+	  goto done;
+	}
+    }
+
+  if (opt_index == cl_options_count)
+    goto done;
+
+  option = &cl_options[opt_index];
+
+  /* Reject negative form of switches that don't take negatives as
+     unrecognized.  */
+  if (!value && (option->flags & CL_REJECT_NEGATIVE))
+    goto done;
+
+  /* We've recognized this switch.  */
+  result = 1;
+
+  /* Check to see if the option is disabled for this configuration.  */
+  if (option->flags & CL_DISABLED)
+    {
+      error ("command line option %qs"
+	     " is not supported by this configuration", opt);
+      goto done;
+    }
+
+  /* Sort out any argument the switch takes.  */
+  if (option->flags & CL_JOINED)
+    {
+      /* Have arg point to the original switch.  This is because
+	 some code, such as disable_builtin_function, expects its
+	 argument to be persistent until the program exits.  */
+      arg = argv[0] + cl_options[opt_index].opt_len + 1;
+      if (!value)
+	arg += strlen ("no-");
+
+      if (*arg == '\0' && !(option->flags & CL_MISSING_OK))
+	{
+	  if (option->flags & CL_SEPARATE)
+	    {
+	      arg = argv[1];
+	      result = 2;
+	    }
+	  else
+	    /* Missing argument.  */
+	    arg = NULL;
+	}
+    }
+  else if (option->flags & CL_SEPARATE)
+    {
+      arg = argv[1];
+      result = 2;
+    }
+
+  /* Now we've swallowed any potential argument, complain if this
+     is a switch for a different front end.  */
+  if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
+    {
+      complain_wrong_lang (argv[0], option, lang_mask);
+      goto done;
+    }
+  else if ((option->flags & CL_TARGET)
+	   && (option->flags & CL_LANG_ALL)
+	   && !(option->flags & lang_mask))
+    {
+      /* Complain for target flag language mismatches if any languages
+	 are specified.  */
+      complain_wrong_lang (argv[0], option, lang_mask);
+      goto done;
+    }
+
+  if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
+    {
+      if (!lang_hooks.missing_argument (opt, opt_index))
+	error ("missing argument to \"%s\"", opt);
+      goto done;
+    }
+
+  /* If the switch takes an integer, convert it.  */
+  if (arg && (option->flags & CL_UINTEGER))
+    {
+      value = integral_argument (arg);
+      if (value == -1)
+	{
+	  error ("argument to \"%s\" should be a non-negative integer",
+		 option->opt_text);
+	  goto done;
+	}
+    }
+
+  if (option->flag_var)
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+	*(int *) option->flag_var = value;
+	break;
+
+      case CLVC_EQUAL:
+	*(int *) option->flag_var = (value
+				     ? option->var_value
+				     : !option->var_value);
+	break;
+
+      case CLVC_BIT_CLEAR:
+      case CLVC_BIT_SET:
+	if ((value != 0) == (option->var_type == CLVC_BIT_SET))
+	  *(int *) option->flag_var |= option->var_value;
+	else
+	  *(int *) option->flag_var &= ~option->var_value;
+	if (option->flag_var == &target_flags)
+	  target_flags_explicit |= option->var_value;
+	break;
+
+      case CLVC_STRING:
+	*(const char **) option->flag_var = arg;
+	break;
+      }
+
+  if (option->flags & lang_mask)
+    if (lang_hooks.handle_option (opt_index, arg, value) == 0)
+      result = 0;
+
+  if (result && (option->flags & CL_COMMON))
+    if (common_handle_option (opt_index, arg, value, lang_mask) == 0)
+      result = 0;
+
+  if (result && (option->flags & CL_TARGET))
+    if (!targetm.handle_option (opt_index, arg, value))
+      result = 0;
+
+ done:
+  if (dup)
+    free (dup);
+  return result;
+}
+
+/* Handle FILENAME from the command line.  */
+static void
+add_input_filename (const char *filename)
+{
+  num_in_fnames++;
+  in_fnames = XRESIZEVEC (const char *, in_fnames, num_in_fnames);
+  in_fnames[num_in_fnames - 1] = filename;
+}
+
+/* Add comma-separated strings to a char_p vector.  */
+
+static void
+add_comma_separated_to_vector (VEC(char_p,heap) **pvec, const char* arg)
+{
+  char *tmp;
+  char *r;
+  char *w;
+  char *token_start;
+
+  /* We never free this string.  */
+  tmp = xstrdup (arg);
+
+  r = tmp;
+  w = tmp;
+  token_start = tmp;
+
+  while (*r != '\0')
+    {
+      if (*r == ',')
+	{
+	  *w++ = '\0';
+	  ++r;
+	  VEC_safe_push (char_p, heap, *pvec, token_start);
+	  token_start = w;
+	}
+      if (*r == '\\' && r[1] == ',')
+	{
+	  *w++ = ',';
+	  r += 2;
+	}
+      else
+	*w++ = *r++;
+    }
+  if (*token_start != '\0')
+    VEC_safe_push (char_p, heap, *pvec, token_start);
+}
+
+/* Return whether we should exclude FNDECL from instrumentation.  */
+
+bool
+flag_instrument_functions_exclude_p (tree fndecl)
+{
+  if (VEC_length (char_p, flag_instrument_functions_exclude_functions) > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = lang_hooks.decl_printable_name (fndecl, 0);
+      for (i = 0;
+	   VEC_iterate (char_p, flag_instrument_functions_exclude_functions,
+			i, s);
+	   ++i)
+	{
+	  if (strstr (name, s) != NULL)
+	    return true;
+	}
+    }
+
+  if (VEC_length (char_p, flag_instrument_functions_exclude_files) > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = DECL_SOURCE_FILE (fndecl);
+      for (i = 0;
+	   VEC_iterate (char_p, flag_instrument_functions_exclude_files, i, s);
+	   ++i)
+	{
+	  if (strstr (name, s) != NULL)
+	    return true;
+	}
+    }
+
+  return false;
+}
+
+
+/* Decode and handle the vector of command line options.  LANG_MASK
+   contains has a single bit set representing the current
+   language.  */
+static void
+handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
+{
+  unsigned int n, i;
+
+  for (i = 1; i < argc; i += n)
+    {
+      const char *opt = argv[i];
+
+      /* Interpret "-" or a non-switch as a file name.  */
+      if (opt[0] != '-' || opt[1] == '\0')
+	{
+	  if (main_input_filename == NULL)
+	    {
+	      main_input_filename = opt;
+	      main_input_baselength
+		= base_of_path (main_input_filename, &main_input_basename);
+	    }
+	  add_input_filename (opt);
+	  n = 1;
+	  continue;
+	}
+
+      n = handle_option (argv + i, lang_mask);
+
+      if (!n)
+	{
+	  n = 1;
+	  error ("unrecognized command line option \"%s\"", opt);
+	}
+    }
+}
+
+/* Parse command line options and set default flag values.  Do minimal
+   options processing.  */
+void
+decode_options (unsigned int argc, const char **argv)
+{
+  static bool first_time_p = true;
+  static int initial_max_aliased_vops;
+  static int initial_avg_aliased_vops;
+  static int initial_min_crossjump_insns;
+  static int initial_max_fields_for_field_sensitive;
+  static int initial_loop_invariant_max_bbs_in_loop;
+  static unsigned int initial_lang_mask;
+
+  unsigned int i, lang_mask;
+  int opt1;
+  int opt2;
+  int opt3;
+  int opt1_max;
+
+  if (first_time_p)
+    {
+      /* Perform language-specific options initialization.  */
+      initial_lang_mask = lang_mask = lang_hooks.init_options (argc, argv);
+
+      lang_hooks.initialize_diagnostics (global_dc);
+
+      /* Save initial values of parameters we reset.  */
+      initial_max_aliased_vops = MAX_ALIASED_VOPS;
+      initial_avg_aliased_vops = AVG_ALIASED_VOPS;
+      initial_min_crossjump_insns
+	= compiler_params[PARAM_MIN_CROSSJUMP_INSNS].value;
+      initial_max_fields_for_field_sensitive
+	= compiler_params[PARAM_MAX_FIELDS_FOR_FIELD_SENSITIVE].value;
+      initial_loop_invariant_max_bbs_in_loop
+	= compiler_params[PARAM_LOOP_INVARIANT_MAX_BBS_IN_LOOP].value;
+    }
+  else
+    lang_mask = initial_lang_mask;
+
+  /* Scan to see what optimization level has been specified.  That will
+     determine the default value of many flags.  */
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (argv[i], "-O"))
+	{
+	  optimize = 1;
+	  optimize_size = 0;
+	}
+      else if (argv[i][0] == '-' && argv[i][1] == 'O')
+	{
+	  /* Handle -Os, -O2, -O3, -O69, ...  */
+	  const char *p = &argv[i][2];
+
+	  if ((p[0] == 's') && (p[1] == 0))
+	    {
+	      optimize_size = 1;
+
+	      /* Optimizing for size forces optimize to be 2.  */
+	      optimize = 2;
+	    }
+	  else
+	    {
+	      const int optimize_val = read_integral_parameter (p, p - 2, -1);
+	      if (optimize_val != -1)
+		{
+		  optimize = optimize_val;
+		  optimize_size = 0;
+		}
+	    }
+	}
+    }
+  
+  /* Use priority coloring if cover classes is not defined for the
+     target.  */
+  if (targetm.ira_cover_classes == NULL)
+    flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+
+  /* -O1 optimizations.  */
+  opt1 = (optimize >= 1);
+  flag_defer_pop = opt1;
+#ifdef DELAY_SLOTS
+  flag_delayed_branch = opt1;
+#endif
+#ifdef CAN_DEBUG_WITHOUT_FP
+  flag_omit_frame_pointer = opt1;
+#endif
+  flag_guess_branch_prob = opt1;
+  flag_cprop_registers = opt1;
+  flag_if_conversion = opt1;
+  flag_if_conversion2 = opt1;
+  flag_ipa_pure_const = opt1;
+  flag_ipa_reference = opt1;
+  flag_merge_constants = opt1;
+  flag_split_wide_types = opt1;
+  flag_tree_ccp = opt1;
+  flag_tree_dce = opt1;
+  flag_tree_dom = opt1;
+  flag_tree_dse = opt1;
+  flag_tree_ter = opt1;
+  flag_tree_sra = opt1;
+  flag_tree_copyrename = opt1;
+  flag_tree_fre = opt1;
+  flag_tree_copy_prop = opt1;
+  flag_tree_sink = opt1;
+  flag_tree_ch = opt1;
+
+  /* -O2 optimizations.  */
+  opt2 = (optimize >= 2);
+  flag_inline_small_functions = opt2;
+  flag_indirect_inlining = opt2;
+  flag_thread_jumps = opt2;
+  flag_crossjumping = opt2;
+  flag_optimize_sibling_calls = opt2;
+  flag_forward_propagate = opt2;
+  flag_cse_follow_jumps = opt2;
+  flag_gcse = opt2;
+  flag_expensive_optimizations = opt2;
+  flag_rerun_cse_after_loop = opt2;
+  flag_caller_saves = opt2;
+  flag_peephole2 = opt2;
+#ifdef INSN_SCHEDULING
+  flag_schedule_insns = opt2;
+  flag_schedule_insns_after_reload = opt2;
+#endif
+  flag_regmove = opt2;
+  flag_strict_aliasing = opt2;
+  flag_strict_overflow = opt2;
+  flag_delete_null_pointer_checks = opt2;
+  flag_reorder_blocks = opt2;
+  flag_reorder_functions = opt2;
+  flag_tree_vrp = opt2;
+  flag_tree_builtin_call_dce = opt2;
+  flag_tree_pre = opt2;
+  flag_tree_switch_conversion = 1;
+  flag_ipa_cp = opt2;
+
+  /* Allow more virtual operators to increase alias precision.  */
+
+  set_param_value ("max-aliased-vops",
+		   (opt2) ? 500 : initial_max_aliased_vops);
+
+  /* Track fields in field-sensitive alias analysis.  */
+  set_param_value ("max-fields-for-field-sensitive",
+		   (opt2) ? 100 : initial_max_fields_for_field_sensitive);
+
+  /* For -O1 only do loop invariant motion for very small loops.  */
+  set_param_value ("loop-invariant-max-bbs-in-loop",
+		   (opt2) ? initial_loop_invariant_max_bbs_in_loop : 1000);
+
+  /* -O3 optimizations.  */
+  opt3 = (optimize >= 3);
+  flag_predictive_commoning = opt3;
+  flag_inline_functions = opt3;
+  flag_unswitch_loops = opt3;
+  flag_gcse_after_reload = opt3;
+  flag_tree_vectorize = opt3;
+  flag_ipa_cp_clone = opt3;
+  if (flag_ipa_cp_clone)
+    flag_ipa_cp = 1;
+
+  /* Allow even more virtual operators.  Max-aliased-vops was set above for
+     -O2, so don't reset it unless we are at -O3.  */
+  if (opt3)
+    set_param_value ("max-aliased-vops", 1000);
+
+  set_param_value ("avg-aliased-vops", (opt3) ? 3 : initial_avg_aliased_vops);
+
+  /* Just -O1/-O0 optimizations.  */
+  opt1_max = (optimize <= 1);
+  align_loops = opt1_max;
+  align_jumps = opt1_max;
+  align_labels = opt1_max;
+  align_functions = opt1_max;
+
+  if (optimize_size)
+    {
+      /* Inlining of functions reducing size is a good idea regardless of them
+	 being declared inline.  */
+      flag_inline_functions = 1;
+
+      /* Basic optimization options.  */
+      optimize_size = 1;
+      if (optimize > 2)
+	optimize = 2;
+
+      /* We want to crossjump as much as possible.  */
+      set_param_value ("min-crossjump-insns", 1);
+    }
+  else
+    set_param_value ("min-crossjump-insns", initial_min_crossjump_insns);
+
+  if (first_time_p)
+    {
+      /* Initialize whether `char' is signed.  */
+      flag_signed_char = DEFAULT_SIGNED_CHAR;
+      /* Set this to a special "uninitialized" value.  The actual default is
+	 set after target options have been processed.  */
+      flag_short_enums = 2;
+
+      /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
+	 modify it.  */
+      target_flags = targetm.default_target_flags;
+
+      /* Some targets have ABI-specified unwind tables.  */
+      flag_unwind_tables = targetm.unwind_tables_default;
+    }
+
+#ifdef OPTIMIZATION_OPTIONS
+  /* Allow default optimizations to be specified on a per-machine basis.  */
+  OPTIMIZATION_OPTIONS (optimize, optimize_size);
+#endif
+
+  handle_options (argc, argv, lang_mask);
+
+  /* Handle related options for unit-at-a-time, toplevel-reorder, and
+     section-anchors.  */
+  if (!flag_unit_at_a_time)
+    {
+      if (flag_section_anchors == 1)
+	error ("Section anchors must be disabled when unit-at-a-time "
+	       "is disabled.");
+      flag_section_anchors = 0;
+      if (flag_toplevel_reorder == 1)
+	error ("Toplevel reorder must be disabled when unit-at-a-time "
+	       "is disabled.");
+      flag_toplevel_reorder = 0;
+    }
+  /* Unless the user has asked for section anchors, we disable toplevel
+     reordering at -O0 to disable transformations that might be surprising
+     to end users and to get -fno-toplevel-reorder tested.  */
+  if (!optimize && flag_toplevel_reorder == 2 && flag_section_anchors != 1)
+    {
+      flag_toplevel_reorder = 0;
+      flag_section_anchors = 0;
+    }
+  if (!flag_toplevel_reorder)
+    {
+      if (flag_section_anchors == 1)
+	error ("section anchors must be disabled when toplevel reorder"
+	       " is disabled");
+      flag_section_anchors = 0;
+    }
+
+  if (first_time_p)
+    {
+      if (flag_pie)
+	flag_pic = flag_pie;
+      if (flag_pic && !flag_pie)
+	flag_shlib = 1;
+    }
+
+  if (optimize == 0)
+    {
+      /* Inlining does not work if not optimizing,
+	 so force it not to be done.  */
+      warn_inline = 0;
+      flag_no_inline = 1;
+    }
+
+  /* The optimization to partition hot and cold basic blocks into separate
+     sections of the .o and executable files does not work (currently)
+     with exception handling.  This is because there is no support for
+     generating unwind info.  If flag_exceptions is turned on we need to
+     turn off the partitioning optimization.  */
+
+  if (flag_exceptions && flag_reorder_blocks_and_partition)
+    {
+      inform (input_location, 
+	      "-freorder-blocks-and-partition does not work with exceptions");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
+  /* If user requested unwind info, then turn off the partitioning
+     optimization.  */
+
+  if (flag_unwind_tables && ! targetm.unwind_tables_default
+      && flag_reorder_blocks_and_partition)
+    {
+      inform (input_location, "-freorder-blocks-and-partition does not support unwind info");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
+  /* If the target requested unwind info, then turn off the partitioning
+     optimization with a different message.  Likewise, if the target does not
+     support named sections.  */
+
+  if (flag_reorder_blocks_and_partition
+      && (!targetm.have_named_sections
+	  || (flag_unwind_tables && targetm.unwind_tables_default)))
+    {
+      inform (input_location,
+	      "-freorder-blocks-and-partition does not work on this architecture");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
+  /* Pipelining of outer loops is only possible when general pipelining
+     capabilities are requested.  */
+  if (!flag_sel_sched_pipelining)
+    flag_sel_sched_pipelining_outer_loops = 0;
+
+  if (!targetm.ira_cover_classes
+      && flag_ira_algorithm == IRA_ALGORITHM_CB)
+    {
+      inform (input_location,
+	      "-fira-algorithm=CB does not work on this architecture");
+      flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+    }
+
+  /* Save the current optimization options if this is the first call.  */
+  if (first_time_p)
+    {
+      optimization_default_node = build_optimization_node ();
+      optimization_current_node = optimization_default_node;
+      first_time_p = false;
+    }
+  if (flag_conserve_stack)
+    {
+      if (!PARAM_SET_P (PARAM_LARGE_STACK_FRAME))
+        PARAM_VALUE (PARAM_LARGE_STACK_FRAME) = 100;
+      if (!PARAM_SET_P (PARAM_STACK_FRAME_GROWTH))
+        PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) = 40;
+    }
+
+}
+
+#define LEFT_COLUMN	27
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column,
+   followed by word-wrapped HELP in a second column.  */
+static void
+wrap_help (const char *help,
+	   const char *item,
+	   unsigned int item_width,
+	   unsigned int columns)
+{
+  unsigned int col_width = LEFT_COLUMN;
+  unsigned int remaining, room, len;
+
+  remaining = strlen (help);
+
+  do
+    {
+      room = columns - 3 - MAX (col_width, item_width);
+      if (room > columns)
+	room = 0;
+      len = remaining;
+
+      if (room < len)
+	{
+	  unsigned int i;
+
+	  for (i = 0; help[i]; i++)
+	    {
+	      if (i >= room && len != remaining)
+		break;
+	      if (help[i] == ' ')
+		len = i;
+	      else if ((help[i] == '-' || help[i] == '/')
+		       && help[i + 1] != ' '
+		       && i > 0 && ISALPHA (help[i - 1]))
+		len = i + 1;
+	    }
+	}
+
+      printf( "  %-*.*s %.*s\n", col_width, item_width, item, len, help);
+      item_width = 0;
+      while (help[len] == ' ')
+	len++;
+      help += len;
+      remaining -= len;
+    }
+  while (remaining);
+}
+
+/* Print help for a specific front-end, etc.  */
+static void
+print_filtered_help (unsigned int include_flags,
+		     unsigned int exclude_flags,
+		     unsigned int any_flags,
+		     unsigned int columns)
+{
+  unsigned int i;
+  const char *help;
+  static char *printed = NULL;
+  bool found = false;
+  bool displayed = false;
+
+  if (include_flags == CL_PARAMS)
+    {
+      for (i = 0; i < LAST_PARAM; i++)
+	{
+	  const char *param = compiler_params[i].option;
+
+	  help = compiler_params[i].help;
+	  if (help == NULL || *help == '\0')
+	    {
+	      if (exclude_flags & CL_UNDOCUMENTED)
+		continue;
+	      help = undocumented_msg;
+	    }
+
+	  /* Get the translation.  */
+	  help = _(help);
+
+	  wrap_help (help, param, strlen (param), columns);
+	}
+      putchar ('\n');
+      return;
+    }
+
+  if (!printed)
+    printed = XCNEWVAR (char, cl_options_count);
+
+  for (i = 0; i < cl_options_count; i++)
+    {
+      static char new_help[128];
+      const struct cl_option *option = cl_options + i;
+      unsigned int len;
+      const char *opt;
+      const char *tab;
+
+      if (include_flags == 0
+	  || ((option->flags & include_flags) != include_flags))
+	{
+	  if ((option->flags & any_flags) == 0)
+	    continue;
+	}
+
+      /* Skip unwanted switches.  */
+      if ((option->flags & exclude_flags) != 0)
+	continue;
+
+      found = true;
+      /* Skip switches that have already been printed.  */
+      if (printed[i])
+	continue;
+
+      printed[i] = true;
+
+      help = option->help;
+      if (help == NULL)
+	{
+	  if (exclude_flags & CL_UNDOCUMENTED)
+	    continue;
+	  help = undocumented_msg;
+	}
+
+      /* Get the translation.  */
+      help = _(help);
+
+      /* Find the gap between the name of the
+	 option and its descriptive text.  */
+      tab = strchr (help, '\t');
+      if (tab)
+	{
+	  len = tab - help;
+	  opt = help;
+	  help = tab + 1;
+	}
+      else
+	{
+	  opt = option->opt_text;
+	  len = strlen (opt);
+	}
+
+      /* With the -Q option enabled we change the descriptive text associated
+	 with an option to be an indication of its current setting.  */
+      if (!quiet_flag)
+	{
+	  if (len < (LEFT_COLUMN + 2))
+	    strcpy (new_help, "\t\t");
+	  else
+	    strcpy (new_help, "\t");
+
+	  if (option->flag_var != NULL)
+	    {
+	      if (option->flags & CL_JOINED)
+		{
+		  if (option->var_type == CLVC_STRING)
+		    {
+		      if (* (const char **) option->flag_var != NULL)
+			snprintf (new_help + strlen (new_help),
+				  sizeof (new_help) - strlen (new_help),
+				  * (const char **) option->flag_var);
+		    }
+		  else
+		    sprintf (new_help + strlen (new_help),
+			     "%#x", * (int *) option->flag_var);
+		}
+	      else
+		strcat (new_help, option_enabled (i)
+			? _("[enabled]") : _("[disabled]"));
+	    }
+
+	  help = new_help;
+	}
+
+      wrap_help (help, opt, len, columns);
+      displayed = true;
+    }
+
+  if (! found)
+    {
+      unsigned int langs = include_flags & CL_LANG_ALL;
+
+      if (langs == 0)
+	printf (_(" No options with the desired characteristics were found\n"));
+      else
+	{
+	  unsigned int i;
+
+	  /* PR 31349: Tell the user how to see all of the
+	     options supported by a specific front end.  */
+	  for (i = 0; (1U << i) < CL_LANG_ALL; i ++)
+	    if ((1U << i) & langs)
+	      printf (_(" None found.  Use --help=%s to show *all* the options supported by the %s front-end\n"),
+		      lang_names[i], lang_names[i]);
+	}
+	
+    }
+  else if (! displayed)
+    printf (_(" All options with the desired characteristics have already been displayed\n"));
+
+  putchar ('\n');
+}
+
+/* Display help for a specified type of option.
+   The options must have ALL of the INCLUDE_FLAGS set
+   ANY of the flags in the ANY_FLAGS set
+   and NONE of the EXCLUDE_FLAGS set.  */
+static void
+print_specific_help (unsigned int include_flags,
+		     unsigned int exclude_flags,
+		     unsigned int any_flags)
+{
+  unsigned int all_langs_mask = (1U << cl_lang_count) - 1;
+  const char * description = NULL;
+  const char * descrip_extra = "";
+  size_t i;
+  unsigned int flag;
+  static unsigned int columns = 0;
+
+  /* Sanity check: Make sure that we do not have more
+     languages than we have bits available to enumerate them.  */
+  gcc_assert ((1U << cl_lang_count) < CL_MIN_OPTION_CLASS);
+
+  /* If we have not done so already, obtain
+     the desired maximum width of the output.  */
+  if (columns == 0)
+    {
+      const char *p;
+
+      GET_ENVIRONMENT (p, "COLUMNS");
+      if (p != NULL)
+	{
+	  int value = atoi (p);
+
+	  if (value > 0)
+	    columns = value;
+	}
+
+      if (columns == 0)
+	/* Use a reasonable default.  */
+	columns = 80;
+    }
+
+  /* Decide upon the title for the options that we are going to display.  */
+  for (i = 0, flag = 1; flag <= CL_MAX_OPTION_CLASS; flag <<= 1, i ++)
+    {
+      switch (flag & include_flags)
+	{
+	case 0:
+	  break;
+
+	case CL_TARGET:
+	  description = _("The following options are target specific");
+	  break;
+	case CL_WARNING:
+	  description = _("The following options control compiler warning messages");
+	  break;
+	case CL_OPTIMIZATION:
+	  description = _("The following options control optimizations");
+	  break;
+	case CL_COMMON:
+	  description = _("The following options are language-independent");
+	  break;
+	case CL_PARAMS:
+	  description = _("The --param option recognizes the following as parameters");
+	  break;
+	default:
+	  if (i >= cl_lang_count)
+	    break;
+	  if (exclude_flags & all_langs_mask)
+	    description = _("The following options are specific to just the language ");
+	  else
+	    description = _("The following options are supported by the language ");
+	  descrip_extra = lang_names [i];
+	  break;
+	}
+    }
+
+  if (description == NULL)
+    {
+      if (any_flags == 0)
+	{
+	  if (include_flags & CL_UNDOCUMENTED)
+	    description = _("The following options are not documented");
+	  else if (include_flags & CL_SEPARATE)
+	    description = _("The following options take separate arguments");
+	  else if (include_flags & CL_JOINED)
+	    description = _("The following options take joined arguments");
+	  else
+	    {
+	      internal_error ("unrecognized include_flags 0x%x passed to print_specific_help",
+			      include_flags);
+	      return;
+	    }
+	}
+      else
+	{
+	  if (any_flags & all_langs_mask)
+	    description = _("The following options are language-related");
+	  else
+	    description = _("The following options are language-independent");
+	}
+    }
+
+  printf ("%s%s:\n", description, descrip_extra);
+  print_filtered_help (include_flags, exclude_flags, any_flags, columns);
+}
+
+/* Handle target- and language-independent options.  Return zero to
+   generate an "unknown option" message.  Only options that need
+   extra handling need to be listed here; if you simply want
+   VALUE assigned to a variable, it happens automatically.  */
+
+static int
+common_handle_option (size_t scode, const char *arg, int value,
+		      unsigned int lang_mask)
+{
+  static bool verbose = false;
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    case OPT__param:
+      handle_param (arg);
+      break;
+
+    case OPT_v:
+      verbose = true;
+      break;
+
+    case OPT_fhelp:
+    case OPT__help:
+      {
+	unsigned int all_langs_mask = (1U << cl_lang_count) - 1;
+	unsigned int undoc_mask;
+	unsigned int i;
+
+	undoc_mask = (verbose | extra_warnings) ? 0 : CL_UNDOCUMENTED;
+	/* First display any single language specific options.  */
+	for (i = 0; i < cl_lang_count; i++)
+	  print_specific_help
+	    (1U << i, (all_langs_mask & (~ (1U << i))) | undoc_mask, 0);
+	/* Next display any multi language specific options.  */
+	print_specific_help (0, undoc_mask, all_langs_mask);
+	/* Then display any remaining, non-language options.  */
+	for (i = CL_MIN_OPTION_CLASS; i <= CL_MAX_OPTION_CLASS; i <<= 1)
+	  print_specific_help (i, undoc_mask, 0);
+	exit_after_options = true;
+	break;
+      }
+
+    case OPT_ftarget_help:
+    case OPT__target_help:
+      print_specific_help (CL_TARGET, CL_UNDOCUMENTED, 0);
+      exit_after_options = true;
+
+      /* Allow the target a chance to give the user some additional information.  */
+      if (targetm.target_help)
+	targetm.target_help ();
+      break;
+
+    case OPT_fhelp_:
+    case OPT__help_:
+      {
+	const char * a = arg;
+	unsigned int include_flags = 0;
+	/* Note - by default we include undocumented options when listing
+	   specific classes.  If you only want to see documented options
+	   then add ",^undocumented" to the --help= option.  E.g.:
+
+	   --help=target,^undocumented  */
+	unsigned int exclude_flags = 0;
+
+	/* Walk along the argument string, parsing each word in turn.
+	   The format is:
+	   arg = [^]{word}[,{arg}]
+	   word = {optimizers|target|warnings|undocumented|
+		   params|common|<language>}  */
+	while (* a != 0)
+	  {
+	    static struct
+	    {
+	      const char * string;
+	      unsigned int flag;
+	    }
+	    specifics[] =
+	    {
+	      { "optimizers", CL_OPTIMIZATION },
+	      { "target", CL_TARGET },
+	      { "warnings", CL_WARNING },
+	      { "undocumented", CL_UNDOCUMENTED },
+	      { "params", CL_PARAMS },
+	      { "joined", CL_JOINED },
+	      { "separate", CL_SEPARATE },
+	      { "common", CL_COMMON },
+	      { NULL, 0 }
+	    };
+	    unsigned int * pflags;
+	    char * comma;
+	    unsigned int lang_flag, specific_flag;
+	    unsigned int len;
+	    unsigned int i;
+
+	    if (* a == '^')
+	      {
+		++ a;
+		pflags = & exclude_flags;
+	      }
+	    else
+	      pflags = & include_flags;
+
+	    comma = strchr (a, ',');
+	    if (comma == NULL)
+	      len = strlen (a);
+	    else
+	      len = comma - a;
+	    if (len == 0)
+	      {
+		a = comma + 1;
+		continue;
+	      }
+
+	    /* Check to see if the string matches an option class name.  */
+	    for (i = 0, specific_flag = 0; specifics[i].string != NULL; i++)
+	      if (strncasecmp (a, specifics[i].string, len) == 0)
+		{
+		  specific_flag = specifics[i].flag;
+		  break;
+		}
+
+	    /* Check to see if the string matches a language name.
+	       Note - we rely upon the alpha-sorted nature of the entries in
+	       the lang_names array, specifically that shorter names appear
+	       before their longer variants.  (i.e. C before C++).  That way
+	       when we are attempting to match --help=c for example we will
+	       match with C first and not C++.  */
+	    for (i = 0, lang_flag = 0; i < cl_lang_count; i++)
+	      if (strncasecmp (a, lang_names[i], len) == 0)
+		{
+		  lang_flag = 1U << i;
+		  break;
+		}
+
+	    if (specific_flag != 0)
+	      {
+		if (lang_flag == 0)
+		  * pflags |= specific_flag;
+		else
+		  {
+		    /* The option's argument matches both the start of a
+		       language name and the start of an option class name.
+		       We have a special case for when the user has
+		       specified "--help=c", but otherwise we have to issue
+		       a warning.  */
+		    if (strncasecmp (a, "c", len) == 0)
+		      * pflags |= lang_flag;
+		    else
+		      fnotice (stderr,
+			       "warning: --help argument %.*s is ambiguous, please be more specific\n",
+			       len, a);
+		  }
+	      }
+	    else if (lang_flag != 0)
+	      * pflags |= lang_flag;
+	    else
+	      fnotice (stderr,
+		       "warning: unrecognized argument to --help= option: %.*s\n",
+		       len, a);
+
+	    if (comma == NULL)
+	      break;
+	    a = comma + 1;
+	  }
+
+	if (include_flags)
+	  print_specific_help (include_flags, exclude_flags, 0);
+	exit_after_options = true;
+	break;
+      }
+
+    case OPT__version:
+      print_version (stderr, "");
+      exit_after_options = true;
+      break;
+
+    case OPT_G:
+      g_switch_value = value;
+      g_switch_set = true;
+      break;
+
+    case OPT_O:
+    case OPT_Os:
+      /* Currently handled in a prescan.  */
+      break;
+
+    case OPT_W:
+      /* For backward compatibility, -W is the same as -Wextra.  */
+      set_Wextra (value);
+      break;
+
+    case OPT_Werror_:
+      enable_warning_as_error (arg, value, lang_mask);
+      break;
+
+    case OPT_Wextra:
+      set_Wextra (value);
+      break;
+
+    case OPT_Wlarger_than_:
+      /* This form corresponds to -Wlarger-than-.  
+	 Kept for backward compatibility. 
+	 Don't use it as the first argument of warning().  */
+
+    case OPT_Wlarger_than_eq:
+      larger_than_size = value;
+      warn_larger_than = value != -1;
+      break;
+
+    case OPT_Wframe_larger_than_:
+      frame_larger_than_size = value;
+      warn_frame_larger_than = value != -1;
+      break;
+
+    case OPT_Wstrict_aliasing:
+      set_Wstrict_aliasing (value);
+      break;
+
+    case OPT_Wstrict_aliasing_:
+      warn_strict_aliasing = value;
+      break;
+
+    case OPT_Wstrict_overflow:
+      warn_strict_overflow = (value
+			      ? (int) WARN_STRICT_OVERFLOW_CONDITIONAL
+			      : 0);
+      break;
+
+    case OPT_Wstrict_overflow_:
+      warn_strict_overflow = value;
+      break;
+
+    case OPT_Wunused:
+      warn_unused = value;
+      break;
+
+    case OPT_aux_info:
+    case OPT_aux_info_:
+      aux_info_file_name = arg;
+      flag_gen_aux_info = 1;
+      break;
+
+    case OPT_auxbase:
+      aux_base_name = arg;
+      break;
+
+    case OPT_auxbase_strip:
+      {
+	char *tmp = xstrdup (arg);
+	strip_off_ending (tmp, strlen (tmp));
+	if (tmp[0])
+	  aux_base_name = tmp;
+      }
+      break;
+
+    case OPT_d:
+      decode_d_option (arg);
+      break;
+
+    case OPT_dumpbase:
+      dump_base_name = arg;
+      break;
+
+    case OPT_falign_functions_:
+      align_functions = value;
+      break;
+
+    case OPT_falign_jumps_:
+      align_jumps = value;
+      break;
+
+    case OPT_falign_labels_:
+      align_labels = value;
+      break;
+
+    case OPT_falign_loops_:
+      align_loops = value;
+      break;
+
+    case OPT_fbranch_probabilities:
+      flag_branch_probabilities_set = true;
+      break;
+
+    case OPT_fcall_used_:
+      fix_register (arg, 0, 1);
+      break;
+
+    case OPT_fcall_saved_:
+      fix_register (arg, 0, 0);
+      break;
+
+    case OPT_fdbg_cnt_:
+      dbg_cnt_process_opt (arg);
+      break;
+
+    case OPT_fdbg_cnt_list:
+      dbg_cnt_list_all_counters ();
+      break;
+
+    case OPT_fdebug_prefix_map_:
+      add_debug_prefix_map (arg);
+      break;
+
+    case OPT_fdiagnostics_show_location_:
+      if (!strcmp (arg, "once"))
+	diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+      else if (!strcmp (arg, "every-line"))
+	diagnostic_prefixing_rule (global_dc)
+	  = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
+      else
+	return 0;
+      break;
+
+    case OPT_fdiagnostics_show_option:
+      global_dc->show_option_requested = true;
+      break;
+
+    case OPT_fdump_:
+      if (!dump_switch_p (arg))
+	return 0;
+      break;
+
+    case OPT_ffast_math:
+      set_fast_math_flags (value);
+      break;
+
+    case OPT_funsafe_math_optimizations:
+      set_unsafe_math_optimizations_flags (value);
+      break;
+
+    case OPT_ffixed_:
+      fix_register (arg, 1, 1);
+      break;
+
+    case OPT_finline_limit_:
+    case OPT_finline_limit_eq:
+      set_param_value ("max-inline-insns-single", value / 2);
+      set_param_value ("max-inline-insns-auto", value / 2);
+      break;
+
+    case OPT_finstrument_functions_exclude_function_list_:
+      add_comma_separated_to_vector
+	(&flag_instrument_functions_exclude_functions, arg);
+      break;
+
+    case OPT_finstrument_functions_exclude_file_list_:
+      add_comma_separated_to_vector
+	(&flag_instrument_functions_exclude_files, arg);
+      break;
+
+    case OPT_fmessage_length_:
+      pp_set_line_maximum_length (global_dc->printer, value);
+      break;
+
+    case OPT_fpack_struct_:
+      if (value <= 0 || (value & (value - 1)) || value > 16)
+	error ("structure alignment must be a small power of two, not %d", value);
+      else
+	{
+	  initial_max_fld_align = value;
+	  maximum_field_alignment = value * BITS_PER_UNIT;
+	}
+      break;
+
+    case OPT_fpeel_loops:
+      flag_peel_loops_set = true;
+      break;
+
+    case OPT_fprofile_arcs:
+      profile_arc_flag_set = true;
+      break;
+
+    case OPT_finline_functions:
+      flag_inline_functions_set = true;
+      break;
+
+    case OPT_fprofile_dir_:
+      profile_data_prefix = xstrdup (arg);
+      break;
+
+    case OPT_fprofile_use_:
+      profile_data_prefix = xstrdup (arg);
+      flag_profile_use = true;
+      value = true;
+      /* No break here - do -fprofile-use processing. */
+    case OPT_fprofile_use:
+      if (!flag_branch_probabilities_set)
+        flag_branch_probabilities = value;
+      if (!flag_profile_values_set)
+        flag_profile_values = value;
+      if (!flag_unroll_loops_set)
+        flag_unroll_loops = value;
+      if (!flag_peel_loops_set)
+        flag_peel_loops = value;
+      if (!flag_tracer_set)
+        flag_tracer = value;
+      if (!flag_value_profile_transformations_set)
+        flag_value_profile_transformations = value;
+      if (!flag_inline_functions_set)
+        flag_inline_functions = value;
+      if (!flag_ipa_cp_set)
+        flag_ipa_cp = value;
+      if (!flag_ipa_cp_clone_set
+	  && value && flag_ipa_cp)
+	flag_ipa_cp_clone = value;
+      if (!flag_predictive_commoning_set)
+	flag_predictive_commoning = value;
+      if (!flag_unswitch_loops_set)
+	flag_unswitch_loops = value;
+      if (!flag_gcse_after_reload_set)
+	flag_gcse_after_reload = value;
+      break;
+
+    case OPT_fprofile_generate_:
+      profile_data_prefix = xstrdup (arg);
+      value = true;
+      /* No break here - do -fprofile-generate processing. */
+    case OPT_fprofile_generate:
+      if (!profile_arc_flag_set)
+        profile_arc_flag = value;
+      if (!flag_profile_values_set)
+        flag_profile_values = value;
+      if (!flag_value_profile_transformations_set)
+        flag_value_profile_transformations = value;
+      if (!flag_inline_functions_set)
+        flag_inline_functions = value;
+      break;
+
+    case OPT_fprofile_values:
+      flag_profile_values_set = true;
+      break;
+
+    case OPT_fvisibility_:
+      {
+        if (!strcmp(arg, "default"))
+          default_visibility = VISIBILITY_DEFAULT;
+        else if (!strcmp(arg, "internal"))
+          default_visibility = VISIBILITY_INTERNAL;
+        else if (!strcmp(arg, "hidden"))
+          default_visibility = VISIBILITY_HIDDEN;
+        else if (!strcmp(arg, "protected"))
+          default_visibility = VISIBILITY_PROTECTED;
+        else
+          error ("unrecognized visibility value \"%s\"", arg);
+      }
+      break;
+
+    case OPT_fvpt:
+      flag_value_profile_transformations_set = true;
+      break;
+
+    case OPT_frandom_seed:
+      /* The real switch is -fno-random-seed.  */
+      if (value)
+	return 0;
+      set_random_seed (NULL);
+      break;
+
+    case OPT_frandom_seed_:
+      set_random_seed (arg);
+      break;
+
+    case OPT_fselective_scheduling:
+    case OPT_fselective_scheduling2:
+      sel_sched_switch_set = true;
+      break;
+
+    case OPT_fsched_verbose_:
+#ifdef INSN_SCHEDULING
+      fix_sched_param ("verbose", arg);
+      break;
+#else
+      return 0;
+#endif
+
+    case OPT_fsched_stalled_insns_:
+      flag_sched_stalled_insns = value;
+      if (flag_sched_stalled_insns == 0)
+	flag_sched_stalled_insns = -1;
+      break;
+
+    case OPT_fsched_stalled_insns_dep_:
+      flag_sched_stalled_insns_dep = value;
+      break;
+
+    case OPT_fstack_check_:
+      if (!strcmp (arg, "no"))
+	flag_stack_check = NO_STACK_CHECK;
+      else if (!strcmp (arg, "generic"))
+	/* This is the old stack checking method.  */
+	flag_stack_check = STACK_CHECK_BUILTIN
+			   ? FULL_BUILTIN_STACK_CHECK
+			   : GENERIC_STACK_CHECK;
+      else if (!strcmp (arg, "specific"))
+	/* This is the new stack checking method.  */
+	flag_stack_check = STACK_CHECK_BUILTIN
+			   ? FULL_BUILTIN_STACK_CHECK
+			   : STACK_CHECK_STATIC_BUILTIN
+			     ? STATIC_BUILTIN_STACK_CHECK
+			     : GENERIC_STACK_CHECK;
+      else
+	warning (0, "unknown stack check parameter \"%s\"", arg);
+      break;
+
+    case OPT_fstack_check:
+      /* This is the same as the "specific" mode above.  */
+      if (value)
+	flag_stack_check = STACK_CHECK_BUILTIN
+			   ? FULL_BUILTIN_STACK_CHECK
+			   : STACK_CHECK_STATIC_BUILTIN
+			     ? STATIC_BUILTIN_STACK_CHECK
+			     : GENERIC_STACK_CHECK;
+      else
+	flag_stack_check = NO_STACK_CHECK;
+      break;
+
+    case OPT_fstack_limit:
+      /* The real switch is -fno-stack-limit.  */
+      if (value)
+	return 0;
+      stack_limit_rtx = NULL_RTX;
+      break;
+
+    case OPT_fstack_limit_register_:
+      {
+	int reg = decode_reg_name (arg);
+	if (reg < 0)
+	  error ("unrecognized register name \"%s\"", arg);
+	else
+	  stack_limit_rtx = gen_rtx_REG (Pmode, reg);
+      }
+      break;
+
+    case OPT_fstack_limit_symbol_:
+      stack_limit_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (arg));
+      break;
+
+    case OPT_ftree_vectorizer_verbose_:
+      vect_set_verbosity_level (arg);
+      break;
+
+    case OPT_ftls_model_:
+      if (!strcmp (arg, "global-dynamic"))
+	flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
+      else if (!strcmp (arg, "local-dynamic"))
+	flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
+      else if (!strcmp (arg, "initial-exec"))
+	flag_tls_default = TLS_MODEL_INITIAL_EXEC;
+      else if (!strcmp (arg, "local-exec"))
+	flag_tls_default = TLS_MODEL_LOCAL_EXEC;
+      else
+	warning (0, "unknown tls-model \"%s\"", arg);
+      break;
+
+    case OPT_fira_algorithm_:
+      if (!strcmp (arg, "CB"))
+	flag_ira_algorithm = IRA_ALGORITHM_CB;
+      else if (!strcmp (arg, "priority"))
+	flag_ira_algorithm = IRA_ALGORITHM_PRIORITY;
+      else
+	warning (0, "unknown ira algorithm \"%s\"", arg);
+      break;
+
+    case OPT_fira_region_:
+      if (!strcmp (arg, "one"))
+	flag_ira_region = IRA_REGION_ONE;
+      else if (!strcmp (arg, "all"))
+	flag_ira_region = IRA_REGION_ALL;
+      else if (!strcmp (arg, "mixed"))
+	flag_ira_region = IRA_REGION_MIXED;
+      else
+	warning (0, "unknown ira region \"%s\"", arg);
+      break;
+
+    case OPT_fira_verbose_:
+      flag_ira_verbose = value;
+      break;
+
+    case OPT_ftracer:
+      flag_tracer_set = true;
+      break;
+
+    case OPT_fipa_cp:
+      flag_ipa_cp_set = true;
+      break;
+
+    case OPT_fipa_cp_clone:
+      flag_ipa_cp_clone_set = true;
+      break;
+
+    case OPT_fpredictive_commoning:
+      flag_predictive_commoning_set = true;
+      break;
+
+    case OPT_funswitch_loops:
+      flag_unswitch_loops_set = true;
+      break;
+
+    case OPT_fgcse_after_reload:
+      flag_gcse_after_reload_set = true;
+      break;
+
+    case OPT_funroll_loops:
+      flag_unroll_loops_set = true;
+      break;
+
+    case OPT_g:
+      set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg);
+      break;
+
+    case OPT_gcoff:
+      set_debug_level (SDB_DEBUG, false, arg);
+      break;
+
+    case OPT_gdwarf_2:
+      set_debug_level (DWARF2_DEBUG, false, arg);
+      break;
+
+    case OPT_ggdb:
+      set_debug_level (NO_DEBUG, 2, arg);
+      break;
+
+    case OPT_gstabs:
+    case OPT_gstabs_:
+      set_debug_level (DBX_DEBUG, code == OPT_gstabs_, arg);
+      break;
+
+    case OPT_gvms:
+      set_debug_level (VMS_DEBUG, false, arg);
+      break;
+
+    case OPT_gxcoff:
+    case OPT_gxcoff_:
+      set_debug_level (XCOFF_DEBUG, code == OPT_gxcoff_, arg);
+      break;
+
+    case OPT_o:
+      asm_file_name = arg;
+      break;
+
+    case OPT_pedantic_errors:
+      flag_pedantic_errors = pedantic = 1;
+      break;
+
+    case OPT_floop_optimize:
+    case OPT_frerun_loop_opt:
+    case OPT_fstrength_reduce:
+    case OPT_ftree_store_copy_prop:
+    case OPT_fforce_addr:
+    case OPT_ftree_salias:
+    case OPT_ftree_store_ccp:
+      /* These are no-ops, preserved for backward compatibility.  */
+      break;
+
+    default:
+      /* If the flag was handled in a standard way, assume the lack of
+	 processing here is intentional.  */
+      gcc_assert (cl_options[scode].flag_var);
+      break;
+    }
+
+  return 1;
+}
+
+/* Handle --param NAME=VALUE.  */
+static void
+handle_param (const char *carg)
+{
+  char *equal, *arg;
+  int value;
+
+  arg = xstrdup (carg);
+  equal = strchr (arg, '=');
+  if (!equal)
+    error ("%s: --param arguments should be of the form NAME=VALUE", arg);
+  else
+    {
+      value = integral_argument (equal + 1);
+      if (value == -1)
+	error ("invalid --param value %qs", equal + 1);
+      else
+	{
+	  *equal = '\0';
+	  set_param_value (arg, value);
+	}
+    }
+
+  free (arg);
+}
+
+/* Handle -W and -Wextra.  */
+static void
+set_Wextra (int setting)
+{
+  extra_warnings = setting;
+
+  /* We save the value of warn_uninitialized, since if they put
+     -Wuninitialized on the command line, we need to generate a
+     warning about not using it without also specifying -O.  */
+  if (setting == 0)
+    warn_uninitialized = 0;
+  else if (warn_uninitialized != 1)
+    warn_uninitialized = 2;
+}
+
+/* Used to set the level of strict aliasing warnings, 
+   when no level is specified (i.e., when -Wstrict-aliasing, and not
+   -Wstrict-aliasing=level was given).
+   ONOFF is assumed to take value 1 when -Wstrict-aliasing is specified,
+   and 0 otherwise.  After calling this function, wstrict_aliasing will be
+   set to the default value of -Wstrict_aliasing=level, currently 3.  */
+void
+set_Wstrict_aliasing (int onoff)
+{
+  gcc_assert (onoff == 0 || onoff == 1);
+  if (onoff != 0)
+    warn_strict_aliasing = 3;
+  else
+    warn_strict_aliasing = 0;
+}
+
+/* The following routines are useful in setting all the flags that
+   -ffast-math and -fno-fast-math imply.  */
+void
+set_fast_math_flags (int set)
+{
+  flag_unsafe_math_optimizations = set;
+  set_unsafe_math_optimizations_flags (set);
+  flag_finite_math_only = set;
+  flag_errno_math = !set;
+  if (set)
+    {
+      flag_signaling_nans = 0;
+      flag_rounding_math = 0;
+      flag_cx_limited_range = 1;
+    }
+}
+
+/* When -funsafe-math-optimizations is set the following 
+   flags are set as well.  */ 
+void
+set_unsafe_math_optimizations_flags (int set)
+{
+  flag_trapping_math = !set;
+  flag_signed_zeros = !set;
+  flag_associative_math = set;
+  flag_reciprocal_math = set;
+}
+
+/* Return true iff flags are set as if -ffast-math.  */
+bool
+fast_math_flags_set_p (void)
+{
+  return (!flag_trapping_math
+	  && flag_unsafe_math_optimizations
+	  && flag_finite_math_only
+	  && !flag_signed_zeros
+	  && !flag_errno_math);
+}
+
+/* Return true iff flags are set as if -ffast-math but using the flags stored
+   in the struct cl_optimization structure.  */
+bool
+fast_math_flags_struct_set_p (struct cl_optimization *opt)
+{
+  return (!opt->flag_trapping_math
+	  && opt->flag_unsafe_math_optimizations
+	  && opt->flag_finite_math_only
+	  && !opt->flag_signed_zeros
+	  && !opt->flag_errno_math);
+}
+
+/* Handle a debug output -g switch.  EXTENDED is true or false to support
+   extended output (2 is special and means "-ggdb" was given).  */
+static void
+set_debug_level (enum debug_info_type type, int extended, const char *arg)
+{
+  static bool type_explicit;
+
+  use_gnu_debug_info_extensions = extended;
+
+  if (type == NO_DEBUG)
+    {
+      if (write_symbols == NO_DEBUG)
+	{
+	  write_symbols = PREFERRED_DEBUGGING_TYPE;
+
+	  if (extended == 2)
+	    {
+#ifdef DWARF2_DEBUGGING_INFO
+	      write_symbols = DWARF2_DEBUG;
+#elif defined DBX_DEBUGGING_INFO
+	      write_symbols = DBX_DEBUG;
+#endif
+	    }
+
+	  if (write_symbols == NO_DEBUG)
+	    warning (0, "target system does not support debug output");
+	}
+    }
+  else
+    {
+      /* Does it conflict with an already selected type?  */
+      if (type_explicit && write_symbols != NO_DEBUG && type != write_symbols)
+	error ("debug format \"%s\" conflicts with prior selection",
+	       debug_type_names[type]);
+      write_symbols = type;
+      type_explicit = true;
+    }
+
+  /* A debug flag without a level defaults to level 2.  */
+  if (*arg == '\0')
+    {
+      if (!debug_info_level)
+	debug_info_level = 2;
+    }
+  else
+    {
+      debug_info_level = integral_argument (arg);
+      if (debug_info_level == (unsigned int) -1)
+	error ("unrecognised debug output level \"%s\"", arg);
+      else if (debug_info_level > 3)
+	error ("debug output level %s is too high", arg);
+    }
+}
+
+/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't
+   a simple on-off switch.  */
+
+int
+option_enabled (int opt_idx)
+{
+  const struct cl_option *option = &(cl_options[opt_idx]);
+
+  if (option->flag_var)
+    switch (option->var_type)
+      {
+      case CLVC_BOOLEAN:
+	return *(int *) option->flag_var != 0;
+
+      case CLVC_EQUAL:
+	return *(int *) option->flag_var == option->var_value;
+
+      case CLVC_BIT_CLEAR:
+	return (*(int *) option->flag_var & option->var_value) == 0;
+
+      case CLVC_BIT_SET:
+	return (*(int *) option->flag_var & option->var_value) != 0;
+
+      case CLVC_STRING:
+	break;
+      }
+  return -1;
+}
+
+/* Fill STATE with the current state of option OPTION.  Return true if
+   there is some state to store.  */
+
+bool
+get_option_state (int option, struct cl_option_state *state)
+{
+  if (cl_options[option].flag_var == 0)
+    return false;
+
+  switch (cl_options[option].var_type)
+    {
+    case CLVC_BOOLEAN:
+    case CLVC_EQUAL:
+      state->data = cl_options[option].flag_var;
+      state->size = sizeof (int);
+      break;
+
+    case CLVC_BIT_CLEAR:
+    case CLVC_BIT_SET:
+      state->ch = option_enabled (option);
+      state->data = &state->ch;
+      state->size = 1;
+      break;
+
+    case CLVC_STRING:
+      state->data = *(const char **) cl_options[option].flag_var;
+      if (state->data == 0)
+	state->data = "";
+      state->size = strlen ((const char *) state->data) + 1;
+      break;
+    }
+  return true;
+}
+
+/* Enable a warning option as an error.  This is used by -Werror= and
+   also by legacy Werror-implicit-function-declaration.  */
+
+void
+enable_warning_as_error (const char *arg, int value, unsigned int lang_mask)
+{
+  char *new_option;
+  int option_index;
+
+  new_option = XNEWVEC (char, strlen (arg) + 2);
+  new_option[0] = 'W';
+  strcpy (new_option + 1, arg);
+  option_index = find_opt (new_option, lang_mask);
+  if (option_index == N_OPTS)
+    {
+      error ("-Werror=%s: No option -%s", arg, new_option);
+    }
+  else
+    {
+      int kind = value ? DK_ERROR : DK_WARNING;
+      diagnostic_classify_diagnostic (global_dc, option_index, kind);
+      
+      /* -Werror=foo implies -Wfoo.  */
+      if (cl_options[option_index].var_type == CLVC_BOOLEAN
+	  && cl_options[option_index].flag_var
+	  && kind == DK_ERROR)
+	*(int *) cl_options[option_index].flag_var = 1;
+    }
+  free (new_option);
+}