OSDN Git Service

* common.opt: Add driver options.
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Aug 2010 10:15:15 +0000 (10:15 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 16 Aug 2010 10:15:15 +0000 (10:15 +0000)
(auxbase, auxbase-strip, quiet, version): Mark RejectDriver.
* doc/options.texi (Driver, RejectDriver): Document.
* gcc.c (pass_exit_codes, print_search_dirs, print_file_name,
print_prog_name, print_multi_directory, print_sysroot,
print_multi_os_directory, print_multi_lib,
print_sysroot_headers_suffix, report_times, combine_flag,
use_pipes, wrapper_string): Remove.
(save_switch, driver_unknown_option_callback,
driver_wrong_lang_callback, driver_post_handling_callback,
driver_handle_option): New.
(spec_lang, last_language_n_infiles): Make file-scope static
instead of local to process_command.
(process_command): Use decode_cmdline_options_to_array and
read_cmdline_option for option processing.  Compute have_c in
prescan of decoded options.
* opt-functions.awk (switch_flags): Handle Driver and
RejectDriver.
(var_type, var_type_struct): Handle Separate options as generating
const char * variables.
* opts-common.c (decode_cmdline_option): Expect CL_COMMON and
CL_TARGET to be passed by caller if required.
(decode_cmdline_options_to_array): Update comment.
* opts.c (complain_wrong_lang): Handle options only valid for the
driver.
(decode_options): Update call to decode_cmdline_options_to_array.
(print_filtered_help): Ignore driver-only options.
(print_specific_help): Ignore CL_DRIVER.
(common_handle_option): Don't call print_specific_help for
CL_DRIVER.
* opts.h (CL_DRIVER, CL_REJECT_DRIVER): Define.
(CL_PARAMS, CL_WARNING, CL_OPTIMIZATION, CL_TARGET, CL_COMMON):
Update values.

c-family:
* c.opt (MDX, MMDX, lang-asm): Mark RejectDriver.

fortran:
* lang.opt (MDX, MMDX): Mark RejectDriver.

java:
* lang.opt (MD_, MMD_, version): Mark RejectDriver.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163279 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/common.opt
gcc/doc/options.texi
gcc/fortran/ChangeLog
gcc/fortran/lang.opt
gcc/gcc.c
gcc/java/ChangeLog
gcc/java/lang.opt
gcc/opt-functions.awk
gcc/opts-common.c
gcc/opts.c
gcc/opts.h

index 57df2ab..92ae264 100644 (file)
@@ -1,3 +1,39 @@
+2010-08-16  Joseph Myers  <joseph@codesourcery.com>
+
+       * common.opt: Add driver options.
+       (auxbase, auxbase-strip, quiet, version): Mark RejectDriver.
+       * doc/options.texi (Driver, RejectDriver): Document.
+       * gcc.c (pass_exit_codes, print_search_dirs, print_file_name,
+       print_prog_name, print_multi_directory, print_sysroot,
+       print_multi_os_directory, print_multi_lib,
+       print_sysroot_headers_suffix, report_times, combine_flag,
+       use_pipes, wrapper_string): Remove.
+       (save_switch, driver_unknown_option_callback,
+       driver_wrong_lang_callback, driver_post_handling_callback,
+       driver_handle_option): New.
+       (spec_lang, last_language_n_infiles): Make file-scope static
+       instead of local to process_command.
+       (process_command): Use decode_cmdline_options_to_array and
+       read_cmdline_option for option processing.  Compute have_c in
+       prescan of decoded options.
+       * opt-functions.awk (switch_flags): Handle Driver and
+       RejectDriver.
+       (var_type, var_type_struct): Handle Separate options as generating
+       const char * variables.
+       * opts-common.c (decode_cmdline_option): Expect CL_COMMON and
+       CL_TARGET to be passed by caller if required.
+       (decode_cmdline_options_to_array): Update comment.
+       * opts.c (complain_wrong_lang): Handle options only valid for the
+       driver.
+       (decode_options): Update call to decode_cmdline_options_to_array.
+       (print_filtered_help): Ignore driver-only options.
+       (print_specific_help): Ignore CL_DRIVER.
+       (common_handle_option): Don't call print_specific_help for
+       CL_DRIVER.
+       * opts.h (CL_DRIVER, CL_REJECT_DRIVER): Define.
+       (CL_PARAMS, CL_WARNING, CL_OPTIMIZATION, CL_TARGET, CL_COMMON):
+       Update values.
+
 2010-08-16  Richard Guenther  <rguenther@suse.de>
 
        * tree-cfg.c (verify_types_in_gimple_reference): Verify
index 56aabb4..80034e6 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-16  Joseph Myers  <joseph@codesourcery.com>
+
+       * c.opt (MDX, MMDX, lang-asm): Mark RejectDriver.
+
 2010-08-12  Joseph Myers  <joseph@codesourcery.com>
 
        * c.opt (MD, MMD): Change to MDX and MMDX.
index 98569cb..d1aa10e 100644 (file)
@@ -73,7 +73,7 @@ C ObjC C++ ObjC++
 Generate make dependencies
 
 MDX
-C ObjC C++ ObjC++ Separate MissingArgError(missing filename after %qs)
+C ObjC C++ ObjC++ RejectDriver Separate MissingArgError(missing filename after %qs)
 -MD    Generate make dependencies and compile
 
 MF
@@ -89,7 +89,7 @@ C ObjC C++ ObjC++
 Like -M but ignore system header files
 
 MMDX
-C ObjC C++ ObjC++ Separate MissingArgError(missing filename after %qs)
+C ObjC C++ ObjC++ RejectDriver Separate MissingArgError(missing filename after %qs)
 -MMD   Like -MD but ignore system header files
 
 MP
@@ -926,7 +926,7 @@ C ObjC C++ ObjC++ Joined Separate
 -iwithprefixbefore <dir>       Add <dir> to the end of the main include path
 
 lang-asm
-C Undocumented
+C Undocumented RejectDriver
 
 nostdinc
 C ObjC C++ ObjC++
index 1285ff0..96d0c9f 100644 (file)
 
 ; Please try to keep this file in ASCII collating order.
 
+###
+Driver
+
 -help
-Common
+Common Driver
 Display this information
 
 -help=
-Common Report Joined
+Common Driver Report Joined
 --help=<class> Display descriptions of a specific class of options.  <class> is one or more of optimizers, target, warnings, undocumented, params
 
 -target-help
-Common
+Common Driver
 Alias for --help=target
 
 ;; The following four entries are to work around the gcc driver
 ;; program's insatiable desire to turn options starting with a
 ;; double dash (--) into options starting with a dash f (-f).
 fhelp
-Common Var(help_flag)
+Common Driver Var(help_flag)
 
 fhelp=
-Common Joined
+Common Driver Joined
 
 ftarget-help
-Common
+Common Driver
 
 fversion
-Common
+Common Driver
 
 -param
 Common Separate
 --param <param>=<value>        Set parameter <param> to value.  See below for a complete list of parameters
 
+-sysroot=
+Driver JoinedOrMissing
+
 -version
-Common
+Common Driver
+
+B
+Driver Joined Separate
+
+E
+Driver
 
 O
 Common JoinedOrMissing Optimization
@@ -69,10 +81,22 @@ Ofast
 Common Optimization
 Optimize for speed disregarding exact standards compliance
 
+S
+Driver
+
 W
 Common RejectNegative Var(extra_warnings) Warning
 This switch is deprecated; use -Wextra instead
 
+Wa,
+Driver JoinedOrMissing
+
+Wl,
+Driver JoinedOrMissing
+
+Wp,
+Driver JoinedOrMissing
+
 Waggregate-return
 Common Var(warn_aggregate_return) Warning
 Warn about returning structures, unions or arrays
@@ -260,6 +284,15 @@ Wcoverage-mismatch
 Common Var(warn_coverage_mismatch) Init(1) Warning
 Warn in case profiles in -fprofile-use do not match
 
+Xassembler
+Driver Separate
+
+Xlinker
+Driver Separate
+
+Xpreprocessor
+Driver Separate
+
 aux-info
 Common Separate
 -aux-info <file>       Emit declaration information into <file>
@@ -268,10 +301,16 @@ aux-info=
 Common Joined
 
 auxbase
-Common Separate
+Common Separate RejectDriver
 
 auxbase-strip
-Common Separate
+Common Separate RejectDriver
+
+combine
+Driver Var(combine_flag)
+
+c
+Driver
 
 d
 Common Joined
@@ -285,6 +324,15 @@ dumpdir
 Common Separate
 -dumpdir <dir> Set the directory name to be used for dumps
 
+dumpmachine
+Driver
+
+dumpspecs
+Driver
+
+dumpversion
+Driver
+
 ; The version of the C++ ABI in use.  The following values are allowed:
 ;
 ; 0: The version of the ABI believed most conformant with the C++ ABI
@@ -410,12 +458,16 @@ fcommon
 Common Report Var(flag_no_common,0) Optimization
 Do not put uninitialized globals in the common section
 
+fcompare-debug
+Driver
+; Converted by the driver to -fcompare-debug= options.
+
 fcompare-debug=
-Common JoinedOrMissing RejectNegative Var(flag_compare_debug_opt)
+Common Driver JoinedOrMissing RejectNegative Var(flag_compare_debug_opt)
 -fcompare-debug[=<opts>]       Compile with and without e.g. -gtoggle, and compare the final-insns dump
 
 fcompare-debug-second
-Common RejectNegative Var(flag_compare_debug)
+Common Driver RejectNegative Var(flag_compare_debug)
 Run only the second compilation of -fcompare-debug
 
 fconserve-stack
@@ -1587,14 +1639,23 @@ iplugindir=
 Common Joined Var(plugindir_string) Init(0)
 -iplugindir=<dir>      Set <dir> to be the default plugin directory
 
+l
+Driver Joined Separate
+
+no-canonical-prefixes
+Driver
+
 o
-Common Joined Separate MissingArgError(missing filename after %qs)
+Common Driver Joined Separate MissingArgError(missing filename after %qs)
 -o <file>      Place output into <file>
 
 p
 Common Var(profile_flag)
 Enable function profiling
 
+pass-exit-codes
+Driver Var(pass_exit_codes)
+
 pedantic
 Common Var(pedantic)
 Issue warnings needed for strict compliance to the standard
@@ -1603,22 +1664,92 @@ pedantic-errors
 Common
 Like -pedantic but issue them as errors
 
+pipe
+Driver Var(use_pipes)
+
+print-file-name=
+Driver JoinedOrMissing Var(print_file_name)
+
+print-libgcc-file-name
+Driver
+
+print-multi-directory
+Driver Var(print_multi_directory)
+
+print-multi-lib
+Driver Var(print_multi_lib)
+
+print-multi-os-directory
+Driver Var(print_multi_os_directory)
+
+print-prog-name=
+Driver JoinedOrMissing Var(print_prog_name)
+
+print-search-dirs
+Driver Var(print_search_dirs)
+
+print-sysroot
+Driver Var(print_sysroot)
+
+print-sysroot-headers-suffix
+Driver Var(print_sysroot_headers_suffix)
+
 quiet
-Common Var(quiet_flag)
+Common Var(quiet_flag) RejectDriver
 Do not display functions compiled or elapsed time
 
+save-temps
+Driver
+
+save-temps=
+Driver Joined
+
+time
+Driver Var(report_times)
+
+time=
+Driver JoinedOrMissing
+
+v
+Driver
+
 version
-Common Var(version_flag)
+Common Var(version_flag) RejectDriver
 Display the compiler's version
 
 w
 Common Var(inhibit_warnings)
 Suppress warnings
 
+wrapper
+Driver Separate Var(wrapper_string)
+
+x
+Driver Joined Separate
+
 shared
 Common RejectNegative Negative(pie)
 Create a shared library
 
+shared-libgcc
+Driver
+
+specs
+Driver Separate
+
+specs=
+Driver Joined
+
+static-libgcc
+Driver
+
+static-libgfortran
+Driver
+; Documented for Fortran, but always accepted by driver.
+
+static-libstdc++
+Driver
+
 pie
 Common RejectNegative Negative(shared)
 Create a position independent executable
index b14b2b4..fff148d 100644 (file)
@@ -102,6 +102,10 @@ The option is available for all languages and targets.
 @item Target
 The option is available for all languages but is target-specific.
 
+@item Driver
+The option is handled by the compiler driver using code not shared
+with the compilers proper (@file{cc1} etc.).
+
 @item @var{language}
 The option is available when compiling for the given language.
 
@@ -109,6 +113,10 @@ It is possible to specify several different languages for the same
 option.  Each @var{language} must have been declared by an earlier
 @code{Language} record.  @xref{Option file format}.
 
+@item RejectDriver
+The option is only handled by the compilers proper (@file{cc1} etc.)@:
+and should not be accepted by the driver.
+
 @item RejectNegative
 The option does not have a ``no-'' form.  All options beginning with
 ``f'', ``W'' or ``m'' are assumed to have a ``no-'' form unless this
index dbb06cf..cf8eb49 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-16  Joseph Myers  <joseph@codesourcery.com>
+
+       * lang.opt (MDX, MMDX): Mark RejectDriver.
+
 2010-08-15  Janus Weil  <janus@gcc.gnu.org>
 
        * trans-expr.c (gfc_trans_assign_vtab_procs): Clean up (we don't have
index 453a241..dea1451 100644 (file)
@@ -61,7 +61,7 @@ Fortran
 ; Documented in C
 
 MDX
-Fortran Separate
+Fortran Separate RejectDriver
 ; Documented in C
 
 MF
@@ -77,7 +77,7 @@ Fortran
 ; Documented in C
 
 MMDX
-Fortran Separate
+Fortran Separate RejectDriver
 ; Documented in C
 
 MP
index 8aef83b..f0a037c 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -140,44 +140,9 @@ int is_cpp_driver;
 /* Flag set to nonzero if an @file argument has been supplied to gcc.  */
 static bool at_file_supplied;
 
-/* Flag saying to pass the greatest exit code returned by a sub-process
-   to the calling program.  */
-static int pass_exit_codes;
-
 /* Definition of string containing the arguments given to configure.  */
 #include "configargs.h"
 
-/* Flag saying to print the directories gcc will search through looking for
-   programs, libraries, etc.  */
-
-static int print_search_dirs;
-
-/* Flag saying to print the full filename of this file
-   as found through our usual search mechanism.  */
-
-static const char *print_file_name = NULL;
-
-/* As print_file_name, but search for executable file.  */
-
-static const char *print_prog_name = NULL;
-
-/* Flag saying to print the relative path we'd use to
-   find libgcc.a given the current compiler flags.  */
-
-static int print_multi_directory;
-
-static int print_sysroot;
-
-/* Flag saying to print the relative path we'd use to
-   find OS libraries given the current compiler flags.  */
-
-static int print_multi_os_directory;
-
-/* Flag saying to print the list of subdirectories and
-   compiler flags used to select them in a standard form.  */
-
-static int print_multi_lib;
-
 /* Flag saying to print the command line options understood by gcc and its
    sub-processes.  */
 
@@ -187,11 +152,6 @@ static int print_help_list;
 
 static int print_version;
 
-/* Flag saying to print the sysroot suffix used for searching for
-   headers.  */
-
-static int print_sysroot_headers_suffix;
-
 /* Flag indicating whether we should print the command and arguments */
 
 static int verbose_flag;
@@ -207,11 +167,6 @@ static int verbose_only_flag;
 
 static int print_subprocess_help;
 
-/* Flag indicating whether we should report subprocess execution times
-   (if this is supported by the system - see pexecute.c).  */
-
-static int report_times;
-
 /* Whether we should report subprocess execution times to a file.  */
 
 FILE *report_times_to_file = NULL;
@@ -250,15 +205,6 @@ static enum save_temps {
 static char *save_temps_prefix = 0;
 static size_t save_temps_length = 0;
 
-/* Nonzero means pass multiple source files to the compiler at one time.  */
-
-static int combine_flag = 0;
-
-/* Nonzero means use pipes to communicate between subprocesses.
-   Overridden by either of the above two flags.  */
-
-static int use_pipes;
-
 /* The compiler version.  */
 
 static const char *compiler_version;
@@ -295,14 +241,6 @@ static struct obstack obstack;
 
 static struct obstack collect_obstack;
 
-/* This is a list of a wrapper program and its arguments.
-   e.g. wrapper_string of "strace,-c"
-   will cause all programs to run as
-       strace -c program arguments
-   instead of just
-       program arguments */
-static const char  *wrapper_string;
-
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 struct prefix_list;
@@ -3506,6 +3444,448 @@ alloc_switch (void)
     }
 }
 
+/* Save an option OPT with N_ARGS arguments in array ARGS, marking it
+   as validated if VALIDATED.  */
+
+static void
+save_switch (const char *opt, size_t n_args, const char *const *args,
+            bool validated)
+{
+  alloc_switch ();
+  switches[n_switches].part1 = opt + 1;
+  if (n_args == 0)
+    switches[n_switches].args = 0;
+  else
+    {
+      switches[n_switches].args = XNEWVEC (const char *, n_args + 1);
+      memcpy (switches[n_switches].args, args, n_args * sizeof (const char *));
+      switches[n_switches].args[n_args] = NULL;
+    }
+
+  switches[n_switches].live_cond = 0;
+  switches[n_switches].validated = validated;
+  switches[n_switches].ordering = 0;
+  n_switches++;
+}
+
+/* Handle an option DECODED that is unknown to the option-processing
+   machinery, but may be known to specs.  */
+
+static bool
+driver_unknown_option_callback (const struct cl_decoded_option *decoded)
+{
+  save_switch (decoded->canonical_option[0],
+              decoded->canonical_option_num_elements - 1,
+              &decoded->canonical_option[1], false);
+
+  return false;
+}
+
+/* Handle an option DECODED that is not marked as CL_DRIVER.
+   LANG_MASK will always be CL_DRIVER.  */
+
+static void
+driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
+                           unsigned int lang_mask ATTRIBUTE_UNUSED)
+{
+  /* At this point, non-driver options are accepted (and expected to
+     be passed down by specs) unless marked to be rejected by the
+     driver.  Options to be rejected by the driver but accepted by the
+     compilers proper are treated just like completely unknown
+     options.  */
+  const struct cl_option *option = &cl_options[decoded->opt_index];
+
+  if (option->flags & CL_REJECT_DRIVER)
+    error ("unrecognized command line option %qs",
+          decoded->orig_option_with_args_text);
+  else
+    driver_unknown_option_callback (decoded);
+}
+
+/* Note that an option (index OPT_INDEX, argument ARG, value VALUE)
+   has been successfully handled with a handler for mask MASK.  */
+
+static void
+driver_post_handling_callback (const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
+                              unsigned int mask ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do here.  */
+}
+
+static const char *spec_lang = 0;
+static int last_language_n_infiles;
+
+/* Handle a driver option; arguments and return value as for
+   handle_option.  */
+
+static bool
+driver_handle_option (const struct cl_decoded_option *decoded,
+                     unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
+                     const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  size_t opt_index = decoded->opt_index;
+  const char *arg = decoded->arg;
+  const char *compare_debug_replacement_opt;
+  int value = decoded->value;
+  bool validated = false;
+  bool do_save = true;
+
+  gcc_assert (kind == DK_UNSPECIFIED);
+
+  switch (opt_index)
+    {
+    case OPT_dumpspecs:
+      {
+       struct spec_list *sl;
+       init_spec ();
+       for (sl = specs; sl; sl = sl->next)
+         printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
+       if (link_command_spec)
+         printf ("*link_command:\n%s\n\n", link_command_spec);
+       exit (0);
+      }
+
+    case OPT_dumpversion:
+      printf ("%s\n", spec_version);
+      exit (0);
+
+    case OPT_dumpmachine:
+      printf ("%s\n", spec_machine);
+      exit (0);
+
+    case OPT_fversion:
+      /* translate_options () has turned --version into -fversion.  */
+      print_version = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--version", strlen ("--version"));
+      add_assembler_option ("--version", strlen ("--version"));
+      add_linker_option ("--version", strlen ("--version"));
+      break;
+
+    case OPT_fhelp:
+      /* translate_options () has turned --help into -fhelp.  */
+      print_help_list = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--help", 6);
+      add_assembler_option ("--help", 6);
+      add_linker_option ("--help", 6);
+      break;
+
+    case OPT_fhelp_:
+      /* translate_options () has turned --help into -fhelp.  */
+      print_subprocess_help = 2;
+      break;
+
+    case OPT_ftarget_help:
+      /* translate_options() has turned --target-help into -ftarget-help.  */
+      print_subprocess_help = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--target-help", 13);
+      add_assembler_option ("--target-help", 13);
+      add_linker_option ("--target-help", 13);
+      break;
+
+    case OPT_pass_exit_codes:
+    case OPT_print_search_dirs:
+    case OPT_print_file_name_:
+    case OPT_print_prog_name_:
+    case OPT_print_multi_lib:
+    case OPT_print_multi_directory:
+    case OPT_print_sysroot:
+    case OPT_print_multi_os_directory:
+    case OPT_print_sysroot_headers_suffix:
+    case OPT_time:
+    case OPT_wrapper:
+      /* These options set the variables specified in common.opt
+        automatically, and do not need to be saved for spec
+        processing.  */
+      do_save = false;
+      break;
+
+    case OPT_print_libgcc_file_name:
+      print_file_name = "libgcc.a";
+      do_save = false;
+      break;
+
+    case OPT_fcompare_debug_second:
+      compare_debug_second = 1;
+      break;
+
+    case OPT_fcompare_debug:
+      switch (value)
+       {
+       case 0:
+         compare_debug_replacement_opt = "-fcompare-debug=";
+         arg = "";
+         goto compare_debug_with_arg;
+
+       case 1:
+         compare_debug_replacement_opt = "-fcompare-debug=-gtoggle";
+         arg = "-gtoggle";
+         goto compare_debug_with_arg;
+
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
+    case OPT_fcompare_debug_:
+      compare_debug_replacement_opt = decoded->canonical_option[0];
+    compare_debug_with_arg:
+      gcc_assert (decoded->canonical_option_num_elements == 1);
+      gcc_assert (arg != NULL);
+      if (arg)
+       compare_debug = 1;
+      else
+       compare_debug = -1;
+      if (compare_debug < 0)
+       compare_debug_opt = NULL;
+      else
+       compare_debug_opt = arg;
+      save_switch (compare_debug_replacement_opt, 0, NULL, validated);
+      return true;
+
+    case OPT_Wa_:
+      {
+       int prev, j;
+       /* Pass the rest of this option to the assembler.  */
+
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_assembler_option (arg + prev, j - prev);
+             prev = j + 1;
+           }
+
+       /* Record the part after the last comma.  */
+       add_assembler_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wp_:
+      {
+       int prev, j;
+       /* Pass the rest of this option to the preprocessor.  */
+
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_preprocessor_option (arg + prev, j - prev);
+             prev = j + 1;
+           }
+
+       /* Record the part after the last comma.  */
+       add_preprocessor_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wl_:
+      {
+       int prev, j;
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_infile (save_string (arg + prev, j - prev), "*");
+             prev = j + 1;
+           }
+       /* Record the part after the last comma.  */
+       add_infile (arg + prev, "*");
+      }
+      do_save = false;
+      break;
+
+    case OPT_Xlinker:
+      add_infile (arg, "*");
+      do_save = false;
+      break;
+
+    case OPT_Xpreprocessor:
+      add_preprocessor_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_Xassembler:
+      add_assembler_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_l:
+      /* POSIX allows separation of -l and the lib arg; canonicalize
+        by concatenating -l with its arg */
+      add_infile (concat ("-l", arg, NULL), "*");
+      do_save = false;
+      break;
+
+    case OPT_save_temps:
+      save_temps_flag = SAVE_TEMPS_CWD;
+      validated = true;
+      break;
+
+    case OPT_save_temps_:
+      if (strcmp (arg, "cwd") == 0)
+       save_temps_flag = SAVE_TEMPS_CWD;
+      else if (strcmp (arg, "obj") == 0
+              || strcmp (arg, "object") == 0)
+       save_temps_flag = SAVE_TEMPS_OBJ;
+      else
+       fatal_error ("%qs is an unknown -save-temps option",
+                    decoded->orig_option_with_args_text);
+      break;
+
+    case OPT_no_canonical_prefixes:
+      /* Already handled as a special case, so ignored here.  */
+      do_save = false;
+      break;
+
+    case OPT_pipe:
+      validated = true;
+      /* Fall through.  */
+    case OPT_combine:
+      /* These options set the variables specified in common.opt
+        automatically, but do need to be saved for spec
+        processing.  */
+      break;
+
+    case OPT_specs:
+    case OPT_specs_:
+      {
+       struct user_specs *user = XNEW (struct user_specs);
+
+       user->next = (struct user_specs *) 0;
+       user->filename = arg;
+       if (user_specs_tail)
+         user_specs_tail->next = user;
+       else
+         user_specs_head = user;
+       user_specs_tail = user;
+      }
+      do_save = false;
+      break;
+
+    case OPT__sysroot_:
+      target_system_root = arg;
+      target_system_root_changed = 1;
+      do_save = false;
+      break;
+
+    case OPT_time_:
+      if (report_times_to_file)
+       fclose (report_times_to_file);
+      report_times_to_file = fopen (arg, "a");
+      do_save = false;
+      break;
+
+    case OPT____:
+      /* "-###"
+        This is similar to -v except that there is no execution
+        of the commands and the echoed arguments are quoted.  It
+        is intended for use in shell scripts to capture the
+        driver-generated command line.  */
+      verbose_only_flag++;
+      verbose_flag++;
+      do_save = false;
+      break;
+
+    case OPT_B:
+      {
+       size_t len = strlen (arg);
+
+       /* Catch the case where the user has forgotten to append a
+          directory separator to the path.  Note, they may be using
+          -B to add an executable name prefix, eg "i386-elf-", in
+          order to distinguish between multiple installations of
+          GCC in the same directory.  Hence we must check to see
+          if appending a directory separator actually makes a
+          valid directory name.  */
+       if (!IS_DIR_SEPARATOR (arg[len - 1])
+           && is_directory (arg, false))
+         {
+           char *tmp = XNEWVEC (char, len + 2);
+           strcpy (tmp, arg);
+           tmp[len] = DIR_SEPARATOR;
+           tmp[++len] = 0;
+           arg = tmp;
+         }
+
+       add_prefix (&exec_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+       add_prefix (&startfile_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+       add_prefix (&include_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+      }
+      validated = true;
+      break;
+
+    case OPT_v:        /* Print our subcommands and print versions.  */
+      verbose_flag++;
+      break;
+
+    case OPT_x:
+      spec_lang = arg;
+      if (!strcmp (spec_lang, "none"))
+       /* Suppress the warning if -xnone comes after the last input
+          file, because alternate command interfaces like g++ might
+          find it useful to place -xnone after each input file.  */
+       spec_lang = 0;
+      else
+       last_language_n_infiles = n_infiles;
+      do_save = false;
+      break;
+
+    case OPT_S:
+    case OPT_c:
+    case OPT_E:
+      /* have_c already set in a prescan above.  */
+      break;
+
+    case OPT_o:
+      have_o = 1;
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
+      arg = convert_filename (arg, ! have_c, 0);
+#endif
+      /* Save the output name in case -save-temps=obj was used.  */
+      save_temps_prefix = xstrdup (arg);
+      /* On some systems, ld cannot handle "-o" without a space.  So
+        split the option from its argument.  */
+      save_switch ("-o", 1, &arg, validated);
+      return true;
+
+    case OPT_static_libgcc:
+    case OPT_shared_libgcc:
+    case OPT_static_libgfortran:
+    case OPT_static_libstdc__:
+      /* These are always valid, since gcc.c itself understands the
+        first two, gfortranspec.c understands -static-libgfortran and
+        g++spec.c understands -static-libstdc++ */
+      validated = true;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (do_save)
+    save_switch (decoded->canonical_option[0],
+                decoded->canonical_option_num_elements - 1,
+                &decoded->canonical_option[1], validated);
+  return true;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -3515,11 +3895,12 @@ process_command (int argc, const char **argv)
   int i;
   const char *temp;
   char *temp1;
-  const char *spec_lang = 0;
-  int last_language_n_infiles;
   const char *tooldir_prefix;
   char *(*get_relative_prefix) (const char *, const char *,
                                const char *) = NULL;
+  struct cl_option_handlers handlers;
+  struct cl_decoded_option *decoded_options;
+  unsigned int decoded_options_count, j;
 
   GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
 
@@ -3735,538 +4116,74 @@ process_command (int argc, const char **argv)
 
   last_language_n_infiles = -1;
 
-  for (i = 1; i < argc; i++)
-    {
-      const char *p = NULL;
-      int c = 0;
-
-      if (argv[i][0] == '-' && argv[i][1] != 0)
-       {
-         p = &argv[i][1];
-         c = *p;
-       }
-
-      if (! strcmp (argv[i], "-dumpspecs"))
-       {
-         struct spec_list *sl;
-         init_spec ();
-         for (sl = specs; sl; sl = sl->next)
-           printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
-         if (link_command_spec)
-           printf ("*link_command:\n%s\n\n", link_command_spec);
-         exit (0);
-       }
-      else if (! strcmp (argv[i], "-dumpversion"))
-       {
-         printf ("%s\n", spec_version);
-         exit (0);
-       }
-      else if (! strcmp (argv[i], "-dumpmachine"))
-       {
-         printf ("%s\n", spec_machine);
-         exit (0);
-       }
-      else if (strcmp (argv[i], "-fversion") == 0)
-       {
-         /* translate_options () has turned --version into -fversion.  */
-         print_version = 1;
+  decode_cmdline_options_to_array (argc, argv, CL_DRIVER,
+                                  &decoded_options, &decoded_options_count);
 
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--version", strlen ("--version"));
-         add_assembler_option ("--version", strlen ("--version"));
-         add_linker_option ("--version", strlen ("--version"));
+  handlers.unknown_option_callback = driver_unknown_option_callback;
+  handlers.wrong_lang_callback = driver_wrong_lang_callback;
+  handlers.post_handling_callback = driver_post_handling_callback;
+  handlers.num_handlers = 1;
+  handlers.handlers[0].handler = driver_handle_option;
+  handlers.handlers[0].mask = CL_DRIVER;
 
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-fhelp") == 0)
-       {
-         /* translate_options () has turned --help into -fhelp.  */
-         print_help_list = 1;
-
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--help", 6);
-         add_assembler_option ("--help", 6);
-         add_linker_option ("--help", 6);
-
-         goto normal_switch;
-       }
-      else if (strncmp (argv[i], "-fhelp=", 7) == 0)
-       {
-         /* translate_options () has turned --help into -fhelp.  */
-         print_subprocess_help = 2;
-
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-ftarget-help") == 0)
-       {
-         /* translate_options() has turned --target-help into -ftarget-help.  */
-         print_subprocess_help = 1;
-
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--target-help", 13);
-         add_assembler_option ("--target-help", 13);
-         add_linker_option ("--target-help", 13);
-
-         goto normal_switch;
-       }
-      else if (! strcmp (argv[i], "-pass-exit-codes"))
-       {
-         pass_exit_codes = 1;
-       }
-      else if (! strcmp (argv[i], "-print-search-dirs"))
-       print_search_dirs = 1;
-      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
-       print_file_name = "libgcc.a";
-      else if (! strncmp (argv[i], "-print-file-name=", 17))
-       print_file_name = argv[i] + 17;
-      else if (! strncmp (argv[i], "-print-prog-name=", 17))
-       print_prog_name = argv[i] + 17;
-      else if (! strcmp (argv[i], "-print-multi-lib"))
-       print_multi_lib = 1;
-      else if (! strcmp (argv[i], "-print-multi-directory"))
-       print_multi_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot"))
-       print_sysroot = 1;
-      else if (! strcmp (argv[i], "-print-multi-os-directory"))
-       print_multi_os_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
-       print_sysroot_headers_suffix = 1;
-      else if (! strcmp (argv[i], "-fcompare-debug-second"))
-       {
-         compare_debug_second = 1;
-         goto normal_switch;
-       }
-      else if (! strcmp (argv[i], "-fno-compare-debug"))
-       {
-         argv[i] = "-fcompare-debug=";
-         p = &argv[i][1];
-         goto compare_debug_with_arg;
-       }
-      else if (! strcmp (argv[i], "-fcompare-debug"))
-       {
-         argv[i] = "-fcompare-debug=-gtoggle";
-         p = &argv[i][1];
-         goto compare_debug_with_arg;
-       }
-#define OPT "-fcompare-debug="
-      else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1))
-       {
-         const char *opt;
-       compare_debug_with_arg:
-         opt = argv[i] + sizeof (OPT) - 1;
-#undef OPT
-         if (*opt)
-           compare_debug = 1;
-         else
-           compare_debug = -1;
-         if (compare_debug < 0)
-           compare_debug_opt = NULL;
-         else
-           compare_debug_opt = opt;
-         goto normal_switch;
-       }
-      else if (! strncmp (argv[i], "-Wa,", 4))
-       {
-         int prev, j;
-         /* Pass the rest of this option to the assembler.  */
-
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_assembler_option (argv[i] + prev, j - prev);
-               prev = j + 1;
-             }
-
-         /* Record the part after the last comma.  */
-         add_assembler_option (argv[i] + prev, j - prev);
-       }
-      else if (! strncmp (argv[i], "-Wp,", 4))
-       {
-         int prev, j;
-         /* Pass the rest of this option to the preprocessor.  */
-
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_preprocessor_option (argv[i] + prev, j - prev);
-               prev = j + 1;
-             }
-
-         /* Record the part after the last comma.  */
-         add_preprocessor_option (argv[i] + prev, j - prev);
-       }
-      else if (strncmp (argv[i], "-Wl,", 4) == 0)
-       {
-         int prev, j;
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_infile (save_string (argv[i] + prev, j - prev), "*");
-               prev = j + 1;
-             }
-         /* Record the part after the last comma.  */
-         add_infile (argv[i] + prev, "*");
-       }
-      else if (strcmp (argv[i], "-Xlinker") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xlinker%> is missing");
-
-         add_infile (argv[i+1], "*");
-         i++;
-       }
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xpreprocessor%> is missing");
-
-         add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
-         i++;
-       }
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xassembler%> is missing");
-
-         add_assembler_option (argv[i+1], strlen (argv[i+1]));
-         i++;
-       }
-      else if (strcmp (argv[i], "-l") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-l%> is missing");
-
-         /* POSIX allows separation of -l and the lib arg;
-            canonicalize by concatenating -l with its arg */
-         add_infile (concat ("-l", argv[i + 1], NULL), "*");
-         i++;
-       }
-      else if (strncmp (argv[i], "-l", 2) == 0)
-       {
-         add_infile (argv[i], "*");
-       }
-      else if (strcmp (argv[i], "-save-temps") == 0)
-       {
-         save_temps_flag = SAVE_TEMPS_CWD;
-         goto normal_switch;
-       }
-      else if (strncmp (argv[i], "-save-temps=", 12) == 0)
-       {
-         if (strcmp (argv[i]+12, "cwd") == 0)
-           save_temps_flag = SAVE_TEMPS_CWD;
-         else if (strcmp (argv[i]+12, "obj") == 0
-                  || strcmp (argv[i]+12, "object") == 0)
-           save_temps_flag = SAVE_TEMPS_OBJ;
-         else
-           fatal_error ("%qs is an unknown -save-temps option", argv[i]);
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-no-canonical-prefixes") == 0)
-       /* Already handled as a special case, so ignored here.  */
-       ;
-      else if (strcmp (argv[i], "-combine") == 0)
-       {
-         combine_flag = 1;
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-specs") == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (++i >= argc)
-           fatal_error ("argument to %<-specs%> is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i];
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (strlen (argv[i]) == 7)
-           fatal_error ("argument to %<-specs=%> is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i] + 7;
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
-       {
-         target_system_root = argv[i] + strlen ("--sysroot=");
-         target_system_root_changed = 1;
-       }
-      else if (strcmp (argv[i], "-time") == 0)
-       report_times = 1;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
-       {
-         if (report_times_to_file)
-           fclose (report_times_to_file);
-         report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a");
-       }
-      else if (strcmp (argv[i], "-pipe") == 0)
-       {
-         /* -pipe has to go into the switches array as well as
-            setting a flag.  */
-         use_pipes = 1;
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        {
-         if (++i >= argc)
-           fatal_error ("argument to %<-wrapper%> is missing");
-
-          wrapper_string = argv[i];
-        }
-      else if (strcmp (argv[i], "-###") == 0)
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      switch (decoded_options[j].opt_index)
        {
-         /* This is similar to -v except that there is no execution
-            of the commands and the echoed arguments are quoted.  It
-            is intended for use in shell scripts to capture the
-            driver-generated command line.  */
-         verbose_only_flag++;
-         verbose_flag++;
+       case OPT_S:
+       case OPT_c:
+       case OPT_E:
+         have_c = 1;
+         break;
        }
-      else if (argv[i][0] == '-' && argv[i][1] != 0)
-       {
-         switch (c)
-           {
-           case 'B':
-             {
-               const char *value;
-               int len;
-
-               if (p[1] == 0 && i + 1 == argc)
-                 fatal_error ("argument to %<-B%> is missing");
-               if (p[1] == 0)
-                 value = argv[i + 1];
-               else
-                 value = p + 1;
-
-               len = strlen (value);
-
-               /* Catch the case where the user has forgotten to append a
-                  directory separator to the path.  Note, they may be using
-                  -B to add an executable name prefix, eg "i386-elf-", in
-                  order to distinguish between multiple installations of
-                  GCC in the same directory.  Hence we must check to see
-                  if appending a directory separator actually makes a
-                  valid directory name.  */
-               if (! IS_DIR_SEPARATOR (value [len - 1])
-                   && is_directory (value, false))
-                 {
-                   char *tmp = XNEWVEC (char, len + 2);
-                   strcpy (tmp, value);
-                   tmp[len] = DIR_SEPARATOR;
-                   tmp[++ len] = 0;
-                   value = tmp;
-                 }
-
-               add_prefix (&exec_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-               add_prefix (&startfile_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-               add_prefix (&include_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-             }
-             goto normal_switch;
-
-           case 'v':   /* Print our subcommands and print versions.  */
-             /* If they do anything other than exactly `-v', don't set
-                verbose_flag; rather, continue on to give the error.  */
-             if (p[1] != 0)
-               break;
-             verbose_flag++;
-             goto normal_switch;
-
-           case 'x':
-             if (p[1] == 0 && i + 1 == argc)
-               fatal_error ("argument to %<-x%> is missing");
-             if (p[1] == 0)
-               spec_lang = argv[++i];
-             else
-               spec_lang = p + 1;
-             if (! strcmp (spec_lang, "none"))
-               /* Suppress the warning if -xnone comes after the last input
-                  file, because alternate command interfaces like g++ might
-                  find it useful to place -xnone after each input file.  */
-               spec_lang = 0;
-             else
-               last_language_n_infiles = n_infiles;
-             break;
-
-           case 'S':
-           case 'c':
-           case 'E':
-             if (p[1] == 0)
-               have_c = 1;
-             goto normal_switch;
-
-           case 'o':
-             have_o = 1;
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
-             if (! have_c)
-               {
-                 int skip;
-
-                 /* Forward scan, just in case -S, -E or -c is specified
-                    after -o.  */
-                 int j = i + 1;
-                 if (p[1] == 0)
-                   ++j;
-                 while (j < argc)
-                   {
-                     if (argv[j][0] == '-')
-                       {
-                         if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
-                             && argv[j][2] == 0)
-                           {
-                             have_c = 1;
-                             break;
-                           }
-                         else if ((skip = SWITCH_TAKES_ARG (argv[j][1])))
-                           j += skip - (argv[j][2] != 0);
-                         else if ((skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1)))
-                           j += skip;
-                       }
-                     j++;
-                   }
-               }
-#endif
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
-             if (p[1] == 0)
-               argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
-             else
-               {
-                 argv[i] = convert_filename (argv[i], ! have_c, 0);
-                 p = &argv[i][1];
-               }
-#endif
-             /* Save the output name in case -save-temps=obj was used.  */
-             if ((p[1] == 0) && argv[i + 1])
-               save_temps_prefix = xstrdup(argv[i + 1]);
-             else
-               save_temps_prefix = xstrdup(argv[i] + 1);
-             goto normal_switch;
-
-           default:
-           normal_switch:
-
-             alloc_switch ();
-             switches[n_switches].part1 = p;
-             /* Deal with option arguments in separate argv elements.  */
-             if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
-                 || WORD_SWITCH_TAKES_ARG (p))
-               {
-                 int j = 0;
-                 int n_args = WORD_SWITCH_TAKES_ARG (p);
+      if (have_c)
+       break;
+    }
 
-                 if (n_args == 0)
-                   {
-                     /* Count only the option arguments in separate
-                        argv elements.  */
-                     n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
-                   }
-                 if (i + n_args >= argc)
-                   fatal_error ("argument to %<-%s%> is missing", p);
-                 switches[n_switches].args
-                   = XNEWVEC (const char *, n_args + 1);
-                 while (j < n_args)
-                   switches[n_switches].args[j++] = argv[++i];
-                 /* Null-terminate the vector.  */
-                 switches[n_switches].args[j] = 0;
-               }
-             else if (c == 'o')
-               {
-                 /* On some systems, ld cannot handle "-o" without
-                    a space.  So split the option from its argument.  */
-                 char *part1 = XNEWVEC (char, 2);
-                 part1[0] = c;
-                 part1[1] = '\0';
-
-                 switches[n_switches].part1 = part1;
-                 switches[n_switches].args = XNEWVEC (const char *, 2);
-                 switches[n_switches].args[0] = xstrdup (p+1);
-                 switches[n_switches].args[1] = 0;
-               }
-             else
-               switches[n_switches].args = 0;
-
-             switches[n_switches].live_cond = 0;
-             switches[n_switches].validated = 0;
-             switches[n_switches].ordering = 0;
-             /* These are always valid, since gcc.c itself understands the
-                first four, gfortranspec.c understands -static-libgfortran
-                and g++spec.c understands -static-libstdc++ */
-             if (!strcmp (p, "save-temps")
-                 || !strcmp (p, "static-libgcc")
-                 || !strcmp (p, "shared-libgcc")
-                 || !strcmp (p, "pipe")
-                 || !strcmp (p, "static-libgfortran")
-                 || !strcmp (p, "static-libstdc++"))
-               switches[n_switches].validated = 1;
-             else
-               {
-                 char ch = switches[n_switches].part1[0];
-                 if (ch == 'B')
-                   switches[n_switches].validated = 1;
-               }
-             n_switches++;
-           }
-       }
-      else
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      if (decoded_options[j].opt_index == OPT_SPECIAL_input_file)
        {
-          const char *p = strrchr (argv[i], '@');
+         const char *arg = decoded_options[j].arg;
+          const char *p = strrchr (arg, '@');
           char *fname;
          long offset;
          int consumed;
 #ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
+         arg = convert_filename (arg, 0, access (arg, F_OK));
 #endif
          /* For LTO static archive support we handle input file
             specifications that are composed of a filename and
             an offset like FNAME@OFFSET.  */
          if (p
-             && p != argv[i]
+             && p != arg
              && sscanf (p, "@%li%n", &offset, &consumed) >= 1
              && strlen (p) == (unsigned int)consumed)
            {
-              fname = (char *)xmalloc (p - argv[i] + 1);
-              memcpy (fname, argv[i], p - argv[i]);
-              fname[p - argv[i]] = '\0';
+              fname = (char *)xmalloc (p - arg + 1);
+              memcpy (fname, arg, p - arg);
+              fname[p - arg] = '\0';
              /* Only accept non-stdin and existing FNAME parts, otherwise
                 try with the full name.  */
              if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
                {
                  free (fname);
-                 fname = xstrdup (argv[i]);
+                 fname = xstrdup (arg);
                }
            }
          else
-           fname = xstrdup (argv[i]);
+           fname = xstrdup (arg);
  
           if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
            perror_with_name (fname);
           else
-           add_infile (argv[i], spec_lang);
+           add_infile (arg, spec_lang);
 
           free (fname);
+         continue;
        }
+
+      read_cmdline_option (decoded_options + j, CL_DRIVER, &handlers);
     }
 
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
index 07674fb..d0da14b 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-16  Joseph Myers  <joseph@codesourcery.com>
+
+       * lang.opt (MD_, MMD_, version): Mark RejectDriver.
+
 2010-08-05  David Daney  <ddaney@caviumnetworks.com>
 
        * class.c (build_utf8_ref): Fix code formatting from previous commit.
index 9e9a8cb..6dba084 100644 (file)
@@ -33,7 +33,7 @@ Java
 ; Documented for C
 
 MD_
-Java Undocumented
+Java Undocumented RejectDriver
 ; Documented for C
 
 MF
@@ -45,7 +45,7 @@ Java
 ; Documented for C
 
 MMD_
-Java Undocumented
+Java Undocumented RejectDriver
 ; Documented for C
 
 MP
@@ -209,7 +209,7 @@ Java Joined
 Set the target VM version
 
 version
-Java
+Java RejectDriver
 
 ;
 ; Warnings handled by ecj.
index 4eeb67b..4ff4068 100644 (file)
@@ -78,6 +78,8 @@ function switch_flags (flags)
        result = result \
          test_flag("Common", flags, " | CL_COMMON") \
          test_flag("Target", flags, " | CL_TARGET") \
+         test_flag("Driver", flags, " | CL_DRIVER") \
+         test_flag("RejectDriver", flags, " | CL_REJECT_DRIVER") \
          test_flag("Save", flags, " | CL_SAVE") \
          test_flag("Joined", flags, " | CL_JOINED") \
          test_flag("JoinedOrMissing", flags, " | CL_JOINED | CL_MISSING_OK") \
@@ -128,7 +130,7 @@ function static_var(name, flags)
 # Return the type of variable that should be associated with the given flags.
 function var_type(flags)
 {
-       if (!flag_set_p("Joined.*", flags))
+       if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags))
                return "int "
        else if (flag_set_p("UInteger", flags))
                return "int "
@@ -143,7 +145,7 @@ function var_type_struct(flags)
 {
        if (flag_set_p("UInteger", flags))
                return "int "
-       else if (!flag_set_p("Joined.*", flags)) {
+       else if (!flag_set_p("Joined.*", flags) && !flag_set_p("Separate", flags)) {
                if (flag_set_p(".*Mask.*", flags))
                        return "int "
                else
index 6125dfa..f7c1040 100644 (file)
@@ -128,8 +128,9 @@ integral_argument (const char *arg)
 }
 
 /* Decode the switch beginning at ARGV for the language indicated by
-   LANG_MASK, into the structure *DECODED.  Returns the number of
-   switches consumed.  */
+   LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into
+   the structure *DECODED.  Returns the number of switches
+   consumed.  */
 
 static unsigned int
 decode_cmdline_option (const char **argv, unsigned int lang_mask,
@@ -147,7 +148,7 @@ decode_cmdline_option (const char **argv, unsigned int lang_mask,
 
   opt = argv[0];
 
-  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+  opt_index = find_opt (opt + 1, lang_mask);
   if (opt_index == OPT_SPECIAL_unknown
       && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
       && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
@@ -161,7 +162,7 @@ decode_cmdline_option (const char **argv, unsigned int lang_mask,
       memcpy (dup + 2, opt + 5, len - 2 + 1);
       opt = dup;
       value = 0;
-      opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+      opt_index = find_opt (opt + 1, lang_mask);
     }
 
   if (opt_index == OPT_SPECIAL_unknown)
@@ -218,11 +219,11 @@ decode_cmdline_option (const char **argv, unsigned int lang_mask,
     }
 
   /* Check if this is a switch for a different front end.  */
-  if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
+  if (!(option->flags & lang_mask))
     errors |= CL_ERR_WRONG_LANG;
   else if ((option->flags & CL_TARGET)
-          && (option->flags & CL_LANG_ALL)
-          && !(option->flags & lang_mask))
+          && (option->flags & (CL_LANG_ALL | CL_DRIVER))
+          && !(option->flags & (lang_mask & ~CL_COMMON & ~CL_TARGET)))
     /* Complain for target flag language mismatches if any languages
        are specified.  */
       errors |= CL_ERR_WRONG_LANG;
@@ -301,8 +302,9 @@ decode_cmdline_option (const char **argv, unsigned int lang_mask,
    array and *DECODED_OPTIONS_COUNT to the number of entries in the
    array.  The first entry in the array is always one for the program
    name (OPT_SPECIAL_program_name).  LANG_MASK indicates the language
-   applicable for decoding.  Do not produce any diagnostics or set
-   state outside of these variables.  */
+   flags applicable for decoding (including CL_COMMON and CL_TARGET if
+   those options should be considered applicable).  Do not produce any
+   diagnostics or set state outside of these variables.  */
 
 void
 decode_cmdline_options_to_array (unsigned int argc, const char **argv, 
index 6e52805..d04e81c 100644 (file)
@@ -418,17 +418,27 @@ complain_wrong_lang (const struct cl_decoded_option *decoded,
 {
   const struct cl_option *option = &cl_options[decoded->opt_index];
   const char *text = decoded->orig_option_with_args_text;
-  char *ok_langs, *bad_lang;
+  char *ok_langs = NULL, *bad_lang = NULL;
+  unsigned int opt_flags = option->flags;
 
   if (!lang_hooks.complain_wrong_lang_p (option))
     return;
 
-  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);
+  opt_flags &= ((1U << cl_lang_count) - 1) | CL_DRIVER;
+  if (opt_flags != CL_DRIVER)
+    ok_langs = write_langs (opt_flags);
+  if (lang_mask != CL_DRIVER)
+    bad_lang = write_langs (lang_mask);
+
+  if (opt_flags == CL_DRIVER)
+    error ("command line option %qs is valid for the driver but not for %s",
+          text, bad_lang);
+  else if (lang_mask == CL_DRIVER)
+    gcc_unreachable ();
+  else
+    /* Eventually this should become a hard error IMO.  */
+    warning (0, "command line option %qs is valid for %s but not for %s",
+            text, ok_langs, bad_lang);
 
   free (ok_langs);
   free (bad_lang);
@@ -681,7 +691,8 @@ decode_options (unsigned int argc, const char **argv,
   else
     lang_mask = initial_lang_mask;
 
-  decode_cmdline_options_to_array (argc, argv, lang_mask,
+  decode_cmdline_options_to_array (argc, argv,
+                                  lang_mask | CL_COMMON | CL_TARGET,
                                   decoded_options, decoded_options_count);
   if (first_time_p)
     /* Perform language-specific options initialization.  */
@@ -1193,6 +1204,12 @@ print_filtered_help (unsigned int include_flags,
       if ((option->flags & exclude_flags) != 0)
        continue;
 
+      /* The driver currently prints its own help text.  */
+      if ((option->flags & CL_DRIVER) != 0
+         && (option->flags & (((1U << cl_lang_count) - 1)
+                              | CL_COMMON | CL_TARGET)) == 0)
+       continue;
+
       found = true;
       /* Skip switches that have already been printed.  */
       if (printed[i])
@@ -1333,6 +1350,7 @@ print_specific_help (unsigned int include_flags,
       switch (flag & include_flags)
        {
        case 0:
+       case CL_DRIVER:
          break;
 
        case CL_TARGET:
@@ -1436,7 +1454,8 @@ common_handle_option (const struct cl_decoded_option *decoded,
        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);
+         if (i != CL_DRIVER)
+           print_specific_help (i, undoc_mask, 0);
        exit_after_options = true;
        break;
       }
index d6412c3..18dfdc2 100644 (file)
@@ -67,11 +67,12 @@ extern const unsigned int cl_options_count;
 extern const char *const lang_names[];
 extern const unsigned int cl_lang_count;
 
-#define CL_PARAMS               (1 << 17) /* Fake entry.  Used to display --param info with --help.  */
-#define CL_WARNING             (1 << 18) /* Enables an (optional) warning message.  */
-#define CL_OPTIMIZATION                (1 << 19) /* Enables an (optional) optimization.  */
-#define CL_TARGET              (1 << 20) /* Target-specific option.  */
-#define CL_COMMON              (1 << 21) /* Language-independent.  */
+#define CL_PARAMS               (1 << 15) /* Fake entry.  Used to display --param info with --help.  */
+#define CL_WARNING             (1 << 16) /* Enables an (optional) warning message.  */
+#define CL_OPTIMIZATION                (1 << 17) /* Enables an (optional) optimization.  */
+#define CL_DRIVER              (1 << 18) /* Driver option.  */
+#define CL_TARGET              (1 << 19) /* Target-specific option.  */
+#define CL_COMMON              (1 << 20) /* Language-independent.  */
 
 #define CL_MIN_OPTION_CLASS    CL_PARAMS
 #define CL_MAX_OPTION_CLASS    CL_COMMON
@@ -81,6 +82,7 @@ extern const unsigned int cl_lang_count;
    This distinction is important because --help will not list options
    which only have these higher bits set.  */
 
+#define CL_REJECT_DRIVER       (1 << 21) /* Reject this option in the driver.  */
 #define CL_SAVE                        (1 << 22) /* Target-specific option for attribute.  */
 #define CL_DISABLED            (1 << 23) /* Disabled in this configuration.  */
 #define CL_REPORT              (1 << 24) /* Report argument with -fverbose-asm  */