Patchwork Make driver process options with *.opt machinery

login
register
mail settings
Submitter Joseph S. Myers
Date Aug. 12, 2010, 9:33 p.m.
Message ID <Pine.LNX.4.64.1008122131420.28932@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/61646/
State New
Headers show

Comments

Joseph S. Myers - Aug. 12, 2010, 9:33 p.m.
This patch (relative to a tree with
<http://gcc.gnu.org/ml/gcc-patches/2010-08/msg00868.html> applied -
that patch is pending review of the driver part) makes the compiler
driver use the same option processing machinery as the core compilers,
a necessary prerequisite for it to use the same option handlers as
well in order that multilib selection can become based on feature
settings computed the same way in the driver as in the compilers
proper.

This particular patch does not cause the option handlers to be shared;
that will come later.  What it does is mark options the driver needs
to handle specially with Driver markings in the .opt files, adding
entries for such options not previously in the .opt files.  It would
make sense for the driver to use the --help machinery from opts.c, but
for now it stays with its own machinery and reporting of driver
options by the opts.c machinery is disabled.  (I have no current plans
to work further on the --help side of things.)

The common machinery is then used to handle the driver options, in
place of a long chain of "if" statements; the callbacks for unknown
options and wrong-language options are used to save options the driver
doesn't handle itself for subsequent processing in specs.  This patch
replaces just the main option handling loop; I intend to move the
decoding of options to an array earlier in future patches, so that
stages such as lang_specific_driver also work on logical options,
prune_options becomes part of the process of generating the array and
translation of options becomes a general system for option aliases in
.opt files.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
commit?

2010-08-12  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.

c-family:
2010-08-12  Joseph Myers  <joseph@codesourcery.com>

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

fortran:
2010-08-12  Joseph Myers  <joseph@codesourcery.com>

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

java:
2010-08-12  Joseph Myers  <joseph@codesourcery.com>

	* lang.opt (MD_, MMD_, version): Mark RejectDriver.
Richard Guenther - Aug. 12, 2010, 10:18 p.m.
On Thu, Aug 12, 2010 at 11:33 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch (relative to a tree with
> <http://gcc.gnu.org/ml/gcc-patches/2010-08/msg00868.html> applied -
> that patch is pending review of the driver part) makes the compiler

These are ok.

> driver use the same option processing machinery as the core compilers,
> a necessary prerequisite for it to use the same option handlers as
> well in order that multilib selection can become based on feature
> settings computed the same way in the driver as in the compilers
> proper.
>
> This particular patch does not cause the option handlers to be shared;
> that will come later.  What it does is mark options the driver needs
> to handle specially with Driver markings in the .opt files, adding
> entries for such options not previously in the .opt files.  It would
> make sense for the driver to use the --help machinery from opts.c, but
> for now it stays with its own machinery and reporting of driver
> options by the opts.c machinery is disabled.  (I have no current plans
> to work further on the --help side of things.)
>
> The common machinery is then used to handle the driver options, in
> place of a long chain of "if" statements; the callbacks for unknown
> options and wrong-language options are used to save options the driver
> doesn't handle itself for subsequent processing in specs.  This patch
> replaces just the main option handling loop; I intend to move the
> decoding of options to an array earlier in future patches, so that
> stages such as lang_specific_driver also work on logical options,
> prune_options becomes part of the process of generating the array and
> translation of options becomes a general system for option aliases in
> .opt files.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok for the middle-end changes.

Thanks,
Richard.

> 2010-08-12  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.
>
> c-family:
> 2010-08-12  Joseph Myers  <joseph@codesourcery.com>
>
>        * c.opt (MDX, MMDX, lang-asm): Mark RejectDriver.
>
> fortran:
> 2010-08-12  Joseph Myers  <joseph@codesourcery.com>
>
>        * lang.opt (MDX, MMDX): Mark RejectDriver.
>
> java:
> 2010-08-12  Joseph Myers  <joseph@codesourcery.com>
>
>        * lang.opt (MD_, MMD_, version): Mark RejectDriver.
>
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/c-family/c.opt gcc-mainline/gcc/c-family/c.opt
> --- gcc-mainline-MD/gcc/c-family/c.opt  2010-08-11 15:59:32.000000000 -0700
> +++ gcc-mainline/gcc/c-family/c.opt     2010-08-12 02:48:01.000000000 -0700
> @@ -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++
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/common.opt gcc-mainline/gcc/common.opt
> --- gcc-mainline-MD/gcc/common.opt      2010-08-11 15:25:33.000000000 -0700
> +++ gcc-mainline/gcc/common.opt 2010-08-12 02:47:21.000000000 -0700
> @@ -23,39 +23,51 @@
>
>  ; 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
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/doc/options.texi gcc-mainline/gcc/doc/options.texi
> --- gcc-mainline-MD/gcc/doc/options.texi        2010-08-11 15:25:31.000000000 -0700
> +++ gcc-mainline/gcc/doc/options.texi   2010-08-12 02:47:21.000000000 -0700
> @@ -102,6 +102,10 @@ The option is available for all language
>  @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 differ
>  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
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/fortran/lang.opt gcc-mainline/gcc/fortran/lang.opt
> --- gcc-mainline-MD/gcc/fortran/lang.opt        2010-08-11 16:00:04.000000000 -0700
> +++ gcc-mainline/gcc/fortran/lang.opt   2010-08-12 02:48:14.000000000 -0700
> @@ -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
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/gcc.c gcc-mainline/gcc/gcc.c
> --- gcc-mainline-MD/gcc/gcc.c   2010-08-11 16:00:28.000000000 -0700
> +++ gcc-mainline/gcc/gcc.c      2010-08-12 09:49:05.000000000 -0700
> @@ -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 **
>   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 **
>
>   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;
> -
> -         /* 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"));
> -
> -         goto normal_switch;
> -       }
> -      else if (strcmp (argv[i], "-fhelp") == 0)
> -       {
> -         /* translate_options () has turned --help into -fhelp.  */
> -         print_help_list = 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 ("--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)
> -       {
> -         /* 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++;
> +  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;
> +
> +  for (j = 1; j < decoded_options_count; j++)
> +    {
> +      switch (decoded_options[j].opt_index)
> +       {
> +       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 (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;
> +      if (have_c)
> +       break;
> +    }
>
> -             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.
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/java/lang.opt gcc-mainline/gcc/java/lang.opt
> --- gcc-mainline-MD/gcc/java/lang.opt   2010-08-11 15:25:31.000000000 -0700
> +++ gcc-mainline/gcc/java/lang.opt      2010-08-12 02:47:21.000000000 -0700
> @@ -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.
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opt-functions.awk gcc-mainline/gcc/opt-functions.awk
> --- gcc-mainline-MD/gcc/opt-functions.awk       2010-08-11 16:00:36.000000000 -0700
> +++ gcc-mainline/gcc/opt-functions.awk  2010-08-12 02:47:21.000000000 -0700
> @@ -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
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts-common.c gcc-mainline/gcc/opts-common.c
> --- gcc-mainline-MD/gcc/opts-common.c   2010-08-11 15:25:31.000000000 -0700
> +++ gcc-mainline/gcc/opts-common.c      2010-08-12 04:31:59.000000000 -0700
> @@ -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
>
>   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
>       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
>     }
>
>   /* 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
>    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,
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts.c gcc-mainline/gcc/opts.c
> --- gcc-mainline-MD/gcc/opts.c  2010-08-11 15:25:33.000000000 -0700
> +++ gcc-mainline/gcc/opts.c     2010-08-12 12:21:14.000000000 -0700
> @@ -418,17 +418,27 @@ complain_wrong_lang (const struct cl_dec
>  {
>   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
>   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 includ
>       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 includ
>       switch (flag & include_flags)
>        {
>        case 0:
> +       case CL_DRIVER:
>          break;
>
>        case CL_TARGET:
> @@ -1436,7 +1454,8 @@ common_handle_option (const struct cl_de
>        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;
>       }
> diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts.h gcc-mainline/gcc/opts.h
> --- gcc-mainline-MD/gcc/opts.h  2010-08-11 15:25:33.000000000 -0700
> +++ gcc-mainline/gcc/opts.h     2010-08-12 02:47:21.000000000 -0700
> @@ -67,11 +67,12 @@ extern const unsigned int cl_options_cou
>  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  */
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>
Tobias Burnus - Aug. 16, 2010, 9:31 a.m.
On 08/12/2010 11:33 PM, Joseph S. Myers wrote:
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?
>
> fortran:
> 2010-08-12  Joseph Myers<joseph@codesourcery.com>
> 	* lang.opt (MDX, MMDX): Mark RejectDriver.

The Fortran bits are OK (Java and middle-end have been approved by 
others) - I think the Fortran changes are close to obvious.

However, I wonder about the following (cf. excerpt below), namely about 
the MissingArgError; shouldn't one use this for all *.opt files?

Tobias

> +++ gcc-mainline/gcc/c-family/c.opt	2010-08-12 02:48:01.000000000 -0700
> MDX
> -C ObjC C++ ObjC++ Separate MissingArgError(missing filename after %qs)
> +C ObjC C++ ObjC++ RejectDriver Separate MissingArgError(missing filename after %qs)

> +++ gcc-mainline/gcc/fortran/lang.opt	2010-08-12 02:48:14.000000000 -0700
>   MDX
> -Fortran Separate
> +Fortran Separate RejectDriver

> +++ gcc-mainline/gcc/java/lang.opt	2010-08-12 02:47:21.000000000 -0700
>   MD_
> -Java Undocumented
> +Java Undocumented RejectDriver
Joseph S. Myers - Aug. 16, 2010, 10:07 a.m.
On Mon, 16 Aug 2010, Tobias Burnus wrote:

>  On 08/12/2010 11:33 PM, Joseph S. Myers wrote:
> > Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> > commit?
> > 
> > fortran:
> > 2010-08-12  Joseph Myers<joseph@codesourcery.com>
> > 	* lang.opt (MDX, MMDX): Mark RejectDriver.
> 
> The Fortran bits are OK (Java and middle-end have been approved by others) - I
> think the Fortran changes are close to obvious.
> 
> However, I wonder about the following (cf. excerpt below), namely about the
> MissingArgError; shouldn't one use this for all *.opt files?

The awk scripts combine such settings from all .opt files.  In general, 
yes, it would be better for such combining not to be needed except for the 
flags saying what front ends an option is for, but I have not tried to fix 
existing .opt entries for that.

Patch

diff -rupN --exclude=.svn gcc-mainline-MD/gcc/c-family/c.opt gcc-mainline/gcc/c-family/c.opt
--- gcc-mainline-MD/gcc/c-family/c.opt	2010-08-11 15:59:32.000000000 -0700
+++ gcc-mainline/gcc/c-family/c.opt	2010-08-12 02:48:01.000000000 -0700
@@ -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++
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/common.opt gcc-mainline/gcc/common.opt
--- gcc-mainline-MD/gcc/common.opt	2010-08-11 15:25:33.000000000 -0700
+++ gcc-mainline/gcc/common.opt	2010-08-12 02:47:21.000000000 -0700
@@ -23,39 +23,51 @@ 
 
 ; 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
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/doc/options.texi gcc-mainline/gcc/doc/options.texi
--- gcc-mainline-MD/gcc/doc/options.texi	2010-08-11 15:25:31.000000000 -0700
+++ gcc-mainline/gcc/doc/options.texi	2010-08-12 02:47:21.000000000 -0700
@@ -102,6 +102,10 @@  The option is available for all language
 @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 differ
 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
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/fortran/lang.opt gcc-mainline/gcc/fortran/lang.opt
--- gcc-mainline-MD/gcc/fortran/lang.opt	2010-08-11 16:00:04.000000000 -0700
+++ gcc-mainline/gcc/fortran/lang.opt	2010-08-12 02:48:14.000000000 -0700
@@ -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
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/gcc.c gcc-mainline/gcc/gcc.c
--- gcc-mainline-MD/gcc/gcc.c	2010-08-11 16:00:28.000000000 -0700
+++ gcc-mainline/gcc/gcc.c	2010-08-12 09:49:05.000000000 -0700
@@ -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 **
   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 **
 
   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;
-
-	  /* 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"));
-
-	  goto normal_switch;
-	}
-      else if (strcmp (argv[i], "-fhelp") == 0)
-	{
-	  /* translate_options () has turned --help into -fhelp.  */
-	  print_help_list = 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 ("--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)
-	{
-	  /* 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++;
+  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;
+
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      switch (decoded_options[j].opt_index)
+	{
+	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 (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;
+      if (have_c)
+	break;
+    }
 
-	      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.
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/java/lang.opt gcc-mainline/gcc/java/lang.opt
--- gcc-mainline-MD/gcc/java/lang.opt	2010-08-11 15:25:31.000000000 -0700
+++ gcc-mainline/gcc/java/lang.opt	2010-08-12 02:47:21.000000000 -0700
@@ -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.
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opt-functions.awk gcc-mainline/gcc/opt-functions.awk
--- gcc-mainline-MD/gcc/opt-functions.awk	2010-08-11 16:00:36.000000000 -0700
+++ gcc-mainline/gcc/opt-functions.awk	2010-08-12 02:47:21.000000000 -0700
@@ -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
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts-common.c gcc-mainline/gcc/opts-common.c
--- gcc-mainline-MD/gcc/opts-common.c	2010-08-11 15:25:31.000000000 -0700
+++ gcc-mainline/gcc/opts-common.c	2010-08-12 04:31:59.000000000 -0700
@@ -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
 
   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
       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
     }
 
   /* 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
    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, 
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts.c gcc-mainline/gcc/opts.c
--- gcc-mainline-MD/gcc/opts.c	2010-08-11 15:25:33.000000000 -0700
+++ gcc-mainline/gcc/opts.c	2010-08-12 12:21:14.000000000 -0700
@@ -418,17 +418,27 @@  complain_wrong_lang (const struct cl_dec
 {
   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
   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 includ
       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 includ
       switch (flag & include_flags)
 	{
 	case 0:
+	case CL_DRIVER:
 	  break;
 
 	case CL_TARGET:
@@ -1436,7 +1454,8 @@  common_handle_option (const struct cl_de
 	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;
       }
diff -rupN --exclude=.svn gcc-mainline-MD/gcc/opts.h gcc-mainline/gcc/opts.h
--- gcc-mainline-MD/gcc/opts.h	2010-08-11 15:25:33.000000000 -0700
+++ gcc-mainline/gcc/opts.h	2010-08-12 02:47:21.000000000 -0700
@@ -67,11 +67,12 @@  extern const unsigned int cl_options_cou
 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  */