Patchwork Make opts-common.c handle unknown options using SWITCH_TAKES_ARG etc.

login
register
mail settings
Submitter Joseph S. Myers
Date June 23, 2010, 8:26 p.m.
Message ID <Pine.LNX.4.64.1006232024410.22427@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/56712/
State New
Headers show

Comments

Joseph S. Myers - June 23, 2010, 8:26 p.m.
This patch is relative to a tree with
<http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01968.html>,
<http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02150.html> and
<http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02260.html> applied.
The first of these patches needs C++ and Ada pieces approved; the
second needs C++ pieces approved; the third needs approval for
everything except c-family, Fortran and Java pieces.

The driver handles some options solely on the basis of specs and the
target macros SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG with no more
structured information about these options.  Although I plan to move
to .opt files having structured information about all options for all
targets (since some such unstructured specs-only options are used in
multilib selection, so such changes are required when multilib
selection ceases to be textually based), an intermediate stage
involved in reaching that point incrementally will have the driver
using shared option processing code for some purposes but still
passing through specs-only options for use in existing
specs-processing code.

Thus the shared option processing code should be able to handle
unknown options using SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG,
until more structured information eliminates those macros, and this
patch implements this.  (Right now it should only have any effect when
cc1 etc. are called directly, since it does nothing for options known
to the core compiler and the other options should not get passed
through to the core compiler.)

One complication is that SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG
can specify options taking more than one argument, a concept not yet
known to the .opt machinery.  Thus, some common options code is
adjusted to handle such options to the extent of storing multiple argv
elements appropriately in the decoded option structure.

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

2010-06-23  Joseph Myers  <joseph@codesourcery.com>

	* config/darwin-driver.c (SWITCH_TAKES_ARG,
	WORD_SWITCH_TAKES_ARG): Remove.
	* cppspec.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Remove.
	* defaults.h (DEFAULT_SWITCH_TAKES_ARG,
	DEFAULT_WORD_SWITCH_TAKES_ARG): Move from gcc.h.
	(SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Move default
	definitions from gcc.c.
	* gcc.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Move to
	defaults.h.
	* gcc.h (DEFAULT_SWITCH_TAKES_ARG, DEFAULT_WORD_SWITCH_TAKES_ARG):
	Move to defaults.h.
	* opts-common.c: Include tm.h.
	(decode_cmdline_option): Use SWITCH_TAKES_ARG and
	WORD_SWITCH_TAKES_ARG to count arguments to unknown options.
	Handle more than one argument.  Set canonical_option_num_elements.
	(decode_cmdline_options_to_array): Set
	canonical_option_num_elements and trailing elements of
	canonical_option.
	* opts.h (struct cl_decoded_option): Allow four elements in
	canonical_option.  Add field canonical_option_num_elements.
	* Makefile.in (opts-common.o): Update dependencies.

ada:
2010-06-23  Joseph Myers  <joseph@codesourcery.com>

	* gcc-interface/misc.c (gnat_init_options): Ignore erroneous
	options.  Check canonical_option_num_elements on options copied.

fortran:
2010-06-23  Joseph Myers  <joseph@codesourcery.com>

	* gfortranspec.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG):
	Remove.
Richard Guenther - June 25, 2010, 2:29 p.m.
On Wed, Jun 23, 2010 at 10:26 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch is relative to a tree with
> <http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01968.html>,
> <http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02150.html> and
> <http://gcc.gnu.org/ml/gcc-patches/2010-06/msg02260.html> applied.
> The first of these patches needs C++ and Ada pieces approved; the
> second needs C++ pieces approved; the third needs approval for
> everything except c-family, Fortran and Java pieces.
>
> The driver handles some options solely on the basis of specs and the
> target macros SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG with no more
> structured information about these options.  Although I plan to move
> to .opt files having structured information about all options for all
> targets (since some such unstructured specs-only options are used in
> multilib selection, so such changes are required when multilib
> selection ceases to be textually based), an intermediate stage
> involved in reaching that point incrementally will have the driver
> using shared option processing code for some purposes but still
> passing through specs-only options for use in existing
> specs-processing code.
>
> Thus the shared option processing code should be able to handle
> unknown options using SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG,
> until more structured information eliminates those macros, and this
> patch implements this.  (Right now it should only have any effect when
> cc1 etc. are called directly, since it does nothing for options known
> to the core compiler and the other options should not get passed
> through to the core compiler.)
>
> One complication is that SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG
> can specify options taking more than one argument, a concept not yet
> known to the .opt machinery.  Thus, some common options code is
> adjusted to handle such options to the extent of storing multiple argv
> elements appropriately in the decoded option structure.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok for the non-frontend specific changes.

Thanks,
Richard.

> 2010-06-23  Joseph Myers  <joseph@codesourcery.com>
>
>        * config/darwin-driver.c (SWITCH_TAKES_ARG,
>        WORD_SWITCH_TAKES_ARG): Remove.
>        * cppspec.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Remove.
>        * defaults.h (DEFAULT_SWITCH_TAKES_ARG,
>        DEFAULT_WORD_SWITCH_TAKES_ARG): Move from gcc.h.
>        (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Move default
>        definitions from gcc.c.
>        * gcc.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG): Move to
>        defaults.h.
>        * gcc.h (DEFAULT_SWITCH_TAKES_ARG, DEFAULT_WORD_SWITCH_TAKES_ARG):
>        Move to defaults.h.
>        * opts-common.c: Include tm.h.
>        (decode_cmdline_option): Use SWITCH_TAKES_ARG and
>        WORD_SWITCH_TAKES_ARG to count arguments to unknown options.
>        Handle more than one argument.  Set canonical_option_num_elements.
>        (decode_cmdline_options_to_array): Set
>        canonical_option_num_elements and trailing elements of
>        canonical_option.
>        * opts.h (struct cl_decoded_option): Allow four elements in
>        canonical_option.  Add field canonical_option_num_elements.
>        * Makefile.in (opts-common.o): Update dependencies.
>
> ada:
> 2010-06-23  Joseph Myers  <joseph@codesourcery.com>
>
>        * gcc-interface/misc.c (gnat_init_options): Ignore erroneous
>        options.  Check canonical_option_num_elements on options copied.
>
> fortran:
> 2010-06-23  Joseph Myers  <joseph@codesourcery.com>
>
>        * gfortranspec.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG):
>        Remove.
>
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/Makefile.in gcc-mainline/gcc/Makefile.in
> --- gcc-mainline-opt3/gcc/Makefile.in   2010-06-22 15:24:00.000000000 -0700
> +++ gcc-mainline/gcc/Makefile.in        2010-06-23 08:44:22.000000000 -0700
> @@ -2796,7 +2796,7 @@ opts.o : opts.c opts.h options.h $(TOPLE
>    $(FLAGS_H) $(PARAMS_H) $(TREE_PASS_H) $(DBGCNT_H) debug.h \
>    $(PLUGIN_H) $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
>  opts-common.o : opts-common.c opts.h $(CONFIG_H) $(SYSTEM_H) \
> -   coretypes.h intl.h $(DIAGNOSTIC_H)
> +   coretypes.h intl.h $(DIAGNOSTIC_H) $(TM_H)
>  targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
>    $(EXPR_H) $(TM_H) $(RTL_H) $(TM_P_H) $(FUNCTION_H) output.h $(TOPLEV_H) \
>    $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h \
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/ada/gcc-interface/misc.c gcc-mainline/gcc/ada/gcc-interface/misc.c
> --- gcc-mainline-opt3/gcc/ada/gcc-interface/misc.c      2010-06-22 16:02:04.000000000 -0700
> +++ gcc-mainline/gcc/ada/gcc-interface/misc.c   2010-06-23 07:46:46.000000000 -0700
> @@ -303,8 +303,13 @@ gnat_init_options (unsigned int decoded_
>   save_argc = 0;
>   for (i = 0; i < decoded_options_count; i++)
>     {
> +      if (decoded_options[i].errors
> +         || decoded_options[i].opt_index == OPT_SPECIAL_unknown)
> +       continue;
> +      gcc_assert (decoded_options[i].canonical_option_num_elements >= 1
> +                 && decoded_options[i].canonical_option_num_elements <= 2);
>       save_argv[save_argc++] = decoded_options[i].canonical_option[0];
> -      if (decoded_options[i].canonical_option[1] != NULL)
> +      if (decoded_options[i].canonical_option_num_elements >= 2)
>        save_argv[save_argc++] = decoded_options[i].canonical_option[1];
>     }
>   save_argv[save_argc] = NULL;
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/config/darwin-driver.c gcc-mainline/gcc/config/darwin-driver.c
> --- gcc-mainline-opt3/gcc/config/darwin-driver.c        2010-06-04 06:35:13.000000000 -0700
> +++ gcc-mainline/gcc/config/darwin-driver.c     2010-06-23 08:24:32.000000000 -0700
> @@ -27,14 +27,6 @@ along with GCC; see the file COPYING3.
>  #include <sys/sysctl.h>
>  #include "xregex.h"
>
> -#ifndef SWITCH_TAKES_ARG
> -#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
> -#endif
> -
> -#ifndef WORD_SWITCH_TAKES_ARG
> -#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
> -#endif
> -
>  /* When running on a Darwin system and using that system's headers and
>    libraries, default the -mmacosx-version-min flag to be the version
>    of the system on which the compiler is running.  */
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/cppspec.c gcc-mainline/gcc/cppspec.c
> --- gcc-mainline-opt3/gcc/cppspec.c     2010-06-04 06:40:58.000000000 -0700
> +++ gcc-mainline/gcc/cppspec.c  2010-06-23 08:24:05.000000000 -0700
> @@ -30,14 +30,6 @@ along with GCC; see the file COPYING3.
>    assume the user knows what they're doing.  If no explicit input is
>    mentioned, it will read stdin.  */
>
> -#ifndef SWITCH_TAKES_ARG
> -#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
> -#endif
> -
> -#ifndef WORD_SWITCH_TAKES_ARG
> -#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
> -#endif
> -
>  /* Suffixes for known sorts of input files.  Note that we do not list
>    files which are normally considered to have been preprocessed already,
>    since the user's expectation is that `cpp' always preprocesses.  */
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/defaults.h gcc-mainline/gcc/defaults.h
> --- gcc-mainline-opt3/gcc/defaults.h    2010-06-11 02:16:45.000000000 -0700
> +++ gcc-mainline/gcc/defaults.h 2010-06-23 08:24:12.000000000 -0700
> @@ -32,6 +32,38 @@ see the files COPYING3 and COPYING.RUNTI
>  #define GET_ENVIRONMENT(VALUE, NAME) do { (VALUE) = getenv (NAME); } while (0)
>  #endif
>
> +/* This defines which switch letters take arguments.  */
> +
> +#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
> +  ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
> +   || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
> +   || (CHAR) == 'I' || (CHAR) == 'J' || (CHAR) == 'm' \
> +   || (CHAR) == 'x' || (CHAR) == 'L' || (CHAR) == 'A' \
> +   || (CHAR) == 'B' )
> +
> +/* This defines which multi-letter switches take arguments.  */
> +
> +#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)             \
> + (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")     \
> +  || !strcmp (STR, "Tbss") || !strcmp (STR, "include") \
> +  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
> +  || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
> +  || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
> +  || !strcmp (STR, "iquote") || !strcmp (STR, "isystem") \
> +  || !strcmp (STR, "isysroot") \
> +  || !strcmp (STR, "-param") || !strcmp (STR, "specs") \
> +  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ") \
> +  || !strcmp (STR, "fintrinsic-modules-path") \
> +  || !strcmp (STR, "dumpbase") || !strcmp (STR, "dumpdir"))
> +
> +#ifndef SWITCH_TAKES_ARG
> +#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG (CHAR)
> +#endif
> +
> +#ifndef WORD_SWITCH_TAKES_ARG
> +#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
> +#endif
> +
>  /* Store in OUTPUT a string (made with alloca) containing an
>    assembler-name for a local static variable or function named NAME.
>    LABELNO is an integer which is different for each call.  */
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/fortran/gfortranspec.c gcc-mainline/gcc/fortran/gfortranspec.c
> --- gcc-mainline-opt3/gcc/fortran/gfortranspec.c        2010-06-16 09:07:30.000000000 -0700
> +++ gcc-mainline/gcc/fortran/gfortranspec.c     2010-06-23 08:25:11.000000000 -0700
> @@ -113,22 +113,6 @@ static void append_arg (const char *);
>  static int g77_newargc;
>  static const char **g77_newargv;
>
> -/* --- This comes from gcc.c (2.8.1) verbatim: */
> -
> -/* This defines which switch letters take arguments.  */
> -
> -#ifndef SWITCH_TAKES_ARG
> -#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
> -#endif
> -
> -/* This defines which multi-letter switches take arguments.  */
> -
> -#ifndef WORD_SWITCH_TAKES_ARG
> -#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
> -#endif
> -
> -/* --- End of verbatim.  */
> -
>  /* Assumes text[0] == '-'.  Returns number of argv items that belong to
>    (and follow) this one, an option id for options important to the
>    caller, and a pointer to the first char of the arg, if embedded (else
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/gcc.c gcc-mainline/gcc/gcc.c
> --- gcc-mainline-opt3/gcc/gcc.c 2010-06-07 02:48:58.000000000 -0700
> +++ gcc-mainline/gcc/gcc.c      2010-06-23 08:22:19.000000000 -0700
> @@ -975,13 +975,6 @@ struct user_specs
>
>  static struct user_specs *user_specs_head, *user_specs_tail;
>
> -#ifndef SWITCH_TAKES_ARG
> -#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
> -#endif
> -
> -#ifndef WORD_SWITCH_TAKES_ARG
> -#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
> -#endif
>
>  #ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
>  /* This defines which switches stop a full compilation.  */
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/gcc.h gcc-mainline/gcc/gcc.h
> --- gcc-mainline-opt3/gcc/gcc.h 2010-05-28 12:31:35.000000000 -0700
> +++ gcc-mainline/gcc/gcc.h      2010-06-23 08:21:07.000000000 -0700
> @@ -32,31 +32,6 @@ struct spec_function
>   const char *(*func) (int, const char **);
>  };
>
> -/* This defines which switch letters take arguments.  */
> -
> -#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
> -  ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
> -   || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
> -   || (CHAR) == 'I' || (CHAR) == 'J' || (CHAR) == 'm' \
> -   || (CHAR) == 'x' || (CHAR) == 'L' || (CHAR) == 'A' \
> -   || (CHAR) == 'B' )
> -
> -/* This defines which multi-letter switches take arguments.  */
> -
> -#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)             \
> - (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")     \
> -  || !strcmp (STR, "Tbss") || !strcmp (STR, "include") \
> -  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
> -  || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
> -  || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
> -  || !strcmp (STR, "iquote") || !strcmp (STR, "isystem") \
> -  || !strcmp (STR, "isysroot") \
> -  || !strcmp (STR, "-param") || !strcmp (STR, "specs") \
> -  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ") \
> -  || !strcmp (STR, "fintrinsic-modules-path") \
> -  || !strcmp (STR, "dumpbase") || !strcmp (STR, "dumpdir"))
> -
> -
>  /* These are exported by gcc.c.  */
>  extern int do_spec (const char *);
>  extern void record_temp_file (const char *, int, int);
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/opts-common.c gcc-mainline/gcc/opts-common.c
> --- gcc-mainline-opt3/gcc/opts-common.c 2010-06-22 15:23:48.000000000 -0700
> +++ gcc-mainline/gcc/opts-common.c      2010-06-23 11:44:40.000000000 -0700
> @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.
>  #include "opts.h"
>  #include "options.h"
>  #include "diagnostic.h"
> +#include "tm.h" /* For SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG.  */
>
>  /* Perform a binary search to find which option the command-line INPUT
>    matches.  Returns its index in the option array, and
> @@ -138,7 +139,9 @@ decode_cmdline_option (const char **argv
>   const char *opt, *arg = 0;
>   char *dup = 0;
>   int value = 1;
> -  unsigned int result = 1;
> +  unsigned int result = 1, i;
> +  size_t total_len;
> +  char *p;
>   const struct cl_option *option;
>   int errors = 0;
>
> @@ -242,22 +245,54 @@ decode_cmdline_option (const char **argv
>   decoded->arg = arg;
>   decoded->value = value;
>   decoded->errors = errors;
> -  switch (result)
> +
> +  if (opt_index == OPT_SPECIAL_unknown)
>     {
> -    case 1:
> -      decoded->orig_option_with_args_text = argv[0];
> -      decoded->canonical_option[0] = argv[0];
> -      decoded->canonical_option[1] = NULL;
> -      break;
> -    case 2:
> -      decoded->orig_option_with_args_text = concat (argv[0], " ",
> -                                                   argv[1], NULL);
> -      decoded->canonical_option[0] = argv[0];
> -      decoded->canonical_option[1] = argv[1];
> -      break;
> -    default:
> -      gcc_unreachable ();
> +      /* Skip the correct number of arguments for options handled
> +        through specs.  */
> +      const char *popt = argv[0] + 1;
> +      int c = *popt;
> +
> +      gcc_assert (result == 1);
> +      if (SWITCH_TAKES_ARG (c) > (popt[1] != 0))
> +       result += SWITCH_TAKES_ARG (c) - (popt[1] != 0);
> +      else if (WORD_SWITCH_TAKES_ARG (popt))
> +       result += WORD_SWITCH_TAKES_ARG (popt);
> +      if (result > 1)
> +       for (i = 1; i < result; i++)
> +         if (argv[i] == NULL)
> +           {
> +             result = i;
> +             break;
> +           }
>     }
> +
> +  gcc_assert (result >= 1 && result <= ARRAY_SIZE (decoded->canonical_option));
> +  decoded->canonical_option_num_elements = result;
> +  total_len = 0;
> +  for (i = 0; i < ARRAY_SIZE (decoded->canonical_option); i++)
> +    {
> +      if (i < result)
> +       {
> +         decoded->canonical_option[i] = argv[i];
> +         total_len += strlen (argv[i]) + 1;
> +       }
> +      else
> +       decoded->canonical_option[i] = NULL;
> +    }
> +  decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len);
> +  for (i = 0; i < result; i++)
> +    {
> +      size_t len = strlen (argv[i]);
> +
> +      memcpy (p, argv[i], len);
> +      p += len;
> +      if (i == result - 1)
> +       *p++ = 0;
> +      else
> +       *p++ = ' ';
> +    }
> +
>   return result;
>  }
>
> @@ -284,8 +319,11 @@ decode_cmdline_options_to_array (unsigne
>   opt_array[0].opt_index = OPT_SPECIAL_program_name;
>   opt_array[0].arg = argv[0];
>   opt_array[0].orig_option_with_args_text = argv[0];
> +  opt_array[0].canonical_option_num_elements = 1;
>   opt_array[0].canonical_option[0] = argv[0];
>   opt_array[0].canonical_option[1] = NULL;
> +  opt_array[0].canonical_option[2] = NULL;
> +  opt_array[0].canonical_option[3] = NULL;
>   opt_array[0].value = 1;
>   opt_array[0].errors = 0;
>   num_decoded_options = 1;
> @@ -300,8 +338,11 @@ decode_cmdline_options_to_array (unsigne
>          opt_array[num_decoded_options].opt_index = OPT_SPECIAL_input_file;
>          opt_array[num_decoded_options].arg = opt;
>          opt_array[num_decoded_options].orig_option_with_args_text = opt;
> +         opt_array[num_decoded_options].canonical_option_num_elements = 1;
>          opt_array[num_decoded_options].canonical_option[0] = opt;
>          opt_array[num_decoded_options].canonical_option[1] = NULL;
> +         opt_array[num_decoded_options].canonical_option[2] = NULL;
> +         opt_array[num_decoded_options].canonical_option[3] = NULL;
>          opt_array[num_decoded_options].value = 1;
>          opt_array[num_decoded_options].errors = 0;
>          num_decoded_options++;
> diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/opts.h gcc-mainline/gcc/opts.h
> --- gcc-mainline-opt3/gcc/opts.h        2010-06-22 15:15:44.000000000 -0700
> +++ gcc-mainline/gcc/opts.h     2010-06-23 07:30:21.000000000 -0700
> @@ -121,10 +121,12 @@ struct cl_decoded_option
>   /* The canonical form of the option and its argument, for when it is
>      necessary to reconstruct argv elements (in particular, for
>      processing specs and passing options to subprocesses from the
> -     driver).  The first element of this array is non-NULL; the second
> -     is NULL if the canonical form uses only one argv element,
> -     non-NULL otherwise.  */
> -  const char *canonical_option[2];
> +     driver).  */
> +  const char *canonical_option[4];
> +
> +  /* The number of elements in the canonical form of the option and
> +     arguments; always at least 1.  */
> +  size_t canonical_option_num_elements;
>
>   /* For a boolean option, 1 for the true case and 0 for the "no-"
>      case.  For an unsigned integer option, the value of the
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>
Tobias Burnus - June 25, 2010, 2:46 p.m.
On 06/23/2010 10:26 PM, Joseph S. Myers wrote:
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?
>   

I regard the Fortran changes as trivial/obvious. But for completeness:
The Fortran part is OK.

Tobias
> fortran:
> 2010-06-23  Joseph Myers  <joseph@codesourcery.com>
>
> 	* gfortranspec.c (SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG):
> 	Remove

Patch

diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/Makefile.in gcc-mainline/gcc/Makefile.in
--- gcc-mainline-opt3/gcc/Makefile.in	2010-06-22 15:24:00.000000000 -0700
+++ gcc-mainline/gcc/Makefile.in	2010-06-23 08:44:22.000000000 -0700
@@ -2796,7 +2796,7 @@  opts.o : opts.c opts.h options.h $(TOPLE
    $(FLAGS_H) $(PARAMS_H) $(TREE_PASS_H) $(DBGCNT_H) debug.h \
    $(PLUGIN_H) $(EXCEPT_H) $(LTO_STREAMER_H) opts-diagnostic.h
 opts-common.o : opts-common.c opts.h $(CONFIG_H) $(SYSTEM_H) \
-   coretypes.h intl.h $(DIAGNOSTIC_H)
+   coretypes.h intl.h $(DIAGNOSTIC_H) $(TM_H)
 targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    $(EXPR_H) $(TM_H) $(RTL_H) $(TM_P_H) $(FUNCTION_H) output.h $(TOPLEV_H) \
    $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h \
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/ada/gcc-interface/misc.c gcc-mainline/gcc/ada/gcc-interface/misc.c
--- gcc-mainline-opt3/gcc/ada/gcc-interface/misc.c	2010-06-22 16:02:04.000000000 -0700
+++ gcc-mainline/gcc/ada/gcc-interface/misc.c	2010-06-23 07:46:46.000000000 -0700
@@ -303,8 +303,13 @@  gnat_init_options (unsigned int decoded_
   save_argc = 0;
   for (i = 0; i < decoded_options_count; i++)
     {
+      if (decoded_options[i].errors
+	  || decoded_options[i].opt_index == OPT_SPECIAL_unknown)
+	continue;
+      gcc_assert (decoded_options[i].canonical_option_num_elements >= 1
+		  && decoded_options[i].canonical_option_num_elements <= 2);
       save_argv[save_argc++] = decoded_options[i].canonical_option[0];
-      if (decoded_options[i].canonical_option[1] != NULL)
+      if (decoded_options[i].canonical_option_num_elements >= 2)
 	save_argv[save_argc++] = decoded_options[i].canonical_option[1];
     }
   save_argv[save_argc] = NULL;
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/config/darwin-driver.c gcc-mainline/gcc/config/darwin-driver.c
--- gcc-mainline-opt3/gcc/config/darwin-driver.c	2010-06-04 06:35:13.000000000 -0700
+++ gcc-mainline/gcc/config/darwin-driver.c	2010-06-23 08:24:32.000000000 -0700
@@ -27,14 +27,6 @@  along with GCC; see the file COPYING3.  
 #include <sys/sysctl.h>
 #include "xregex.h"
 
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
-#endif
-
-#ifndef WORD_SWITCH_TAKES_ARG
-#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
-#endif
-
 /* When running on a Darwin system and using that system's headers and
    libraries, default the -mmacosx-version-min flag to be the version
    of the system on which the compiler is running.  */
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/cppspec.c gcc-mainline/gcc/cppspec.c
--- gcc-mainline-opt3/gcc/cppspec.c	2010-06-04 06:40:58.000000000 -0700
+++ gcc-mainline/gcc/cppspec.c	2010-06-23 08:24:05.000000000 -0700
@@ -30,14 +30,6 @@  along with GCC; see the file COPYING3.  
    assume the user knows what they're doing.  If no explicit input is
    mentioned, it will read stdin.  */
 
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
-#endif
-
-#ifndef WORD_SWITCH_TAKES_ARG
-#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
-#endif
-
 /* Suffixes for known sorts of input files.  Note that we do not list
    files which are normally considered to have been preprocessed already,
    since the user's expectation is that `cpp' always preprocesses.  */
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/defaults.h gcc-mainline/gcc/defaults.h
--- gcc-mainline-opt3/gcc/defaults.h	2010-06-11 02:16:45.000000000 -0700
+++ gcc-mainline/gcc/defaults.h	2010-06-23 08:24:12.000000000 -0700
@@ -32,6 +32,38 @@  see the files COPYING3 and COPYING.RUNTI
 #define GET_ENVIRONMENT(VALUE, NAME) do { (VALUE) = getenv (NAME); } while (0)
 #endif
 
+/* This defines which switch letters take arguments.  */
+
+#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+  ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
+   || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
+   || (CHAR) == 'I' || (CHAR) == 'J' || (CHAR) == 'm' \
+   || (CHAR) == 'x' || (CHAR) == 'L' || (CHAR) == 'A' \
+   || (CHAR) == 'B' )
+
+/* This defines which multi-letter switches take arguments.  */
+
+#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)		\
+ (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")	\
+  || !strcmp (STR, "Tbss") || !strcmp (STR, "include")	\
+  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
+  || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
+  || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
+  || !strcmp (STR, "iquote") || !strcmp (STR, "isystem") \
+  || !strcmp (STR, "isysroot") \
+  || !strcmp (STR, "-param") || !strcmp (STR, "specs") \
+  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ") \
+  || !strcmp (STR, "fintrinsic-modules-path") \
+  || !strcmp (STR, "dumpbase") || !strcmp (STR, "dumpdir"))
+
+#ifndef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG (CHAR)
+#endif
+
+#ifndef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
+#endif
+
 /* Store in OUTPUT a string (made with alloca) containing an
    assembler-name for a local static variable or function named NAME.
    LABELNO is an integer which is different for each call.  */
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/fortran/gfortranspec.c gcc-mainline/gcc/fortran/gfortranspec.c
--- gcc-mainline-opt3/gcc/fortran/gfortranspec.c	2010-06-16 09:07:30.000000000 -0700
+++ gcc-mainline/gcc/fortran/gfortranspec.c	2010-06-23 08:25:11.000000000 -0700
@@ -113,22 +113,6 @@  static void append_arg (const char *);
 static int g77_newargc;
 static const char **g77_newargv;
 
-/* --- This comes from gcc.c (2.8.1) verbatim: */
-
-/* This defines which switch letters take arguments.  */
-
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
-#endif
-
-/* This defines which multi-letter switches take arguments.  */
-
-#ifndef WORD_SWITCH_TAKES_ARG
-#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
-#endif
-
-/* --- End of verbatim.  */
-
 /* Assumes text[0] == '-'.  Returns number of argv items that belong to
    (and follow) this one, an option id for options important to the
    caller, and a pointer to the first char of the arg, if embedded (else
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/gcc.c gcc-mainline/gcc/gcc.c
--- gcc-mainline-opt3/gcc/gcc.c	2010-06-07 02:48:58.000000000 -0700
+++ gcc-mainline/gcc/gcc.c	2010-06-23 08:22:19.000000000 -0700
@@ -975,13 +975,6 @@  struct user_specs
 
 static struct user_specs *user_specs_head, *user_specs_tail;
 
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
-#endif
-
-#ifndef WORD_SWITCH_TAKES_ARG
-#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
-#endif
 
 #ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
 /* This defines which switches stop a full compilation.  */
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/gcc.h gcc-mainline/gcc/gcc.h
--- gcc-mainline-opt3/gcc/gcc.h	2010-05-28 12:31:35.000000000 -0700
+++ gcc-mainline/gcc/gcc.h	2010-06-23 08:21:07.000000000 -0700
@@ -32,31 +32,6 @@  struct spec_function
   const char *(*func) (int, const char **);
 };
 
-/* This defines which switch letters take arguments.  */
-
-#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
-  ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
-   || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
-   || (CHAR) == 'I' || (CHAR) == 'J' || (CHAR) == 'm' \
-   || (CHAR) == 'x' || (CHAR) == 'L' || (CHAR) == 'A' \
-   || (CHAR) == 'B' )
-
-/* This defines which multi-letter switches take arguments.  */
-
-#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)		\
- (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")	\
-  || !strcmp (STR, "Tbss") || !strcmp (STR, "include")	\
-  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
-  || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
-  || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
-  || !strcmp (STR, "iquote") || !strcmp (STR, "isystem") \
-  || !strcmp (STR, "isysroot") \
-  || !strcmp (STR, "-param") || !strcmp (STR, "specs") \
-  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ") \
-  || !strcmp (STR, "fintrinsic-modules-path") \
-  || !strcmp (STR, "dumpbase") || !strcmp (STR, "dumpdir"))
-
-
 /* These are exported by gcc.c.  */
 extern int do_spec (const char *);
 extern void record_temp_file (const char *, int, int);
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/opts-common.c gcc-mainline/gcc/opts-common.c
--- gcc-mainline-opt3/gcc/opts-common.c	2010-06-22 15:23:48.000000000 -0700
+++ gcc-mainline/gcc/opts-common.c	2010-06-23 11:44:40.000000000 -0700
@@ -24,6 +24,7 @@  along with GCC; see the file COPYING3.  
 #include "opts.h"
 #include "options.h"
 #include "diagnostic.h"
+#include "tm.h" /* For SWITCH_TAKES_ARG and WORD_SWITCH_TAKES_ARG.  */
 
 /* Perform a binary search to find which option the command-line INPUT
    matches.  Returns its index in the option array, and
@@ -138,7 +139,9 @@  decode_cmdline_option (const char **argv
   const char *opt, *arg = 0;
   char *dup = 0;
   int value = 1;
-  unsigned int result = 1;
+  unsigned int result = 1, i;
+  size_t total_len;
+  char *p;
   const struct cl_option *option;
   int errors = 0;
 
@@ -242,22 +245,54 @@  decode_cmdline_option (const char **argv
   decoded->arg = arg;
   decoded->value = value;
   decoded->errors = errors;
-  switch (result)
+
+  if (opt_index == OPT_SPECIAL_unknown)
     {
-    case 1:
-      decoded->orig_option_with_args_text = argv[0];
-      decoded->canonical_option[0] = argv[0];
-      decoded->canonical_option[1] = NULL;
-      break;
-    case 2:
-      decoded->orig_option_with_args_text = concat (argv[0], " ",
-						    argv[1], NULL);
-      decoded->canonical_option[0] = argv[0];
-      decoded->canonical_option[1] = argv[1];
-      break;
-    default:
-      gcc_unreachable ();
+      /* Skip the correct number of arguments for options handled
+	 through specs.  */
+      const char *popt = argv[0] + 1;
+      int c = *popt;
+
+      gcc_assert (result == 1);
+      if (SWITCH_TAKES_ARG (c) > (popt[1] != 0))
+	result += SWITCH_TAKES_ARG (c) - (popt[1] != 0);
+      else if (WORD_SWITCH_TAKES_ARG (popt))
+	result += WORD_SWITCH_TAKES_ARG (popt);
+      if (result > 1)
+	for (i = 1; i < result; i++)
+	  if (argv[i] == NULL)
+	    {
+	      result = i;
+	      break;
+	    }
     }
+
+  gcc_assert (result >= 1 && result <= ARRAY_SIZE (decoded->canonical_option));
+  decoded->canonical_option_num_elements = result;
+  total_len = 0;
+  for (i = 0; i < ARRAY_SIZE (decoded->canonical_option); i++)
+    {
+      if (i < result)
+	{
+	  decoded->canonical_option[i] = argv[i];
+	  total_len += strlen (argv[i]) + 1;
+	}
+      else
+	decoded->canonical_option[i] = NULL;
+    }
+  decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len);
+  for (i = 0; i < result; i++)
+    {
+      size_t len = strlen (argv[i]);
+
+      memcpy (p, argv[i], len);
+      p += len;
+      if (i == result - 1)
+	*p++ = 0;
+      else
+	*p++ = ' ';
+    }
+
   return result;
 }
 
@@ -284,8 +319,11 @@  decode_cmdline_options_to_array (unsigne
   opt_array[0].opt_index = OPT_SPECIAL_program_name;
   opt_array[0].arg = argv[0];
   opt_array[0].orig_option_with_args_text = argv[0];
+  opt_array[0].canonical_option_num_elements = 1;
   opt_array[0].canonical_option[0] = argv[0];
   opt_array[0].canonical_option[1] = NULL;
+  opt_array[0].canonical_option[2] = NULL;
+  opt_array[0].canonical_option[3] = NULL;
   opt_array[0].value = 1;
   opt_array[0].errors = 0;
   num_decoded_options = 1;
@@ -300,8 +338,11 @@  decode_cmdline_options_to_array (unsigne
 	  opt_array[num_decoded_options].opt_index = OPT_SPECIAL_input_file;
 	  opt_array[num_decoded_options].arg = opt;
 	  opt_array[num_decoded_options].orig_option_with_args_text = opt;
+	  opt_array[num_decoded_options].canonical_option_num_elements = 1;
 	  opt_array[num_decoded_options].canonical_option[0] = opt;
 	  opt_array[num_decoded_options].canonical_option[1] = NULL;
+	  opt_array[num_decoded_options].canonical_option[2] = NULL;
+	  opt_array[num_decoded_options].canonical_option[3] = NULL;
 	  opt_array[num_decoded_options].value = 1;
 	  opt_array[num_decoded_options].errors = 0;
 	  num_decoded_options++;
diff -rupN --exclude=.svn gcc-mainline-opt3/gcc/opts.h gcc-mainline/gcc/opts.h
--- gcc-mainline-opt3/gcc/opts.h	2010-06-22 15:15:44.000000000 -0700
+++ gcc-mainline/gcc/opts.h	2010-06-23 07:30:21.000000000 -0700
@@ -121,10 +121,12 @@  struct cl_decoded_option
   /* The canonical form of the option and its argument, for when it is
      necessary to reconstruct argv elements (in particular, for
      processing specs and passing options to subprocesses from the
-     driver).  The first element of this array is non-NULL; the second
-     is NULL if the canonical form uses only one argv element,
-     non-NULL otherwise.  */
-  const char *canonical_option[2];
+     driver).  */
+  const char *canonical_option[4];
+
+  /* The number of elements in the canonical form of the option and
+     arguments; always at least 1.  */
+  size_t canonical_option_num_elements;
 
   /* For a boolean option, 1 for the true case and 0 for the "no-"
      case.  For an unsigned integer option, the value of the