Index: opts-common.c
===================================================================
--- opts-common.c	(revision 160599)
+++ opts-common.c	(working copy)
@@ -1,5 +1,5 @@
 /* Command line option handling.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  
 #include "intl.h"
 #include "coretypes.h"
 #include "opts.h"
+#include "options.h"
 
 /* Perform a binary search to find which option the command-line INPUT
    matches.  Returns its index in the option array, and N_OPTS
@@ -107,6 +108,138 @@ find_opt (const char *input, int lang_ma
   return match_wrong_lang;
 }
 
+/* If ARG is a non-negative integer made up solely of digits, return its
+   value, otherwise return -1.  */
+
+int
+integral_argument (const char *arg)
+{
+  const char *p = arg;
+
+  while (*p && ISDIGIT (*p))
+    p++;
+
+  if (*p == '\0')
+    return atoi (arg);
+
+  return -1;
+}
+
+/* Decode the switch beginning at ARGV for the language indicated by
+   LANG_MASK, into the structure *DECODED.  Returns the number of
+   switches consumed.  */
+
+unsigned int
+decode_cmdline_option (const char **argv, unsigned int lang_mask,
+		       struct cl_decoded_option *decoded)
+{
+  size_t opt_index;
+  const char *opt, *arg = 0;
+  char *dup = 0;
+  int value = 1;
+  unsigned int result = 1;
+  const struct cl_option *option;
+  int errors = 0;
+
+  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)
+    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))
+    {
+      opt_index = cl_options_count;
+      goto done;
+    }
+
+  /* Check to see if the option is disabled for this configuration.  */
+  if (option->flags & CL_DISABLED)
+    errors |= CL_ERR_DISABLED;
+
+  /* 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;
+	      if (arg == NULL)
+		result = 1;
+	    }
+	  else
+	    /* Missing argument.  */
+	    arg = NULL;
+	}
+    }
+  else if (option->flags & CL_SEPARATE)
+    {
+      arg = argv[1];
+      result = 2;
+      if (arg == NULL)
+	result = 1;
+    }
+
+  /* Check if this is a switch for a different front end.  */
+  if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
+    errors |= CL_ERR_WRONG_LANG;
+  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.  */
+      errors |= CL_ERR_WRONG_LANG;
+
+  if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
+    errors |= CL_ERR_MISSING_ARG;
+
+  /* If the switch takes an integer, convert it.  */
+  if (arg && (option->flags & CL_UINTEGER))
+    {
+      value = integral_argument (arg);
+      if (value == -1)
+	errors |= CL_ERR_UINT_ARG;
+    }
+
+ done:
+  if (dup)
+    free (dup);
+  decoded->opt_index = opt_index;
+  decoded->arg = arg;
+  decoded->value = value;
+  decoded->errors = errors;
+  return result;
+}
+
 /* Return true if NEXT_OPT_IDX cancels OPT_IDX.  Return false if the
    next one is the same as ORIG_NEXT_OPT_IDX.  */
 
Index: testsuite/gcc.dg/funroll-loops-all.c
===================================================================
--- testsuite/gcc.dg/funroll-loops-all.c	(revision 160599)
+++ testsuite/gcc.dg/funroll-loops-all.c	(working copy)
@@ -1,4 +1,4 @@
 /* PR 17594 */
 /* { dg-do compile } */
 /* { dg-options "-funroll-loops-all" } */
-/* { dg-error "unrecognized command line option \"-funroll-loops-all\"" "" { target *-*-* } 0 } */
+/* { dg-error "unrecognized command line option '-funroll-loops-all'" "" { target *-*-* } 0 } */
Index: opts.c
===================================================================
--- opts.c	(revision 160599)
+++ opts.c	(working copy)
@@ -381,22 +381,6 @@ static void complain_wrong_lang (const c
 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)
@@ -536,131 +520,61 @@ handle_option (int opt_index, int value,
 static unsigned int
 read_cmdline_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;
+  struct cl_decoded_option decoded;
+  unsigned int result;
+  const char *opt;
   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.  */
+  result = decode_cmdline_option (argv, lang_mask, &decoded);
+  if (decoded.opt_index == cl_options_count)
+    {
+      if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
+	/* We don't generate warnings for unknown -Wno-* options
+	   unless we issue diagnostics.  */
 	  postpone_unknown_option_warning (argv[0]);
-	  result = 1;
-	  goto done;
-	}
+      else
+	error ("unrecognized command line option %qs", opt);
+      return result;
     }
 
-  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;
+  option = &cl_options[decoded.opt_index];
 
-  /* Check to see if the option is disabled for this configuration.  */
-  if (option->flags & CL_DISABLED)
+  if (decoded.errors & CL_ERR_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)))
+  if (decoded.errors & CL_ERR_WRONG_LANG)
     {
       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))
+
+  if (decoded.errors & CL_ERR_MISSING_ARG)
     {
-      /* Complain for target flag language mismatches if any languages
-	 are specified.  */
-      complain_wrong_lang (argv[0], option, lang_mask);
+      if (!lang_hooks.missing_argument (opt, decoded.opt_index))
+	error ("missing argument to %qs", opt);
       goto done;
     }
 
-  if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
+  if (decoded.errors & CL_ERR_UINT_ARG)
     {
-      if (!lang_hooks.missing_argument (opt, opt_index))
-	error ("missing argument to \"%s\"", opt);
+      error ("argument to %qs should be a non-negative integer",
+	     option->opt_text);
       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;
-	}
-    }
+  gcc_assert (!decoded.errors);
 
-  if (!handle_option (opt_index, value, arg, lang_mask, DK_UNSPECIFIED))
-    result = 0;
+  if (!handle_option (decoded.opt_index, decoded.value, decoded.arg,
+		      lang_mask, DK_UNSPECIFIED))
+    error ("unrecognized command line option %qs", opt);
 
  done:
-  if (dup)
-    free (dup);
   return result;
 }
 
@@ -780,12 +694,6 @@ read_cmdline_options (unsigned int argc,
 	}
 
       n = read_cmdline_option (argv + i, lang_mask);
-
-      if (!n)
-	{
-	  n = 1;
-	  error ("unrecognized command line option \"%s\"", opt);
-	}
     }
 }
 
Index: opts.h
===================================================================
--- opts.h	(revision 160599)
+++ opts.h	(working copy)
@@ -1,5 +1,5 @@
 /* Command line option handling.
-   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008
+   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -90,6 +90,34 @@ extern const unsigned int cl_lang_count;
 #define CL_UINTEGER		(1 << 29) /* Argument is an integer >=0.  */
 #define CL_UNDOCUMENTED		(1 << 30) /* Do not output with --help.  */
 
+/* Possible ways in which a command-line option may be erroneous.
+   These do not include not being known at all; an option index of
+   cl_options_count is used for that.  */
+
+#define CL_ERR_DISABLED		(1 << 0) /* Disabled in this configuration.  */
+#define CL_ERR_MISSING_ARG	(1 << 1) /* Argument required but missing.  */
+#define CL_ERR_WRONG_LANG	(1 << 2) /* Option for wrong language.  */
+#define CL_ERR_UINT_ARG		(1 << 3) /* Bad unsigned integer argument.  */
+
+/* Structure describing the result of decoding an option.  */
+
+struct cl_decoded_option
+{
+  /* The index of this option, or cl_options_count if not known.  */
+  size_t opt_index;
+
+  /* The string argument, or NULL if none.  */
+  const char *arg;
+
+  /* For a boolean option, 1 for the true case and 0 for the "no-"
+     case.  For an unsigned integer option, the value of the
+     argument.  1 in all other cases.  */
+  int value;
+
+  /* Any flags describing errors detected in this option.  */
+  int errors;
+};
+
 /* Input file names.  */
 
 extern const char **in_fnames;
@@ -99,6 +127,10 @@ extern const char **in_fnames;
 extern unsigned num_in_fnames;
 
 size_t find_opt (const char *input, int lang_mask);
+extern int integral_argument (const char *arg);
+extern unsigned int decode_cmdline_option (const char **argv,
+					   unsigned int lang_mask,
+					   struct cl_decoded_option *decoded);
 extern void prune_options (int *argcp, char ***argvp);
 extern void decode_options (unsigned int argc, const char **argv);
 extern int option_enabled (int opt_idx);
