public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Guenther <richard.guenther@gmail.com>
To: "Joseph S. Myers" <joseph@codesourcery.com>
Cc: gcc-patches@gcc.gnu.org, fortran@gcc.gnu.org, java-patches@gcc.gnu.org
Subject: Re: Make driver process options with *.opt machinery
Date: Thu, 12 Aug 2010 22:23:00 -0000	[thread overview]
Message-ID: <AANLkTi=aQJtX3_uojjJuGRdBS0nr=jZPVHT84dR9NKDd@mail.gmail.com> (raw)
In-Reply-To: <Pine.LNX.4.64.1008122131420.28932@digraph.polyomino.org.uk>

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
>

  reply	other threads:[~2010-08-12 22:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-12 21:37 Joseph S. Myers
2010-08-12 22:23 ` Richard Guenther [this message]
2010-08-16  9:37 ` Tobias Burnus
2010-08-16 10:20   ` Joseph S. Myers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='AANLkTi=aQJtX3_uojjJuGRdBS0nr=jZPVHT84dR9NKDd@mail.gmail.com' \
    --to=richard.guenther@gmail.com \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=java-patches@gcc.gnu.org \
    --cc=joseph@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).