diff gcc/opts-common.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/opts-common.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/opts-common.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,5 +1,5 @@
 /* Command line option handling.
-   Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,11 +22,30 @@
 #include "intl.h"
 #include "coretypes.h"
 #include "opts.h"
-#include "flags.h"
+#include "options.h"
 #include "diagnostic.h"
+#include "spellcheck.h"
 
 static void prune_options (struct cl_decoded_option **, unsigned int *);
 
+/* An option that is undocumented, that takes a joined argument, and
+   that doesn't fit any of the classes of uses (language/common,
+   driver, target) is assumed to be a prefix used to catch
+   e.g. negated options, and stop them from being further shortened to
+   a prefix that could use the negated option as an argument.  For
+   example, we want -gno-statement-frontiers to be taken as a negation
+   of -gstatement-frontiers, but without catching the gno- prefix and
+   signaling it's to be used for option remapping, it would end up
+   backtracked to g with no-statemnet-frontiers as the debug level.  */
+
+static bool
+remapping_prefix_p (const struct cl_option *opt)
+{
+  return opt->flags & CL_UNDOCUMENTED
+    && opt->flags & CL_JOINED
+    && !(opt->flags & (CL_DRIVER | CL_TARGET | CL_COMMON | CL_LANG_ALL));
+}
+
 /* Perform a binary search to find which option the command-line INPUT
    matches.  Returns its index in the option array, and
    OPT_SPECIAL_unknown on failure.
@@ -52,7 +71,7 @@
    front end, the longest match for a different front end is returned
    (or N_OPTS if none) and the caller emits an error message.  */
 size_t
-find_opt (const char *input, int lang_mask)
+find_opt (const char *input, unsigned int lang_mask)
 {
   size_t mn, mn_orig, mx, md, opt_len;
   size_t match_wrong_lang;
@@ -97,6 +116,9 @@
 	  if (opt->flags & lang_mask)
 	    return mn;
 
+	  if (remapping_prefix_p (opt))
+	    return OPT_SPECIAL_unknown;
+
 	  /* If we haven't remembered a prior match, remember this
 	     one.  Any prior match is necessarily better.  */
 	  if (match_wrong_lang == OPT_SPECIAL_unknown)
@@ -147,7 +169,7 @@
   return match_wrong_lang;
 }
 
-/* If ARG is a non-negative integer made up solely of digits, return its
+/* If ARG is a non-negative decimal or hexadecimal integer, return its
    value, otherwise return -1.  */
 
 int
@@ -161,6 +183,17 @@
   if (*p == '\0')
     return atoi (arg);
 
+  /* It wasn't a decimal number - try hexadecimal.  */
+  if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X'))
+    {
+      p = arg + 2;
+      while (*p && ISXDIGIT (*p))
+	p++;
+
+      if (p != arg + 2 && *p == '\0')
+	return strtol (arg, NULL, 16);
+    }
+
   return -1;
 }
 
@@ -212,6 +245,22 @@
   return false;
 }
 
+/* Look up ARG in the enum used by option OPT_INDEX for language
+   LANG_MASK, returning true and storing the value in *VALUE if found,
+   and returning false without modifying *VALUE if not found.  */
+
+bool
+opt_enum_arg_to_value (size_t opt_index, const char *arg, int *value,
+		       unsigned int lang_mask)
+{
+  const struct cl_option *option = &cl_options[opt_index];
+
+  gcc_assert (option->var_type == CLVC_ENUM);
+
+  return enum_arg_to_value (cl_enums[option->var_enum].values, arg,
+			    value, lang_mask);
+}
+
 /* Look of VALUE in ENUM_ARGS for language LANG_MASK and store the
    corresponding string in *ARGP, returning true if the found string
    was marked as canonical, false otherwise.  If VALUE is not found
@@ -257,10 +306,11 @@
   const char *opt_text = option->opt_text;
 
   if (value == 0
-      && !(option->flags & CL_REJECT_NEGATIVE)
-      && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm'))
+      && !option->cl_reject_negative
+      && (opt_text[1] == 'W' || opt_text[1] == 'f'
+	  || opt_text[1] == 'g' || opt_text[1] == 'm'))
     {
-      char *t = XNEWVEC (char, option->opt_len + 5);
+      char *t = XOBNEWVEC (&opts_obstack, char, option->opt_len + 5);
       t[0] = '-';
       t[1] = opt_text[1];
       t[2] = 'n';
@@ -276,7 +326,7 @@
   if (arg)
     {
       if ((option->flags & CL_SEPARATE)
-	  && !(option->flags & CL_SEPARATE_ALIAS))
+	  && !option->cl_separate_alias)
 	{
 	  decoded->canonical_option[0] = opt_text;
 	  decoded->canonical_option[1] = arg;
@@ -285,7 +335,7 @@
       else
 	{
 	  gcc_assert (option->flags & CL_JOINED);
-	  decoded->canonical_option[0] = concat (opt_text, arg, NULL);
+	  decoded->canonical_option[0] = opts_concat (opt_text, arg, NULL);
 	  decoded->canonical_option[1] = NULL;
 	  decoded->canonical_option_num_elements = 1;
 	}
@@ -321,6 +371,7 @@
   {
     { "-Wno-", NULL, "-W", false, true },
     { "-fno-", NULL, "-f", false, true },
+    { "-gno-", NULL, "-g", false, true },
     { "-mno-", NULL, "-m", false, true },
     { "--debug=", NULL, "-g", false, false },
     { "--machine-", NULL, "-m", true, false },
@@ -338,6 +389,55 @@
     { "--no-", NULL, "-f", false, true }
   };
 
+/* Helper function for gcc.c's driver::suggest_option, for populating the
+   vec of suggestions for misspelled options.
+
+   option_map above provides various prefixes for spelling command-line
+   options, which decode_cmdline_option uses to map spellings of options
+   to specific options.  We want to do the reverse: to find all the ways
+   that a user could validly spell an option.
+
+   Given valid OPT_TEXT (with a leading dash) for OPTION, add it and all
+   of its valid variant spellings to CANDIDATES, each without a leading
+   dash.
+
+   For example, given "-Wabi-tag", the following are added to CANDIDATES:
+     "Wabi-tag"
+     "Wno-abi-tag"
+     "-warn-abi-tag"
+     "-warn-no-abi-tag".
+
+   The added strings must be freed using free.  */
+
+void
+add_misspelling_candidates (auto_vec<char *> *candidates,
+			    const struct cl_option *option,
+			    const char *opt_text)
+{
+  gcc_assert (candidates);
+  gcc_assert (option);
+  gcc_assert (opt_text);
+  if (remapping_prefix_p (option))
+    return;
+  candidates->safe_push (xstrdup (opt_text + 1));
+  for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++)
+    {
+      const char *opt0 = option_map[i].opt0;
+      const char *new_prefix = option_map[i].new_prefix;
+      size_t new_prefix_len = strlen (new_prefix);
+
+      if (option->cl_reject_negative && option_map[i].negated)
+	continue;
+
+      if (strncmp (opt_text, new_prefix, new_prefix_len) == 0)
+	{
+	  char *alternative = concat (opt0 + 1, opt_text + new_prefix_len,
+				      NULL);
+	  candidates->safe_push (alternative);
+	}
+    }
+}
+
 /* Decode the switch beginning at ARGV for the language indicated by
    LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into
    the structure *DECODED.  Returns the number of switches
@@ -412,7 +512,7 @@
 
   /* Reject negative form of switches that don't take negatives as
      unrecognized.  */
-  if (!value && (option->flags & CL_REJECT_NEGATIVE))
+  if (!value && option->cl_reject_negative)
     {
       opt_index = OPT_SPECIAL_unknown;
       errors |= CL_ERR_NEGATIVE;
@@ -424,18 +524,17 @@
   warn_message = option->warn_message;
 
   /* Check to see if the option is disabled for this configuration.  */
-  if (option->flags & CL_DISABLED)
+  if (option->cl_disabled)
     errors |= CL_ERR_DISABLED;
 
   /* Determine whether there may be a separate argument based on
      whether this option is being processed for the driver, and, if
      so, how many such arguments.  */
   separate_arg_flag = ((option->flags & CL_SEPARATE)
-		       && !((option->flags & CL_NO_DRIVER_ARG)
+		       && !(option->cl_no_driver_arg
 			    && (lang_mask & CL_DRIVER)));
   separate_args = (separate_arg_flag
-		   ? ((option->flags & CL_SEPARATE_NARGS_MASK)
-		      >> CL_SEPARATE_NARGS_SHIFT) + 1
+		   ? option->cl_separate_nargs + 1
 		   : 0);
   joined_arg_flag = (option->flags & CL_JOINED) != 0;
 
@@ -447,7 +546,7 @@
 	 argument to be persistent until the program exits.  */
       arg = argv[extra_args] + cl_options[opt_index].opt_len + 1 + adjust_len;
 
-      if (*arg == '\0' && !(option->flags & CL_MISSING_OK))
+      if (*arg == '\0' && !option->cl_missing_ok)
 	{
 	  if (separate_arg_flag)
 	    {
@@ -483,7 +582,7 @@
   /* Is this option an alias (or an ignored option, marked as an alias
      of OPT_SPECIAL_ignore)?  */
   if (option->alias_target != N_OPTS
-      && (!(option->flags & CL_SEPARATE_ALIAS) || have_separate_arg))
+      && (!option->cl_separate_alias || have_separate_arg))
     {
       size_t new_opt_index = option->alias_target;
 
@@ -501,12 +600,13 @@
 
 	  /* The new option must not be an alias itself.  */
 	  gcc_assert (new_option->alias_target == N_OPTS
-		      || (new_option->flags & CL_SEPARATE_ALIAS));
+		      || new_option->cl_separate_alias);
 
 	  if (option->neg_alias_arg)
 	    {
 	      gcc_assert (option->alias_arg != NULL);
 	      gcc_assert (arg == NULL);
+	      gcc_assert (!option->cl_negative_alias);
 	      if (value)
 		arg = option->alias_arg;
 	      else
@@ -517,31 +617,34 @@
 	    {
 	      gcc_assert (value == 1);
 	      gcc_assert (arg == NULL);
+	      gcc_assert (!option->cl_negative_alias);
 	      arg = option->alias_arg;
 	    }
 
+	  if (option->cl_negative_alias)
+	    value = !value;
+
 	  opt_index = new_opt_index;
 	  option = new_option;
 
 	  if (value == 0)
-	    gcc_assert (!(option->flags & CL_REJECT_NEGATIVE));
+	    gcc_assert (!option->cl_reject_negative);
 
 	  /* Recompute what arguments are allowed.  */
 	  separate_arg_flag = ((option->flags & CL_SEPARATE)
-			       && !((option->flags & CL_NO_DRIVER_ARG)
+			       && !(option->cl_no_driver_arg
 				    && (lang_mask & CL_DRIVER)));
 	  joined_arg_flag = (option->flags & CL_JOINED) != 0;
 
-	  if (separate_args > 1 || (option->flags & CL_SEPARATE_NARGS_MASK))
+	  if (separate_args > 1 || option->cl_separate_nargs)
 	    gcc_assert (separate_args
-			== ((option->flags & CL_SEPARATE_NARGS_MASK)
-			    >> CL_SEPARATE_NARGS_SHIFT) + 1);
+			== (unsigned int) option->cl_separate_nargs + 1);
 
 	  if (!(errors & CL_ERR_MISSING_ARG))
 	    {
 	      if (separate_arg_flag || joined_arg_flag)
 		{
-		  if ((option->flags & CL_MISSING_OK) && arg == NULL)
+		  if (option->cl_missing_ok && arg == NULL)
 		    arg = "";
 		  gcc_assert (arg != NULL);
 		}
@@ -555,7 +658,7 @@
 	      gcc_assert (warn_message == NULL);
 	      warn_message = option->warn_message;
 	    }
-	  if (option->flags & CL_DISABLED)
+	  if (option->cl_disabled)
 	    errors |= CL_ERR_DISABLED;
 	}
     }
@@ -564,12 +667,30 @@
   if (!option_ok_for_language (option, lang_mask))
     errors |= CL_ERR_WRONG_LANG;
 
+  /* Convert the argument to lowercase if appropriate.  */
+  if (arg && option->cl_tolower)
+    {
+      size_t j;
+      size_t len = strlen (arg);
+      char *arg_lower = XOBNEWVEC (&opts_obstack, char, len + 1);
+
+      for (j = 0; j < len; j++)
+	arg_lower[j] = TOLOWER ((unsigned char) arg[j]);
+      arg_lower[len] = 0;
+      arg = arg_lower;
+    }
+
   /* If the switch takes an integer, convert it.  */
-  if (arg && (option->flags & CL_UINTEGER))
+  if (arg && option->cl_uinteger)
     {
       value = integral_argument (arg);
       if (value == -1)
 	errors |= CL_ERR_UINT_ARG;
+
+      /* Reject value out of a range.  */
+      if (option->range_max != -1
+	  && (value < option->range_min || value > option->range_max))
+	errors |= CL_ERR_INT_RANGE_ARG;
     }
 
   /* If the switch takes an enumerated argument, convert it.  */
@@ -636,7 +757,8 @@
 	  decoded->canonical_option_num_elements = result;
 	}
     }
-  decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len);
+  decoded->orig_option_with_args_text
+    = p = XOBNEWVEC (&opts_obstack, char, total_len);
   for (i = 0; i < result; i++)
     {
       size_t len = strlen (argv[i]);
@@ -659,6 +781,40 @@
   return result;
 }
 
+/* Obstack for option strings.  */
+
+struct obstack opts_obstack;
+
+/* Like libiberty concat, but allocate using opts_obstack.  */
+
+char *
+opts_concat (const char *first, ...)
+{
+  char *newstr, *end;
+  size_t length = 0;
+  const char *arg;
+  va_list ap;
+
+  /* First compute the size of the result and get sufficient memory.  */
+  va_start (ap, first);
+  for (arg = first; arg; arg = va_arg (ap, const char *))
+    length += strlen (arg);
+  newstr = XOBNEWVEC (&opts_obstack, char, length + 1);
+  va_end (ap);
+
+  /* Now copy the individual pieces to the result string. */
+  va_start (ap, first);
+  for (arg = first, end = newstr; arg; arg = va_arg (ap, const char *))
+    {
+      length = strlen (arg);
+      memcpy (end, arg, length);
+      end += length;
+    }
+  *end = '\0';
+  va_end (ap);
+  return newstr;
+}
+
 /* Decode command-line options (ARGC and ARGV being the arguments of
    main) into an array, setting *DECODED_OPTIONS to a pointer to that
    array and *DECODED_OPTIONS_COUNT to the number of entries in the
@@ -677,7 +833,6 @@
   unsigned int n, i;
   struct cl_decoded_option *opt_array;
   unsigned int num_decoded_options;
-  bool argv_copied = false;
 
   opt_array = XNEWVEC (struct cl_decoded_option, argc);
 
@@ -712,8 +867,6 @@
       num_decoded_options++;
     }
 
-  if (argv_copied)
-    free (argv);
   *decoded_options = opt_array;
   *decoded_options_count = num_decoded_options;
   prune_options (decoded_options, decoded_options_count);
@@ -750,6 +903,7 @@
     = XNEWVEC (struct cl_decoded_option, old_decoded_options_count);
   unsigned int i;
   const struct cl_option *option;
+  unsigned int fdiagnostics_color_idx = 0;
 
   /* Remove arguments which are negated by others after them.  */
   new_decoded_options_count = 0;
@@ -769,6 +923,11 @@
 	case OPT_SPECIAL_input_file:
 	  goto keep;
 
+	/* Do not save OPT_fdiagnostics_color_, just remember the last one.  */
+	case OPT_fdiagnostics_color_:
+	  fdiagnostics_color_idx = i;
+	  continue;
+
 	default:
 	  gcc_assert (opt_idx < cl_options_count);
 	  option = &cl_options[opt_idx];
@@ -804,6 +963,17 @@
 	}
     }
 
+  if (fdiagnostics_color_idx >= 1)
+    {
+      /* We put the last -fdiagnostics-color= at the first position
+	 after argv[0] so it can take effect immediately.  */
+      memmove (new_decoded_options + 2, new_decoded_options + 1,
+	       sizeof (struct cl_decoded_option) 
+	       * (new_decoded_options_count - 1));
+      new_decoded_options[1] = old_decoded_options[fdiagnostics_color_idx];
+      new_decoded_options_count++;
+    }
+
   free (old_decoded_options);
   new_decoded_options = XRESIZEVEC (struct cl_decoded_option,
 				    new_decoded_options,
@@ -819,9 +989,10 @@
    option for options from the source file, UNKNOWN_LOCATION
    otherwise.  GENERATED_P is true for an option generated as part of
    processing another option or otherwise generated internally, false
-   for one explicitly passed by the user.  Returns false if the switch
-   was invalid.  DC is the diagnostic context for options affecting
-   diagnostics state, or NULL.  */
+   for one explicitly passed by the user.  control_warning_option
+   generated options are considered explicitly passed by the user.
+   Returns false if the switch was invalid.  DC is the diagnostic
+   context for options affecting diagnostics state, or NULL.  */
 
 static bool
 handle_option (struct gcc_options *opts,
@@ -847,11 +1018,9 @@
       {
 	if (!handlers->handlers[i].handler (opts, opts_set, decoded,
 					    lang_mask, kind, loc,
-					    handlers, dc))
+					    handlers, dc,
+					    handlers->target_option_override_hook))
 	  return false;
-	else
-	  handlers->post_handling_callback (decoded,
-					    handlers->handlers[i].mask);
       }
   
   return true;
@@ -868,13 +1037,13 @@
 			 size_t opt_index, const char *arg, int value,
 			 unsigned int lang_mask, int kind, location_t loc,
 			 const struct cl_option_handlers *handlers,
-			 diagnostic_context *dc)
+			 bool generated_p, diagnostic_context *dc)
 {
   struct cl_decoded_option decoded;
 
   generate_option (opt_index, arg, value, lang_mask, &decoded);
   return handle_option (opts, opts_set, &decoded, lang_mask, kind, loc,
-			handlers, true, dc);
+			handlers, generated_p, dc);
 }
 
 /* Fill in *DECODED with an option described by OPT_INDEX, ARG and
@@ -904,8 +1073,8 @@
 
     case 2:
       decoded->orig_option_with_args_text
-	= concat (decoded->canonical_option[0], " ",
-		  decoded->canonical_option[1], NULL);
+	= opts_concat (decoded->canonical_option[0], " ",
+		       decoded->canonical_option[1], NULL);
       break;
 
     default:
@@ -932,6 +1101,112 @@
   decoded->errors = 0;
 }
 
+/* Helper function for listing valid choices and hint for misspelled
+   value.  CANDIDATES is a vector containing all valid strings,
+   STR is set to a heap allocated string that contains all those
+   strings concatenated, separated by spaces, and the return value
+   is the closest string from those to ARG, or NULL if nothing is
+   close enough.  Callers should XDELETEVEC (STR) after using it
+   to avoid memory leaks.  */
+
+const char *
+candidates_list_and_hint (const char *arg, char *&str,
+			  const auto_vec <const char *> &candidates)
+{
+  size_t len = 0;
+  int i;
+  const char *candidate;
+  char *p;
+
+  FOR_EACH_VEC_ELT (candidates, i, candidate)
+    len += strlen (candidate) + 1;
+
+  str = p = XNEWVEC (char, len);
+  FOR_EACH_VEC_ELT (candidates, i, candidate)
+    {
+      len = strlen (candidate);
+      memcpy (p, candidate, len);
+      p[len] = ' ';
+      p += len + 1;
+    }
+  p[-1] = '\0';
+  return find_closest_string (arg, &candidates);
+}
+
+/* Perform diagnostics for read_cmdline_option and control_warning_option
+   functions.  Returns true if an error has been diagnosed.
+   LOC and LANG_MASK arguments like in read_cmdline_option.
+   OPTION is the option to report diagnostics for, OPT the name
+   of the option as text, ARG the argument of the option (for joined
+   options), ERRORS is bitmask of CL_ERR_* values.  */
+
+static bool
+cmdline_handle_error (location_t loc, const struct cl_option *option,
+		      const char *opt, const char *arg, int errors,
+		      unsigned int lang_mask)
+{
+  if (errors & CL_ERR_DISABLED)
+    {
+      error_at (loc, "command line option %qs"
+		     " is not supported by this configuration", opt);
+      return true;
+    }
+
+  if (errors & CL_ERR_MISSING_ARG)
+    {
+      if (option->missing_argument_error)
+	error_at (loc, option->missing_argument_error, opt);
+      else
+	error_at (loc, "missing argument to %qs", opt);
+      return true;
+    }
+
+  if (errors & CL_ERR_UINT_ARG)
+    {
+      error_at (loc, "argument to %qs should be a non-negative integer",
+		option->opt_text);
+      return true;
+    }
+
+  if (errors & CL_ERR_INT_RANGE_ARG)
+    {
+      error_at (loc, "argument to %qs is not between %d and %d",
+		option->opt_text, option->range_min, option->range_max);
+      return true;
+    }
+
+  if (errors & CL_ERR_ENUM_ARG)
+    {
+      const struct cl_enum *e = &cl_enums[option->var_enum];
+      unsigned int i;
+      char *s;
+
+      if (e->unknown_error)
+	error_at (loc, e->unknown_error, arg);
+      else
+	error_at (loc, "unrecognized argument in option %qs", opt);
+
+      auto_vec <const char *> candidates;
+      for (i = 0; e->values[i].arg != NULL; i++)
+	{
+	  if (!enum_arg_ok_for_language (&e->values[i], lang_mask))
+	    continue;
+	  candidates.safe_push (e->values[i].arg);
+	}
+      const char *hint = candidates_list_and_hint (arg, s, candidates);
+      if (hint)
+	inform (loc, "valid arguments to %qs are: %s; did you mean %qs?",
+		option->opt_text, s, hint);
+      else
+	inform (loc, "valid arguments to %qs are: %s", option->opt_text, s);
+      XDELETEVEC (s);
+
+      return true;
+    }
+
+  return false;
+}
+
 /* Handle the switch DECODED (location LOC) for the language indicated
    by LANG_MASK, using the handlers in *HANDLERS and setting fields in
    OPTS and OPTS_SET and using diagnostic context DC (if not NULL) for
@@ -964,58 +1239,10 @@
 
   option = &cl_options[decoded->opt_index];
 
-  if (decoded->errors & CL_ERR_DISABLED)
-    {
-      error_at (loc, "command line option %qs"
-		" is not supported by this configuration", opt);
-      return;
-    }
-
-  if (decoded->errors & CL_ERR_MISSING_ARG)
-    {
-      if (option->missing_argument_error)
-	error_at (loc, option->missing_argument_error, opt);
-      else
-	error_at (loc, "missing argument to %qs", opt);
-      return;
-    }
-
-  if (decoded->errors & CL_ERR_UINT_ARG)
-    {
-      error_at (loc, "argument to %qs should be a non-negative integer",
-		option->opt_text);
-      return;
-    }
-
-  if (decoded->errors & CL_ERR_ENUM_ARG)
-    {
-      const struct cl_enum *e = &cl_enums[option->var_enum];
-      unsigned int i;
-      size_t len;
-      char *s, *p;
-
-      if (e->unknown_error)
-	error_at (loc, e->unknown_error, decoded->arg);
-      else
-	error_at (loc, "unrecognized argument in option %qs", opt);
-
-      len = 0;
-      for (i = 0; e->values[i].arg != NULL; i++)
-	len += strlen (e->values[i].arg) + 1;
-
-      s = XALLOCAVEC (char, len);
-      p = s;
-      for (i = 0; e->values[i].arg != NULL; i++)
-	{
-	  size_t arglen = strlen (e->values[i].arg);
-	  memcpy (p, e->values[i].arg, arglen);
-	  p[arglen] = ' ';
-	  p += arglen + 1;
-	}
-      p[-1] = 0;
-      inform (loc, "valid arguments to %qs are: %s", option->opt_text, s);
-      return;
-    }
+  if (decoded->errors
+      && cmdline_handle_error (loc, option, opt, decoded->arg,
+			       decoded->errors, lang_mask))
+    return;
 
   if (decoded->errors & CL_ERR_WRONG_LANG)
     {
@@ -1047,6 +1274,9 @@
   if (!flag_var)
     return;
 
+  if ((diagnostic_t) kind != DK_UNSPECIFIED && dc != NULL)
+    diagnostic_classify_diagnostic (dc, opt_index, (diagnostic_t) kind, loc);
+
   if (opts_set != NULL)
     set_flag_var = option_flag_var (opt_index, opts_set);
 
@@ -1059,9 +1289,14 @@
 	break;
 
     case CLVC_EQUAL:
-	*(int *) flag_var = (value
-			     ? option->var_value
-			     : !option->var_value);
+	if (option->cl_host_wide_int) 
+	  *(HOST_WIDE_INT *) flag_var = (value
+					 ? option->var_value
+					 : !option->var_value);
+	else
+	  *(int *) flag_var = (value
+			       ? option->var_value
+			       : !option->var_value);
 	if (set_flag_var)
 	  *(int *) set_flag_var = 1;
 	break;
@@ -1069,11 +1304,26 @@
     case CLVC_BIT_CLEAR:
     case CLVC_BIT_SET:
 	if ((value != 0) == (option->var_type == CLVC_BIT_SET))
-	  *(int *) flag_var |= option->var_value;
+	  {
+	    if (option->cl_host_wide_int) 
+	      *(HOST_WIDE_INT *) flag_var |= option->var_value;
+	    else 
+	      *(int *) flag_var |= option->var_value;
+	  }
 	else
-	  *(int *) flag_var &= ~option->var_value;
+	  {
+	    if (option->cl_host_wide_int) 
+	      *(HOST_WIDE_INT *) flag_var &= ~option->var_value;
+	    else 
+	      *(int *) flag_var &= ~option->var_value;
+	  }
 	if (set_flag_var)
-	  *(int *) set_flag_var |= option->var_value;
+	  {
+	    if (option->cl_host_wide_int) 
+	      *(HOST_WIDE_INT *) set_flag_var |= option->var_value;
+	    else
+	      *(int *) set_flag_var |= option->var_value;
+	  }
 	break;
 
     case CLVC_STRING:
@@ -1094,24 +1344,18 @@
 
     case CLVC_DEFER:
 	{
-	  VEC(cl_deferred_option,heap) *vec
-	    = (VEC(cl_deferred_option,heap) *) *(void **) flag_var;
-	  cl_deferred_option *p;
-
-	  p = VEC_safe_push (cl_deferred_option, heap, vec, NULL);
-	  p->opt_index = opt_index;
-	  p->arg = arg;
-	  p->value = value;
-	  *(void **) flag_var = vec;
+	  vec<cl_deferred_option> *v
+	    = (vec<cl_deferred_option> *) *(void **) flag_var;
+	  cl_deferred_option p = {opt_index, arg, value};
+	  if (!v)
+	    v = XCNEW (vec<cl_deferred_option>);
+	  v->safe_push (p);
+	  *(void **) flag_var = v;
 	  if (set_flag_var)
-	    *(void **) set_flag_var = vec;
+	    *(void **) set_flag_var = v;
 	}
 	break;
     }
-
-  if ((diagnostic_t) kind != DK_UNSPECIFIED
-      && dc != NULL)
-    diagnostic_classify_diagnostic (dc, opt_index, (diagnostic_t) kind, loc);
 }
 
 /* Return the address of the flag variable for option OPT_INDEX in
@@ -1144,13 +1388,22 @@
 	return *(int *) flag_var != 0;
 
       case CLVC_EQUAL:
-	return *(int *) flag_var == option->var_value;
+	if (option->cl_host_wide_int) 
+	  return *(HOST_WIDE_INT *) flag_var == option->var_value;
+	else
+	  return *(int *) flag_var == option->var_value;
 
       case CLVC_BIT_CLEAR:
-	return (*(int *) flag_var & option->var_value) == 0;
+	if (option->cl_host_wide_int) 
+	  return (*(HOST_WIDE_INT *) flag_var & option->var_value) == 0;
+	else
+	  return (*(int *) flag_var & option->var_value) == 0;
 
       case CLVC_BIT_SET:
-	return (*(int *) flag_var & option->var_value) != 0;
+	if (option->cl_host_wide_int) 
+	  return (*(HOST_WIDE_INT *) flag_var & option->var_value) != 0;
+	else 
+	  return (*(int *) flag_var & option->var_value) != 0;
 
       case CLVC_STRING:
       case CLVC_ENUM:
@@ -1177,7 +1430,9 @@
     case CLVC_BOOLEAN:
     case CLVC_EQUAL:
       state->data = flag_var;
-      state->size = sizeof (int);
+      state->size = (cl_options[option].cl_host_wide_int
+		     ? sizeof (HOST_WIDE_INT)
+		     : sizeof (int));
       break;
 
     case CLVC_BIT_CLEAR:
@@ -1208,30 +1463,86 @@
 /* Set a warning option OPT_INDEX (language mask LANG_MASK, option
    handlers HANDLERS) to have diagnostic kind KIND for option
    structures OPTS and OPTS_SET and diagnostic context DC (possibly
-   NULL), at location LOC (UNKNOWN_LOCATION for -Werror=).  If IMPLY,
+   NULL), at location LOC (UNKNOWN_LOCATION for -Werror=).  ARG is the
+   argument of the option for joined options, or NULL otherwise.  If IMPLY,
    the warning option in question is implied at this point.  This is
    used by -Werror= and #pragma GCC diagnostic.  */
 
 void
-control_warning_option (unsigned int opt_index, int kind, bool imply,
-			location_t loc, unsigned int lang_mask,
+control_warning_option (unsigned int opt_index, int kind, const char *arg,
+			bool imply, location_t loc, unsigned int lang_mask,
 			const struct cl_option_handlers *handlers,
 			struct gcc_options *opts,
 			struct gcc_options *opts_set,
 			diagnostic_context *dc)
 {
   if (cl_options[opt_index].alias_target != N_OPTS)
-    opt_index = cl_options[opt_index].alias_target;
+    {
+      gcc_assert (!cl_options[opt_index].cl_separate_alias
+		  && !cl_options[opt_index].cl_negative_alias);
+      if (cl_options[opt_index].alias_arg)
+	arg = cl_options[opt_index].alias_arg;
+      opt_index = cl_options[opt_index].alias_target;
+    }
   if (opt_index == OPT_SPECIAL_ignore)
     return;
   if (dc)
     diagnostic_classify_diagnostic (dc, opt_index, (diagnostic_t) kind, loc);
   if (imply)
     {
+      const struct cl_option *option = &cl_options[opt_index];
+
       /* -Werror=foo implies -Wfoo.  */
-      if (cl_options[opt_index].var_type == CLVC_BOOLEAN)
-	handle_generated_option (opts, opts_set,
-				 opt_index, NULL, 1, lang_mask,
-				 kind, loc, handlers, dc);
+      if (option->var_type == CLVC_BOOLEAN || option->var_type == CLVC_ENUM)
+	{
+	  int value = 1;
+
+	  if (arg && *arg == '\0' && !option->cl_missing_ok)
+	    arg = NULL;
+
+	  if ((option->flags & CL_JOINED) && arg == NULL)
+	    {
+	      cmdline_handle_error (loc, option, option->opt_text, arg,
+				    CL_ERR_MISSING_ARG, lang_mask);
+	      return;
+	    }
+
+	  /* If the switch takes an integer, convert it.  */
+	  if (arg && option->cl_uinteger)
+	    {
+	      value = integral_argument (arg);
+	      if (value == -1)
+		{
+		  cmdline_handle_error (loc, option, option->opt_text, arg,
+					CL_ERR_UINT_ARG, lang_mask);
+		  return;
+		}
+	    }
+
+	  /* If the switch takes an enumerated argument, convert it.  */
+	  if (arg && option->var_type == CLVC_ENUM)
+	    {
+	      const struct cl_enum *e = &cl_enums[option->var_enum];
+
+	      if (enum_arg_to_value (e->values, arg, &value, lang_mask))
+		{
+		  const char *carg = NULL;
+
+		  if (enum_value_to_arg (e->values, &carg, value, lang_mask))
+		    arg = carg;
+		  gcc_assert (carg != NULL);
+		}
+	      else
+		{
+		  cmdline_handle_error (loc, option, option->opt_text, arg,
+					CL_ERR_ENUM_ARG, lang_mask);
+		  return;
+		}
+	    }
+
+	  handle_generated_option (opts, opts_set,
+				   opt_index, arg, value, lang_mask,
+				   kind, loc, handlers, false, dc);
+	}
     }
 }