diff gcc/gcc.c @ 69:1b10fe6932e1

merge 69
author Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp>
date Sun, 21 Aug 2011 07:53:12 +0900
parents 326d9e06c2e3 f6334be47118
children b81903832de2
line wrap: on
line diff
--- a/gcc/gcc.c	Tue Dec 14 03:58:33 2010 +0900
+++ b/gcc/gcc.c	Sun Aug 21 07:53:12 2011 +0900
@@ -1,6 +1,7 @@
 /* Compiler driver program that can handle many languages.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -29,72 +30,20 @@
 Once it knows which kind of compilation to perform, the procedure for
 compilation is specified by a string called a "spec".  */
 
-/* A Short Introduction to Adding a Command-Line Option.
-
-   Before adding a command-line option, consider if it is really
-   necessary.  Each additional command-line option adds complexity and
-   is difficult to remove in subsequent versions.
-
-   In the following, consider adding the command-line argument
-   `--bar'.
-
-   1. Each command-line option is specified in the specs file.  The
-   notation is described below in the comment entitled "The Specs
-   Language".  Read it.
-
-   2. In this file, add an entry to "option_map" equating the long
-   `--' argument version and any shorter, single letter version.  Read
-   the comments in the declaration of "struct option_map" for an
-   explanation.  Do not omit the first `-'.
-
-   3. Look in the "specs" file to determine which program or option
-   list should be given the argument, e.g., "cc1_options".  Add the
-   appropriate syntax for the shorter option version to the
-   corresponding "const char *" entry in this file.  Omit the first
-   `-' from the option.  For example, use `-bar', rather than `--bar'.
-
-   4. If the argument takes an argument, e.g., `--baz argument1',
-   modify either DEFAULT_SWITCH_TAKES_ARG or
-   DEFAULT_WORD_SWITCH_TAKES_ARG in gcc.h.  Omit the first `-'
-   from `--baz'.
-
-   5. Document the option in this file's display_help().  If the
-   option is passed to a subprogram, modify its corresponding
-   function, e.g., cppinit.c:print_help() or toplev.c:display_help(),
-   instead.
-
-   6. Compile and test.  Make sure that your new specs file is being
-   read.  For example, use a debugger to investigate the value of
-   "specs_file" in main().  */
-
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "multilib.h" /* before tm.h */
 #include "tm.h"
-#include <signal.h>
-#if ! defined( SIGCHLD ) && defined( SIGCLD )
-#  define SIGCHLD SIGCLD
-#endif
 #include "xregex.h"
 #include "obstack.h"
 #include "intl.h"
 #include "prefix.h"
 #include "gcc.h"
+#include "diagnostic.h"
 #include "flags.h"
 #include "opts.h"
-
-#ifdef HAVE_MMAP_FILE
-# include <sys/mman.h>
-# ifdef HAVE_MINCORE
-/* This is on Solaris.  */
-#  include <sys/types.h>
-# endif
-#endif
-
-#ifndef MAP_FAILED
-# define MAP_FAILED ((void *)-1)
-#endif
+#include "vec.h"
 
 /* By default there is no special suffix for target executables.  */
 /* FIXME: when autoconf is fixed, remove the host check - dj */
@@ -123,10 +72,6 @@
 #define LIBRARY_PATH_ENV "LIBRARY_PATH"
 #endif
 
-#ifndef HAVE_KILL
-#define kill(p,s) raise(s)
-#endif
-
 /* If a stage of compilation returns an exit status >= 1,
    compilation of that file ceases.  */
 
@@ -138,44 +83,9 @@
 /* Flag set to nonzero if an @file argument has been supplied to gcc.  */
 static bool at_file_supplied;
 
-/* Flag saying to pass the greatest exit code returned by a sub-process
-   to the calling program.  */
-static int pass_exit_codes;
-
 /* Definition of string containing the arguments given to configure.  */
 #include "configargs.h"
 
-/* Flag saying to print the directories gcc will search through looking for
-   programs, libraries, etc.  */
-
-static int print_search_dirs;
-
-/* Flag saying to print the full filename of this file
-   as found through our usual search mechanism.  */
-
-static const char *print_file_name = NULL;
-
-/* As print_file_name, but search for executable file.  */
-
-static const char *print_prog_name = NULL;
-
-/* Flag saying to print the relative path we'd use to
-   find libgcc.a given the current compiler flags.  */
-
-static int print_multi_directory;
-
-static int print_sysroot;
-
-/* Flag saying to print the relative path we'd use to
-   find OS libraries given the current compiler flags.  */
-
-static int print_multi_os_directory;
-
-/* Flag saying to print the list of subdirectories and
-   compiler flags used to select them in a standard form.  */
-
-static int print_multi_lib;
-
 /* Flag saying to print the command line options understood by gcc and its
    sub-processes.  */
 
@@ -185,15 +95,6 @@
 
 static int print_version;
 
-/* Flag saying to print the sysroot suffix used for searching for
-   headers.  */
-
-static int print_sysroot_headers_suffix;
-
-/* Flag indicating whether we should print the command and arguments */
-
-static int verbose_flag;
-
 /* Flag indicating whether we should ONLY print the command and
    arguments (like verbose_flag) without executing the command.
    Displayed arguments are quoted so that the generated command
@@ -205,11 +106,6 @@
 
 static int print_subprocess_help;
 
-/* Flag indicating whether we should report subprocess execution times
-   (if this is supported by the system - see pexecute.c).  */
-
-static int report_times;
-
 /* Whether we should report subprocess execution times to a file.  */
 
 FILE *report_times_to_file = NULL;
@@ -248,24 +144,15 @@
 static char *save_temps_prefix = 0;
 static size_t save_temps_length = 0;
 
-/* Nonzero means pass multiple source files to the compiler at one time.  */
-
-static int combine_flag = 0;
-
-/* Nonzero means use pipes to communicate between subprocesses.
-   Overridden by either of the above two flags.  */
-
-static int use_pipes;
-
 /* The compiler version.  */
 
 static const char *compiler_version;
 
-/* The target version specified with -V */
+/* The target version.  */
 
 static const char *const spec_version = DEFAULT_TARGET_VERSION;
 
-/* The target machine specified with -b.  */
+/* The target machine.  */
 
 static const char *spec_machine = DEFAULT_TARGET_MACHINE;
 
@@ -278,27 +165,6 @@
 static const char *cross_compile = "0";
 #endif
 
-#ifdef MODIFY_TARGET_NAME
-
-/* Information on how to alter the target name based on a command-line
-   switch.  The only case we support now is simply appending or deleting a
-   string to or from the end of the first part of the configuration name.  */
-
-enum add_del {ADD, DELETE};
-
-static const struct modify_target
-{
-  const char *const sw;
-  const enum add_del add_del;
-  const char *const str;
-}
-modify_target[] = MODIFY_TARGET_NAME;
-#endif
-
-/* The number of errors that have occurred; the link phase will not be
-   run if this is nonzero.  */
-static int error_count = 0;
-
 /* Greatest exit code of sub-processes that has been encountered up to
    now.  */
 static int greatest_status = 1;
@@ -314,14 +180,6 @@
 
 static struct obstack collect_obstack;
 
-/* This is a list of a wrapper program and its arguments.
-   e.g. wrapper_string of "strace,-c"
-   will cause all programs to run as
-       strace -c program arguments
-   instead of just
-       program arguments */
-static const char  *wrapper_string;
-
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 struct prefix_list;
@@ -344,7 +202,6 @@
 			int, int, int);
 static void add_sysrooted_prefix (struct path_prefix *, const char *,
 				  const char *, int, int, int);
-static void translate_options (int *, const char *const **);
 static char *skip_whitespace (char *);
 static void delete_if_ordinary (const char *);
 static void delete_temp_files (void);
@@ -377,17 +234,15 @@
 static void set_multilib_dir (void);
 static void print_multilib_info (void);
 static void perror_with_name (const char *);
-static void fatal_ice (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
-static void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
 static void display_help (void);
 static void add_preprocessor_option (const char *, int);
 static void add_assembler_option (const char *, int);
 static void add_linker_option (const char *, int);
-static void process_command (int, const char **);
+static void process_command (unsigned int, struct cl_decoded_option *);
 static int execute (void);
 static void alloc_args (void);
 static void clear_args (void);
-static void fatal_error (int);
+static void fatal_signal (int);
 #if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
 static void init_gcc_specs (struct obstack *, const char *, const char *,
 			    const char *);
@@ -400,12 +255,16 @@
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
 static const char *replace_outfile_spec_function (int, const char **);
+static const char *remove_outfile_spec_function (int, const char **);
 static const char *version_compare_spec_function (int, const char **);
 static const char *include_spec_function (int, const char **);
+static const char *find_file_spec_function (int, const char **);
+static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
 static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
+static const char *pass_through_libs_spec_func (int, const char **);
 
 /* The Specs Language
 
@@ -531,6 +390,7 @@
         Note - this command is position dependent.  % commands in the
         spec string before this one will see -S, % commands in the
         spec string after this one will not.
+ %>S	Similar to "%<S", but keep it in the GCC command line.
  %<S*	remove all occurrences of all switches beginning with -S from the
         command line.
  %:function(args)
@@ -664,6 +524,16 @@
 #define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}"
 #endif
 
+/* When using -fsplit-stack we need to wrap pthread_create, in order
+   to initialize the stack guard.  We always use wrapping, rather than
+   shared library ordering, and we keep the wrapper function in
+   libgcc.  This is not yet a real spec, though it could become one;
+   it is currently just stuffed into LINK_SPEC.  FIXME: This wrapping
+   only works with GNU ld and gold.  FIXME: This is incompatible with
+   -fmudflap when linking statically, which wants to do its own
+   wrapping.  */
+#define STACK_SPLIT_SPEC " %{fsplit-stack: --wrap=pthread_create}"
+
 /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
    included.  */
 #ifndef LIBGCC_SPEC
@@ -683,18 +553,6 @@
   "%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
 #endif
 
-/* config.h can define SWITCHES_NEED_SPACES to control which options
-   require spaces between the option and the argument.
-
-   We define SWITCHES_NEED_SPACES to include "o" by default.  This
-   causes "-ofoo.o" to be split into "-o foo.o" during the initial
-   processing of the command-line, before being seen by the specs
-   machinery.  This makes sure we record "foo.o" as the temporary file
-   to be deleted in the case of error, rather than "-ofoo.o".  */
-#ifndef SWITCHES_NEED_SPACES
-#define SWITCHES_NEED_SPACES "o"
-#endif
-
 /* config.h can define ENDFILE_SPEC to override the default crtn files.  */
 #ifndef ENDFILE_SPEC
 #define ENDFILE_SPEC ""
@@ -763,6 +621,20 @@
 # endif
 #endif
 
+/* Conditional to test whether plugin is used or not.
+   FIXME: For slim LTO we will need to enable plugin unconditionally.  This
+   still cause problems with PLUGIN_LD != LD and when plugin is built but
+   not useable.  For GCC 4.6 we don't support slim LTO and thus we can enable
+   plugin only when LTO is enabled.  We still honor explicit
+   -fuse-linker-plugin.  */
+#ifdef HAVE_LTO_PLUGIN
+#define PLUGIN_COND "!fno-use-linker-plugin:%{flto|flto=*|fuse-linker-plugin"
+#define PLUGIN_COND_CLOSE "}"
+#else
+#define PLUGIN_COND "fuse-linker-plugin"
+#define PLUGIN_COND_CLOSE ""
+#endif
+
 
 /* -u* was put back because both BSD and SysV seem to support it.  */
 /* %{static:} simply prevents an error message if the target machine
@@ -770,30 +642,29 @@
 /* We want %{T*} after %{L*} and %D so that it can be used to specify linker
    scripts which exist in user specified directories, or in standard
    directories.  */
-/* We pass any -flto and -fwhopr flags on to the linker, which is expected
+/* We pass any -flto flags on to the linker, which is expected
    to understand them.  In practice, this means it had better be collect2.  */
+/* %{e*} includes -export-dynamic; see comment in common.opt.  */
 #ifndef LINK_COMMAND_SPEC
 #define LINK_COMMAND_SPEC "\
 %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
     %(linker) \
-    %{fuse-linker-plugin: \
+    %{"PLUGIN_COND": \
     -plugin %(linker_plugin_file) \
     -plugin-opt=%(lto_wrapper) \
-    -plugin-opt=%(lto_gcc) \
-    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}	\
-    %{static:-plugin-opt=-pass-through=-lc}	\
-    %{O*:-plugin-opt=-O%*} \
-    %{w:-plugin-opt=-w} \
-    %{f*:-plugin-opt=-f%*} \
-    } \
-    %{flto} %{fwhopr} %l " LINK_PIE_SPEC \
-   "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
-    %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
+    -plugin-opt=-fresolution=%u.res \
+    %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
+    }"PLUGIN_COND_CLOSE" \
+    %{flto|flto=*:%<fcompare-debug*} \
+    %{flto} %{flto=*} %l " LINK_PIE_SPEC \
+   "%X %{o*} %{e*} %{N} %{n} %{r}\
+    %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
-    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+    %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
-    %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
+    %{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}"
 #endif
 
 #ifndef LINK_LIBGCC_SPEC
@@ -833,12 +704,10 @@
 static const char *libgcc_spec = LIBGCC_SPEC;
 static const char *endfile_spec = ENDFILE_SPEC;
 static const char *startfile_spec = STARTFILE_SPEC;
-static const char *switches_need_spaces = SWITCHES_NEED_SPACES;
 static const char *linker_name_spec = LINKER_NAME;
 static const char *linker_plugin_file_spec = "";
 static const char *lto_wrapper_spec = "";
 static const char *lto_gcc_spec = "";
-static const char *lto_libgcc_spec = "";
 static const char *link_command_spec = LINK_COMMAND_SPEC;
 static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
 static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
@@ -856,19 +725,19 @@
    call cc1 (or cc1obj in objc/lang-specs.h) from the main specs so
    that we default the front end language better.  */
 static const char *trad_capable_cpp =
-"cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}";
+"cc1 -E %{traditional|traditional-cpp:-traditional-cpp}";
 
 /* We don't wrap .d files in %W{} since a missing .d file, and
    therefore no dependency entry, confuses make into thinking a .o
    file that happens to exist is up-to-date.  */
 static const char *cpp_unique_options =
-"%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}}\
- %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
+"%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
  %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\
  %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
  %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
  %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
  %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\
@@ -891,21 +760,23 @@
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
- %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
+ %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
  %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
  %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
- %{Qn:-fno-ident} %{--help:--help}\
- %{--target-help:--target-help}\
- %{--help=*:--help=%(VALUE)}\
+ %{Qn:-fno-ident} %{Qy:} %{-help:--help}\
+ %{-target-help:--target-help}\
+ %{-version:--version}\
+ %{-help=*:--help=%*}\
  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
  %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}\
  %{coverage:-fprofile-arcs -ftest-coverage}";
 
 static const char *asm_options =
-"%{--target-help:%:print-asm-header()} "
+"%{-target-help:%:print-asm-header()} "
 #if HAVE_GNU_AS
 /* If GNU AS is used, then convert -w (no warnings), -I, and -v
    to the assembler equivalents.  */
@@ -979,25 +850,7 @@
 
 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.  */
-#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
-  ((CHAR) == 'c' || (CHAR) == 'S' || (CHAR) == 'E')
-
-#ifndef SWITCH_CURTAILS_COMPILATION
-#define SWITCH_CURTAILS_COMPILATION(CHAR) \
-  DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR)
-#endif
-#endif
-
 /* Record the mapping from file suffixes for compilation specs.  */
 
 struct compiler
@@ -1059,32 +912,26 @@
   {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
+  {".go", "#Go", 0, 1, 0},
   /* Next come the entries for C.  */
-  {".c", "@c", 0, 1, 1},
 #ifndef noCbC
   {".cbc", "@c", 0, 1, 1},
 #endif
+  {".c", "@c", 0, 0, 1},
   {"@c",
    /* cc1 has an integrated ISO C preprocessor.  We should invoke the
       external preprocessor if -save-temps is given.  */
      "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\
       %{!E:%{!M:%{!MM:\
-          %{traditional|ftraditional:\
+          %{traditional:\
 %eGNU C no longer supports -traditional without -E}\
-       %{!combine:\
-	  %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
-		%(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
-		    cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
-			%(cc1_options)}\
-	  %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
-		cc1 %(cpp_unique_options) %(cc1_options)}}}\
-          %{!fsyntax-only:%(invoke_as)}} \
-      %{combine:\
-	  %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
-		%(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i}}\
-	  %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
-		cc1 %(cpp_unique_options) %(cc1_options)}}\
-                %{!fsyntax-only:%(invoke_as)}}}}}}", 0, 1, 1},
+      %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
+	  %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
+	    cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
+	  %(cc1_options)}\
+      %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
+	  cc1 %(cpp_unique_options) %(cc1_options)}}}\
+      %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 1},
   {"-",
    "%{!E:%e-E or -x required when input is from standard input}\
     %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0},
@@ -1098,20 +945,20 @@
 		%(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
 		    cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
 			%(cc1_options)\
-                        -o %g.s %{!o*:--output-pch=%i.gch}\
-                        %W{o*:--output-pch=%*}%V}\
+                        %{!fdump-ada-spec*:-o %g.s %{!o*:--output-pch=%i.gch}\
+                        %W{o*:--output-pch=%*}}%V}\
 	  %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
 		cc1 %(cpp_unique_options) %(cc1_options)\
-                    -o %g.s %{!o*:--output-pch=%i.gch}\
-                    %W{o*:--output-pch=%*}%V}}}}}}", 0, 0, 0},
-  {".i", "@cpp-output", 0, 1, 0},
+                    %{!fdump-ada-spec*:-o %g.s %{!o*:--output-pch=%i.gch}\
+                    %W{o*:--output-pch=%*}}%V}}}}}}", 0, 0, 0},
+  {".i", "@cpp-output", 0, 0, 0},
   {"@cpp-output",
-   "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0},
-  {".s", "@assembler", 0, 1, 0},
+   "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
+  {".s", "@assembler", 0, 0, 0},
   {"@assembler",
-   "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 1, 0},
-  {".sx", "@assembler-with-cpp", 0, 1, 0},
-  {".S", "@assembler-with-cpp", 0, 1, 0},
+   "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 0, 0},
+  {".sx", "@assembler-with-cpp", 0, 0, 0},
+  {".S", "@assembler-with-cpp", 0, 0, 0},
   {"@assembler-with-cpp",
 #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
    "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
@@ -1124,7 +971,7 @@
       %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
        as %(asm_debug) %(asm_options) %m.s %A }}}}"
 #endif
-   , 0, 1, 0},
+   , 0, 0, 0},
 
 #include "specs.h"
   /* Mark end of table.  */
@@ -1135,361 +982,24 @@
 
 static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
 
+typedef char *char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(char_p);
+DEF_VEC_ALLOC_P(char_p,heap);
+
 /* A vector of options to give to the linker.
    These options are accumulated by %x,
    and substituted into the linker command with %X.  */
-static int n_linker_options;
-static char **linker_options;
+static VEC(char_p,heap) *linker_options;
 
 /* A vector of options to give to the assembler.
    These options are accumulated by -Wa,
    and substituted into the assembler command with %Y.  */
-static int n_assembler_options;
-static char **assembler_options;
+static VEC(char_p,heap) *assembler_options;
 
 /* A vector of options to give to the preprocessor.
    These options are accumulated by -Wp,
    and substituted into the preprocessor command with %Z.  */
-static int n_preprocessor_options;
-static char **preprocessor_options;
-
-/* Define how to map long options into short ones.  */
-
-/* This structure describes one mapping.  */
-struct option_map
-{
-  /* The long option's name.  */
-  const char *const name;
-  /* The equivalent short option.  */
-  const char *const equivalent;
-  /* Argument info.  A string of flag chars; NULL equals no options.
-     a => argument required.
-     o => argument optional.
-     j => join argument to equivalent, making one word.
-     * => require other text after NAME as an argument.  */
-  const char *const arg_info;
-};
-
-/* This is the table of mappings.  Mappings are tried sequentially
-   for each option encountered; the first one that matches, wins.  */
-
-static const struct option_map option_map[] =
- {
-   {"--all-warnings", "-Wall", 0},
-   {"--ansi", "-ansi", 0},
-   {"--assemble", "-S", 0},
-   {"--assert", "-A", "a"},
-   {"--classpath", "-fclasspath=", "aj"},
-   {"--bootclasspath", "-fbootclasspath=", "aj"},
-   {"--CLASSPATH", "-fclasspath=", "aj"},
-   {"--combine", "-combine", 0},
-   {"--comments", "-C", 0},
-   {"--comments-in-macros", "-CC", 0},
-   {"--compile", "-c", 0},
-   {"--debug", "-g", "oj"},
-   {"--define-macro", "-D", "aj"},
-   {"--dependencies", "-M", 0},
-   {"--dump", "-d", "a"},
-   {"--dumpbase", "-dumpbase", "a"},
-   {"--encoding", "-fencoding=", "aj"},
-   {"--entry", "-e", 0},
-   {"--extra-warnings", "-W", 0},
-   {"--extdirs", "-fextdirs=", "aj"},
-   {"--for-assembler", "-Wa", "a"},
-   {"--for-linker", "-Xlinker", "a"},
-   {"--force-link", "-u", "a"},
-   {"--coverage", "-coverage", 0},
-   {"--imacros", "-imacros", "a"},
-   {"--include", "-include", "a"},
-   {"--include-barrier", "-I-", 0},
-   {"--include-directory", "-I", "aj"},
-   {"--include-directory-after", "-idirafter", "a"},
-   {"--include-prefix", "-iprefix", "a"},
-   {"--include-with-prefix", "-iwithprefix", "a"},
-   {"--include-with-prefix-before", "-iwithprefixbefore", "a"},
-   {"--include-with-prefix-after", "-iwithprefix", "a"},
-   {"--language", "-x", "a"},
-   {"--library-directory", "-L", "a"},
-   {"--machine", "-m", "aj"},
-   {"--machine-", "-m", "*j"},
-   {"--no-canonical-prefixes", "-no-canonical-prefixes", 0},
-   {"--no-integrated-cpp", "-no-integrated-cpp", 0},
-   {"--no-line-commands", "-P", 0},
-   {"--no-precompiled-includes", "-noprecomp", 0},
-   {"--no-standard-includes", "-nostdinc", 0},
-   {"--no-standard-libraries", "-nostdlib", 0},
-   {"--no-warnings", "-w", 0},
-   {"--optimize", "-O", "oj"},
-   {"--output", "-o", "a"},
-   {"--output-class-directory", "-foutput-class-dir=", "ja"},
-   {"--param", "--param", "a"},
-   {"--pass-exit-codes", "-pass-exit-codes", 0},
-   {"--pedantic", "-pedantic", 0},
-   {"--pedantic-errors", "-pedantic-errors", 0},
-   {"--pie", "-pie", 0},
-   {"--pipe", "-pipe", 0},
-   {"--prefix", "-B", "a"},
-   {"--preprocess", "-E", 0},
-   {"--print-search-dirs", "-print-search-dirs", 0},
-   {"--print-file-name", "-print-file-name=", "aj"},
-   {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
-   {"--print-missing-file-dependencies", "-MG", 0},
-   {"--print-multi-lib", "-print-multi-lib", 0},
-   {"--print-multi-directory", "-print-multi-directory", 0},
-   {"--print-multi-os-directory", "-print-multi-os-directory", 0},
-   {"--print-prog-name", "-print-prog-name=", "aj"},
-   {"--print-sysroot", "-print-sysroot", 0},
-   {"--print-sysroot-headers-suffix", "-print-sysroot-headers-suffix", 0},
-   {"--profile", "-p", 0},
-   {"--profile-blocks", "-a", 0},
-   {"--quiet", "-q", 0},
-   {"--resource", "-fcompile-resource=", "aj"},
-   {"--save-temps", "-save-temps", 0},
-   {"--shared", "-shared", 0},
-   {"--silent", "-q", 0},
-   {"--specs", "-specs=", "aj"},
-   {"--static", "-static", 0},
-   {"--std", "-std=", "aj"},
-   {"--symbolic", "-symbolic", 0},
-   {"--sysroot", "--sysroot=", "aj"},
-   {"--time", "-time", 0},
-   {"--trace-includes", "-H", 0},
-   {"--traditional", "-traditional", 0},
-   {"--traditional-cpp", "-traditional-cpp", 0},
-   {"--trigraphs", "-trigraphs", 0},
-   {"--undefine-macro", "-U", "aj"},
-   {"--user-dependencies", "-MM", 0},
-   {"--verbose", "-v", 0},
-   {"--warn-", "-W", "*j"},
-   {"--write-dependencies", "-MD", 0},
-   {"--write-user-dependencies", "-MMD", 0},
-   {"--", "-f", "*j"}
- };
-
-
-#ifdef TARGET_OPTION_TRANSLATE_TABLE
-static const struct {
-  const char *const option_found;
-  const char *const replacements;
-} target_option_translations[] =
-{
-  TARGET_OPTION_TRANSLATE_TABLE,
-  { 0, 0 }
-};
-#endif
-
-/* Translate the options described by *ARGCP and *ARGVP.
-   Make a new vector and store it back in *ARGVP,
-   and store its length in *ARGCP.  */
-
-static void
-translate_options (int *argcp, const char *const **argvp)
-{
-  int i;
-  int argc = *argcp;
-  const char *const *argv = *argvp;
-  int newvsize = (argc + 2) * 2 * sizeof (const char *);
-  const char **newv = XNEWVAR (const char *, newvsize);
-  int newindex = 0;
-
-  i = 0;
-  newv[newindex++] = argv[i++];
-
-  while (i < argc)
-    {
-#ifdef TARGET_OPTION_TRANSLATE_TABLE
-      int tott_idx;
-
-      for (tott_idx = 0;
-	   target_option_translations[tott_idx].option_found;
-	   tott_idx++)
-	{
-	  if (strcmp (target_option_translations[tott_idx].option_found,
-		      argv[i]) == 0)
-	    {
-	      int spaces = 1;
-	      const char *sp;
-	      char *np;
-
-	      for (sp = target_option_translations[tott_idx].replacements;
-		   *sp; sp++)
-		{
-		  if (*sp == ' ')
-		    spaces ++;
-		}
-
-	      newvsize += spaces * sizeof (const char *);
-	      newv =  XRESIZEVAR (const char *, newv, newvsize);
-
-	      sp = target_option_translations[tott_idx].replacements;
-	      np = xstrdup (sp);
-
-	      while (1)
-		{
-		  while (*np == ' ')
-		    np++;
-		  if (*np == 0)
-		    break;
-		  newv[newindex++] = np;
-		  while (*np != ' ' && *np)
-		    np++;
-		  if (*np == 0)
-		    break;
-		  *np++ = 0;
-		}
-
-	      i ++;
-	      break;
-	    }
-	}
-      if (target_option_translations[tott_idx].option_found)
-	continue;
-#endif
-
-      /* Translate -- options.  */
-      if (argv[i][0] == '-' && argv[i][1] == '-')
-	{
-	  size_t j;
-	  /* Find a mapping that applies to this option.  */
-	  for (j = 0; j < ARRAY_SIZE (option_map); j++)
-	    {
-	      size_t optlen = strlen (option_map[j].name);
-	      size_t arglen = strlen (argv[i]);
-	      size_t complen = arglen > optlen ? optlen : arglen;
-	      const char *arginfo = option_map[j].arg_info;
-
-	      if (arginfo == 0)
-		arginfo = "";
-
-	      if (!strncmp (argv[i], option_map[j].name, complen))
-		{
-		  const char *arg = 0;
-
-		  if (arglen < optlen)
-		    {
-		      size_t k;
-		      for (k = j + 1; k < ARRAY_SIZE (option_map); k++)
-			if (strlen (option_map[k].name) >= arglen
-			    && !strncmp (argv[i], option_map[k].name, arglen))
-			  {
-			    error ("ambiguous abbreviation %s", argv[i]);
-			    break;
-			  }
-
-		      if (k != ARRAY_SIZE (option_map))
-			break;
-		    }
-
-		  if (arglen > optlen)
-		    {
-		      /* If the option has an argument, accept that.  */
-		      if (argv[i][optlen] == '=')
-			arg = argv[i] + optlen + 1;
-
-		      /* If this mapping requires extra text at end of name,
-			 accept that as "argument".  */
-		      else if (strchr (arginfo, '*') != 0)
-			arg = argv[i] + optlen;
-
-		      /* Otherwise, extra text at end means mismatch.
-			 Try other mappings.  */
-		      else
-			continue;
-		    }
-
-		  else if (strchr (arginfo, '*') != 0)
-		    {
-		      error ("incomplete '%s' option", option_map[j].name);
-		      break;
-		    }
-
-		  /* Handle arguments.  */
-		  if (strchr (arginfo, 'a') != 0)
-		    {
-		      if (arg == 0)
-			{
-			  if (i + 1 == argc)
-			    {
-			      error ("missing argument to '%s' option",
-				     option_map[j].name);
-			      break;
-			    }
-
-			  arg = argv[++i];
-			}
-		    }
-		  else if (strchr (arginfo, '*') != 0)
-		    ;
-		  else if (strchr (arginfo, 'o') == 0)
-		    {
-		      if (arg != 0)
-			error ("extraneous argument to '%s' option",
-			       option_map[j].name);
-		      arg = 0;
-		    }
-
-		  /* Store the translation as one argv elt or as two.  */
-		  if (arg != 0 && strchr (arginfo, 'j') != 0)
-		    newv[newindex++] = concat (option_map[j].equivalent, arg,
-					       NULL);
-		  else if (arg != 0)
-		    {
-		      newv[newindex++] = option_map[j].equivalent;
-		      newv[newindex++] = arg;
-		    }
-		  else
-		    newv[newindex++] = option_map[j].equivalent;
-
-		  break;
-		}
-	    }
-	  i++;
-	}
-
-      /* Handle old-fashioned options--just copy them through,
-	 with their arguments.  */
-      else if (argv[i][0] == '-')
-	{
-	  const char *p = argv[i] + 1;
-	  int c = *p;
-	  int nskip = 1;
-
-	  if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
-	    nskip += SWITCH_TAKES_ARG (c) - (p[1] != 0);
-	  else if (WORD_SWITCH_TAKES_ARG (p))
-	    nskip += WORD_SWITCH_TAKES_ARG (p);
-	  else if ((c == 'B' || c == 'b' || c == 'x')
-		   && p[1] == 0)
-	    nskip += 1;
-	  else if (! strcmp (p, "Xlinker"))
-	    nskip += 1;
-	  else if (! strcmp (p, "Xpreprocessor"))
-	    nskip += 1;
-	  else if (! strcmp (p, "Xassembler"))
-	    nskip += 1;
-
-	  /* Watch out for an option at the end of the command line that
-	     is missing arguments, and avoid skipping past the end of the
-	     command line.  */
-	  if (nskip + i > argc)
-	    nskip = argc - i;
-
-	  while (nskip > 0)
-	    {
-	      newv[newindex++] = argv[i++];
-	      nskip--;
-	    }
-	}
-      else
-	/* Ordinary operands, or +e options.  */
-	newv[newindex++] = argv[i++];
-    }
-
-  newv[newindex] = 0;
-
-  *argvp = newv;
-  *argcp = newindex;
-}
+static VEC(char_p,heap) *preprocessor_options;
 
 static char *
 skip_whitespace (char *p)
@@ -1674,7 +1184,6 @@
   INIT_STATIC_SPEC ("link_gomp",		&link_gomp_spec),
   INIT_STATIC_SPEC ("libgcc",			&libgcc_spec),
   INIT_STATIC_SPEC ("startfile",		&startfile_spec),
-  INIT_STATIC_SPEC ("switches_need_spaces",	&switches_need_spaces),
   INIT_STATIC_SPEC ("cross_compile",		&cross_compile),
   INIT_STATIC_SPEC ("version",			&compiler_version),
   INIT_STATIC_SPEC ("multilib",			&multilib_select),
@@ -1687,7 +1196,6 @@
   INIT_STATIC_SPEC ("linker_plugin_file",	&linker_plugin_file_spec),
   INIT_STATIC_SPEC ("lto_wrapper",		&lto_wrapper_spec),
   INIT_STATIC_SPEC ("lto_gcc",			&lto_gcc_spec),
-  INIT_STATIC_SPEC ("lto_libgcc",		&lto_libgcc_spec),
   INIT_STATIC_SPEC ("link_libgcc",		&link_libgcc_spec),
   INIT_STATIC_SPEC ("md_exec_prefix",		&md_exec_prefix),
   INIT_STATIC_SPEC ("md_startfile_prefix",	&md_startfile_prefix),
@@ -1723,12 +1231,16 @@
   { "if-exists",		if_exists_spec_function },
   { "if-exists-else",		if_exists_else_spec_function },
   { "replace-outfile",		replace_outfile_spec_function },
+  { "remove-outfile",		remove_outfile_spec_function },
   { "version-compare",		version_compare_spec_function },
   { "include",			include_spec_function },
+  { "find-file",		find_file_spec_function },
+  { "find-plugindir",		find_plugindir_spec_function },
   { "print-asm-header",		print_asm_header_spec_function },
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
+  { "pass-through-libs",	pass_through_libs_spec_func },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -1795,7 +1307,7 @@
     return;			/* Already initialized.  */
 
   if (verbose_flag)
-    notice ("Using built-in specs.\n");
+    fnotice (stderr, "Using built-in specs.\n");
 
 #ifdef EXTRA_SPECS
   extra_specs = XCNEWVEC (struct spec_list, ARRAY_SIZE (extra_specs_1));
@@ -1867,7 +1379,8 @@
 			    "-lgcc_eh"
 #ifdef USE_LIBUNWIND_EXCEPTIONS
 # ifdef HAVE_LD_STATIC_DYNAMIC
-			    " %{!static:-Bstatic} -lunwind %{!static:-Bdynamic}"
+			    " %{!static:" LD_STATIC_OPTION "} -lunwind"
+			    " %{!static:" LD_DYNAMIC_OPTION "}"
 # else
 			    " -lunwind"
 # endif
@@ -1980,7 +1493,7 @@
 
 #ifdef DEBUG_SPECS
   if (verbose_flag)
-    notice ("Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
+    fnotice (stderr, "Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
 #endif
 
   /* Free the old spec.  */
@@ -1992,19 +1505,15 @@
 
 /* Accumulate a command (program name and args), and run it.  */
 
+typedef const char *const_char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p,heap);
+
 /* Vector of pointers to arguments in the current line of specifications.  */
 
-static const char **argbuf;
-
-/* Number of elements allocated in argbuf.  */
-
-static int argbuf_length;
-
-/* Number of elements in argbuf currently in use (containing args).  */
-
-static int argbuf_index;
-
-/* Position in the argbuf array containing the name of the output file
+static VEC(const_char_p,heap) *argbuf;
+
+/* Position in the argbuf vector containing the name of the output file
    (the value associated with the "-o" flag).  */
 
 static int have_o_argbuf_index = 0;
@@ -2035,18 +1544,13 @@
 /* Number of commands that exited with a signal.  */
 
 static int signal_count;
-
-/* Name with which this program was invoked.  */
-
-static const char *programname;
 
 /* Allocate the argument vector.  */
 
 static void
 alloc_args (void)
 {
-  argbuf_length = 10;
-  argbuf = XNEWVEC (const char *, argbuf_length);
+  argbuf = VEC_alloc (const_char_p, heap, 10);
 }
 
 /* Clear out the vector of arguments (after a command is executed).  */
@@ -2054,7 +1558,7 @@
 static void
 clear_args (void)
 {
-  argbuf_index = 0;
+  VEC_truncate (const_char_p, argbuf, 0);
 }
 
 /* Add one argument to the vector at the end.
@@ -2067,16 +1571,20 @@
 static void
 store_arg (const char *arg, int delete_always, int delete_failure)
 {
-  if (argbuf_index + 1 == argbuf_length)
-    argbuf = XRESIZEVEC (const char *, argbuf, (argbuf_length *= 2));
-
-  argbuf[argbuf_index++] = arg;
-  argbuf[argbuf_index] = 0;
+  VEC_safe_push (const_char_p, heap, argbuf, arg);
 
   if (strcmp (arg, "-o") == 0)
-    have_o_argbuf_index = argbuf_index;
+    have_o_argbuf_index = VEC_length (const_char_p, argbuf);
   if (delete_always || delete_failure)
-    record_temp_file (arg, delete_always, delete_failure);
+    {
+      const char *p;
+      /* If the temporary file we should delete is specified as
+	 part of a joined argument extract the filename.  */
+      if (arg[0] == '-'
+	  && (p = strrchr (arg, '=')))
+	arg = p + 1;
+      record_temp_file (arg, delete_always, delete_failure);
+    }
 }
 
 /* Load specs from a file name named FILENAME, replacing occurrences of
@@ -2095,7 +1603,7 @@
   char *specs_p;
 
   if (verbose_flag)
-    notice ("Reading specs from %s\n", filename);
+    fnotice (stderr, "Reading specs from %s\n", filename);
 
   /* Open and stat the file.  */
   desc = open (filename, O_RDONLY, 0);
@@ -2191,8 +1699,9 @@
 		p1++;
 
 	      if (*p1++ != '<' || p[-2] != '>')
-		fatal ("specs %%include syntax malformed after %ld characters",
-		       (long) (p1 - buffer + 1));
+		fatal_error ("specs %%include syntax malformed after "
+			     "%ld characters",
+			     (long) (p1 - buffer + 1));
 
 	      p[-2] = '\0';
 	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
@@ -2210,15 +1719,16 @@
 		p1++;
 
 	      if (*p1++ != '<' || p[-2] != '>')
-		fatal ("specs %%include syntax malformed after %ld characters",
-		       (long) (p1 - buffer + 1));
+		fatal_error ("specs %%include syntax malformed after "
+			     "%ld characters",
+			     (long) (p1 - buffer + 1));
 
 	      p[-2] = '\0';
 	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
 	      if (new_filename)
 		read_specs (new_filename, FALSE);
 	      else if (verbose_flag)
-		notice ("could not find specs file %s\n", p1);
+		fnotice (stderr, "could not find specs file %s\n", p1);
 	      continue;
 	    }
 	  else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
@@ -2235,16 +1745,18 @@
 		p1++;
 
 	      if (! ISALPHA ((unsigned char) *p1))
-		fatal ("specs %%rename syntax malformed after %ld characters",
-		       (long) (p1 - buffer));
+		fatal_error ("specs %%rename syntax malformed after "
+			     "%ld characters",
+			     (long) (p1 - buffer));
 
 	      p2 = p1;
 	      while (*p2 && !ISSPACE ((unsigned char) *p2))
 		p2++;
 
 	      if (*p2 != ' ' && *p2 != '\t')
-		fatal ("specs %%rename syntax malformed after %ld characters",
-		       (long) (p2 - buffer));
+		fatal_error ("specs %%rename syntax malformed after "
+			     "%ld characters",
+			     (long) (p2 - buffer));
 
 	      name_len = p2 - p1;
 	      *p2++ = '\0';
@@ -2252,8 +1764,9 @@
 		p2++;
 
 	      if (! ISALPHA ((unsigned char) *p2))
-		fatal ("specs %%rename syntax malformed after %ld characters",
-		       (long) (p2 - buffer));
+		fatal_error ("specs %%rename syntax malformed after "
+			     "%ld characters",
+			     (long) (p2 - buffer));
 
 	      /* Get new spec name.  */
 	      p3 = p2;
@@ -2261,8 +1774,9 @@
 		p3++;
 
 	      if (p3 != p - 1)
-		fatal ("specs %%rename syntax malformed after %ld characters",
-		       (long) (p3 - buffer));
+		fatal_error ("specs %%rename syntax malformed after "
+			     "%ld characters",
+			     (long) (p3 - buffer));
 	      *p3 = '\0';
 
 	      for (sl = specs; sl; sl = sl->next)
@@ -2270,21 +1784,22 @@
 		  break;
 
 	      if (!sl)
-		fatal ("specs %s spec was not found to be renamed", p1);
+		fatal_error ("specs %s spec was not found to be renamed", p1);
 
 	      if (strcmp (p1, p2) == 0)
 		continue;
 
 	      for (newsl = specs; newsl; newsl = newsl->next)
 		if (strcmp (newsl->name, p2) == 0)
-		  fatal ("%s: attempt to rename spec '%s' to already defined spec '%s'",
+		  fatal_error ("%s: attempt to rename spec %qs to "
+			       "already defined spec %qs",
 		    filename, p1, p2);
 
 	      if (verbose_flag)
 		{
-		  notice ("rename spec %s to %s\n", p1, p2);
+		  fnotice (stderr, "rename spec %s to %s\n", p1, p2);
 #ifdef DEBUG_SPECS
-		  notice ("spec is '%s'\n\n", *(sl->ptr_spec));
+		  fnotice (stderr, "spec is '%s'\n\n", *(sl->ptr_spec));
 #endif
 		}
 
@@ -2297,8 +1812,8 @@
 	      continue;
 	    }
 	  else
-	    fatal ("specs unknown %% command after %ld characters",
-		   (long) (p1 - buffer));
+	    fatal_error ("specs unknown %% command after %ld characters",
+			 (long) (p1 - buffer));
 	}
 
       /* Find the colon that should end the suffix.  */
@@ -2308,8 +1823,8 @@
 
       /* The colon shouldn't be missing.  */
       if (*p1 != ':')
-	fatal ("specs file malformed after %ld characters",
-	       (long) (p1 - buffer));
+	fatal_error ("specs file malformed after %ld characters",
+		     (long) (p1 - buffer));
 
       /* Skip back over trailing whitespace.  */
       p2 = p1;
@@ -2321,8 +1836,8 @@
       /* Find the next line.  */
       p = skip_whitespace (p1 + 1);
       if (p[1] == 0)
-	fatal ("specs file malformed after %ld characters",
-	       (long) (p - buffer));
+	fatal_error ("specs file malformed after %ld characters",
+		     (long) (p - buffer));
 
       p1 = p;
       /* Find next blank line or end of string.  */
@@ -2373,7 +1888,7 @@
     }
 
   if (link_command_spec == 0)
-    fatal ("spec file has no spec for linking");
+    fatal_error ("spec file has no spec for linking");
 }
 
 /* Record the names of temporary files we tell compilers to write,
@@ -2701,7 +2216,7 @@
 xputenv (const char *string)
 {
   if (verbose_flag)
-    notice ("%s\n", string);
+    fnotice (stderr, "%s\n", string);
   putenv (CONST_CAST (char *, string));
 }
 
@@ -2902,7 +2417,7 @@
 		      int require_machine_suffix, int os_multilib)
 {
   if (!IS_ABSOLUTE_PATH (prefix))
-    fatal ("system path '%s' is not absolute", prefix);
+    fatal_error ("system path %qs is not absolute", prefix);
 
   if (target_system_root)
     {
@@ -2937,6 +2452,7 @@
     const char *prog;		/* program name.  */
     const char **argv;		/* vector of args.  */
   };
+  const char *arg;
 
   struct command *commands;	/* each command buffer with above info.  */
 
@@ -2944,14 +2460,16 @@
 
   if (wrapper_string)
     {
-      string = find_a_file (&exec_prefixes, argbuf[0], X_OK, false);
-      argbuf[0] = (string) ? string : argbuf[0];
+      string = find_a_file (&exec_prefixes,
+			    VEC_index (const_char_p, argbuf, 0), X_OK, false);
+      if (string)
+	VEC_replace (const_char_p, argbuf, 0, string);
       insert_wrapper (wrapper_string);
     }
 
   /* Count # of piped commands.  */
-  for (n_commands = 1, i = 0; i < argbuf_index; i++)
-    if (strcmp (argbuf[i], "|") == 0)
+  for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+    if (strcmp (arg, "|") == 0)
       n_commands++;
 
   /* Get storage for each command.  */
@@ -2961,8 +2479,10 @@
      and record info about each one.
      Also search for the programs that are to be run.  */
 
-  commands[0].prog = argbuf[0]; /* first command.  */
-  commands[0].argv = &argbuf[0];
+  VEC_safe_push (const_char_p, heap, argbuf, 0);
+
+  commands[0].prog = VEC_index (const_char_p, argbuf, 0); /* first command.  */
+  commands[0].argv = VEC_address (const_char_p, argbuf);
 
   if (!wrapper_string)
     {
@@ -2970,15 +2490,17 @@
       commands[0].argv[0] = (string) ? string : commands[0].argv[0];
     }
 
-  for (n_commands = 1, i = 0; i < argbuf_index; i++)
-    if (strcmp (argbuf[i], "|") == 0)
+  for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+    if (arg && strcmp (arg, "|") == 0)
       {				/* each command.  */
 #if defined (__MSDOS__) || defined (OS2) || defined (VMS)
-	fatal ("-pipe not supported");
+	fatal_error ("-pipe not supported");
 #endif
-	argbuf[i] = 0;	/* termination of command args.  */
-	commands[n_commands].prog = argbuf[i + 1];
-	commands[n_commands].argv = &argbuf[i + 1];
+	VEC_replace (const_char_p, argbuf, i, 0); /* Termination of
+						     command args.  */
+	commands[n_commands].prog = VEC_index (const_char_p, argbuf, i + 1);
+	commands[n_commands].argv
+	  = &(VEC_address (const_char_p, argbuf))[i + 1];
 	string = find_a_file (&exec_prefixes, commands[n_commands].prog,
 			      X_OK, false);
 	if (string)
@@ -2986,8 +2508,6 @@
 	n_commands++;
       }
 
-  argbuf[argbuf_index] = 0;
-
   /* If -v, print what we are about to do, and maybe query.  */
 
   if (verbose_flag)
@@ -3006,19 +2526,35 @@
 	      for (j = commands[i].argv; *j; j++)
 		{
 		  const char *p;
-		  fprintf (stderr, " \"");
 		  for (p = *j; *p; ++p)
+		    if (!ISALNUM ((unsigned char) *p)
+			&& *p != '_' && *p != '/' && *p != '-' && *p != '.')
+		      break;
+		  if (*p || !*j)
 		    {
-		      if (*p == '"' || *p == '\\' || *p == '$')
-			fputc ('\\', stderr);
-		      fputc (*p, stderr);
+		      fprintf (stderr, " \"");
+		      for (p = *j; *p; ++p)
+			{
+			  if (*p == '"' || *p == '\\' || *p == '$')
+			    fputc ('\\', stderr);
+			  fputc (*p, stderr);
+			}
+		      fputc ('"', stderr);
 		    }
-		  fputc ('"', stderr);
+		  /* If it's empty, print "".  */
+		  else if (!**j)
+		    fprintf (stderr, " \"\"");
+		  else
+		    fprintf (stderr, " %s", *j);
 		}
 	    }
 	  else
 	    for (j = commands[i].argv; *j; j++)
-	      fprintf (stderr, " %s", *j);
+	      /* If it's empty, print "".  */
+	      if (!**j)
+		fprintf (stderr, " \"\"");
+	      else
+		fprintf (stderr, " %s", *j);
 
 	  /* Print a pipe symbol after all but the last command.  */
 	  if (i + 1 != n_commands)
@@ -3036,7 +2572,7 @@
 	  return 0;
         }
 #ifdef DEBUG
-      notice ("\nGo ahead? (y or n) ");
+      fnotice (stderr, "\nGo ahead? (y or n) ");
       fflush (stderr);
       i = getchar ();
       if (i != '\n')
@@ -3079,9 +2615,9 @@
 
   pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file)
 				   ? PEX_RECORD_TIMES : 0),
-		  programname, temp_filename);
+		  progname, temp_filename);
   if (pex == NULL)
-    pfatal_with_name (_("pex_init failed"));
+    fatal_error ("pex_init failed: %m");
 
   for (i = 0; i < n_commands; i++)
     {
@@ -3097,7 +2633,7 @@
       if (errmsg != NULL)
 	{
 	  if (err == 0)
-	    fatal (errmsg);
+	    fatal_error (errmsg);
 	  else
 	    {
 	      errno = err;
@@ -3120,13 +2656,13 @@
 
     statuses = (int *) alloca (n_commands * sizeof (int));
     if (!pex_get_status (pex, n_commands, statuses))
-      pfatal_with_name (_("failed to get exit status"));
+      fatal_error ("failed to get exit status: %m");
 
     if (report_times || report_times_to_file)
       {
 	times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
 	if (!pex_get_times (pex, n_commands, times))
-	  pfatal_with_name (_("failed to get process times"));
+	  fatal_error ("failed to get process times: %m");
       }
 
     pex_free (pex);
@@ -3152,12 +2688,8 @@
 	      }
 	    else
 #endif
-	      fatal_ice ("\
-Internal error: %s (program %s)\n\
-Please submit a full bug report.\n\
-See %s for instructions.",
-		 	strsignal (WTERMSIG (status)), commands[i].prog,
-		 	bug_report_url);
+	      internal_error ("%s (program %s)",
+			      strsignal (WTERMSIG (status)), commands[i].prog);
 	  }
 	else if (WIFEXITED (status)
 		 && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
@@ -3180,7 +2712,8 @@
 	    if (ut + st != 0)
 	      {
 		if (report_times)
-		  notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st);
+		  fnotice (stderr, "# %s %.2f %.2f\n",
+			   commands[i].prog, ut, st);
 
 		if (report_times_to_file)
 		  {
@@ -3232,12 +2765,16 @@
    SWITCH_LIVE to indicate this switch is true in a conditional spec.
    SWITCH_FALSE to indicate this switch is overridden by a later switch.
    SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
+   SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored
+   in all do_spec calls afterwards.  Used for %<S from self specs.
    The `validated' field is nonzero if any spec has looked at this switch;
    if it remains zero at the end of the run, it must be meaningless.  */
 
-#define SWITCH_LIVE    0x1
-#define SWITCH_FALSE   0x2
-#define SWITCH_IGNORE  0x4
+#define SWITCH_LIVE    			(1 << 0)
+#define SWITCH_FALSE   			(1 << 1)
+#define SWITCH_IGNORE			(1 << 2)
+#define SWITCH_IGNORE_PERMANENTLY	(1 << 3)
+#define SWITCH_KEEP_FOR_GCC		(1 << 4)
 
 struct switchstr
 {
@@ -3252,6 +2789,8 @@
 
 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
@@ -3273,6 +2812,8 @@
 
 static int n_switches_debug_check[2];
 
+static int n_switches_alloc_debug_check[2];
+
 static char *debug_check_temp_file[2];
 
 /* Language is one of three things:
@@ -3297,6 +2838,8 @@
 
 int n_infiles;
 
+static int n_infiles_alloc;
+
 /* True if multiple input files are being compiled to a single
    assembly file.  */
 
@@ -3371,7 +2914,7 @@
 static void
 display_help (void)
 {
-  printf (_("Usage: %s [options] file...\n"), programname);
+  printf (_("Usage: %s [options] file...\n"), progname);
   fputs (_("Options:\n"), stdout);
 
   fputs (_("  -pass-exit-codes         Exit with highest error code from a phase\n"), stdout);
@@ -3402,7 +2945,6 @@
   fputs (_("  -Xassembler <arg>        Pass <arg> on to the assembler\n"), stdout);
   fputs (_("  -Xpreprocessor <arg>     Pass <arg> on to the preprocessor\n"), stdout);
   fputs (_("  -Xlinker <arg>           Pass <arg> on to the linker\n"), stdout);
-  fputs (_("  -combine                 Pass multiple source files to compiler at once\n"), stdout);
   fputs (_("  -save-temps              Do not delete intermediate files\n"), stdout);
   fputs (_("  -save-temps=<arg>        Do not delete intermediate files\n"), stdout);
   fputs (_("\
@@ -3416,8 +2958,6 @@
   --sysroot=<directory>    Use <directory> as the root directory for headers\n\
                            and libraries\n"), stdout);
   fputs (_("  -B <directory>           Add <directory> to the compiler's search paths\n"), stdout);
-  fputs (_("  -b <machine>             Run gcc for target <machine>, if installed\n"), stdout);
-  fputs (_("  -V <version>             Run gcc version number <version>, if installed\n"), stdout);
   fputs (_("  -v                       Display the programs invoked by the compiler\n"), stdout);
   fputs (_("  -###                     Like -v but options quoted and commands not executed\n"), stdout);
   fputs (_("  -E                       Preprocess only; do not compile, assemble or link\n"), stdout);
@@ -3435,7 +2975,7 @@
 \nOptions starting with -g, -f, -m, -O, -W, or --param are automatically\n\
  passed on to the various sub-processes invoked by %s.  In order to pass\n\
  other options on to these processes the -W<letter> options must be used.\n\
-"), programname);
+"), progname);
 
   /* The rest of the options are displayed by invocations of the various
      sub-processes.  */
@@ -3444,66 +2984,543 @@
 static void
 add_preprocessor_option (const char *option, int len)
 {
-  n_preprocessor_options++;
-
-  if (! preprocessor_options)
-    preprocessor_options = XNEWVEC (char *, n_preprocessor_options);
-  else
-    preprocessor_options = XRESIZEVEC (char *, preprocessor_options,
-				       n_preprocessor_options);
-
-  preprocessor_options [n_preprocessor_options - 1] =
-    save_string (option, len);
+  VEC_safe_push (char_p, heap, preprocessor_options,
+		 save_string (option, len));
 }
 
 static void
 add_assembler_option (const char *option, int len)
 {
-  n_assembler_options++;
-
-  if (! assembler_options)
-    assembler_options = XNEWVEC (char *, n_assembler_options);
-  else
-    assembler_options = XRESIZEVEC (char *, assembler_options,
-				    n_assembler_options);
-
-  assembler_options [n_assembler_options - 1] = save_string (option, len);
+  VEC_safe_push (char_p, heap, assembler_options, save_string (option, len));
 }
 
 static void
 add_linker_option (const char *option, int len)
 {
-  n_linker_options++;
-
-  if (! linker_options)
-    linker_options = XNEWVEC (char *, n_linker_options);
-  else
-    linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
-
-  linker_options [n_linker_options - 1] = save_string (option, len);
+  VEC_safe_push (char_p, heap, linker_options, 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);
+    }
+}
+
+/* Save an option OPT with N_ARGS arguments in array ARGS, marking it
+   as validated if VALIDATED.  */
+
+static void
+save_switch (const char *opt, size_t n_args, const char *const *args,
+	     bool validated)
+{
+  alloc_switch ();
+  switches[n_switches].part1 = opt + 1;
+  if (n_args == 0)
+    switches[n_switches].args = 0;
+  else
+    {
+      switches[n_switches].args = XNEWVEC (const char *, n_args + 1);
+      memcpy (switches[n_switches].args, args, n_args * sizeof (const char *));
+      switches[n_switches].args[n_args] = NULL;
+    }
+
+  switches[n_switches].live_cond = 0;
+  switches[n_switches].validated = validated;
+  switches[n_switches].ordering = 0;
+  n_switches++;
+}
+
+/* Handle an option DECODED that is unknown to the option-processing
+   machinery, but may be known to specs.  */
+
+static bool
+driver_unknown_option_callback (const struct cl_decoded_option *decoded)
+{
+  save_switch (decoded->canonical_option[0],
+	       decoded->canonical_option_num_elements - 1,
+	       &decoded->canonical_option[1], false);
+
+  return false;
+}
+
+/* Handle an option DECODED that is not marked as CL_DRIVER.
+   LANG_MASK will always be CL_DRIVER.  */
+
+static void
+driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
+			    unsigned int lang_mask ATTRIBUTE_UNUSED)
+{
+  /* At this point, non-driver options are accepted (and expected to
+     be passed down by specs) unless marked to be rejected by the
+     driver.  Options to be rejected by the driver but accepted by the
+     compilers proper are treated just like completely unknown
+     options.  */
+  const struct cl_option *option = &cl_options[decoded->opt_index];
+
+  if (option->flags & CL_REJECT_DRIVER)
+    error ("unrecognized command line option %qs",
+	   decoded->orig_option_with_args_text);
+  else
+    driver_unknown_option_callback (decoded);
+}
+
+/* Note that an option (index OPT_INDEX, argument ARG, value VALUE)
+   has been successfully handled with a handler for mask MASK.  */
+
+static void
+driver_post_handling_callback (const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
+			       unsigned int mask ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do here.  */
+}
+
+static const char *spec_lang = 0;
+static int last_language_n_infiles;
+
+/* Handle a driver option; arguments and return value as for
+   handle_option.  */
+
+static bool
+driver_handle_option (struct gcc_options *opts,
+		      struct gcc_options *opts_set,
+		      const struct cl_decoded_option *decoded,
+		      unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
+		      location_t loc,
+		      const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
+		      diagnostic_context *dc)
+{
+  size_t opt_index = decoded->opt_index;
+  const char *arg = decoded->arg;
+  const char *compare_debug_replacement_opt;
+  int value = decoded->value;
+  bool validated = false;
+  bool do_save = true;
+
+  gcc_assert (opts == &global_options);
+  gcc_assert (opts_set == &global_options_set);
+  gcc_assert (kind == DK_UNSPECIFIED);
+  gcc_assert (loc == UNKNOWN_LOCATION);
+  gcc_assert (dc == global_dc);
+
+  switch (opt_index)
+    {
+    case OPT_dumpspecs:
+      {
+	struct spec_list *sl;
+	init_spec ();
+	for (sl = specs; sl; sl = sl->next)
+	  printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
+	if (link_command_spec)
+	  printf ("*link_command:\n%s\n\n", link_command_spec);
+	exit (0);
+      }
+
+    case OPT_dumpversion:
+      printf ("%s\n", spec_version);
+      exit (0);
+
+    case OPT_dumpmachine:
+      printf ("%s\n", spec_machine);
+      exit (0);
+
+    case OPT__version:
+      print_version = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+	add_preprocessor_option ("--version", strlen ("--version"));
+      add_assembler_option ("--version", strlen ("--version"));
+      add_linker_option ("--version", strlen ("--version"));
+      break;
+
+    case OPT__help:
+      print_help_list = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+	add_preprocessor_option ("--help", 6);
+      add_assembler_option ("--help", 6);
+      add_linker_option ("--help", 6);
+      break;
+
+    case OPT__help_:
+      print_subprocess_help = 2;
+      break;
+
+    case OPT__target_help:
+      print_subprocess_help = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+	add_preprocessor_option ("--target-help", 13);
+      add_assembler_option ("--target-help", 13);
+      add_linker_option ("--target-help", 13);
+      break;
+
+    case OPT_pass_exit_codes:
+    case OPT_print_search_dirs:
+    case OPT_print_file_name_:
+    case OPT_print_prog_name_:
+    case OPT_print_multi_lib:
+    case OPT_print_multi_directory:
+    case OPT_print_sysroot:
+    case OPT_print_multi_os_directory:
+    case OPT_print_sysroot_headers_suffix:
+    case OPT_time:
+    case OPT_wrapper:
+      /* These options set the variables specified in common.opt
+	 automatically, and do not need to be saved for spec
+	 processing.  */
+      do_save = false;
+      break;
+
+    case OPT_print_libgcc_file_name:
+      print_file_name = "libgcc.a";
+      do_save = false;
+      break;
+
+    case OPT_fcompare_debug_second:
+      compare_debug_second = 1;
+      break;
+
+    case OPT_fcompare_debug:
+      switch (value)
+	{
+	case 0:
+	  compare_debug_replacement_opt = "-fcompare-debug=";
+	  arg = "";
+	  goto compare_debug_with_arg;
+
+	case 1:
+	  compare_debug_replacement_opt = "-fcompare-debug=-gtoggle";
+	  arg = "-gtoggle";
+	  goto compare_debug_with_arg;
+
+	default:
+	  gcc_unreachable ();
+	}
+      break;
+
+    case OPT_fcompare_debug_:
+      compare_debug_replacement_opt = decoded->canonical_option[0];
+    compare_debug_with_arg:
+      gcc_assert (decoded->canonical_option_num_elements == 1);
+      gcc_assert (arg != NULL);
+      if (arg)
+	compare_debug = 1;
+      else
+	compare_debug = -1;
+      if (compare_debug < 0)
+	compare_debug_opt = NULL;
+      else
+	compare_debug_opt = arg;
+      save_switch (compare_debug_replacement_opt, 0, NULL, validated);
+      return true;
+
+    case OPT_Wa_:
+      {
+	int prev, j;
+	/* Pass the rest of this option to the assembler.  */
+
+	/* Split the argument at commas.  */
+	prev = 0;
+	for (j = 0; arg[j]; j++)
+	  if (arg[j] == ',')
+	    {
+	      add_assembler_option (arg + prev, j - prev);
+	      prev = j + 1;
+	    }
+
+	/* Record the part after the last comma.  */
+	add_assembler_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wp_:
+      {
+	int prev, j;
+	/* Pass the rest of this option to the preprocessor.  */
+
+	/* Split the argument at commas.  */
+	prev = 0;
+	for (j = 0; arg[j]; j++)
+	  if (arg[j] == ',')
+	    {
+	      add_preprocessor_option (arg + prev, j - prev);
+	      prev = j + 1;
+	    }
+
+	/* Record the part after the last comma.  */
+	add_preprocessor_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wl_:
+      {
+	int prev, j;
+	/* Split the argument at commas.  */
+	prev = 0;
+	for (j = 0; arg[j]; j++)
+	  if (arg[j] == ',')
+	    {
+	      add_infile (save_string (arg + prev, j - prev), "*");
+	      prev = j + 1;
+	    }
+	/* Record the part after the last comma.  */
+	add_infile (arg + prev, "*");
+      }
+      do_save = false;
+      break;
+
+    case OPT_Xlinker:
+      add_infile (arg, "*");
+      do_save = false;
+      break;
+
+    case OPT_Xpreprocessor:
+      add_preprocessor_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_Xassembler:
+      add_assembler_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_l:
+      /* POSIX allows separation of -l and the lib arg; canonicalize
+	 by concatenating -l with its arg */
+      add_infile (concat ("-l", arg, NULL), "*");
+      do_save = false;
+      break;
+
+    case OPT_L:
+      /* Similarly, canonicalize -L for linkers that may not accept
+	 separate arguments.  */
+      save_switch (concat ("-L", arg, NULL), 0, NULL, validated);
+      return true;
+
+    case OPT_F:
+      /* Likewise -F.  */
+      save_switch (concat ("-F", arg, NULL), 0, NULL, validated);
+      return true;
+
+    case OPT_save_temps:
+      save_temps_flag = SAVE_TEMPS_CWD;
+      validated = true;
+      break;
+
+    case OPT_save_temps_:
+      if (strcmp (arg, "cwd") == 0)
+	save_temps_flag = SAVE_TEMPS_CWD;
+      else if (strcmp (arg, "obj") == 0
+	       || strcmp (arg, "object") == 0)
+	save_temps_flag = SAVE_TEMPS_OBJ;
+      else
+	fatal_error ("%qs is an unknown -save-temps option",
+		     decoded->orig_option_with_args_text);
+      break;
+
+    case OPT_no_canonical_prefixes:
+      /* Already handled as a special case, so ignored here.  */
+      do_save = false;
+      break;
+
+    case OPT_pipe:
+      validated = true;
+      /* These options set the variables specified in common.opt
+	 automatically, but do need to be saved for spec
+	 processing.  */
+      break;
+
+    case OPT_specs_:
+      {
+	struct user_specs *user = XNEW (struct user_specs);
+
+	user->next = (struct user_specs *) 0;
+	user->filename = arg;
+	if (user_specs_tail)
+	  user_specs_tail->next = user;
+	else
+	  user_specs_head = user;
+	user_specs_tail = user;
+      }
+      do_save = false;
+      break;
+
+    case OPT__sysroot_:
+      target_system_root = arg;
+      target_system_root_changed = 1;
+      do_save = false;
+      break;
+
+    case OPT_time_:
+      if (report_times_to_file)
+	fclose (report_times_to_file);
+      report_times_to_file = fopen (arg, "a");
+      do_save = false;
+      break;
+
+    case OPT____:
+      /* "-###"
+	 This is similar to -v except that there is no execution
+	 of the commands and the echoed arguments are quoted.  It
+	 is intended for use in shell scripts to capture the
+	 driver-generated command line.  */
+      verbose_only_flag++;
+      verbose_flag = 1;
+      do_save = false;
+      break;
+
+    case OPT_B:
+      {
+	size_t len = strlen (arg);
+
+	/* Catch the case where the user has forgotten to append a
+	   directory separator to the path.  Note, they may be using
+	   -B to add an executable name prefix, eg "i386-elf-", in
+	   order to distinguish between multiple installations of
+	   GCC in the same directory.  Hence we must check to see
+	   if appending a directory separator actually makes a
+	   valid directory name.  */
+	if (!IS_DIR_SEPARATOR (arg[len - 1])
+	    && is_directory (arg, false))
+	  {
+	    char *tmp = XNEWVEC (char, len + 2);
+	    strcpy (tmp, arg);
+	    tmp[len] = DIR_SEPARATOR;
+	    tmp[++len] = 0;
+	    arg = tmp;
+	  }
+
+	add_prefix (&exec_prefixes, arg, NULL,
+		    PREFIX_PRIORITY_B_OPT, 0, 0);
+	add_prefix (&startfile_prefixes, arg, NULL,
+		    PREFIX_PRIORITY_B_OPT, 0, 0);
+	add_prefix (&include_prefixes, arg, NULL,
+		    PREFIX_PRIORITY_B_OPT, 0, 0);
+      }
+      validated = true;
+      break;
+
+    case OPT_x:
+      spec_lang = arg;
+      if (!strcmp (spec_lang, "none"))
+	/* Suppress the warning if -xnone comes after the last input
+	   file, because alternate command interfaces like g++ might
+	   find it useful to place -xnone after each input file.  */
+	spec_lang = 0;
+      else
+	last_language_n_infiles = n_infiles;
+      do_save = false;
+      break;
+
+    case OPT_o:
+      have_o = 1;
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
+      arg = convert_filename (arg, ! have_c, 0);
+#endif
+      /* Save the output name in case -save-temps=obj was used.  */
+      save_temps_prefix = xstrdup (arg);
+      /* On some systems, ld cannot handle "-o" without a space.  So
+	 split the option from its argument.  */
+      save_switch ("-o", 1, &arg, validated);
+      return true;
+
+    case OPT_static_libgcc:
+    case OPT_shared_libgcc:
+    case OPT_static_libgfortran:
+    case OPT_static_libstdc__:
+      /* These are always valid, since gcc.c itself understands the
+	 first two, gfortranspec.c understands -static-libgfortran and
+	 g++spec.c understands -static-libstdc++ */
+      validated = true;
+      break;
+
+    default:
+      /* Various driver options need no special processing at this
+	 point, having been handled in a prescan above or being
+	 handled by specs.  */
+      break;
+    }
+
+  if (do_save)
+    save_switch (decoded->canonical_option[0],
+		 decoded->canonical_option_num_elements - 1,
+		 &decoded->canonical_option[1], validated);
+  return true;
+}
+
+/* Put the driver's standard set of option handlers in *HANDLERS.  */
+
+static void
+set_option_handlers (struct cl_option_handlers *handlers)
+{
+  handlers->unknown_option_callback = driver_unknown_option_callback;
+  handlers->wrong_lang_callback = driver_wrong_lang_callback;
+  handlers->post_handling_callback = driver_post_handling_callback;
+  handlers->num_handlers = 1;
+  handlers->handlers[0].handler = driver_handle_option;
+  handlers->handlers[0].mask = CL_DRIVER;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
 static void
-process_command (int argc, const char **argv)
+process_command (unsigned int decoded_options_count,
+		 struct cl_decoded_option *decoded_options)
 {
-  int i;
   const char *temp;
   char *temp1;
-  const char *spec_lang = 0;
-  int last_language_n_infiles;
-  int lang_n_infiles = 0;
-#ifdef MODIFY_TARGET_NAME
-  int is_modify_target_name;
-  unsigned int j;
-#endif
   const char *tooldir_prefix;
   char *(*get_relative_prefix) (const char *, const char *,
 				const char *) = NULL;
-
-  GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
+  struct cl_option_handlers handlers;
+  unsigned int j;
+
+  gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
 
   n_switches = 0;
   n_infiles = 0;
@@ -3522,99 +3539,13 @@
 	}
     }
 
-  /* If there is a -V or -b option (or both), process it now, before
-     trying to interpret the rest of the command line.
-     Use heuristic that all configuration names must have at least
-     one dash '-'. This allows us to pass options starting with -b.  */
-  if (argc > 1 && argv[1][0] == '-'
-      && (argv[1][1] == 'V'
-	  || (argv[1][1] == 'b'
-	      && (argv[1][2] == '\0'
-		  || NULL != strchr (argv[1] + 2, '-')))))
-    {
-      const char *new_version = DEFAULT_TARGET_VERSION;
-      const char *new_machine = DEFAULT_TARGET_MACHINE;
-      const char *progname = argv[0];
-      char **new_argv;
-      char *new_argv0;
-      int baselen;
-      int status = 0;
-      int err = 0;
-      const char *errmsg;
-
-      while (argc > 1 && argv[1][0] == '-'
-	     && (argv[1][1] == 'V'
-		 || (argv[1][1] == 'b'
-		     && (argv[1][2] == '\0'
-			 || NULL != strchr (argv[1] + 2, '-')))))
-	{
-	  char opt = argv[1][1];
-	  const char *arg;
-	  if (argv[1][2] != '\0')
-	    {
-	      arg = argv[1] + 2;
-	      argc -= 1;
-	      argv += 1;
-	    }
-	  else if (argc > 2)
-	    {
-	      arg = argv[2];
-	      argc -= 2;
-	      argv += 2;
-	    }
-	  else
-	    fatal ("'-%c' option must have argument", opt);
-	  if (opt == 'V')
-	    new_version = arg;
-	  else
-	    new_machine = arg;
-	}
-
-      for (baselen = strlen (progname); baselen > 0; baselen--)
-	if (IS_DIR_SEPARATOR (progname[baselen-1]))
-	  break;
-      new_argv0 = XDUPVAR (char, progname, baselen,
-			   baselen + concat_length (new_version, new_machine,
-						    "-gcc-", NULL) + 1);
-      strcpy (new_argv0 + baselen, new_machine);
-      strcat (new_argv0, "-gcc-");
-      strcat (new_argv0, new_version);
-
-      new_argv = XDUPVEC (char *, argv, argc + 1);
-      new_argv[0] = new_argv0;
-
-      errmsg = pex_one (PEX_SEARCH, new_argv0, new_argv, progname, NULL,
-			NULL, &status, &err);
-
-      if (errmsg)
-	{
-	  if (err == 0)
-	    fatal ("couldn't run '%s': %s", new_argv0, errmsg);
-	  else
-	    fatal ("couldn't run '%s': %s: %s", new_argv0, errmsg,
-		    xstrerror (err));
-        }
-      exit (status);
-    }
-
-  /* Convert new-style -- options to old-style.  */
-  translate_options (&argc,
-		     CONST_CAST2 (const char *const **, const char ***,
-				  &argv));
-
-  /* Do language-specific adjustment/addition of flags.  */
-  lang_specific_driver (&argc,
-			CONST_CAST2 (const char *const **, const char ***,
-				     &argv),
-			&added_libraries);
-
   /* Handle any -no-canonical-prefixes flag early, to assign the function
      that builds relative prefixes.  This function creates default search
      paths that are needed later in normal option handling.  */
 
-  for (i = 1; i < argc; i++)
+  for (j = 1; j < decoded_options_count; j++)
     {
-      if (! strcmp (argv[i], "-no-canonical-prefixes"))
+      if (decoded_options[j].opt_index == OPT_no_canonical_prefixes)
 	{
 	  get_relative_prefix = make_relative_prefix_ignore_links;
 	  break;
@@ -3624,17 +3555,18 @@
     get_relative_prefix = make_relative_prefix;
 
   /* Set up the default search paths.  If there is no GCC_EXEC_PREFIX,
-     see if we can create it from the pathname specified in argv[0].  */
+     see if we can create it from the pathname specified in
+     decoded_options[0].arg.  */
 
   gcc_libexec_prefix = standard_libexec_prefix;
 #ifndef VMS
   /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
   if (!gcc_exec_prefix)
     {
-      gcc_exec_prefix = get_relative_prefix (argv[0],
+      gcc_exec_prefix = get_relative_prefix (decoded_options[0].arg,
 					     standard_bindir_prefix,
 					     standard_exec_prefix);
-      gcc_libexec_prefix = get_relative_prefix (argv[0],
+      gcc_libexec_prefix = get_relative_prefix (decoded_options[0].arg,
 					     standard_bindir_prefix,
 					     standard_libexec_prefix);
       if (gcc_exec_prefix)
@@ -3661,7 +3593,12 @@
 #endif
   /* From this point onward, gcc_exec_prefix is non-null if the toolchain
      is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX
-     or an automatically created GCC_EXEC_PREFIX from argv[0].  */
+     or an automatically created GCC_EXEC_PREFIX from
+     decoded_options[0].arg.  */
+
+  /* Do language-specific adjustment/addition of flags.  */
+  lang_specific_driver (&decoded_options, &decoded_options_count,
+			&added_libraries);
 
   if (gcc_exec_prefix)
     {
@@ -3688,7 +3625,7 @@
   /* COMPILER_PATH and LIBRARY_PATH have values
      that are lists of directory names with colons.  */
 
-  GET_ENVIRONMENT (temp, "COMPILER_PATH");
+  temp = getenv ("COMPILER_PATH");
   if (temp)
     {
       const char *startp, *endp;
@@ -3722,7 +3659,7 @@
 	}
     }
 
-  GET_ENVIRONMENT (temp, LIBRARY_PATH_ENV);
+  temp = getenv (LIBRARY_PATH_ENV);
   if (temp && *cross_compile == '0')
     {
       const char *startp, *endp;
@@ -3755,7 +3692,7 @@
     }
 
   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
-  GET_ENVIRONMENT (temp, "LPATH");
+  temp = getenv ("LPATH");
   if (temp && *cross_compile == '0')
     {
       const char *startp, *endp;
@@ -3787,476 +3724,73 @@
 	}
     }
 
-  /* 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).  */
-
-  for (i = 1; i < argc; i++)
+  /* Process the options and store input files and switches in their
+     vectors.  */
+
+  last_language_n_infiles = -1;
+
+  set_option_handlers (&handlers);
+
+  for (j = 1; j < decoded_options_count; j++)
     {
-      if (! strcmp (argv[i], "-dumpspecs"))
-	{
-	  struct spec_list *sl;
-	  init_spec ();
-	  for (sl = specs; sl; sl = sl->next)
-	    printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
-	  if (link_command_spec)
-	    printf ("*link_command:\n%s\n\n", link_command_spec);
-	  exit (0);
-	}
-      else if (! strcmp (argv[i], "-dumpversion"))
-	{
-	  printf ("%s\n", spec_version);
-	  exit (0);
-	}
-      else if (! strcmp (argv[i], "-dumpmachine"))
-	{
-	  printf ("%s\n", spec_machine);
-	  exit (0);
-	}
-      else if (strcmp (argv[i], "-fversion") == 0)
-	{
-	  /* translate_options () has turned --version into -fversion.  */
-	  print_version = 1;
-
-	  /* 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"));
-	}
-      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);
-	}
-      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++;
-	}
-      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);
-	}
-      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;
-      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
-	print_file_name = "libgcc.a";
-      else if (! strncmp (argv[i], "-print-file-name=", 17))
-	print_file_name = argv[i] + 17;
-      else if (! strncmp (argv[i], "-print-prog-name=", 17))
-	print_prog_name = argv[i] + 17;
-      else if (! strcmp (argv[i], "-print-multi-lib"))
-	print_multi_lib = 1;
-      else if (! strcmp (argv[i], "-print-multi-directory"))
-	print_multi_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot"))
-	print_sysroot = 1;
-      else if (! strcmp (argv[i], "-print-multi-os-directory"))
-	print_multi_os_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
-	print_sysroot_headers_suffix = 1;
-      else if (! strcmp (argv[i], "-fcompare-debug-second"))
-	{
-	  compare_debug_second = 1;
-	  n_switches++;
-	}
-      else if (! strcmp (argv[i], "-fno-compare-debug"))
-	{
-	  argv[i] = "-fcompare-debug=";
-	  goto compare_debug_with_arg;
-	}
-      else if (! strcmp (argv[i], "-fcompare-debug"))
+      switch (decoded_options[j].opt_index)
 	{
-	  argv[i] = "-fcompare-debug=-gtoggle";
-	  goto compare_debug_with_arg;
-	}
-#define OPT "-fcompare-debug="
-      else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1))
-	{
-	  const char *opt;
-	compare_debug_with_arg:
-	  opt = argv[i] + sizeof (OPT) - 1;
-#undef OPT
-	  if (*opt)
-	    compare_debug = 1;
-	  else
-	    compare_debug = -1;
-	  if (compare_debug < 0)
-	    compare_debug_opt = NULL;
-	  else
-	    compare_debug_opt = opt;
-	  n_switches++;
-	}
-      else if (! strncmp (argv[i], "-Wa,", 4))
-	{
-	  int prev, j;
-	  /* Pass the rest of this option to the assembler.  */
-
-	  /* Split the argument at commas.  */
-	  prev = 4;
-	  for (j = 4; argv[i][j]; j++)
-	    if (argv[i][j] == ',')
-	      {
-		add_assembler_option (argv[i] + prev, j - prev);
-		prev = j + 1;
-	      }
-
-	  /* Record the part after the last comma.  */
-	  add_assembler_option (argv[i] + prev, j - prev);
-	}
-      else if (! strncmp (argv[i], "-Wp,", 4))
-	{
-	  int prev, j;
-	  /* Pass the rest of this option to the preprocessor.  */
-
-	  /* Split the argument at commas.  */
-	  prev = 4;
-	  for (j = 4; argv[i][j]; j++)
-	    if (argv[i][j] == ',')
-	      {
-		add_preprocessor_option (argv[i] + prev, j - prev);
-		prev = j + 1;
-	      }
-
-	  /* Record the part after the last comma.  */
-	  add_preprocessor_option (argv[i] + prev, j - prev);
-	}
-      else if (argv[i][0] == '+' && argv[i][1] == 'e')
-	/* The +e options to the C++ front-end.  */
-	n_switches++;
-      else if (strncmp (argv[i], "-Wl,", 4) == 0)
-	{
-	  int j;
-	  /* Split the argument at commas.  */
-	  for (j = 3; argv[i][j]; j++)
-	    n_infiles += (argv[i][j] == ',');
-	}
-      else if (strcmp (argv[i], "-Xlinker") == 0)
-	{
-	  if (i + 1 == argc)
-	    fatal ("argument to '-Xlinker' is missing");
-
-	  n_infiles++;
-	  i++;
-	}
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-	{
-	  if (i + 1 == argc)
-	    fatal ("argument to '-Xpreprocessor' is missing");
-
-	  add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
-	}
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-	{
-	  if (i + 1 == argc)
-	    fatal ("argument to '-Xassembler' is missing");
-
-	  add_assembler_option (argv[i+1], strlen (argv[i+1]));
-	}
-      else if (strcmp (argv[i], "-l") == 0)
-	{
-	  if (i + 1 == argc)
-	    fatal ("argument to '-l' is missing");
-
-	  n_infiles++;
-	  i++;
-	}
-      else if (strncmp (argv[i], "-l", 2) == 0)
-	n_infiles++;
-      else if (strcmp (argv[i], "-save-temps") == 0)
-	{
-	  save_temps_flag = SAVE_TEMPS_CWD;
-	  n_switches++;
-	}
-      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
-		   || strcmp (argv[i]+12, "object") == 0)
-	    save_temps_flag = SAVE_TEMPS_OBJ;
-	  else
-	    fatal ("'%s' is an unknown -save-temps option", argv[i]);
-	}
-      else if (strcmp (argv[i], "-no-canonical-prefixes") == 0)
-	/* Already handled as a special case, so ignored here.  */
-	;
-      else if (strcmp (argv[i], "-combine") == 0)
-	{
-	  combine_flag = 1;
-	  n_switches++;
+	case OPT_S:
+	case OPT_c:
+	case OPT_E:
+	  have_c = 1;
+	  break;
 	}
-      else if (strcmp (argv[i], "-specs") == 0)
-	{
-	  struct user_specs *user = XNEW (struct user_specs);
-	  if (++i >= argc)
-	    fatal ("argument to '-specs' is missing");
-
-	  user->next = (struct user_specs *) 0;
-	  user->filename = argv[i];
-	  if (user_specs_tail)
-	    user_specs_tail->next = user;
-	  else
-	    user_specs_head = user;
-	  user_specs_tail = user;
-	}
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-	{
-	  struct user_specs *user = XNEW (struct user_specs);
-	  if (strlen (argv[i]) == 7)
-	    fatal ("argument to '-specs=' is missing");
-
-	  user->next = (struct user_specs *) 0;
-	  user->filename = argv[i] + 7;
-	  if (user_specs_tail)
-	    user_specs_tail->next = user;
-	  else
-	    user_specs_head = user;
-	  user_specs_tail = user;
-	}
-      else if (strcmp (argv[i], "-time") == 0)
-	report_times = 1;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
+      if (have_c)
+	break;
+    }
+
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      if (decoded_options[j].opt_index == OPT_SPECIAL_input_file)
 	{
-	  if (report_times_to_file)
-	    fclose (report_times_to_file);
-	  report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a");
-	}
-      else if (strcmp (argv[i], "-pipe") == 0)
-	{
-	  /* -pipe has to go into the switches array as well as
-	     setting a flag.  */
-	  use_pipes = 1;
-	  n_switches++;
-	}
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        {
-	  if (++i >= argc)
-	    fatal ("argument to '-wrapper' is missing");
-
-          wrapper_string = argv[i];
-	  n_switches++;
-	  n_switches++;
-        }
-      else if (strcmp (argv[i], "-###") == 0)
-	{
-	  /* This is similar to -v except that there is no execution
-	     of the commands and the echoed arguments are quoted.  It
-	     is intended for use in shell scripts to capture the
-	     driver-generated command line.  */
-	  verbose_only_flag++;
-	  verbose_flag++;
-	}
-      else if (argv[i][0] == '-' && argv[i][1] != 0)
-	{
-	  const char *p = &argv[i][1];
-	  int c = *p;
-
-	  switch (c)
+	  const char *arg = decoded_options[j].arg;
+          const char *p = strrchr (arg, '@');
+          char *fname;
+	  long offset;
+	  int consumed;
+#ifdef HAVE_TARGET_OBJECT_SUFFIX
+	  arg = convert_filename (arg, 0, access (arg, F_OK));
+#endif
+	  /* For LTO static archive support we handle input file
+	     specifications that are composed of a filename and
+	     an offset like FNAME@OFFSET.  */
+	  if (p
+	      && p != arg
+	      && sscanf (p, "@%li%n", &offset, &consumed) >= 1
+	      && strlen (p) == (unsigned int)consumed)
 	    {
-	    case 'b':
-	      if (p[1] && NULL == strchr (argv[i] + 2, '-'))
-		goto normal_switch;
-
-	      /* Fall through.  */
-	    case 'V':
-	      fatal ("'-%c' must come at the start of the command line", c);
-	      break;
-
-	    case 'B':
-	      {
-		const char *value;
-		int len;
-
-		if (p[1] == 0 && i + 1 == argc)
-		  fatal ("argument to '-B' is missing");
-		if (p[1] == 0)
-		  value = argv[++i];
-		else
-		  value = p + 1;
-
-		len = strlen (value);
-
-		/* Catch the case where the user has forgotten to append a
-		   directory separator to the path.  Note, they may be using
-		   -B to add an executable name prefix, eg "i386-elf-", in
-		   order to distinguish between multiple installations of
-		   GCC in the same directory.  Hence we must check to see
-		   if appending a directory separator actually makes a
-		   valid directory name.  */
-		if (! IS_DIR_SEPARATOR (value [len - 1])
-		    && is_directory (value, false))
-		  {
-		    char *tmp = XNEWVEC (char, len + 2);
-		    strcpy (tmp, value);
-		    tmp[len] = DIR_SEPARATOR;
-		    tmp[++ len] = 0;
-		    value = tmp;
-		  }
-
-		add_prefix (&exec_prefixes, value, NULL,
-			    PREFIX_PRIORITY_B_OPT, 0, 0);
-		add_prefix (&startfile_prefixes, value, NULL,
-			    PREFIX_PRIORITY_B_OPT, 0, 0);
-		add_prefix (&include_prefixes, value, NULL,
-			    PREFIX_PRIORITY_B_OPT, 0, 0);
-		n_switches++;
-	      }
-	      break;
-
-	    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++;
-	      break;
-
-	    case 'S':
-	    case 'c':
-	    case 'E':
-	      if (p[1] == 0)
-		{
-		  have_c = 1;
-		  n_switches++;
-		  break;
-		}
-	      goto normal_switch;
-
-	    case 'o':
-	      have_o = 1;
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
-	      if (! have_c)
+              fname = (char *)xmalloc (p - arg + 1);
+              memcpy (fname, arg, p - arg);
+              fname[p - arg] = '\0';
+	      /* Only accept non-stdin and existing FNAME parts, otherwise
+		 try with the full name.  */
+	      if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
 		{
-		  int skip;
-
-		  /* Forward scan, just in case -S, -E or -c is specified
-		     after -o.  */
-		  int j = i + 1;
-		  if (p[1] == 0)
-		    ++j;
-		  while (j < argc)
-		    {
-		      if (argv[j][0] == '-')
-			{
-			  if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
-			      && argv[j][2] == 0)
-			    {
-			      have_c = 1;
-			      break;
-			    }
-			  else if ((skip = SWITCH_TAKES_ARG (argv[j][1])))
-			    j += skip - (argv[j][2] != 0);
-			  else if ((skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1)))
-			    j += skip;
-			}
-		      j++;
-		    }
+		  free (fname);
+		  fname = xstrdup (arg);
 		}
-#endif
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
-	      if (p[1] == 0)
-		argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
-	      else
-		argv[i] = convert_filename (argv[i], ! have_c, 0);
-#endif
-	      /* Save the output name in case -save-temps=obj was used.  */
-	      if ((p[1] == 0) && argv[i + 1])
-		save_temps_prefix = xstrdup(argv[i + 1]);
-	      else
-		save_temps_prefix = xstrdup(argv[i] + 1);
-	      goto normal_switch;
-
-	    default:
-	    normal_switch:
-
-#ifdef MODIFY_TARGET_NAME
-	      is_modify_target_name = 0;
-
-	      for (j = 0; j < ARRAY_SIZE (modify_target); j++)
-		if (! strcmp (argv[i], modify_target[j].sw))
-		  {
-		    char *new_name = XNEWVEC (char, strlen (modify_target[j].str)
-					      + strlen (spec_machine));
-		    const char *p, *r;
-		    char *q;
-		    int made_addition = 0;
-
-		    is_modify_target_name = 1;
-		    for (p = spec_machine, q = new_name; *p != 0; )
-		      {
-			if (modify_target[j].add_del == DELETE
-			    && (! strncmp (q, modify_target[j].str,
-					   strlen (modify_target[j].str))))
-			  p += strlen (modify_target[j].str);
-			else if (modify_target[j].add_del == ADD
-				 && ! made_addition && *p == '-')
-			  {
-			    for (r = modify_target[j].str; *r != 0; )
-			      *q++ = *r++;
-			    made_addition = 1;
-			  }
-
-			*q++ = *p++;
-		      }
-
-		    spec_machine = new_name;
-		  }
-
-	      if (is_modify_target_name)
-		break;
-#endif
-
-	      n_switches++;
-
-	      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);
 	    }
+	  else
+	    fname = xstrdup (arg);
+ 
+          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
+	    perror_with_name (fname);
+          else
+	    add_infile (arg, spec_lang);
+
+          free (fname);
+	  continue;
 	}
-      else
-	{
-	  n_infiles++;
-	  lang_n_infiles++;
-	}
+
+      read_cmdline_option (&global_options, &global_options_set,
+			   decoded_options + j, UNKNOWN_LOCATION,
+			   CL_DRIVER, &handlers, global_dc);
     }
 
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
@@ -4282,7 +3816,7 @@
     {
       /* -save-temps overrides -pipe, so that temp files are produced */
       if (save_temps_flag)
-	error ("warning: -pipe ignored because -save-temps specified");
+	warning (0, "-pipe ignored because -save-temps specified");
       use_pipes = 0;
     }
 
@@ -4294,13 +3828,11 @@
 	{
 	  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)
@@ -4353,9 +3885,9 @@
      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],
+      char *tmp_prefix = get_relative_prefix (decoded_options[0].arg,
 					      standard_bindir_prefix,
 					      target_system_root);
       if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0)
@@ -4369,242 +3901,12 @@
   /* 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.  */
-#ifdef MODIFY_TARGET_NAME
-      is_modify_target_name = 0;
-
-      for (j = 0; j < ARRAY_SIZE (modify_target); j++)
-	if (! strcmp (argv[i], modify_target[j].sw))
-	  is_modify_target_name = 1;
-
-      if (is_modify_target_name)
-	;
-      else
-#endif
-      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 (argv[i][0] == '+' && argv[i][1] == 'e')
-	{
-	  /* Compensate for the +e options to the C++ front-end;
-	     they're there simply for cfront call-compatibility.  We do
-	     some magic in default_compilers to pass them down properly.
-	     Note we deliberately start at the `+' here, to avoid passing
-	     -e0 or -e1 down into the linker.  */
-	  switches[n_switches].part1 = &argv[i][0];
-	  switches[n_switches].args = 0;
-	  switches[n_switches].live_cond = 0;
-	  switches[n_switches].validated = 0;
-	  n_switches++;
-	}
-      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 ("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 ("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 and gfortranspec.c understands -static-libgfortran.  */
-	  if (!strcmp (p, "save-temps")
-	      || !strcmp (p, "static-libgcc")
-	      || !strcmp (p, "shared-libgcc")
-	      || !strcmp (p, "pipe")
-	      || !strcmp (p, "static-libgfortran"))
-	    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 = strchr (argv[i], '@');
-          char *fname;
-#ifdef HAVE_TARGET_OBJECT_SUFFIX
-	  argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
-#endif
-          if (!p)
-            fname = xstrdup (argv[i]);
-          else
-            {
-              fname = (char *)xmalloc (p - argv[i] + 1);
-              memcpy (fname, argv[i], p - argv[i]);
-              fname[p - argv[i]] = '\0';
-            }
-
-          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
-            {
-              perror_with_name (fname);
-              error_count++;
-            }
-          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)
-    error ("warning: '-x %s' after last input file has no effect", spec_lang);
+    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);
@@ -4619,15 +3921,16 @@
   /* 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;
 }
 
@@ -4656,7 +3959,9 @@
       first_time = FALSE;
 
       /* Ignore elided switches.  */
-      if ((switches[i].live_cond & SWITCH_IGNORE) != 0)
+      if ((switches[i].live_cond
+	   & (SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC))
+	  == SWITCH_IGNORE)
 	continue;
 
       obstack_grow (&collect_obstack, "'-", 2);
@@ -4697,7 +4002,7 @@
    sans all directory names, and basename_length is the number
    of characters starting there excluding the suffix .c or whatever.  */
 
-static const char *input_filename;
+static const char *gcc_input_filename;
 static int input_file_number;
 size_t input_filename_length;
 static int basename_length;
@@ -4764,7 +4069,7 @@
 
 	  if (full_script_path == NULL)
 	    {
-	      error (_("unable to locate default linker script '%s' in the library search paths"), string);
+	      error ("unable to locate default linker script %qs in the library search paths", string);
 	      /* Script was not found on search path.  */
 	      return;
 	    }
@@ -4789,6 +4094,7 @@
   int i;
   char *buf = xstrdup (wrapper);
   char *p = buf;
+  unsigned int old_length = VEC_length (const_char_p, argbuf);
 
   do
     {
@@ -4798,15 +4104,10 @@
     }
   while ((p = strchr (p, ',')) != NULL);
 
-  if (argbuf_index + n >= argbuf_length)
-    {
-      argbuf_length = argbuf_length * 2;
-      while (argbuf_length < argbuf_index + n)
-	argbuf_length *= 2;
-      argbuf = XRESIZEVEC (const char *, argbuf, argbuf_length);
-    }
-  for (i = argbuf_index - 1; i >= 0; i--)
-    argbuf[i + n] = argbuf[i];
+  VEC_safe_grow (const_char_p, heap, argbuf, old_length + n);
+  memmove (VEC_address (const_char_p, argbuf) + n,
+	   VEC_address (const_char_p, argbuf),
+	   old_length * sizeof (const_char_p));
 
   i = 0;
   p = buf;
@@ -4817,11 +4118,11 @@
           *p = 0;
           p++;
         }
-      argbuf[i++] = p;
+      VEC_replace (const_char_p, argbuf, i, p);
+      i++;
     }
   while ((p = strchr (p, ',')) != NULL);
   gcc_assert (i == n);
-  argbuf_index += n;
 }
 
 /* Process the spec SPEC and run the commands specified therein.
@@ -4838,12 +4139,13 @@
      If -pipe, this forces out the last command if it ended in `|'.  */
   if (value == 0)
     {
-      if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
-	argbuf_index--;
+      if (VEC_length (const_char_p, argbuf) > 0
+	  && !strcmp (VEC_last (const_char_p, argbuf), "|"))
+	VEC_pop (const_char_p, argbuf);
 
       set_collect_gcc_options ();
 
-      if (argbuf_index > 0)
+      if (VEC_length (const_char_p, argbuf) > 0)
 	value = execute ();
     }
 
@@ -4927,73 +4229,76 @@
 static void
 do_self_spec (const char *spec)
 {
+  int i;
+
   do_spec_2 (spec);
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0)
+  /* Mark %<S switches processed by do_self_spec to be ignored permanently.
+     do_self_specs adds the replacements to switches array, so it shouldn't
+     be processed afterwards.  */
+  for (i = 0; i < n_switches; i++)
+    if ((switches[i].live_cond & SWITCH_IGNORE))
+      switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
+
+  if (VEC_length (const_char_p, argbuf) > 0)
     {
-      int i;
-
-      switches = XRESIZEVEC (struct switchstr, switches,
-			     n_switches + argbuf_index + 1);
-
-      for (i = 0; i < argbuf_index; i++)
+      const char **argbuf_copy;
+      struct cl_decoded_option *decoded_options;
+      struct cl_option_handlers handlers;
+      unsigned int decoded_options_count;
+      unsigned int j;
+
+      /* Create a copy of argbuf with a dummy argv[0] entry for
+	 decode_cmdline_options_to_array.  */
+      argbuf_copy = XNEWVEC (const char *,
+			     VEC_length (const_char_p, argbuf) + 1);
+      argbuf_copy[0] = "";
+      memcpy (argbuf_copy + 1, VEC_address (const_char_p, argbuf),
+	      VEC_length (const_char_p, argbuf) * sizeof (const char *));
+
+      decode_cmdline_options_to_array (VEC_length (const_char_p, argbuf) + 1,
+				       argbuf_copy,
+				       CL_DRIVER, &decoded_options,
+				       &decoded_options_count);
+
+      set_option_handlers (&handlers);
+
+      for (j = 1; j < decoded_options_count; j++)
 	{
-	  struct switchstr *sw;
-	  const char *p = argbuf[i];
-	  int c = *p;
-
-	  /* Each switch should start with '-'.  */
-	  if (c != '-')
-	    fatal ("switch '%s' does not start with '-'", argbuf[i]);
-
-	  p++;
-	  c = *p;
-
-	  sw = &switches[n_switches++];
-	  sw->part1 = p;
-	  sw->live_cond = 0;
-	  sw->validated = 0;
-	  sw->ordering = 0;
-
-	  /* Deal with option arguments in separate argv elements.  */
-	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
-	      || WORD_SWITCH_TAKES_ARG (p))
+	  switch (decoded_options[j].opt_index)
 	    {
-	      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 >= argbuf_index)
-		fatal ("argument to '-%s' is missing", p);
-	      sw->args
-		= XNEWVEC (const char *, n_args + 1);
-	      while (j < n_args)
-		sw->args[j++] = argbuf[++i];
-	      /* Null-terminate the vector.  */
-	      sw->args[j] = 0;
+	    case OPT_SPECIAL_input_file:
+	      /* Specs should only generate options, not input
+		 files.  */
+	      if (strcmp (decoded_options[j].arg, "-") != 0)
+		fatal_error ("switch %qs does not start with %<-%>",
+			     decoded_options[j].arg);
+	      else
+		fatal_error ("spec-generated switch is just %<-%>");
+	      break;
+
+	    case OPT_fcompare_debug_second:
+	    case OPT_fcompare_debug:
+	    case OPT_fcompare_debug_:
+	    case OPT_o:
+	      /* Avoid duplicate processing of some options from
+		 compare-debug specs; just save them here.  */
+	      save_switch (decoded_options[j].canonical_option[0],
+			   (decoded_options[j].canonical_option_num_elements
+			    - 1),
+			   &decoded_options[j].canonical_option[1], false);
+	      break;
+
+	    default:
+	      read_cmdline_option (&global_options, &global_options_set,
+				   decoded_options + j, UNKNOWN_LOCATION,
+				   CL_DRIVER, &handlers, global_dc);
+	      break;
 	    }
-	  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';
-
-	      sw->part1 = part1;
-	      sw->args = XNEWVEC (const char *, 2);
-	      sw->args[0] = xstrdup (p+1);
-	      sw->args[1] = 0;
-	    }
-	  else
-	    sw->args = 0;
 	}
 
+      alloc_switch ();
       switches[n_switches].part1 = 0;
     }
 }
@@ -5061,20 +4366,20 @@
   int status;
 
   if (f == NULL)
-    fatal ("could not open temporary response file %s",
-	   temp_file);
+    fatal_error ("could not open temporary response file %s",
+		 temp_file);
 
   status = writeargv (argv, f);
 
   if (status)
-    fatal ("could not write to temporary response file %s",
-	   temp_file);
+    fatal_error ("could not write to temporary response file %s",
+		 temp_file);
 
   status = fclose (f);
 
   if (EOF == status)
-    fatal ("could not close temporary response file %s",
-	   temp_file);
+    fatal_error ("could not close temporary response file %s",
+		 temp_file);
 
   store_arg (at_argument, 0, 0);
 
@@ -5092,6 +4397,22 @@
   return false;
 }
 
+/* Process each member of VEC as a spec.  */
+
+static void
+do_specs_vec (VEC(char_p,heap) *vec)
+{
+  unsigned ix;
+  char *opt;
+
+  FOR_EACH_VEC_ELT (char_p, vec, ix, opt)
+    {
+      do_spec_1 (opt, 1, NULL);
+      /* Make each accumulated option a separate argument.  */
+      do_spec_1 (" ", 0, NULL);
+    }
+}
+
 /* Process the sub-spec SPEC as a portion of a larger spec.
    This is like processing a whole spec except that we do
    not initialize at the beginning and we do not supply a
@@ -5112,6 +4433,10 @@
   int i;
   int value;
 
+  /* If it's an empty string argument to a switch, keep it as is.  */
+  if (inswitch && !*p)
+    arg_going = 1;
+
   while ((c = *p++))
     /* If substituting a switch, treat all chars like letters.
        Otherwise, NL, SPC, TAB and % are special.  */
@@ -5120,7 +4445,8 @@
       case '\n':
 	end_going_arg ();
 
-	if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
+	if (VEC_length (const_char_p, argbuf) > 0
+	    && !strcmp (VEC_last (const_char_p, argbuf), "|"))
 	  {
 	    /* A `|' before the newline means use a pipe here,
 	       but only if -pipe was specified.
@@ -5131,12 +4457,12 @@
 		break;
 	      }
 	    else
-	      argbuf_index--;
+	      VEC_pop (const_char_p, argbuf);
 	  }
 
 	set_collect_gcc_options ();
 
-	if (argbuf_index > 0)
+	if (VEC_length (const_char_p, argbuf) > 0)
 	  {
 	    value = execute ();
 	    if (value)
@@ -5175,7 +4501,7 @@
 	switch (c = *p++)
 	  {
 	  case 0:
-	    fatal ("spec '%s' invalid", spec);
+	    fatal_error ("spec %qs invalid", spec);
 
 	  case 'b':
 	    if (save_temps_length)
@@ -5237,7 +4563,7 @@
 	      buf = (char *) alloca (p - q + 1);
 	      strncpy (buf, q, p - q);
 	      buf[p - q] = 0;
-	      error ("%s", buf);
+	      error ("%s", _(buf));
 	      return -1;
 	    }
 	    break;
@@ -5251,7 +4577,7 @@
 	      buf = (char *) alloca (p - q + 1);
 	      strncpy (buf, q, p - q);
 	      buf[p - q] = 0;
-	      notice ("%s\n", buf);
+	      inform (0, "%s", _(buf));
 	      if (*p)
 		p++;
 	    }
@@ -5324,7 +4650,7 @@
 		    p += 2;
 		    /* We don't support extra suffix characters after %O.  */
 		    if (*p == '.' || ISALNUM ((unsigned char) *p))
-		      fatal ("spec '%s' has invalid '%%0%c'", spec, *p);
+		      fatal_error ("spec %qs has invalid %<%%0%c%>", spec, *p);
 		    if (suffix_length == 0)
 		      suffix = TARGET_OBJECT_SUFFIX;
 		    else
@@ -5365,7 +4691,7 @@
 		    break;
 		  }
 
-		/* If the input_filename has the same suffix specified
+		/* If the gcc_input_filename has the same suffix specified
 		   for the %g, %u, or %U, and -save-temps is specified,
 		   we could end up using that file as an intermediate
 		   thus clobbering the user's source file (.e.g.,
@@ -5383,7 +4709,7 @@
 		    tmp[basename_length + suffix_length] = '\0';
 		    temp_filename = tmp;
 
-		    if (strcmp (temp_filename, input_filename) != 0)
+		    if (strcmp (temp_filename, gcc_input_filename) != 0)
 		      {
 #ifndef HOST_LACKS_INODE_NUMBERS
 			struct stat st_temp;
@@ -5391,12 +4717,13 @@
 			/* Note, set_input() resets input_stat_set to 0.  */
 			if (input_stat_set == 0)
 			  {
-			    input_stat_set = stat (input_filename, &input_stat);
+			    input_stat_set = stat (gcc_input_filename,
+						   &input_stat);
 			    if (input_stat_set >= 0)
 			      input_stat_set = 1;
 			  }
 
-			/* If we have the stat for the input_filename
+			/* If we have the stat for the gcc_input_filename
 			   and we can do the stat for the temp_filename
 			   then the they could still refer to the same
 			   file if st_dev/st_ino's are the same.  */
@@ -5406,7 +4733,7 @@
 			    || input_stat.st_ino != st_temp.st_ino)
 #else
 			/* Just compare canonical pathnames.  */
-			char* input_realname = lrealpath (input_filename);
+			char* input_realname = lrealpath (gcc_input_filename);
 			char* temp_realname = lrealpath (temp_filename);
 			bool files_differ = strcmp (input_realname, temp_realname);
 			free (input_realname);
@@ -5508,7 +4835,8 @@
 	      }
 	    else
 	      {
-		obstack_grow (&obstack, input_filename, input_filename_length);
+		obstack_grow (&obstack, gcc_input_filename,
+			      input_filename_length);
 		arg_going = 1;
 	      }
 	    break;
@@ -5630,18 +4958,18 @@
 
 	  case 'W':
 	    {
-	      int cur_index = argbuf_index;
+	      unsigned int cur_index = VEC_length (const_char_p, argbuf);
 	      /* Handle the {...} following the %W.  */
 	      if (*p != '{')
-		fatal ("spec '%s' has invalid '%%W%c", spec, *p);
+		fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p);
 	      p = handle_braces (p + 1);
 	      if (p == 0)
 		return -1;
 	      end_going_arg ();
 	      /* If any args were output, mark the last one for deletion
 		 on failure.  */
-	      if (argbuf_index != cur_index)
-		record_temp_file (argbuf[argbuf_index - 1], 0, 1);
+	      if (VEC_length (const_char_p, argbuf) != cur_index)
+		record_temp_file (VEC_last (const_char_p, argbuf), 0, 1);
 	      break;
 	    }
 
@@ -5650,17 +4978,19 @@
 	    {
 	      const char *p1 = p;
 	      char *string;
+	      char *opt;
+	      unsigned ix;
 
 	      /* Skip past the option value and make a copy.  */
 	      if (*p != '{')
-		fatal ("spec '%s' has invalid '%%x%c'", spec, *p);
+		fatal_error ("spec %qs has invalid %<%%x%c%>", spec, *p);
 	      while (*p++ != '}')
 		;
 	      string = save_string (p1 + 1, p - p1 - 2);
 
 	      /* See if we already recorded this option.  */
-	      for (i = 0; i < n_linker_options; i++)
-		if (! strcmp (string, linker_options[i]))
+	      FOR_EACH_VEC_ELT (char_p, linker_options, ix, opt)
+		if (! strcmp (string, opt))
 		  {
 		    free (string);
 		    return 0;
@@ -5673,32 +5003,17 @@
 
 	  /* Dump out the options accumulated previously using %x.  */
 	  case 'X':
-	    for (i = 0; i < n_linker_options; i++)
-	      {
-		do_spec_1 (linker_options[i], 1, NULL);
-		/* Make each accumulated option a separate argument.  */
-		do_spec_1 (" ", 0, NULL);
-	      }
+	    do_specs_vec (linker_options);
 	    break;
 
 	  /* Dump out the options accumulated previously using -Wa,.  */
 	  case 'Y':
-	    for (i = 0; i < n_assembler_options; i++)
-	      {
-		do_spec_1 (assembler_options[i], 1, NULL);
-		/* Make each accumulated option a separate argument.  */
-		do_spec_1 (" ", 0, NULL);
-	      }
+	    do_specs_vec (assembler_options);
 	    break;
 
 	  /* Dump out the options accumulated previously using -Wp,.  */
 	  case 'Z':
-	    for (i = 0; i < n_preprocessor_options; i++)
-	      {
-		do_spec_1 (preprocessor_options[i], 1, NULL);
-		/* Make each accumulated option a separate argument.  */
-		do_spec_1 (" ", 0, NULL);
-	      }
+	    do_specs_vec (preprocessor_options);
 	    break;
 
 	    /* Here are digits and numbers that just process
@@ -5815,10 +5130,17 @@
 	   /* Henceforth ignore the option(s) matching the pattern
 	      after the %<.  */
 	  case '<':
+	  case '>':
 	    {
 	      unsigned len = 0;
 	      int have_wildcard = 0;
 	      int i;
+	      int switch_option;
+
+	      if (c == '>')
+		switch_option = SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC;
+	      else
+		switch_option = SWITCH_IGNORE;
 
 	      while (p[len] && p[len] != ' ' && p[len] != '\t')
 		len++;
@@ -5830,7 +5152,7 @@
 		if (!strncmp (switches[i].part1, p, len - have_wildcard)
 		    && (have_wildcard || switches[i].part1[len] == '\0'))
 		  {
-		    switches[i].live_cond |= SWITCH_IGNORE;
+		    switches[i].live_cond |= switch_option;
 		    switches[i].validated = 1;
 		  }
 
@@ -5841,14 +5163,15 @@
 	  case '*':
 	    if (soft_matched_part)
 	      {
-		do_spec_1 (soft_matched_part, 1, NULL);
+		if (soft_matched_part[0])
+		  do_spec_1 (soft_matched_part, 1, NULL);
 		do_spec_1 (" ", 0, NULL);
 	      }
 	    else
 	      /* Catch the case where a spec string contains something like
 		 '%{foo:%*}'.  i.e. there is no * in the pattern on the left
 		 hand side of the :.  */
-	      error ("spec failure: '%%*' has not been initialized by pattern match");
+	      error ("spec failure: %<%%*%> has not been initialized by pattern match");
 	    break;
 
 	    /* Process a string found as the value of a spec given by name.
@@ -5857,7 +5180,7 @@
 	       %[...] modifies -D options the way %P does;
 	       %(...) uses the spec unmodified.  */
 	  case '[':
-	    error ("warning: use of obsolete %%[ operator in specs");
+	    warning (0, "use of obsolete %%[ operator in specs");
 	  case '(':
 	    {
 	      const char *name = p;
@@ -5875,7 +5198,7 @@
 		  {
 		    name = *(sl->ptr_spec);
 #ifdef DEBUG_SPECS
-		    notice ("Processing spec %c%s%c, which is '%s'\n",
+		    fnotice (stderr, "Processing spec %c%s%c, which is '%s'\n",
 			    c, sl->name, (c == '(') ? ')' : ']', name);
 #endif
 		    break;
@@ -5938,7 +5261,7 @@
 	    break;
 
 	  default:
-	    error ("spec failure: unrecognized spec option '%c'", c);
+	    error ("spec failure: unrecognized spec option %qc", c);
 	    break;
 	  }
 	break;
@@ -5985,9 +5308,7 @@
   const char *funcval;
 
   /* Saved spec processing context.  */
-  int save_argbuf_index;
-  int save_argbuf_length;
-  const char **save_argbuf;
+  VEC(const_char_p,heap) *save_argbuf;
 
   int save_arg_going;
   int save_delete_this_arg;
@@ -6000,11 +5321,9 @@
 
   sf = lookup_spec_function (func);
   if (sf == NULL)
-    fatal ("unknown spec function '%s'", func);
+    fatal_error ("unknown spec function %qs", func);
 
   /* Push the spec processing context.  */
-  save_argbuf_index = argbuf_index;
-  save_argbuf_length = argbuf_length;
   save_argbuf = argbuf;
 
   save_arg_going = arg_going;
@@ -6020,17 +5339,16 @@
 
   alloc_args ();
   if (do_spec_2 (args) < 0)
-    fatal ("error in args to spec function '%s'", func);
+    fatal_error ("error in args to spec function %qs", func);
 
   /* argbuf_index is an index for the next argument to be inserted, and
      so contains the count of the args already inserted.  */
 
-  funcval = (*sf->func) (argbuf_index, argbuf);
+  funcval = (*sf->func) (VEC_length (const_char_p, argbuf),
+			 VEC_address (const_char_p, argbuf));
 
   /* Pop the spec processing context.  */
-  argbuf_index = save_argbuf_index;
-  argbuf_length = save_argbuf_length;
-  free (argbuf);
+  VEC_free (const_char_p, heap, argbuf);
   argbuf = save_argbuf;
 
   arg_going = save_arg_going;
@@ -6069,10 +5387,10 @@
         break;
       /* Only allow [A-Za-z0-9], -, and _ in function names.  */
       if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_'))
-	fatal ("malformed spec function name");
+	fatal_error ("malformed spec function name");
     }
   if (*endp != '(')		/* ) */
-    fatal ("no arguments for spec function");
+    fatal_error ("no arguments for spec function");
   func = save_string (p, endp - p);
   p = ++endp;
 
@@ -6091,7 +5409,7 @@
     }
   /* ( */
   if (*endp != ')')
-    fatal ("malformed spec function arguments");
+    fatal_error ("malformed spec function arguments");
   args = save_string (p, endp - p);
   p = ++endp;
 
@@ -6337,7 +5655,7 @@
   return p;
 
  invalid:
-  fatal ("braced spec '%s' is invalid at '%c'", orig, *p);
+  fatal_error ("braced spec %qs is invalid at %qc", orig, *p);
 
 #undef SKIP_WHITE
 }
@@ -6425,7 +5743,7 @@
   return p;
 
  invalid:
-  fatal ("braced spec body '%s' is invalid", body);
+  fatal_error ("braced spec body %qs is invalid", body);
 }
 
 /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
@@ -6447,7 +5765,8 @@
   if (switches[switchnum].live_cond != 0)
     return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
 	    && (switches[switchnum].live_cond & SWITCH_FALSE) == 0
-	    && (switches[switchnum].live_cond & SWITCH_IGNORE) == 0);
+	    && (switches[switchnum].live_cond & SWITCH_IGNORE_PERMANENTLY)
+	       == 0);
 
   /* In the common case of {<at-most-one-letter>*}, a negating
      switch would always match, so ignore that case.  We will just
@@ -6613,9 +5932,9 @@
 {
   const char *p;
 
-  input_filename = filename;
-  input_filename_length = strlen (input_filename);
-  input_basename = lbasename (input_filename);
+  gcc_input_filename = filename;
+  input_filename_length = strlen (gcc_input_filename);
+  input_basename = lbasename (gcc_input_filename);
 
   /* Find a suffix starting with the last period,
      and set basename_length to exclude that suffix.  */
@@ -6633,7 +5952,7 @@
     input_suffix = "";
 
   /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then
-     we will need to do a stat on the input_filename.  The
+     we will need to do a stat on the gcc_input_filename.  The
      INPUT_STAT_SET signals that the stat is needed.  */
   input_stat_set = 0;
 }
@@ -6641,7 +5960,7 @@
 /* On fatal signals, delete all the temporary files.  */
 
 static void
-fatal_error (int signum)
+fatal_signal (int signum)
 {
   signal (signum, SIG_DFL);
   delete_failure_queue ();
@@ -6674,7 +5993,7 @@
 	if (stat (cmpfile[i], &st) < 0 || !S_ISREG (st.st_mode))
 	  {
 	    error ("%s: could not determine length of compare-debug file %s",
-		   input_filename, cmpfile[i]);
+		   gcc_input_filename, cmpfile[i]);
 	    ret = 1;
 	    break;
 	  }
@@ -6684,7 +6003,7 @@
 
     if (!ret && length[0] != length[1])
       {
-	error ("%s: -fcompare-debug failure (length)", input_filename);
+	error ("%s: -fcompare-debug failure (length)", gcc_input_filename);
 	ret = 1;
       }
 
@@ -6695,7 +6014,7 @@
 	  if (fd < 0)
 	    {
 	      error ("%s: could not open compare-debug file %s",
-		     input_filename, cmpfile[i]);
+		     gcc_input_filename, cmpfile[i]);
 	      ret = 1;
 	      break;
 	    }
@@ -6714,7 +6033,7 @@
       {
 	if (memcmp (map[0], map[1], length[0]) != 0)
 	  {
-	    error ("%s: -fcompare-debug failure", input_filename);
+	    error ("%s: -fcompare-debug failure", gcc_input_filename);
 	    ret = 1;
 	  }
       }
@@ -6736,7 +6055,7 @@
       if (!temp[i])
 	{
 	  error ("%s: could not open compare-debug file %s",
-		 input_filename, cmpfile[i]);
+		 gcc_input_filename, cmpfile[i]);
 	  ret = 1;
 	  break;
 	}
@@ -6752,7 +6071,7 @@
 	if (c0 != c1)
 	  {
 	    error ("%s: -fcompare-debug failure",
-		   input_filename);
+		   gcc_input_filename);
 	    ret = 1;
 	    break;
 	  }
@@ -6782,9 +6101,12 @@
   int num_linker_inputs = 0;
   char *explicit_link_files;
   char *specs_file;
+  char *lto_wrapper_file;
   const char *p;
   struct user_specs *uptr;
   char **old_argv = argv;
+  struct cl_decoded_option *decoded_options;
+  unsigned int decoded_options_count;
 
   /* Initialize here, not in definition.  The IRIX 6 O32 cc sometimes chokes
      on ?: in file-scope variable initializations.  */
@@ -6793,9 +6115,9 @@
   p = argv[0] + strlen (argv[0]);
   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
     --p;
-  programname = p;
-
-  xmalloc_set_program_name (programname);
+  progname = p;
+
+  xmalloc_set_program_name (progname);
 
   expandargv (&argc, &argv);
 
@@ -6803,7 +6125,12 @@
   if (argv != old_argv)
     at_file_supplied = true;
 
-  prune_options (&argc, &argv);
+  global_options = global_options_init;
+
+  decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **,
+						      argv),
+				   CL_DRIVER,
+				   &decoded_options, &decoded_options_count);
 
 #ifdef GCC_DRIVER_HOST_INITIALIZATION
   /* Perform host dependent initialization when needed.  */
@@ -6815,17 +6142,21 @@
 
   gcc_init_libintl ();
 
+  diagnostic_initialize (global_dc, 0);
+  if (atexit (delete_temp_files) != 0)
+    fatal_error ("atexit failed");
+
   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
-    signal (SIGINT, fatal_error);
+    signal (SIGINT, fatal_signal);
 #ifdef SIGHUP
   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
-    signal (SIGHUP, fatal_error);
+    signal (SIGHUP, fatal_signal);
 #endif
   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
-    signal (SIGTERM, fatal_error);
+    signal (SIGTERM, fatal_signal);
 #ifdef SIGPIPE
   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
-    signal (SIGPIPE, fatal_error);
+    signal (SIGPIPE, fatal_signal);
 #endif
 #ifdef SIGCHLD
   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
@@ -6889,7 +6220,7 @@
      Make a table of specified input files (infiles, n_infiles).
      Decode switches that are handled locally.  */
 
-  process_command (argc, CONST_CAST2 (const char **, char **, argv));
+  process_command (decoded_options_count, decoded_options);
 
   /* Initialize the vector of specs to just the default.
      This means one element containing 0s, as a terminator.  */
@@ -6941,14 +6272,17 @@
       if (!compare_debug_second)
 	{
 	  n_switches_debug_check[1] = n_switches;
+	  n_switches_alloc_debug_check[1] = n_switches_alloc;
 	  switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
-					     n_switches + 1);
+					     n_switches_alloc);
 
 	  do_self_spec ("%:compare-debug-self-opt()");
 	  n_switches_debug_check[0] = n_switches;
+	  n_switches_alloc_debug_check[0] = n_switches_alloc;
 	  switches_debug_check[0] = switches;
 
 	  n_switches = n_switches_debug_check[1];
+	  n_switches_alloc = n_switches_alloc_debug_check[1];
 	  switches = switches_debug_check[1];
 	}
 
@@ -6964,9 +6298,11 @@
       if (!compare_debug_second)
 	{
 	  n_switches_debug_check[1] = n_switches;
+	  n_switches_alloc_debug_check[1] = n_switches_alloc;
 	  switches_debug_check[1] = switches;
 	  compare_debug = -compare_debug;
 	  n_switches = n_switches_debug_check[0];
+	  n_switches_alloc = n_switches_debug_check[0];
 	  switches = switches_debug_check[0];
 	}
     }
@@ -6986,10 +6322,10 @@
   if (*sysroot_suffix_spec != 0
       && do_spec_2 (sysroot_suffix_spec) == 0)
     {
-      if (argbuf_index > 1)
+      if (VEC_length (const_char_p, argbuf) > 1)
         error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
-      else if (argbuf_index == 1)
-        target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]);
+      else if (VEC_length (const_char_p, argbuf) == 1)
+        target_sysroot_suffix = xstrdup (VEC_last (const_char_p, argbuf));
     }
 
 #ifdef HAVE_LD_SYSROOT
@@ -7009,10 +6345,10 @@
   if (*sysroot_hdrs_suffix_spec != 0
       && do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
     {
-      if (argbuf_index > 1)
+      if (VEC_length (const_char_p, argbuf) > 1)
         error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
-      else if (argbuf_index == 1)
-        target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]);
+      else if (VEC_length (const_char_p, argbuf) == 1)
+        target_sysroot_hdrs_suffix = xstrdup (VEC_last (const_char_p, argbuf));
     }
 
   /* Look for startfiles in the standard places.  */
@@ -7020,9 +6356,10 @@
       && do_spec_2 (startfile_prefix_spec) == 0
       && do_spec_1 (" ", 0, NULL) == 0)
     {
+      const char *arg;
       int ndx;
-      for (ndx = 0; ndx < argbuf_index; ndx++)
-	add_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS",
+      FOR_EACH_VEC_ELT (const_char_p, argbuf, ndx, arg)
+	add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS",
 			      PREFIX_PRIORITY_LAST, 0, 1);
     }
   /* We should eventually get rid of all these and stick to
@@ -7094,7 +6431,7 @@
   set_multilib_dir ();
 
   /* Set up to remember the pathname of gcc and any options
-     needed for collect.  We use argv[0] instead of programname because
+     needed for collect.  We use argv[0] instead of progname because
      we need the complete pathname.  */
   obstack_init (&collect_obstack);
   obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
@@ -7103,9 +6440,10 @@
 
   /* Set up to remember the pathname of the lto wrapper. */
 
-  lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
-  if (lto_wrapper_spec)
+  lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
+  if (lto_wrapper_file)
     {
+      lto_wrapper_spec = lto_wrapper_file;
       obstack_init (&collect_obstack);
       obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
 		    sizeof ("COLLECT_LTO_WRAPPER=") - 1);
@@ -7118,7 +6456,7 @@
 
   for (i = 0; (int) i < n_switches; i++)
     if (! switches[i].validated)
-      error ("unrecognized option '-%s'", switches[i].part1);
+      error ("unrecognized option %<-%s%>", switches[i].part1);
 
   /* Obey some of the options.  */
 
@@ -7195,7 +6533,7 @@
       else
 	/* The error status indicates that only one set of fixed
 	   headers should be built.  */
-	fatal ("not configured with sysroot headers suffix");
+	fatal_error ("not configured with sysroot headers suffix");
     }
 
   if (print_help_list)
@@ -7220,9 +6558,9 @@
 
   if (print_version)
     {
-      printf (_("%s %s%s\n"), programname, pkgversion_string,
+      printf (_("%s %s%s\n"), progname, pkgversion_string,
 	      version_string);
-      printf ("Copyright %s 2009 Free Software Foundation, Inc.\n",
+      printf ("Copyright %s 2011 Free Software Foundation, Inc.\n",
 	      _("(C)"));
       fputs (_("This is free software; see the source for copying conditions.  There is NO\n\
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
@@ -7241,8 +6579,8 @@
       int n;
       const char *thrmod;
 
-      notice ("Target: %s\n", spec_machine);
-      notice ("Configured with: %s\n", configuration_arguments);
+      fnotice (stderr, "Target: %s\n", spec_machine);
+      fnotice (stderr, "Configured with: %s\n", configuration_arguments);
 
 #ifdef THREAD_MODEL_SPEC
       /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
@@ -7256,7 +6594,7 @@
       thrmod = thread_model;
 #endif
 
-      notice ("Thread model: %s\n", thrmod);
+      fnotice (stderr, "Thread model: %s\n", thrmod);
 
       /* compiler_version is truncated at the first space when initialized
 	 from version string, so truncate version_string at the first space
@@ -7267,17 +6605,21 @@
 
       if (! strncmp (version_string, compiler_version, n)
 	  && compiler_version[n] == 0)
-	notice ("gcc version %s %s\n", version_string, pkgversion_string);
+	fnotice (stderr, "gcc version %s %s\n", version_string,
+		 pkgversion_string);
       else
-	notice ("gcc driver version %s %sexecuting gcc version %s\n",
-		version_string, pkgversion_string, compiler_version);
+	fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n",
+		 version_string, pkgversion_string, compiler_version);
 
       if (n_infiles == 0)
 	return (0);
     }
 
   if (n_infiles == added_libraries)
-    fatal ("no input files");
+    fatal_error ("no input files");
+
+  if (seen_error ())
+    goto out;
 
   /* Make a place to record the compiler output file names
      that correspond to the input files.  */
@@ -7290,10 +6632,7 @@
 
   explicit_link_files = XCNEWVEC (char, n_infiles);
 
-  if (combine_flag)
-    combine_inputs = true;
-  else
-    combine_inputs = false;
+  combine_inputs = have_o || flag_wpa;
 
   for (i = 0; (int) i < n_infiles; i++)
     {
@@ -7326,62 +6665,7 @@
     }
 
   if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
-   fatal ("cannot specify -o with -c, -S or -E with multiple files");
-
-  if (combine_flag && save_temps_flag)
-    {
-      bool save_combine_inputs = combine_inputs;
-      /* Must do a separate pre-processing pass for C & Objective-C files, to
-	 obtain individual .i files.  */
-
-      combine_inputs = false;
-      for (i = 0; (int) i < n_infiles; i++)
-	{
-	  int this_file_error = 0;
-
-	  input_file_number = i;
-	  set_input (infiles[i].name);
-	  if (infiles[i].incompiler
-	      && (infiles[i].incompiler)->needs_preprocessing)
-	    input_file_compiler = infiles[i].incompiler;
-	  else
-	    continue;
-
-	  if (input_file_compiler)
-	    {
-	      if (input_file_compiler->spec[0] == '#')
-		{
-		  error ("%s: %s compiler not installed on this system",
-			 input_filename, &input_file_compiler->spec[1]);
-		  this_file_error = 1;
-		}
-	      else
-		{
-		  value = do_spec (input_file_compiler->spec);
-		  infiles[i].preprocessed = true;
-		  if (!have_o_argbuf_index)
-		    fatal ("spec '%s' is invalid", input_file_compiler->spec);
-		  infiles[i].name = argbuf[have_o_argbuf_index];
-		  infiles[i].incompiler
-		    = lookup_compiler (infiles[i].name,
-				       strlen (infiles[i].name),
-				       infiles[i].language);
-
-		  if (value < 0)
-		    this_file_error = 1;
-		}
-	    }
-
-	  if (this_file_error)
-	    {
-	      delete_failure_queue ();
-	      error_count++;
-	      break;
-	    }
-	  clear_failure_queue ();
-	}
-      combine_inputs = save_combine_inputs;
-    }
+    fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
 
   for (i = 0; (int) i < n_infiles; i++)
     {
@@ -7397,16 +6681,13 @@
 
       /* Use the same thing in %o, unless cp->spec says otherwise.  */
 
-      outfiles[i] = input_filename;
+      outfiles[i] = gcc_input_filename;
 
       /* Figure out which compiler from the file's suffix.  */
 
-      if (! combine_inputs)
-	input_file_compiler
-	  = lookup_compiler (infiles[i].name, input_filename_length,
-			     infiles[i].language);
-      else
-	input_file_compiler = infiles[i].incompiler;
+      input_file_compiler
+	= lookup_compiler (infiles[i].name, input_filename_length,
+			   infiles[i].language);
 
       if (input_file_compiler)
 	{
@@ -7415,7 +6696,7 @@
 	  if (input_file_compiler->spec[0] == '#')
 	    {
 	      error ("%s: %s compiler not installed on this system",
-		     input_filename, &input_file_compiler->spec[1]);
+		     gcc_input_filename, &input_file_compiler->spec[1]);
 	      this_file_error = 1;
 	    }
 	  else
@@ -7438,16 +6719,18 @@
 	      else if (compare_debug && debug_check_temp_file[0])
 		{
 		  if (verbose_flag)
-		    error ("Recompiling with -fcompare-debug");
+		    inform (0, "recompiling with -fcompare-debug");
 
 		  compare_debug = -compare_debug;
 		  n_switches = n_switches_debug_check[1];
+		  n_switches_alloc = n_switches_alloc_debug_check[1];
 		  switches = switches_debug_check[1];
 
 		  value = do_spec (input_file_compiler->spec);
 
 		  compare_debug = -compare_debug;
 		  n_switches = n_switches_debug_check[0];
+		  n_switches_alloc = n_switches_alloc_debug_check[0];
 		  switches = switches_debug_check[0];
 
 		  if (value < 0)
@@ -7461,7 +6744,7 @@
 					 debug_check_temp_file[1]));
 
 		  if (verbose_flag)
-		    error ("Comparing final insns dumps");
+		    inform (0, "comparing final insns dumps");
 
 		  if (compare_files (debug_check_temp_file))
 		    this_file_error = 1;
@@ -7492,7 +6775,7 @@
       if (this_file_error)
 	{
 	  delete_failure_queue ();
-	  error_count++;
+	  errorcount++;
 	}
       /* If this compilation succeeded, don't delete those files later.  */
       clear_failure_queue ();
@@ -7507,20 +6790,21 @@
       int i;
 
       for (i = 0; i < n_infiles ; i++)
-	if (infiles[i].language && infiles[i].language[0] != '*')
+	if (infiles[i].incompiler
+	    || (infiles[i].language && infiles[i].language[0] != '*'))
 	  {
 	    set_input (infiles[i].name);
 	    break;
 	  }
     }
 
-  if (error_count == 0)
+  if (!seen_error ())
     {
       /* Make sure INPUT_FILE_NUMBER points to first available open
 	 slot.  */
       input_file_number = n_infiles;
       if (lang_specific_pre_link ())
-	error_count++;
+	errorcount++;
     }
 
   /* Determine if there are any linker input files.  */
@@ -7531,10 +6815,14 @@
 
   /* Run ld to link all the compiler output files.  */
 
-  if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2)
+  if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
     {
       int tmp = execution_count;
+#ifdef HAVE_LTO_PLUGIN
+      const char *fno_use_linker_plugin = "fno-use-linker-plugin";
+#else
       const char *fuse_linker_plugin = "fuse-linker-plugin";
+#endif
 
       /* We'll use ld if we can't find collect2.  */
       if (! strcmp (linker_name_spec, "collect2"))
@@ -7544,19 +6832,19 @@
 	    linker_name_spec = "ld";
 	}
 
+#ifdef HAVE_LTO_PLUGIN
+      if (!switch_matches (fno_use_linker_plugin,
+			   fno_use_linker_plugin + strlen (fno_use_linker_plugin), 0))
+#else
       if (switch_matches (fuse_linker_plugin,
 			  fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
+#endif
 	{
 	  linker_plugin_file_spec = find_a_file (&exec_prefixes,
-						 "liblto_plugin.so", X_OK,
+						 LTOPLUGINSONAME, R_OK,
 						 false);
 	  if (!linker_plugin_file_spec)
-	    fatal ("-fuse-linker-plugin, but liblto_plugin.so not found");
-
-	  lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
-					 R_OK, true);
-	  if (!lto_libgcc_spec)
-	    fatal ("could not find libgcc.a");
+	    fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
 	}
       lto_gcc_spec = argv[0];
 
@@ -7574,23 +6862,23 @@
 	}
       value = do_spec (link_command_spec);
       if (value < 0)
-	error_count = 1;
+	errorcount = 1;
       linker_was_run = (tmp != execution_count);
     }
 
   /* If options said don't run linker,
      complain about input files to be given to the linker.  */
 
-  if (! linker_was_run && error_count == 0)
+  if (! linker_was_run && !seen_error ())
     for (i = 0; (int) i < n_infiles; i++)
       if (explicit_link_files[i]
 	  && !(infiles[i].language && infiles[i].language[0] == '*'))
-	error ("%s: linker input file unused because linking not done",
-	       outfiles[i]);
+	warning (0, "%s: linker input file unused because linking not done",
+		 outfiles[i]);
 
   /* Delete some or all of the temporary files we made.  */
 
-  if (error_count)
+  if (seen_error ())
     delete_failure_queue ();
   delete_temp_files ();
 
@@ -7600,8 +6888,9 @@
       printf ("%s\n", bug_report_url);
     }
 
+ out:
   return (signal_count != 0 ? 2
-	  : error_count > 0 ? (pass_exit_codes ? greatest_status : 1)
+	  : seen_error () ? (pass_exit_codes ? greatest_status : 1)
 	  : 0);
 }
 
@@ -7696,76 +6985,7 @@
 static void
 perror_with_name (const char *name)
 {
-  error ("%s: %s", name, xstrerror (errno));
-}
-
-/* Output an error message and exit.  */
-
-void
-fancy_abort (const char *file, int line, const char *func)
-{
-  fatal_ice ("internal gcc abort in %s, at %s:%d", func, file, line);
-}
-
-/* Output an error message and exit.  */
-
-void
-fatal_ice (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
-  fprintf (stderr, "\n");
-  delete_temp_files ();
-  exit (pass_exit_codes ? ICE_EXIT_CODE : 1);
-}
-
-void
-fatal (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
-  fprintf (stderr, "\n");
-  delete_temp_files ();
-  exit (1);
-}
-
-/* The argument is actually c-format, not gcc-internal-format,
-   but because functions with identical names are used through
-   the rest of the compiler with gcc-internal-format, we just
-   need to hope all users of these functions use the common
-   subset between c-format and gcc-internal-format.  */
-
-void
-error (const char *gmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, gmsgid);
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(gmsgid), ap);
-  va_end (ap);
-
-  fprintf (stderr, "\n");
-}
-
-static void
-notice (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
+  error ("%s: %m", name);
 }
 
 static inline void
@@ -7920,7 +7140,8 @@
 	      if (*q == '\0')
 		{
 		invalid_matches:
-		  fatal ("multilib spec '%s' is invalid", multilib_matches);
+		  fatal_error ("multilib spec %qs is invalid",
+			       multilib_matches);
 		}
 	      q++;
 	    }
@@ -8111,8 +7332,8 @@
 	  if (*p == '\0')
 	    {
 	    invalid_exclusions:
-	      fatal ("multilib exclusions '%s' is invalid",
-		     multilib_exclusions);
+	      fatal_error ("multilib exclusions %qs is invalid",
+			   multilib_exclusions);
 	    }
 
 	  if (! ok)
@@ -8169,8 +7390,8 @@
 	  if (*p == '\0')
 	    {
 	    invalid_select:
-	      fatal ("multilib select '%s' is invalid",
-		     multilib_select);
+	      fatal_error ("multilib select %qs is invalid",
+			   multilib_select);
 	    }
 	  ++p;
 	}
@@ -8310,7 +7531,7 @@
 	  if (*p == '\0')
 	    {
 	    invalid_select:
-	      fatal ("multilib select '%s' is invalid", multilib_select);
+	      fatal_error ("multilib select %qs is invalid", multilib_select);
 	    }
 
 	  ++p;
@@ -8348,8 +7569,8 @@
 		if (*e == '\0')
 		  {
 		  invalid_exclusion:
-		    fatal ("multilib exclusion '%s' is invalid",
-			   multilib_exclusions);
+		    fatal_error ("multilib exclusion %qs is invalid",
+				 multilib_exclusions);
 		  }
 
 		if (! m)
@@ -8554,7 +7775,7 @@
 
   value = getenv (argv[0]);
   if (!value)
-    fatal ("environment variable \"%s\" not defined", argv[0]);
+    fatal_error ("environment variable %qs not defined", argv[0]);
 
   /* We have to escape every character of the environment variable so
      they are not interpreted as active spec characters.  A
@@ -8630,6 +7851,27 @@
   return NULL;
 }
 
+/* remove-outfile built-in spec function.
+ *
+ *    This looks for the first argument in the outfiles array's name and
+ *       removes it.  */
+
+static const char *
+remove_outfile_spec_function (int argc, const char **argv)
+{
+  int i;
+  /* Must have exactly one argument.  */
+  if (argc != 1)
+    abort ();
+
+  for (i = 0; i < n_infiles; i++)
+    {
+      if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+        outfiles[i] = NULL;
+    }
+  return NULL;
+}
+
 /* Given two version numbers, compares the two numbers.
    A version number must match the regular expression
    ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))*
@@ -8645,12 +7887,12 @@
     abort ();
   rresult = regexec (&r, v1, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal ("invalid version number `%s'", v1);
+    fatal_error ("invalid version number %qs", v1);
   else if (rresult != 0)
     abort ();
   rresult = regexec (&r, v2, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal ("invalid version number `%s'", v2);
+    fatal_error ("invalid version number %qs", v2);
   else if (rresult != 0)
     abort ();
 
@@ -8693,13 +7935,13 @@
   bool result;
 
   if (argc < 3)
-    fatal ("too few arguments to %%:version-compare");
+    fatal_error ("too few arguments to %%:version-compare");
   if (argv[0][0] == '\0')
     abort ();
   if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!')
     nargs = 2;
   if (argc != nargs + 3)
-    fatal ("too many arguments to %%:version-compare");
+    fatal_error ("too many arguments to %%:version-compare");
 
   switch_len = strlen (argv[nargs + 1]);
   for (i = 0; i < n_switches; i++)
@@ -8740,7 +7982,7 @@
       break;
 
     default:
-      fatal ("unknown operator '%s' in %%:version-compare", argv[0]);
+      fatal_error ("unknown operator %qs in %%:version-compare", argv[0]);
     }
   if (! result)
     return NULL;
@@ -8767,6 +8009,38 @@
   return NULL;
 }
 
+/* %:find-file spec function.  This function replaces its argument by
+    the file found thru find_file, that is the -print-file-name gcc
+    program option. */
+static const char *
+find_file_spec_function (int argc, const char **argv)
+{
+  const char *file;
+
+  if (argc != 1)
+    abort ();
+
+  file = find_file (argv[0]);
+  return file;
+}
+
+
+/* %:find-plugindir spec function.  This function replaces its argument
+    by the -iplugindir=<dir> option.  `dir' is found thru find_file, that
+    is the -print-file-name gcc program option. */
+static const char *
+find_plugindir_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
+{
+  const char *option;
+
+  if (argc != 0)
+    abort ();
+
+  option = concat ("-iplugindir=", find_file ("plugin"), NULL);
+  return option;
+}
+
+
 /* %:print-asm-header spec function.  Print a banner to say that the
    following output is from the assembler.  */
 
@@ -8821,24 +8095,25 @@
   static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3];
 
   if (arg != 0)
-    fatal ("too many arguments to %%:compare-debug-dump-opt");
+    fatal_error ("too many arguments to %%:compare-debug-dump-opt");
 
   do_spec_2 ("%{fdump-final-insns=*:%*}");
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], "."))
+  if (VEC_length (const_char_p, argbuf) > 0
+      && strcmp (argv[VEC_length (const_char_p, argbuf) - 1], "."))
     {
       if (!compare_debug)
 	return NULL;
 
-      name = xstrdup (argv[argbuf_index - 1]);
+      name = xstrdup (argv[VEC_length (const_char_p, argbuf) - 1]);
       ret = NULL;
     }
   else
     {
       const char *ext = NULL;
 
-      if (argbuf_index > 0)
+      if (VEC_length (const_char_p, argbuf) > 0)
 	{
 	  do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
 	  ext = ".gkd";
@@ -8850,9 +8125,9 @@
 
       do_spec_1 (" ", 0, NULL);
 
-      gcc_assert (argbuf_index > 0);
-
-      name = concat (argbuf[argbuf_index - 1], ext, NULL);
+      gcc_assert (VEC_length (const_char_p, argbuf) > 0);
+
+      name = concat (VEC_last (const_char_p, argbuf), ext, NULL);
 
       ret = concat ("-fdump-final-insns=", name, NULL);
     }
@@ -8888,7 +8163,7 @@
 				      const char **argv ATTRIBUTE_UNUSED)
 {
   if (arg != 0)
-    fatal ("too many arguments to %%:compare-debug-self-opt");
+    fatal_error ("too many arguments to %%:compare-debug-self-opt");
 
   if (compare_debug >= 0)
     return NULL;
@@ -8896,9 +8171,9 @@
   do_spec_2 ("%{c|S:%{o*:%*}}");
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0)
+  if (VEC_length (const_char_p, argbuf) > 0)
     debug_auxbase_opt = concat ("-auxbase-strip ",
-				argbuf[argbuf_index - 1],
+				VEC_last (const_char_p, argbuf),
 				NULL);
   else
     debug_auxbase_opt = NULL;
@@ -8923,17 +8198,18 @@
   int len;
 
   if (arg == 0)
-    fatal ("too few arguments to %%:compare-debug-auxbase-opt");
+    fatal_error ("too few arguments to %%:compare-debug-auxbase-opt");
 
   if (arg != 1)
-    fatal ("too many arguments to %%:compare-debug-auxbase-opt");
+    fatal_error ("too many arguments to %%:compare-debug-auxbase-opt");
 
   if (compare_debug >= 0)
     return NULL;
 
   len = strlen (argv[0]);
   if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
-    fatal ("argument to %%:compare-debug-auxbase-opt does not end in .gk");
+    fatal_error ("argument to %%:compare-debug-auxbase-opt "
+		 "does not end in .gk");
 
   if (debug_auxbase_opt)
     return debug_auxbase_opt;
@@ -8950,3 +8226,46 @@
 
   return name;
 }
+
+/* %:pass-through-libs spec function.  Finds all -l options and input
+   file names in the lib spec passed to it, and makes a list of them
+   prepended with the plugin option to cause them to be passed through
+   to the final link after all the new object files have been added.  */
+
+const char *
+pass_through_libs_spec_func (int argc, const char **argv)
+{
+  char *prepended = xstrdup (" ");
+  int n;
+  /* Shlemiel the painter's algorithm.  Innately horrible, but at least
+     we know that there will never be more than a handful of strings to
+     concat, and it's only once per run, so it's not worth optimising.  */
+  for (n = 0; n < argc; n++)
+    {
+      char *old = prepended;
+      /* Anything that isn't an option is a full path to an output
+         file; pass it through if it ends in '.a'.  Among options,
+	 pass only -l.  */
+      if (argv[n][0] == '-' && argv[n][1] == 'l')
+	{
+	  const char *lopt = argv[n] + 2;
+	  /* Handle both joined and non-joined -l options.  If for any
+	     reason there's a trailing -l with no joined or following
+	     arg just discard it.  */
+	  if (!*lopt && ++n >= argc)
+	    break;
+	  else if (!*lopt)
+	    lopt = argv[n];
+	  prepended = concat (prepended, "-plugin-opt=-pass-through=-l",
+		lopt, " ", NULL);
+	}
+      else if (!strcmp (".a", argv[n] + strlen (argv[n]) - 2))
+	{
+	  prepended = concat (prepended, "-plugin-opt=-pass-through=",
+		argv[n], " ", NULL);
+	}
+      if (prepended != old)
+	free (old);
+    }
+  return prepended;
+}