Patchwork Merge two passes over options in gcc.c

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

Comments

Joseph S. Myers - June 26, 2010, 1:05 p.m.
Continuing preparation for making the driver share option processing
machinery with the compiler proper, this patch replaces two passes
over options in the driver with a single pass, which fits more
naturally with the option processing model used elsewhere of a pass
over options that calls appropriate handlers for each option in turn.
(There are several other passes to assimilate to the model of first
decoding options then working with decoded options, but these two
passes are the main ones that will need converting to use decoded
options as part of the initial integration of shared option processing
machinery in the driver; the others can follow later.)

Previously, the first pass would act on some options and work out how
much memory to allocate for other options and input files, while the
second pass would act on other options and store options for use of
specs as well as storing a list of input files.  By making the code
increase the size of the relevant arrays as needed (size doubling like
this is already used elsewhere in the driver), the two passes can be
integrated.

The two passes were in fact out of sync as regards -Xpreprocessor and
-Xassembler; the second pass would skip their operands when looking
for the next option, but the first pass would not, resulting in such
operands being wrongly interpreted as driver options.

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

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

	* gcc.c (n_switches_alloc, n_infiles_alloc, alloc_infile,
	add_infile, alloc_switch): New.
	(process_command): Remove variable lang_n_infiles.  Process
	options in a single pass.  Use new functions for allocating
	infiles and switches arrays.  Properly skip operands of
	-Xpreprocessor and -Xassembler.

testsuite:
2010-06-26  Joseph Myers  <joseph@codesourcery.com>

	* gcc.dg/opts-3.c: New test.
Richard Guenther - June 26, 2010, 1:07 p.m.
On Sat, Jun 26, 2010 at 3:05 PM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> Continuing preparation for making the driver share option processing
> machinery with the compiler proper, this patch replaces two passes
> over options in the driver with a single pass, which fits more
> naturally with the option processing model used elsewhere of a pass
> over options that calls appropriate handlers for each option in turn.
> (There are several other passes to assimilate to the model of first
> decoding options then working with decoded options, but these two
> passes are the main ones that will need converting to use decoded
> options as part of the initial integration of shared option processing
> machinery in the driver; the others can follow later.)
>
> Previously, the first pass would act on some options and work out how
> much memory to allocate for other options and input files, while the
> second pass would act on other options and store options for use of
> specs as well as storing a list of input files.  By making the code
> increase the size of the relevant arrays as needed (size doubling like
> this is already used elsewhere in the driver), the two passes can be
> integrated.
>
> The two passes were in fact out of sync as regards -Xpreprocessor and
> -Xassembler; the second pass would skip their operands when looking
> for the next option, but the first pass would not, resulting in such
> operands being wrongly interpreted as driver options.
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit?

Ok.

Thanks,
Richard.

> 2010-06-26  Joseph Myers  <joseph@codesourcery.com>
>
>        * gcc.c (n_switches_alloc, n_infiles_alloc, alloc_infile,
>        add_infile, alloc_switch): New.
>        (process_command): Remove variable lang_n_infiles.  Process
>        options in a single pass.  Use new functions for allocating
>        infiles and switches arrays.  Properly skip operands of
>        -Xpreprocessor and -Xassembler.
>
> testsuite:
> 2010-06-26  Joseph Myers  <joseph@codesourcery.com>
>
>        * gcc.dg/opts-3.c: New test.
>
> diff -rupN --exclude=.svn gcc-mainline-opt4-takes-arg/gcc/gcc.c gcc-mainline/gcc/gcc.c
> --- gcc-mainline-opt4-takes-arg/gcc/gcc.c       2010-06-25 08:11:25.000000000 -0700
> +++ gcc-mainline/gcc/gcc.c      2010-06-26 03:36:56.000000000 -0700
> @@ -3244,6 +3244,8 @@ static struct switchstr *switches;
>
>  static int n_switches;
>
> +static int n_switches_alloc;
> +
>  /* Set to zero if -fcompare-debug is disabled, positive if it's
>    enabled and we're running the first compilation, negative if it's
>    enabled and we're running the second compilation.  For most of the
> @@ -3289,6 +3291,8 @@ static struct infile *infiles;
>
>  int n_infiles;
>
> +static int n_infiles_alloc;
> +
>  /* True if multiple input files are being compiled to a single
>    assembly file.  */
>
> @@ -3473,6 +3477,51 @@ add_linker_option (const char *option, i
>   linker_options [n_linker_options - 1] = save_string (option, len);
>  }
>
> +/* Allocate space for an input file in infiles.  */
> +
> +static void
> +alloc_infile (void)
> +{
> +  if (n_infiles_alloc == 0)
> +    {
> +      n_infiles_alloc = 16;
> +      infiles = XNEWVEC (struct infile, n_infiles_alloc);
> +    }
> +  else if (n_infiles_alloc == n_infiles)
> +    {
> +      n_infiles_alloc *= 2;
> +      infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc);
> +    }
> +}
> +
> +/* Store an input file with the given NAME and LANGUAGE in
> +   infiles.  */
> +
> +static void
> +add_infile (const char *name, const char *language)
> +{
> +  alloc_infile ();
> +  infiles[n_infiles].name = name;
> +  infiles[n_infiles++].language = language;
> +}
> +
> +/* Allocate space for a switch in switches.  */
> +
> +static void
> +alloc_switch (void)
> +{
> +  if (n_switches_alloc == 0)
> +    {
> +      n_switches_alloc = 16;
> +      switches = XNEWVEC (struct switchstr, n_switches_alloc);
> +    }
> +  else if (n_switches_alloc == n_switches)
> +    {
> +      n_switches_alloc *= 2;
> +      switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc);
> +    }
> +}
> +
>  /* Create the vector `switches' and its contents.
>    Store its length in `n_switches'.  */
>
> @@ -3484,7 +3533,6 @@ process_command (int argc, const char **
>   char *temp1;
>   const char *spec_lang = 0;
>   int last_language_n_infiles;
> -  int lang_n_infiles = 0;
>   const char *tooldir_prefix;
>   char *(*get_relative_prefix) (const char *, const char *,
>                                const char *) = NULL;
> @@ -3698,12 +3746,22 @@ process_command (int argc, const char **
>        }
>     }
>
> -  /* Scan argv twice.  Here, the first time, just count how many switches
> -     there will be in their vector, and how many input files in theirs.
> -     Here we also parse the switches that cc itself uses (e.g. -v).  */
> +  /* Process the options and store input files and switches in their
> +     vectors.  */
> +
> +  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;
> @@ -3729,59 +3787,50 @@ process_command (int argc, const char **
>          /* translate_options () has turned --version into -fversion.  */
>          print_version = 1;
>
> -         /* We will be passing a dummy file on to the sub-processes.  */
> -         n_infiles++;
> -         n_switches++;
> -
>          /* 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;
>
> -         /* We will be passing a dummy file on to the sub-processes.  */
> -         n_infiles++;
> -         n_switches++;
> -
>          /* 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;
>
> -         /* We will be passing a dummy file on to the sub-processes.  */
> -         n_infiles++;
> -         n_switches++;
> +         goto normal_switch;
>        }
>       else if (strcmp (argv[i], "-ftarget-help") == 0)
>        {
>          /* translate_options() has turned --target-help into -ftarget-help.  */
>          print_subprocess_help = 1;
>
> -         /* We will be passing a dummy file on to the sub-processes.  */
> -         n_infiles++;
> -         n_switches++;
> -
>          /* 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;
> -         n_switches++;
>        }
>       else if (! strcmp (argv[i], "-print-search-dirs"))
>        print_search_dirs = 1;
> @@ -3804,16 +3853,18 @@ process_command (int argc, const char **
>       else if (! strcmp (argv[i], "-fcompare-debug-second"))
>        {
>          compare_debug_second = 1;
> -         n_switches++;
> +         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="
> @@ -3831,7 +3882,7 @@ process_command (int argc, const char **
>            compare_debug_opt = NULL;
>          else
>            compare_debug_opt = opt;
> -         n_switches++;
> +         goto normal_switch;
>        }
>       else if (! strncmp (argv[i], "-Wa,", 4))
>        {
> @@ -3869,17 +3920,24 @@ process_command (int argc, const char **
>        }
>       else if (strncmp (argv[i], "-Wl,", 4) == 0)
>        {
> -         int j;
> +         int prev, j;
>          /* Split the argument at commas.  */
> -         for (j = 3; argv[i][j]; j++)
> -           n_infiles += (argv[i][j] == ',');
> +         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");
>
> -         n_infiles++;
> +         add_infile (argv[i+1], "*");
>          i++;
>        }
>       else if (strcmp (argv[i], "-Xpreprocessor") == 0)
> @@ -3888,6 +3946,7 @@ process_command (int argc, const char **
>            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)
>        {
> @@ -3895,25 +3954,29 @@ process_command (int argc, const char **
>            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");
>
> -         n_infiles++;
> +         /* 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)
> -       n_infiles++;
> +       {
> +         add_infile (argv[i], "*");
> +       }
>       else if (strcmp (argv[i], "-save-temps") == 0)
>        {
>          save_temps_flag = SAVE_TEMPS_CWD;
> -         n_switches++;
> +         goto normal_switch;
>        }
>       else if (strncmp (argv[i], "-save-temps=", 12) == 0)
>        {
> -         n_switches++;
>          if (strcmp (argv[i]+12, "cwd") == 0)
>            save_temps_flag = SAVE_TEMPS_CWD;
>          else if (strcmp (argv[i]+12, "obj") == 0
> @@ -3921,6 +3984,7 @@ process_command (int argc, const char **
>            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.  */
> @@ -3928,7 +3992,7 @@ process_command (int argc, const char **
>       else if (strcmp (argv[i], "-combine") == 0)
>        {
>          combine_flag = 1;
> -         n_switches++;
> +         goto normal_switch;
>        }
>       else if (strcmp (argv[i], "-specs") == 0)
>        {
> @@ -3958,6 +4022,11 @@ process_command (int argc, const char **
>            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)
> @@ -3971,7 +4040,7 @@ process_command (int argc, const char **
>          /* -pipe has to go into the switches array as well as
>             setting a flag.  */
>          use_pipes = 1;
> -         n_switches++;
> +         goto normal_switch;
>        }
>       else if (strcmp (argv[i], "-wrapper") == 0)
>         {
> @@ -3979,8 +4048,6 @@ process_command (int argc, const char **
>            fatal_error ("argument to %<-wrapper%> is missing");
>
>           wrapper_string = argv[i];
> -         n_switches++;
> -         n_switches++;
>         }
>       else if (strcmp (argv[i], "-###") == 0)
>        {
> @@ -3993,9 +4060,6 @@ process_command (int argc, const char **
>        }
>       else if (argv[i][0] == '-' && argv[i][1] != 0)
>        {
> -         const char *p = &argv[i][1];
> -         int c = *p;
> -
>          switch (c)
>            {
>            case 'B':
> @@ -4006,7 +4070,7 @@ process_command (int argc, const char **
>                if (p[1] == 0 && i + 1 == argc)
>                  fatal_error ("argument to %<-B%> is missing");
>                if (p[1] == 0)
> -                 value = argv[++i];
> +                 value = argv[i + 1];
>                else
>                  value = p + 1;
>
> @@ -4035,28 +4099,38 @@ process_command (int argc, const char **
>                            PREFIX_PRIORITY_B_OPT, 0, 0);
>                add_prefix (&include_prefixes, value, NULL,
>                            PREFIX_PRIORITY_B_OPT, 0, 0);
> -               n_switches++;
>              }
> -             break;
> +             goto normal_switch;
>
>            case 'v':   /* Print our subcommands and print versions.  */
> -             n_switches++;
>              /* 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;
> -                 n_switches++;
> -                 break;
> -               }
> +               have_c = 1;
>              goto normal_switch;
>
>            case 'o':
> @@ -4094,7 +4168,10 @@ process_command (int argc, const char **
>              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);
> +               {
> +                 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])
> @@ -4106,18 +4183,105 @@ process_command (int argc, const char **
>            default:
>            normal_switch:
>
> -             n_switches++;
> +             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 (SWITCH_TAKES_ARG (c) > (p[1] != 0))
> -               i += SWITCH_TAKES_ARG (c) - (p[1] != 0);
> -             else if (WORD_SWITCH_TAKES_ARG (p))
> -               i += 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 (strchr (switches_need_spaces, c))
> +               {
> +                 /* On some systems, ld cannot handle some options without
> +                    a space.  So split the option from its argument.  */
> +                 char *part1 = XNEWVEC (char, 2);
> +                 part1[0] = c;
> +                 part1[1] = '\0';
> +
> +                 switches[n_switches].part1 = part1;
> +                 switches[n_switches].args = XNEWVEC (const char *, 2);
> +                 switches[n_switches].args[0] = xstrdup (p+1);
> +                 switches[n_switches].args[1] = 0;
> +               }
> +             else
> +               switches[n_switches].args = 0;
> +
> +             switches[n_switches].live_cond = 0;
> +             switches[n_switches].validated = 0;
> +             switches[n_switches].ordering = 0;
> +             /* These are always valid, since gcc.c itself understands the
> +                first four, gfortranspec.c understands -static-libgfortran
> +                and g++spec.c understands -static-libstdc++ */
> +             if (!strcmp (p, "save-temps")
> +                 || !strcmp (p, "static-libgcc")
> +                 || !strcmp (p, "shared-libgcc")
> +                 || !strcmp (p, "pipe")
> +                 || !strcmp (p, "static-libgfortran")
> +                 || !strcmp (p, "static-libstdc++"))
> +               switches[n_switches].validated = 1;
> +             else
> +               {
> +                 char ch = switches[n_switches].part1[0];
> +                 if (ch == 'B')
> +                   switches[n_switches].validated = 1;
> +               }
> +             n_switches++;
>            }
>        }
>       else
>        {
> -         n_infiles++;
> -         lang_n_infiles++;
> +          const char *p = strrchr (argv[i], '@');
> +          char *fname;
> +         long offset;
> +         int consumed;
> +#ifdef HAVE_TARGET_OBJECT_SUFFIX
> +         argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
> +             && 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';
> +             /* 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]);
> +               }
> +           }
> +         else
> +           fname = xstrdup (argv[i]);
> +
> +          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
> +           perror_with_name (fname);
> +          else
> +           add_infile (argv[i], spec_lang);
> +
> +          free (fname);
>        }
>     }
>
> @@ -4156,13 +4320,11 @@ process_command (int argc, const char **
>        {
>          compare_debug = 2;
>          compare_debug_opt = gcd;
> -         n_switches++;
>        }
>       else if (gcd && *gcd && strcmp (gcd, "0"))
>        {
>          compare_debug = 3;
>          compare_debug_opt = "-gtoggle";
> -         n_switches++;
>        }
>     }
>   else if (compare_debug < 0)
> @@ -4215,7 +4377,7 @@ process_command (int argc, const char **
>      then consider it to relocate with the rest of the GCC installation
>      if GCC_EXEC_PREFIX is set.
>      ``make_relative_prefix'' is not compiled for VMS, so don't call it.  */
> -  if (target_system_root && gcc_exec_prefix)
> +  if (target_system_root && !target_system_root_changed && gcc_exec_prefix)
>     {
>       char *tmp_prefix = get_relative_prefix (argv[0],
>                                              standard_bindir_prefix,
> @@ -4231,232 +4393,12 @@ process_command (int argc, const char **
>   /* More prefixes are enabled in main, after we read the specs file
>      and determine whether this is cross-compilation or not.  */
>
> -  /* Then create the space for the vectors and scan again.  */
> -
> -  switches = XNEWVEC (struct switchstr, n_switches + 1);
> -  infiles = XNEWVEC (struct infile, n_infiles + 1);
> -  n_switches = 0;
> -  n_infiles = 0;
> -  last_language_n_infiles = -1;
> -
> -  /* This, time, copy the text of each switch and store a pointer
> -     to the copy in the vector of switches.
> -     Store all the infiles in their vector.  */
> -
> -  for (i = 1; i < argc; i++)
> -    {
> -      /* Just skip the switches that were handled by the preceding loop.  */
> -      if (! strncmp (argv[i], "-Wa,", 4))
> -       ;
> -      else if (! strncmp (argv[i], "-Wp,", 4))
> -       ;
> -      else if (! strcmp (argv[i], "-no-canonical-prefixes"))
> -       ;
> -      else if (! strcmp (argv[i], "-pass-exit-codes"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-search-dirs"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
> -       ;
> -      else if (! strncmp (argv[i], "-print-file-name=", 17))
> -       ;
> -      else if (! strncmp (argv[i], "-print-prog-name=", 17))
> -       ;
> -      else if (! strcmp (argv[i], "-print-multi-lib"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-multi-directory"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-sysroot"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-multi-os-directory"))
> -       ;
> -      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
> -       ;
> -      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
> -       {
> -         target_system_root = argv[i] + strlen ("--sysroot=");
> -         target_system_root_changed = 1;
> -       }
> -      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] == ',')
> -             {
> -               infiles[n_infiles].language = "*";
> -               infiles[n_infiles++].name
> -                 = save_string (argv[i] + prev, j - prev);
> -               prev = j + 1;
> -             }
> -         /* Record the part after the last comma.  */
> -         infiles[n_infiles].language = "*";
> -         infiles[n_infiles++].name = argv[i] + prev;
> -       }
> -      else if (strcmp (argv[i], "-Xlinker") == 0)
> -       {
> -         infiles[n_infiles].language = "*";
> -         infiles[n_infiles++].name = argv[++i];
> -       }
> -      /* Xassembler and Xpreprocessor were already handled in the first argv
> -        scan, so all we need to do here is ignore them and their argument.  */
> -      else if (strcmp (argv[i], "-Xassembler") == 0)
> -       i++;
> -      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
> -       i++;
> -      else if (strcmp (argv[i], "-l") == 0)
> -       { /* POSIX allows separation of -l and the lib arg;
> -            canonicalize by concatenating -l with its arg */
> -         infiles[n_infiles].language = "*";
> -         infiles[n_infiles++].name = concat ("-l", argv[++i], NULL);
> -       }
> -      else if (strncmp (argv[i], "-l", 2) == 0)
> -       {
> -         infiles[n_infiles].language = "*";
> -         infiles[n_infiles++].name = argv[i];
> -       }
> -      else if (strcmp (argv[i], "-wrapper") == 0)
> -        i++;
> -      else if (strcmp (argv[i], "-specs") == 0)
> -       i++;
> -      else if (strncmp (argv[i], "-specs=", 7) == 0)
> -       ;
> -      else if (strcmp (argv[i], "-time") == 0)
> -       ;
> -      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
> -       ;
> -      else if (strcmp (argv[i], "-###") == 0)
> -       ;
> -      else if (argv[i][0] == '-' && argv[i][1] != 0)
> -       {
> -         const char *p = &argv[i][1];
> -         int c = *p;
> -
> -         if (c == '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;
> -             continue;
> -           }
> -         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 (strchr (switches_need_spaces, c))
> -           {
> -             /* On some systems, ld cannot handle some options without
> -                a space.  So split the option from its argument.  */
> -             char *part1 = XNEWVEC (char, 2);
> -             part1[0] = c;
> -             part1[1] = '\0';
> -
> -             switches[n_switches].part1 = part1;
> -             switches[n_switches].args = XNEWVEC (const char *, 2);
> -             switches[n_switches].args[0] = xstrdup (p+1);
> -             switches[n_switches].args[1] = 0;
> -           }
> -         else
> -           switches[n_switches].args = 0;
> -
> -         switches[n_switches].live_cond = 0;
> -         switches[n_switches].validated = 0;
> -         switches[n_switches].ordering = 0;
> -         /* These are always valid, since gcc.c itself understands the
> -            first four, gfortranspec.c understands -static-libgfortran
> -            and g++spec.c understands -static-libstdc++ */
> -         if (!strcmp (p, "save-temps")
> -             || !strcmp (p, "static-libgcc")
> -             || !strcmp (p, "shared-libgcc")
> -             || !strcmp (p, "pipe")
> -             || !strcmp (p, "static-libgfortran")
> -             || !strcmp (p, "static-libstdc++"))
> -           switches[n_switches].validated = 1;
> -         else
> -           {
> -             char ch = switches[n_switches].part1[0];
> -             if (ch == 'B')
> -               switches[n_switches].validated = 1;
> -           }
> -         n_switches++;
> -       }
> -      else
> -       {
> -          const char *p = strrchr (argv[i], '@');
> -          char *fname;
> -         long offset;
> -         int consumed;
> -#ifdef HAVE_TARGET_OBJECT_SUFFIX
> -         argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
> -             && 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';
> -             /* 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]);
> -               }
> -           }
> -         else
> -           fname = xstrdup (argv[i]);
> -
> -          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
> -           perror_with_name (fname);
> -          else
> -            {
> -              infiles[n_infiles].language = spec_lang;
> -              infiles[n_infiles++].name = argv[i];
> -            }
> -
> -          free (fname);
> -       }
> -    }
> -
>   if (n_infiles == last_language_n_infiles && spec_lang != 0)
>     warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
>
>   if (compare_debug == 2 || compare_debug == 3)
>     {
> +      alloc_switch ();
>       switches[n_switches].part1 = concat ("fcompare-debug=",
>                                           compare_debug_opt,
>                                           NULL);
> @@ -4471,15 +4413,16 @@ process_command (int argc, const char **
>   /* Ensure we only invoke each subprocess once.  */
>   if (print_subprocess_help || print_help_list || print_version)
>     {
> -      n_infiles = 1;
> +      n_infiles = 0;
>
>       /* Create a dummy input file, so that we can pass
>         the help option on to the various sub-processes.  */
> -      infiles[0].language = "c";
> -      infiles[0].name   = "help-dummy";
> +      add_infile ("help-dummy", "c");
>     }
>
> +  alloc_switch ();
>   switches[n_switches].part1 = 0;
> +  alloc_infile ();
>   infiles[n_infiles].name = 0;
>  }
>
> diff -rupN --exclude=.svn gcc-mainline-opt4-takes-arg/gcc/testsuite/gcc.dg/opts-3.c gcc-mainline/gcc/testsuite/gcc.dg/opts-3.c
> --- gcc-mainline-opt4-takes-arg/gcc/testsuite/gcc.dg/opts-3.c   1969-12-31 16:00:00.000000000 -0800
> +++ gcc-mainline/gcc/testsuite/gcc.dg/opts-3.c  2010-06-25 17:37:27.000000000 -0700
> @@ -0,0 +1,7 @@
> +/* Parameters of -Xassembler should not be interpreted as driver
> +   options (and so cause the driver to exit prematurely, as in this
> +   testcase, or have other unintended effects).  */
> +/* { dg-do compile } */
> +/* { dg-options "-Xassembler -dumpmachine" } */
> +
> +int int x; /* { dg-error "two or more data types" } */
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Patch

diff -rupN --exclude=.svn gcc-mainline-opt4-takes-arg/gcc/gcc.c gcc-mainline/gcc/gcc.c
--- gcc-mainline-opt4-takes-arg/gcc/gcc.c	2010-06-25 08:11:25.000000000 -0700
+++ gcc-mainline/gcc/gcc.c	2010-06-26 03:36:56.000000000 -0700
@@ -3244,6 +3244,8 @@  static struct switchstr *switches;
 
 static int n_switches;
 
+static int n_switches_alloc;
+
 /* Set to zero if -fcompare-debug is disabled, positive if it's
    enabled and we're running the first compilation, negative if it's
    enabled and we're running the second compilation.  For most of the
@@ -3289,6 +3291,8 @@  static struct infile *infiles;
 
 int n_infiles;
 
+static int n_infiles_alloc;
+
 /* True if multiple input files are being compiled to a single
    assembly file.  */
 
@@ -3473,6 +3477,51 @@  add_linker_option (const char *option, i
   linker_options [n_linker_options - 1] = save_string (option, len);
 }
 
+/* Allocate space for an input file in infiles.  */
+
+static void
+alloc_infile (void)
+{
+  if (n_infiles_alloc == 0)
+    {
+      n_infiles_alloc = 16;
+      infiles = XNEWVEC (struct infile, n_infiles_alloc);
+    }
+  else if (n_infiles_alloc == n_infiles)
+    {
+      n_infiles_alloc *= 2;
+      infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc);
+    }
+}
+
+/* Store an input file with the given NAME and LANGUAGE in
+   infiles.  */
+
+static void
+add_infile (const char *name, const char *language)
+{
+  alloc_infile ();
+  infiles[n_infiles].name = name;
+  infiles[n_infiles++].language = language;
+}
+
+/* Allocate space for a switch in switches.  */
+
+static void
+alloc_switch (void)
+{
+  if (n_switches_alloc == 0)
+    {
+      n_switches_alloc = 16;
+      switches = XNEWVEC (struct switchstr, n_switches_alloc);
+    }
+  else if (n_switches_alloc == n_switches)
+    {
+      n_switches_alloc *= 2;
+      switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc);
+    }
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -3484,7 +3533,6 @@  process_command (int argc, const char **
   char *temp1;
   const char *spec_lang = 0;
   int last_language_n_infiles;
-  int lang_n_infiles = 0;
   const char *tooldir_prefix;
   char *(*get_relative_prefix) (const char *, const char *,
 				const char *) = NULL;
@@ -3698,12 +3746,22 @@  process_command (int argc, const char **
 	}
     }
 
-  /* Scan argv twice.  Here, the first time, just count how many switches
-     there will be in their vector, and how many input files in theirs.
-     Here we also parse the switches that cc itself uses (e.g. -v).  */
+  /* Process the options and store input files and switches in their
+     vectors.  */
+
+  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;
@@ -3729,59 +3787,50 @@  process_command (int argc, const char **
 	  /* translate_options () has turned --version into -fversion.  */
 	  print_version = 1;
 
-	  /* We will be passing a dummy file on to the sub-processes.  */
-	  n_infiles++;
-	  n_switches++;
-
 	  /* 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;
 
-	  /* We will be passing a dummy file on to the sub-processes.  */
-	  n_infiles++;
-	  n_switches++;
-
 	  /* 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;
 
-	  /* We will be passing a dummy file on to the sub-processes.  */
-	  n_infiles++;
-	  n_switches++;
+	  goto normal_switch;
 	}
       else if (strcmp (argv[i], "-ftarget-help") == 0)
 	{
 	  /* translate_options() has turned --target-help into -ftarget-help.  */
 	  print_subprocess_help = 1;
 
-	  /* We will be passing a dummy file on to the sub-processes.  */
-	  n_infiles++;
-	  n_switches++;
-
 	  /* 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;
-	  n_switches++;
 	}
       else if (! strcmp (argv[i], "-print-search-dirs"))
 	print_search_dirs = 1;
@@ -3804,16 +3853,18 @@  process_command (int argc, const char **
       else if (! strcmp (argv[i], "-fcompare-debug-second"))
 	{
 	  compare_debug_second = 1;
-	  n_switches++;
+	  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="
@@ -3831,7 +3882,7 @@  process_command (int argc, const char **
 	    compare_debug_opt = NULL;
 	  else
 	    compare_debug_opt = opt;
-	  n_switches++;
+	  goto normal_switch;
 	}
       else if (! strncmp (argv[i], "-Wa,", 4))
 	{
@@ -3869,17 +3920,24 @@  process_command (int argc, const char **
 	}
       else if (strncmp (argv[i], "-Wl,", 4) == 0)
 	{
-	  int j;
+	  int prev, j;
 	  /* Split the argument at commas.  */
-	  for (j = 3; argv[i][j]; j++)
-	    n_infiles += (argv[i][j] == ',');
+	  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");
 
-	  n_infiles++;
+	  add_infile (argv[i+1], "*");
 	  i++;
 	}
       else if (strcmp (argv[i], "-Xpreprocessor") == 0)
@@ -3888,6 +3946,7 @@  process_command (int argc, const char **
 	    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)
 	{
@@ -3895,25 +3954,29 @@  process_command (int argc, const char **
 	    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");
 
-	  n_infiles++;
+	  /* 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)
-	n_infiles++;
+	{
+	  add_infile (argv[i], "*");
+	}
       else if (strcmp (argv[i], "-save-temps") == 0)
 	{
 	  save_temps_flag = SAVE_TEMPS_CWD;
-	  n_switches++;
+	  goto normal_switch;
 	}
       else if (strncmp (argv[i], "-save-temps=", 12) == 0)
 	{
-	  n_switches++;
 	  if (strcmp (argv[i]+12, "cwd") == 0)
 	    save_temps_flag = SAVE_TEMPS_CWD;
 	  else if (strcmp (argv[i]+12, "obj") == 0
@@ -3921,6 +3984,7 @@  process_command (int argc, const char **
 	    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.  */
@@ -3928,7 +3992,7 @@  process_command (int argc, const char **
       else if (strcmp (argv[i], "-combine") == 0)
 	{
 	  combine_flag = 1;
-	  n_switches++;
+	  goto normal_switch;
 	}
       else if (strcmp (argv[i], "-specs") == 0)
 	{
@@ -3958,6 +4022,11 @@  process_command (int argc, const char **
 	    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)
@@ -3971,7 +4040,7 @@  process_command (int argc, const char **
 	  /* -pipe has to go into the switches array as well as
 	     setting a flag.  */
 	  use_pipes = 1;
-	  n_switches++;
+	  goto normal_switch;
 	}
       else if (strcmp (argv[i], "-wrapper") == 0)
         {
@@ -3979,8 +4048,6 @@  process_command (int argc, const char **
 	    fatal_error ("argument to %<-wrapper%> is missing");
 
           wrapper_string = argv[i];
-	  n_switches++;
-	  n_switches++;
         }
       else if (strcmp (argv[i], "-###") == 0)
 	{
@@ -3993,9 +4060,6 @@  process_command (int argc, const char **
 	}
       else if (argv[i][0] == '-' && argv[i][1] != 0)
 	{
-	  const char *p = &argv[i][1];
-	  int c = *p;
-
 	  switch (c)
 	    {
 	    case 'B':
@@ -4006,7 +4070,7 @@  process_command (int argc, const char **
 		if (p[1] == 0 && i + 1 == argc)
 		  fatal_error ("argument to %<-B%> is missing");
 		if (p[1] == 0)
-		  value = argv[++i];
+		  value = argv[i + 1];
 		else
 		  value = p + 1;
 
@@ -4035,28 +4099,38 @@  process_command (int argc, const char **
 			    PREFIX_PRIORITY_B_OPT, 0, 0);
 		add_prefix (&include_prefixes, value, NULL,
 			    PREFIX_PRIORITY_B_OPT, 0, 0);
-		n_switches++;
 	      }
-	      break;
+	      goto normal_switch;
 
 	    case 'v':	/* Print our subcommands and print versions.  */
-	      n_switches++;
 	      /* 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;
-		  n_switches++;
-		  break;
-		}
+		have_c = 1;
 	      goto normal_switch;
 
 	    case 'o':
@@ -4094,7 +4168,10 @@  process_command (int argc, const char **
 	      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);
+		{
+		  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])
@@ -4106,18 +4183,105 @@  process_command (int argc, const char **
 	    default:
 	    normal_switch:
 
-	      n_switches++;
+	      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 (SWITCH_TAKES_ARG (c) > (p[1] != 0))
-		i += SWITCH_TAKES_ARG (c) - (p[1] != 0);
-	      else if (WORD_SWITCH_TAKES_ARG (p))
-		i += 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 (strchr (switches_need_spaces, c))
+		{
+		  /* On some systems, ld cannot handle some options without
+		     a space.  So split the option from its argument.  */
+		  char *part1 = XNEWVEC (char, 2);
+		  part1[0] = c;
+		  part1[1] = '\0';
+
+		  switches[n_switches].part1 = part1;
+		  switches[n_switches].args = XNEWVEC (const char *, 2);
+		  switches[n_switches].args[0] = xstrdup (p+1);
+		  switches[n_switches].args[1] = 0;
+		}
+	      else
+		switches[n_switches].args = 0;
+
+	      switches[n_switches].live_cond = 0;
+	      switches[n_switches].validated = 0;
+	      switches[n_switches].ordering = 0;
+	      /* These are always valid, since gcc.c itself understands the
+		 first four, gfortranspec.c understands -static-libgfortran
+		 and g++spec.c understands -static-libstdc++ */
+	      if (!strcmp (p, "save-temps")
+		  || !strcmp (p, "static-libgcc")
+		  || !strcmp (p, "shared-libgcc")
+		  || !strcmp (p, "pipe")
+		  || !strcmp (p, "static-libgfortran")
+		  || !strcmp (p, "static-libstdc++"))
+		switches[n_switches].validated = 1;
+	      else
+		{
+		  char ch = switches[n_switches].part1[0];
+		  if (ch == 'B')
+		    switches[n_switches].validated = 1;
+		}
+	      n_switches++;
 	    }
 	}
       else
 	{
-	  n_infiles++;
-	  lang_n_infiles++;
+          const char *p = strrchr (argv[i], '@');
+          char *fname;
+	  long offset;
+	  int consumed;
+#ifdef HAVE_TARGET_OBJECT_SUFFIX
+	  argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
+	      && 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';
+	      /* 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]);
+		}
+	    }
+	  else
+	    fname = xstrdup (argv[i]);
+ 
+          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
+	    perror_with_name (fname);
+          else
+	    add_infile (argv[i], spec_lang);
+
+          free (fname);
 	}
     }
 
@@ -4156,13 +4320,11 @@  process_command (int argc, const char **
 	{
 	  compare_debug = 2;
 	  compare_debug_opt = gcd;
-	  n_switches++;
 	}
       else if (gcd && *gcd && strcmp (gcd, "0"))
 	{
 	  compare_debug = 3;
 	  compare_debug_opt = "-gtoggle";
-	  n_switches++;
 	}
     }
   else if (compare_debug < 0)
@@ -4215,7 +4377,7 @@  process_command (int argc, const char **
      then consider it to relocate with the rest of the GCC installation
      if GCC_EXEC_PREFIX is set.
      ``make_relative_prefix'' is not compiled for VMS, so don't call it.  */
-  if (target_system_root && gcc_exec_prefix)
+  if (target_system_root && !target_system_root_changed && gcc_exec_prefix)
     {
       char *tmp_prefix = get_relative_prefix (argv[0],
 					      standard_bindir_prefix,
@@ -4231,232 +4393,12 @@  process_command (int argc, const char **
   /* More prefixes are enabled in main, after we read the specs file
      and determine whether this is cross-compilation or not.  */
 
-  /* Then create the space for the vectors and scan again.  */
-
-  switches = XNEWVEC (struct switchstr, n_switches + 1);
-  infiles = XNEWVEC (struct infile, n_infiles + 1);
-  n_switches = 0;
-  n_infiles = 0;
-  last_language_n_infiles = -1;
-
-  /* This, time, copy the text of each switch and store a pointer
-     to the copy in the vector of switches.
-     Store all the infiles in their vector.  */
-
-  for (i = 1; i < argc; i++)
-    {
-      /* Just skip the switches that were handled by the preceding loop.  */
-      if (! strncmp (argv[i], "-Wa,", 4))
-	;
-      else if (! strncmp (argv[i], "-Wp,", 4))
-	;
-      else if (! strcmp (argv[i], "-no-canonical-prefixes"))
-	;
-      else if (! strcmp (argv[i], "-pass-exit-codes"))
-	;
-      else if (! strcmp (argv[i], "-print-search-dirs"))
-	;
-      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
-	;
-      else if (! strncmp (argv[i], "-print-file-name=", 17))
-	;
-      else if (! strncmp (argv[i], "-print-prog-name=", 17))
-	;
-      else if (! strcmp (argv[i], "-print-multi-lib"))
-	;
-      else if (! strcmp (argv[i], "-print-multi-directory"))
-	;
-      else if (! strcmp (argv[i], "-print-sysroot"))
-	;
-      else if (! strcmp (argv[i], "-print-multi-os-directory"))
-	;
-      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
-	;
-      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
-	{
-	  target_system_root = argv[i] + strlen ("--sysroot=");
-	  target_system_root_changed = 1;
-	}
-      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] == ',')
-	      {
-		infiles[n_infiles].language = "*";
-		infiles[n_infiles++].name
-		  = save_string (argv[i] + prev, j - prev);
-		prev = j + 1;
-	      }
-	  /* Record the part after the last comma.  */
-	  infiles[n_infiles].language = "*";
-	  infiles[n_infiles++].name = argv[i] + prev;
-	}
-      else if (strcmp (argv[i], "-Xlinker") == 0)
-	{
-	  infiles[n_infiles].language = "*";
-	  infiles[n_infiles++].name = argv[++i];
-	}
-      /* Xassembler and Xpreprocessor were already handled in the first argv
-	 scan, so all we need to do here is ignore them and their argument.  */
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-	i++;
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-	i++;
-      else if (strcmp (argv[i], "-l") == 0)
-	{ /* POSIX allows separation of -l and the lib arg;
-	     canonicalize by concatenating -l with its arg */
-	  infiles[n_infiles].language = "*";
-	  infiles[n_infiles++].name = concat ("-l", argv[++i], NULL);
-	}
-      else if (strncmp (argv[i], "-l", 2) == 0)
-	{
-	  infiles[n_infiles].language = "*";
-	  infiles[n_infiles++].name = argv[i];
-	}
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        i++;
-      else if (strcmp (argv[i], "-specs") == 0)
-	i++;
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-	;
-      else if (strcmp (argv[i], "-time") == 0)
-	;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
-	;
-      else if (strcmp (argv[i], "-###") == 0)
-	;
-      else if (argv[i][0] == '-' && argv[i][1] != 0)
-	{
-	  const char *p = &argv[i][1];
-	  int c = *p;
-
-	  if (c == '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;
-	      continue;
-	    }
-	  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 (strchr (switches_need_spaces, c))
-	    {
-	      /* On some systems, ld cannot handle some options without
-		 a space.  So split the option from its argument.  */
-	      char *part1 = XNEWVEC (char, 2);
-	      part1[0] = c;
-	      part1[1] = '\0';
-
-	      switches[n_switches].part1 = part1;
-	      switches[n_switches].args = XNEWVEC (const char *, 2);
-	      switches[n_switches].args[0] = xstrdup (p+1);
-	      switches[n_switches].args[1] = 0;
-	    }
-	  else
-	    switches[n_switches].args = 0;
-
-	  switches[n_switches].live_cond = 0;
-	  switches[n_switches].validated = 0;
-	  switches[n_switches].ordering = 0;
-	  /* These are always valid, since gcc.c itself understands the
-	     first four, gfortranspec.c understands -static-libgfortran
-	     and g++spec.c understands -static-libstdc++ */
-	  if (!strcmp (p, "save-temps")
-	      || !strcmp (p, "static-libgcc")
-	      || !strcmp (p, "shared-libgcc")
-	      || !strcmp (p, "pipe")
-	      || !strcmp (p, "static-libgfortran")
-	      || !strcmp (p, "static-libstdc++"))
-	    switches[n_switches].validated = 1;
-	  else
-	    {
-	      char ch = switches[n_switches].part1[0];
-	      if (ch == 'B')
-		switches[n_switches].validated = 1;
-	    }
-	  n_switches++;
-	}
-      else
-	{
-          const char *p = strrchr (argv[i], '@');
-          char *fname;
-	  long offset;
-	  int consumed;
-#ifdef HAVE_TARGET_OBJECT_SUFFIX
-	  argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
-	      && 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';
-	      /* 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]);
-		}
-	    }
-	  else
-	    fname = xstrdup (argv[i]);
- 
-          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
-	    perror_with_name (fname);
-          else
-            {
-              infiles[n_infiles].language = spec_lang;
-              infiles[n_infiles++].name = argv[i];
-            }
-
-          free (fname);
-	}
-    }
-
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
     warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
 
   if (compare_debug == 2 || compare_debug == 3)
     {
+      alloc_switch ();
       switches[n_switches].part1 = concat ("fcompare-debug=",
 					   compare_debug_opt,
 					   NULL);
@@ -4471,15 +4413,16 @@  process_command (int argc, const char **
   /* Ensure we only invoke each subprocess once.  */
   if (print_subprocess_help || print_help_list || print_version)
     {
-      n_infiles = 1;
+      n_infiles = 0;
 
       /* Create a dummy input file, so that we can pass
 	 the help option on to the various sub-processes.  */
-      infiles[0].language = "c";
-      infiles[0].name   = "help-dummy";
+      add_infile ("help-dummy", "c");
     }
 
+  alloc_switch ();
   switches[n_switches].part1 = 0;
+  alloc_infile ();
   infiles[n_infiles].name = 0;
 }
 
diff -rupN --exclude=.svn gcc-mainline-opt4-takes-arg/gcc/testsuite/gcc.dg/opts-3.c gcc-mainline/gcc/testsuite/gcc.dg/opts-3.c
--- gcc-mainline-opt4-takes-arg/gcc/testsuite/gcc.dg/opts-3.c	1969-12-31 16:00:00.000000000 -0800
+++ gcc-mainline/gcc/testsuite/gcc.dg/opts-3.c	2010-06-25 17:37:27.000000000 -0700
@@ -0,0 +1,7 @@ 
+/* Parameters of -Xassembler should not be interpreted as driver
+   options (and so cause the driver to exit prematurely, as in this
+   testcase, or have other unintended effects).  */
+/* { dg-do compile } */
+/* { dg-options "-Xassembler -dumpmachine" } */
+
+int int x; /* { dg-error "two or more data types" } */