OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 54da667..939dcc8 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,7 +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,
-   2010
+   2010, 2011, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -30,72 +30,22 @@ CC recognizes how to compile each input file by suffixes in the file names.
 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 "params.h"
+#include "vec.h"
+#include "filenames.h"
 
 /* By default there is no special suffix for target executables.  */
 /* FIXME: when autoconf is fixed, remove the host check - dj */
@@ -124,10 +74,6 @@ static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
 #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.  */
 
@@ -139,44 +85,9 @@ int is_cpp_driver;
 /* Flag set to nonzero if an @file argument has been supplied to gcc.  */
 static bool at_file_supplied;
 
-/* Flag saying to pass the greatest exit code returned by a sub-process
-   to the calling program.  */
-static int pass_exit_codes;
-
 /* Definition of string containing the arguments given to configure.  */
 #include "configargs.h"
 
-/* Flag saying to print the directories gcc will search through looking for
-   programs, libraries, etc.  */
-
-static int print_search_dirs;
-
-/* Flag saying to print the full filename of this file
-   as found through our usual search mechanism.  */
-
-static const char *print_file_name = NULL;
-
-/* As print_file_name, but search for executable file.  */
-
-static const char *print_prog_name = NULL;
-
-/* Flag saying to print the relative path we'd use to
-   find libgcc.a given the current compiler flags.  */
-
-static int print_multi_directory;
-
-static int print_sysroot;
-
-/* Flag saying to print the relative path we'd use to
-   find OS libraries given the current compiler flags.  */
-
-static int print_multi_os_directory;
-
-/* Flag saying to print the list of subdirectories and
-   compiler flags used to select them in a standard form.  */
-
-static int print_multi_lib;
-
 /* Flag saying to print the command line options understood by gcc and its
    sub-processes.  */
 
@@ -186,15 +97,6 @@ static int print_help_list;
 
 static int print_version;
 
-/* Flag saying to print the sysroot suffix used for searching for
-   headers.  */
-
-static int print_sysroot_headers_suffix;
-
-/* Flag indicating whether we should print the command and arguments */
-
-static int verbose_flag;
-
 /* 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
@@ -206,11 +108,6 @@ static int verbose_only_flag;
 
 static int print_subprocess_help;
 
-/* Flag indicating whether we should report subprocess execution times
-   (if this is supported by the system - see pexecute.c).  */
-
-static int report_times;
-
 /* Whether we should report subprocess execution times to a file.  */
 
 FILE *report_times_to_file = NULL;
@@ -249,15 +146,6 @@ static enum save_temps {
 static char *save_temps_prefix = 0;
 static size_t save_temps_length = 0;
 
-/* Nonzero means pass multiple source files to the compiler at one time.  */
-
-static int combine_flag = 0;
-
-/* Nonzero means use pipes to communicate between subprocesses.
-   Overridden by either of the above two flags.  */
-
-static int use_pipes;
-
 /* The compiler version.  */
 
 static const char *compiler_version;
@@ -279,27 +167,6 @@ static const char *cross_compile = "1";
 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;
@@ -315,14 +182,6 @@ static struct obstack obstack;
 
 static struct obstack collect_obstack;
 
-/* This is a list of a wrapper program and its arguments.
-   e.g. wrapper_string of "strace,-c"
-   will cause all programs to run as
-       strace -c program arguments
-   instead of just
-       program arguments */
-static const char  *wrapper_string;
-
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 struct prefix_list;
@@ -345,7 +204,6 @@ static void add_prefix (struct path_prefix *, const char *, const char *,
                        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,16 +235,12 @@ static int used_arg (const char *, int);
 static int default_arg (const char *, int);
 static void set_multilib_dir (void);
 static void print_multilib_info (void);
-static void inform (int, const char *, ...) ATTRIBUTE_PRINTF_2;
 static void perror_with_name (const char *);
-static void internal_error (const char *, ...)
-  ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
-static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2;
 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);
@@ -403,13 +257,17 @@ static const char *getenv_spec_function (int, const char **);
 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 **);
+static char *convert_white_space (char *);
 \f
 /* The Specs Language
 
@@ -535,6 +393,7 @@ or with constant text in a single argument.
         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)
@@ -580,7 +439,6 @@ or with constant text in a single argument.
           This may be combined with '.', '!', ',', '|', and '*' as above.
 
  %(Spec) processes a specification defined in a specs file as *Spec:
- %[Spec] as above, but put __ around -D arguments
 
 The conditional text X in a %{S:X} or similar construct may contain
 other nested % constructs or spaces, or even newlines.  They are
@@ -660,7 +518,7 @@ proper position among the other output files.  */
 /* XXX: should exactly match hooks provided by libmudflap.a */
 #define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \
  --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\
- --wrap=mmap --wrap=munmap --wrap=alloca\
+ --wrap=mmap --wrap=mmap64 --wrap=munmap --wrap=alloca\
 } %{fmudflapth: --wrap=pthread_create\
 }} %{fmudflap|fmudflapth: --wrap=main}"
 #endif
@@ -668,6 +526,16 @@ proper position among the other output files.  */
 #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
@@ -687,18 +555,6 @@ proper position among the other output files.  */
   "%{!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 ""
@@ -767,6 +623,38 @@ proper position among the other output files.  */
 # endif
 #endif
 
+/* Conditional to test whether the LTO 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 if the linker used understands -plugin.  */
+
+/* The linker has some plugin support.  */
+#if HAVE_LTO_PLUGIN > 0
+/* The linker used has full plugin support, use LTO plugin by default.  */
+#if HAVE_LTO_PLUGIN == 2
+#define PLUGIN_COND "!fno-use-linker-plugin:%{flto|flto=*|fuse-linker-plugin"
+#define PLUGIN_COND_CLOSE "}"
+#else
+/* The linker used has limited plugin support, use LTO plugin with explicit
+   -fuse-linker-plugin.  */
+#define PLUGIN_COND "fuse-linker-plugin"
+#define PLUGIN_COND_CLOSE ""
+#endif
+#define LINK_PLUGIN_SPEC \
+    "%{"PLUGIN_COND": \
+    -plugin %(linker_plugin_file) \
+    -plugin-opt=%(lto_wrapper) \
+    -plugin-opt=-fresolution=%u.res \
+    %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
+    }"PLUGIN_COND_CLOSE
+#else
+/* The linker used doesn't support -plugin, reject -fuse-linker-plugin.  */
+#define LINK_PLUGIN_SPEC "%{fuse-linker-plugin:\
+    %e-fuse-linker-plugin is not supported in this configuration}"
+#endif
+
 
 /* -u* was put back because both BSD and SysV seem to support it.  */
 /* %{static:} simply prevents an error message if the target machine
@@ -774,27 +662,25 @@ proper position among the other output files.  */
 /* 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 %(linker_plugin_file) \
-    -plugin-opt=%(lto_wrapper) \
-    -plugin-opt=-fresolution=%u.res \
-    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}    \
-    %{static:-plugin-opt=-pass-through=-lc}    \
-    } \
-    %{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}}}\
+    %(linker) " \
+    LINK_PLUGIN_SPEC \
+    "%{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)}\
+    %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
+    %(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
@@ -834,18 +720,17 @@ static const char *link_gomp_spec = "";
 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;
 static const char *sysroot_spec = SYSROOT_SPEC;
 static const char *sysroot_suffix_spec = SYSROOT_SUFFIX_SPEC;
 static const char *sysroot_hdrs_suffix_spec = SYSROOT_HEADERS_SUFFIX_SPEC;
+static const char *self_spec = "";
 
 /* Standard options to cpp, cc1, and as, to reduce duplication in specs.
    There should be no need to override these in target dependent files,
@@ -857,20 +742,19 @@ static const char *sysroot_hdrs_suffix_spec = SYSROOT_HEADERS_SUFFIX_SPEC;
    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*:-iplugindir=%:find-file(plugin)}}\
+ %{!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}\
@@ -893,22 +777,23 @@ static const char *cpp_debug_options = "%{d*}";
 /* 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}}\
- %{!iplugindir*:%{fplugin*:-iplugindir=%:find-file(plugin)}}\
- %1 %{!Q:-quiet} %{!dumpbase:-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.  */
@@ -956,9 +841,14 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 #define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
 #endif
 
+/* Likewise for -fgnu-tm.  */
+#ifndef GTM_SELF_SPECS
+#define GTM_SELF_SPECS "%{fgnu-tm: -pthread}"
+#endif
+
 static const char *const driver_self_specs[] = {
   "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
-  DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS
+  DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS, GTM_SELF_SPECS
 };
 
 #ifndef OPTION_DEFAULT_SPECS
@@ -982,25 +872,7 @@ struct user_specs
 
 static struct user_specs *user_specs_head, *user_specs_tail;
 
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
-#endif
-
-#ifndef WORD_SWITCH_TAKES_ARG
-#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
-#endif
 \f
-#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
@@ -1062,29 +934,23 @@ static const struct compiler default_compilers[] =
   {".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},
+  {".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 +964,20 @@ static const struct compiler default_compilers[] =
                %(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 +990,7 @@ static const struct compiler default_compilers[] =
       %{!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,362 +1001,24 @@ static const struct compiler default_compilers[] =
 
 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;
-\f
-/* 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"},
-   {"--dumpdir", "-dumpdir", "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"}
- };
-\f
-
-#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;
 \f
 static char *
 skip_whitespace (char *p)
@@ -1626,10 +1154,15 @@ static const char *multilib_dir;
    set_multilib_dir based on the compilation options.  */
 
 static const char *multilib_os_dir;
+
+/* Subdirectory to use for locating libraries in multiarch conventions.  Set by
+   set_multilib_dir based on the compilation options.  */
+
+static const char *multiarch_dir;
 \f
 /* Structure to keep track of the specs that have been defined so far.
-   These are accessed using %(specname) or %[specname] in a compiler
-   or link spec.  */
+   These are accessed using %(specname) in a compiler or link
+   spec.  */
 
 struct spec_list
 {
@@ -1675,7 +1208,6 @@ static struct spec_list static_specs[] =
   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),
@@ -1688,7 +1220,6 @@ static struct spec_list static_specs[] =
   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),
@@ -1697,6 +1228,7 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("sysroot_spec",             &sysroot_spec),
   INIT_STATIC_SPEC ("sysroot_suffix_spec",     &sysroot_suffix_spec),
   INIT_STATIC_SPEC ("sysroot_hdrs_suffix_spec",        &sysroot_hdrs_suffix_spec),
+  INIT_STATIC_SPEC ("self_spec",               &self_spec),
 };
 
 #ifdef EXTRA_SPECS             /* additional specs needed */
@@ -1724,13 +1256,16 @@ static const struct spec_function static_spec_functions[] =
   { "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
@@ -1869,7 +1404,8 @@ init_spec (void)
                            "-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
@@ -1916,7 +1452,8 @@ init_spec (void)
   }
 #endif
 
-#if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC
+#if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC || \
+    defined LINKER_HASH_STYLE
 # ifdef LINK_BUILDID_SPEC
   /* Prepend LINK_BUILDID_SPEC to whatever link_spec we had before.  */
   obstack_grow (&obstack, LINK_BUILDID_SPEC, sizeof(LINK_BUILDID_SPEC) - 1);
@@ -1925,6 +1462,16 @@ init_spec (void)
   /* Prepend LINK_EH_SPEC to whatever link_spec we had before.  */
   obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1);
 # endif
+# ifdef LINKER_HASH_STYLE
+  /* Prepend --hash-style=LINKER_HASH_STYLE to whatever link_spec we had
+     before.  */
+  {
+    static const char hash_style[] = "--hash-style=";
+    obstack_grow (&obstack, hash_style, sizeof(hash_style) - 1);
+    obstack_grow (&obstack, LINKER_HASH_STYLE, sizeof(LINKER_HASH_STYLE) - 1);
+    obstack_1grow (&obstack, ' ');
+  }
+# endif
   obstack_grow0 (&obstack, link_spec, strlen (link_spec));
   link_spec = XOBFINISH (&obstack, const char *);
 #endif
@@ -1994,19 +1541,15 @@ set_spec (const char *name, const char *spec)
 \f
 /* Accumulate a command (program name and args), and run it.  */
 
-/* Vector of pointers to arguments in the current line of specifications.  */
-
-static const char **argbuf;
+typedef const char *const_char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p,heap);
 
-/* Number of elements allocated in argbuf.  */
-
-static int argbuf_length;
-
-/* Number of elements in argbuf currently in use (containing args).  */
+/* Vector of pointers to arguments in the current line of specifications.  */
 
-static int argbuf_index;
+static VEC(const_char_p,heap) *argbuf;
 
-/* Position in the argbuf array containing the name of the output file
+/* 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;
@@ -2037,18 +1580,13 @@ static int execution_count;
 /* Number of commands that exited with a signal.  */
 
 static int signal_count;
-
-/* Name with which this program was invoked.  */
-
-static const char *programname;
 \f
 /* 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).  */
@@ -2056,7 +1594,7 @@ alloc_args (void)
 static void
 clear_args (void)
 {
-  argbuf_index = 0;
+  VEC_truncate (const_char_p, argbuf, 0);
 }
 
 /* Add one argument to the vector at the end.
@@ -2069,14 +1607,10 @@ clear_args (void)
 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)
     {
       const char *p;
@@ -2293,8 +1827,8 @@ read_specs (const char *filename, int main_p)
 
              for (newsl = specs; newsl; newsl = newsl->next)
                if (strcmp (newsl->name, p2) == 0)
-                 fatal_error ("%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)
@@ -2441,7 +1975,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete)
     {
       struct temp_file *temp;
       for (temp = always_delete_queue; temp; temp = temp->next)
-       if (! strcmp (name, temp->name))
+       if (! filename_cmp (name, temp->name))
          goto already1;
 
       temp = XNEW (struct temp_file);
@@ -2456,7 +1990,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete)
     {
       struct temp_file *temp;
       for (temp = failure_delete_queue; temp; temp = temp->next)
-       if (! strcmp (name, temp->name))
+       if (! filename_cmp (name, temp->name))
          goto already2;
 
       temp = XNEW (struct temp_file);
@@ -2550,6 +2084,7 @@ for_each_path (const struct path_prefix *paths,
   struct prefix_list *pl;
   const char *multi_dir = NULL;
   const char *multi_os_dir = NULL;
+  const char *multiarch_suffix = NULL;
   const char *multi_suffix;
   const char *just_multi_suffix;
   char *path = NULL;
@@ -2567,11 +2102,14 @@ for_each_path (const struct path_prefix *paths,
     }
   if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
     multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
+  if (multiarch_dir)
+    multiarch_suffix = concat (multiarch_dir, dir_separator_str, NULL);
 
   while (1)
     {
       size_t multi_dir_len = 0;
       size_t multi_os_dir_len = 0;
+      size_t multiarch_len = 0;
       size_t suffix_len;
       size_t just_suffix_len;
       size_t len;
@@ -2580,16 +2118,15 @@ for_each_path (const struct path_prefix *paths,
        multi_dir_len = strlen (multi_dir);
       if (multi_os_dir)
        multi_os_dir_len = strlen (multi_os_dir);
+      if (multiarch_suffix)
+       multiarch_len = strlen (multiarch_suffix);
       suffix_len = strlen (multi_suffix);
       just_suffix_len = strlen (just_multi_suffix);
 
       if (path == NULL)
        {
          len = paths->max_len + extra_space + 1;
-         if (suffix_len > multi_os_dir_len)
-           len += suffix_len;
-         else
-           len += multi_os_dir_len;
+         len += MAX (MAX (suffix_len, multi_os_dir_len), multiarch_len);
          path = XNEWVEC (char, len);
        }
 
@@ -2618,6 +2155,16 @@ for_each_path (const struct path_prefix *paths,
                break;
            }
 
+         /* Now try the multiarch path.  */
+         if (!skip_multi_dir
+             && !pl->require_machine_suffix && multiarch_dir)
+           {
+             memcpy (path + len, multiarch_suffix, multiarch_len + 1);
+             ret = callback (path, callback_info);
+             if (ret)
+               break;
+           }
+
          /* Now try the base path.  */
          if (!pl->require_machine_suffix
              && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir))
@@ -2919,13 +2466,21 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
                      int require_machine_suffix, int os_multilib)
 {
   if (!IS_ABSOLUTE_PATH (prefix))
-    fatal_error ("system path '%s' is not absolute", prefix);
+    fatal_error ("system path %qs is not absolute", prefix);
 
   if (target_system_root)
     {
+      char *sysroot_no_trailing_dir_separator = xstrdup (target_system_root);
+      size_t sysroot_len = strlen (target_system_root);
+
+      if (sysroot_len > 0
+         && target_system_root[sysroot_len - 1] == DIR_SEPARATOR)
+       sysroot_no_trailing_dir_separator[sysroot_len - 1] = '\0';
+
       if (target_sysroot_suffix)
          prefix = concat (target_sysroot_suffix, prefix, NULL);
-      prefix = concat (target_system_root, prefix, NULL);
+      prefix = concat (sysroot_no_trailing_dir_separator, prefix, NULL);
+      free (sysroot_no_trailing_dir_separator);
 
       /* We have to override this because GCC's notion of sysroot
         moves along with GCC.  */
@@ -2954,6 +2509,7 @@ execute (void)
     const char *prog;          /* program name.  */
     const char **argv;         /* vector of args.  */
   };
+  const char *arg;
 
   struct command *commands;    /* each command buffer with above info.  */
 
@@ -2961,14 +2517,16 @@ execute (void)
 
   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.  */
@@ -2978,8 +2536,10 @@ execute (void)
      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)
     {
@@ -2987,15 +2547,17 @@ execute (void)
       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_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)
@@ -3003,8 +2565,6 @@ execute (void)
        n_commands++;
       }
 
-  argbuf[argbuf_index] = 0;
-
   /* If -v, print what we are about to do, and maybe query.  */
 
   if (verbose_flag)
@@ -3038,13 +2598,20 @@ execute (void)
                        }
                      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)
@@ -3105,9 +2672,9 @@ execute (void)
 
   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++)
     {
@@ -3146,13 +2713,13 @@ execute (void)
 
     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);
@@ -3178,12 +2745,8 @@ execute (void)
              }
            else
 #endif
-             internal_error ("\
-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)
@@ -3264,10 +2827,11 @@ See %s for instructions.",
    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_IGNORE_PERMANENTLY      0x8
+#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
 {
@@ -3282,6 +2846,8 @@ static struct switchstr *switches;
 
 static int n_switches;
 
+static int n_switches_alloc;
+
 /* Set to zero if -fcompare-debug is disabled, positive if it's
    enabled and we're running the first compilation, negative if it's
    enabled and we're running the second compilation.  For most of the
@@ -3303,6 +2869,8 @@ static struct switchstr *switches_debug_check[2];
 
 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:
@@ -3327,6 +2895,8 @@ static struct infile *infiles;
 
 int n_infiles;
 
+static int n_infiles_alloc;
+
 /* True if multiple input files are being compiled to a single
    assembly file.  */
 
@@ -3401,13 +2971,13 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED,
 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);
   fputs (_("  --help                   Display this information\n"), stdout);
   fputs (_("  --target-help            Display target specific command line options\n"), stdout);
-  fputs (_("  --help={target|optimizers|warnings|params|[^]{joined|separate|undocumented}}[,...]\n"), stdout);
+  fputs (_("  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...]\n"), stdout);
   fputs (_("                           Display specific types of command line options\n"), stdout);
   if (! verbose_flag)
     fputs (_("  (Use '-v --help' to display command line options of sub-processes)\n"), stdout);
@@ -3419,6 +2989,9 @@ display_help (void)
   fputs (_("  -print-libgcc-file-name  Display the name of the compiler's companion library\n"), stdout);
   fputs (_("  -print-file-name=<lib>   Display the full path to library <lib>\n"), stdout);
   fputs (_("  -print-prog-name=<prog>  Display the full path to compiler component <prog>\n"), stdout);
+  fputs (_("\
+  -print-multiarch         Display the target's normalized GNU triplet, used as\n\
+                           a component in the library path\n"), stdout);
   fputs (_("  -print-multi-directory   Display the root directory for versions of libgcc\n"), stdout);
   fputs (_("\
   -print-multi-lib         Display the mapping between command line options and\n\
@@ -3432,7 +3005,6 @@ display_help (void)
   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 (_("\
@@ -3452,6 +3024,8 @@ display_help (void)
   fputs (_("  -S                       Compile only; do not assemble or link\n"), stdout);
   fputs (_("  -c                       Compile and assemble, but do not link\n"), stdout);
   fputs (_("  -o <file>                Place the output into <file>\n"), stdout);
+  fputs (_("  -pie                     Create a position independent executable\n"), stdout);
+  fputs (_("  -shared                  Create a shared library\n"), stdout);
   fputs (_("\
   -x <language>            Specify the language of the following input files\n\
                            Permissible languages include: c c++ assembler none\n\
@@ -3463,7 +3037,7 @@ display_help (void)
 \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.  */
@@ -3472,97 +3046,573 @@ display_help (void)
 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));
 }
 \f
-/* Create the vector `switches' and its contents.
-   Store its length in `n_switches'.  */
+/* Allocate space for an input file in infiles.  */
 
 static void
-process_command (int argc, const char **argv)
+alloc_infile (void)
 {
-  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;
+  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);
+    }
+}
 
-  GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
+/* Store an input file with the given NAME and LANGUAGE in
+   infiles.  */
 
-  n_switches = 0;
-  n_infiles = 0;
-  added_libraries = 0;
+static void
+add_infile (const char *name, const char *language)
+{
+  alloc_infile ();
+  infiles[n_infiles].name = name;
+  infiles[n_infiles++].language = language;
+}
 
-  /* Figure compiler version from version string.  */
+/* Allocate space for a switch in switches.  */
 
-  compiler_version = temp1 = xstrdup (version_string);
+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);
+    }
+}
 
-  for (; *temp1; ++temp1)
+/* 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
     {
-      if (*temp1 == ' ')
-       {
-         *temp1 = '\0';
-         break;
-       }
+      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;
     }
 
-  /* Convert new-style -- options to old-style.  */
-  translate_options (&argc,
-                    CONST_CAST2 (const char *const **, const char ***,
-                                 &argv));
+  switches[n_switches].live_cond = 0;
+  switches[n_switches].validated = validated;
+  switches[n_switches].ordering = 0;
+  n_switches++;
+}
 
-  /* 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.  */
+/* Handle an option DECODED that is unknown to the option-processing
+   machinery.  */
 
-  for (i = 1; i < argc; i++)
+static bool
+driver_unknown_option_callback (const struct cl_decoded_option *decoded)
+{
+  const char *opt = decoded->arg;
+  if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-'
+      && !(decoded->errors & CL_ERR_NEGATIVE))
     {
-      if (! strcmp (argv[i], "-no-canonical-prefixes"))
-       {
+      /* Leave unknown -Wno-* options for the compiler proper, to be
+        diagnosed only if there are warnings.  */
+      save_switch (decoded->canonical_option[0],
+                  decoded->canonical_option_num_elements - 1,
+                  &decoded->canonical_option[1], false);
+      return false;
+    }
+  else
+    return true;
+}
+
+/* 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->cl_reject_driver)
+    error ("unrecognized command line option %qs",
+          decoded->orig_option_with_args_text);
+  else
+    save_switch (decoded->canonical_option[0],
+                decoded->canonical_option_num_elements - 1,
+                &decoded->canonical_option[1], false);
+}
+
+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_multiarch:
+    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->num_handlers = 3;
+  handlers->handlers[0].handler = driver_handle_option;
+  handlers->handlers[0].mask = CL_DRIVER;
+  handlers->handlers[1].handler = common_handle_option;
+  handlers->handlers[1].mask = CL_COMMON;
+  handlers->handlers[2].handler = target_handle_option;
+  handlers->handlers[2].mask = CL_TARGET;
+}
+
+/* Create the vector `switches' and its contents.
+   Store its length in `n_switches'.  */
+
+static void
+process_command (unsigned int decoded_options_count,
+                struct cl_decoded_option *decoded_options)
+{
+  const char *temp;
+  char *temp1;
+  const char *tooldir_prefix;
+  char *(*get_relative_prefix) (const char *, const char *,
+                               const char *) = NULL;
+  struct cl_option_handlers handlers;
+  unsigned int j;
+
+  gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
+
+  n_switches = 0;
+  n_infiles = 0;
+  added_libraries = 0;
+
+  /* Figure compiler version from version string.  */
+
+  compiler_version = temp1 = xstrdup (version_string);
+
+  for (; *temp1; ++temp1)
+    {
+      if (*temp1 == ' ')
+       {
+         *temp1 = '\0';
+         break;
+       }
+    }
+
+  /* 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 (j = 1; j < decoded_options_count; j++)
+    {
+      if (decoded_options[j].opt_index == OPT_no_canonical_prefixes)
+       {
          get_relative_prefix = make_relative_prefix_ignore_links;
          break;
        }
@@ -3571,17 +3621,18 @@ process_command (int argc, const char **argv)
     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)
@@ -3608,12 +3659,11 @@ process_command (int argc, const char **argv)
 #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 (&argc,
-                       CONST_CAST2 (const char *const **, const char ***,
-                                    &argv),
+  lang_specific_driver (&decoded_options, &decoded_options_count,
                        &added_libraries);
 
   if (gcc_exec_prefix)
@@ -3625,9 +3675,9 @@ process_command (int argc, const char **argv)
        {
          temp = gcc_exec_prefix + len - sizeof ("/lib/gcc/") + 1;
          if (IS_DIR_SEPARATOR (*temp)
-             && strncmp (temp + 1, "lib", 3) == 0
+             && filename_ncmp (temp + 1, "lib", 3) == 0
              && IS_DIR_SEPARATOR (temp[4])
-             && strncmp (temp + 5, "gcc", 3) == 0)
+             && filename_ncmp (temp + 5, "gcc", 3) == 0)
            len -= sizeof ("/lib/gcc/") - 1;
        }
 
@@ -3641,7 +3691,7 @@ process_command (int argc, const char **argv)
   /* 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;
@@ -3675,7 +3725,7 @@ process_command (int argc, const char **argv)
        }
     }
 
-  GET_ENVIRONMENT (temp, LIBRARY_PATH_ENV);
+  temp = getenv (LIBRARY_PATH_ENV);
   if (temp && *cross_compile == '0')
     {
       const char *startp, *endp;
@@ -3708,7 +3758,7 @@ process_command (int argc, const char **argv)
     }
 
   /* 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;
@@ -3740,467 +3790,73 @@ process_command (int argc, const char **argv)
        }
     }
 
-  /* 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++)
-    {
-      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;
+  /* Process the options and store input files and switches in their
+     vectors.  */
 
-         /* 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"))
-       {
-         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_error ("argument to '-Xlinker' is missing");
-
-         n_infiles++;
-         i++;
-       }
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to '-Xpreprocessor' is missing");
-
-         add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
-       }
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to '-Xassembler' is missing");
+  last_language_n_infiles = -1;
 
-         add_assembler_option (argv[i+1], strlen (argv[i+1]));
-       }
-      else if (strcmp (argv[i], "-l") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to '-l' is missing");
+  set_option_handlers (&handlers);
 
-         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_error ("'%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++;
-       }
-      else if (strcmp (argv[i], "-specs") == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (++i >= argc)
-           fatal_error ("argument to '-specs' is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i];
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (strlen (argv[i]) == 7)
-           fatal_error ("argument to '-specs=' is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i] + 7;
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (strcmp (argv[i], "-time") == 0)
-       report_times = 1;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
-       {
-         if (report_times_to_file)
-           fclose (report_times_to_file);
-         report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a");
-       }
-      else if (strcmp (argv[i], "-pipe") == 0)
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      switch (decoded_options[j].opt_index)
        {
-         /* -pipe has to go into the switches array as well as
-            setting a flag.  */
-         use_pipes = 1;
-         n_switches++;
+       case OPT_S:
+       case OPT_c:
+       case OPT_E:
+         have_c = 1;
+         break;
        }
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        {
-         if (++i >= argc)
-           fatal_error ("argument to '-wrapper' is missing");
+      if (have_c)
+       break;
+    }
 
-          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)
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      if (decoded_options[j].opt_index == OPT_SPECIAL_input_file)
        {
-         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':
-             {
-               const char *value;
-               int len;
-
-               if (p[1] == 0 && i + 1 == argc)
-                 fatal_error ("argument to '-B' is missing");
-               if (p[1] == 0)
-                 value = argv[++i];
-               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.
@@ -4238,13 +3894,11 @@ process_command (int argc, const char **argv)
        {
          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)
@@ -4297,9 +3951,9 @@ process_command (int argc, const char **argv)
      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)
@@ -4313,259 +3967,12 @@ process_command (int argc, const char **argv)
   /* 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_error ("argument to '-x' is missing");
-             if (p[1] == 0)
-               spec_lang = argv[++i];
-             else
-               spec_lang = p + 1;
-             if (! strcmp (spec_lang, "none"))
-               /* Suppress the warning if -xnone comes after the last input
-                  file, because alternate command interfaces like g++ might
-                  find it useful to place -xnone after each input file.  */
-               spec_lang = 0;
-             else
-               last_language_n_infiles = n_infiles;
-             continue;
-           }
-         switches[n_switches].part1 = p;
-         /* Deal with option arguments in separate argv elements.  */
-         if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
-             || WORD_SWITCH_TAKES_ARG (p))
-           {
-             int j = 0;
-             int n_args = WORD_SWITCH_TAKES_ARG (p);
-
-             if (n_args == 0)
-               {
-                 /* Count only the option arguments in separate argv elements.  */
-                 n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
-               }
-             if (i + n_args >= argc)
-               fatal_error ("argument to '-%s' is missing", p);
-             switches[n_switches].args
-               = XNEWVEC (const char *, n_args + 1);
-             while (j < n_args)
-               switches[n_switches].args[j++] = argv[++i];
-             /* Null-terminate the vector.  */
-             switches[n_switches].args[j] = 0;
-           }
-         else if (strchr (switches_need_spaces, c))
-           {
-             /* On some systems, ld cannot handle some options without
-                a space.  So split the option from its argument.  */
-             char *part1 = XNEWVEC (char, 2);
-             part1[0] = c;
-             part1[1] = '\0';
-
-             switches[n_switches].part1 = part1;
-             switches[n_switches].args = XNEWVEC (const char *, 2);
-             switches[n_switches].args[0] = xstrdup (p+1);
-             switches[n_switches].args[1] = 0;
-           }
-         else
-           switches[n_switches].args = 0;
-
-         switches[n_switches].live_cond = 0;
-         switches[n_switches].validated = 0;
-         switches[n_switches].ordering = 0;
-         /* These are always valid, since gcc.c itself understands the
-            first four, gfortranspec.c understands -static-libgfortran
-            and g++spec.c understands -static-libstdc++ */
-         if (!strcmp (p, "save-temps")
-             || !strcmp (p, "static-libgcc")
-             || !strcmp (p, "shared-libgcc")
-             || !strcmp (p, "pipe")
-             || !strcmp (p, "static-libgfortran")
-             || !strcmp (p, "static-libstdc++"))
-           switches[n_switches].validated = 1;
-         else
-           {
-             char ch = switches[n_switches].part1[0];
-             if (ch == 'B')
-               switches[n_switches].validated = 1;
-           }
-         n_switches++;
-       }
-      else
-       {
-          const char *p = strrchr (argv[i], '@');
-          char *fname;
-         long offset;
-         int consumed;
-#ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
-#endif
-         /* For LTO static archive support we handle input file
-            specifications that are composed of a filename and
-            an offset like FNAME@OFFSET.  */
-         if (p
-             && p != argv[i]
-             && sscanf (p, "@%li%n", &offset, &consumed) >= 1
-             && strlen (p) == (unsigned int)consumed)
-           {
-              fname = (char *)xmalloc (p - argv[i] + 1);
-              memcpy (fname, argv[i], p - argv[i]);
-              fname[p - argv[i]] = '\0';
-             /* Only accept non-stdin and existing FNAME parts, otherwise
-                try with the full name.  */
-             if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
-               {
-                 free (fname);
-                 fname = xstrdup (argv[i]);
-               }
-           }
-         else
-           fname = xstrdup (argv[i]);
-          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
-            {
-              perror_with_name (fname);
-              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)
-    warning (0, "'-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);
@@ -4580,15 +3987,16 @@ process_command (int argc, const char **argv)
   /* 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;
 }
 
@@ -4617,7 +4025,9 @@ set_collect_gcc_options (void)
       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);
@@ -4658,7 +4068,7 @@ set_collect_gcc_options (void)
    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;
@@ -4725,7 +4135,7 @@ end_going_arg (void)
 
          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;
            }
@@ -4750,6 +4160,7 @@ insert_wrapper (const char *wrapper)
   int i;
   char *buf = xstrdup (wrapper);
   char *p = buf;
+  unsigned int old_length = VEC_length (const_char_p, argbuf);
 
   do
     {
@@ -4759,15 +4170,10 @@ insert_wrapper (const char *wrapper)
     }
   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;
@@ -4778,11 +4184,11 @@ insert_wrapper (const char *wrapper)
           *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.
@@ -4799,12 +4205,13 @@ do_spec (const char *spec)
      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 ();
     }
 
@@ -4900,68 +4307,64 @@ do_self_spec (const char *spec)
     if ((switches[i].live_cond & SWITCH_IGNORE))
       switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
 
-  if (argbuf_index > 0)
+  if (VEC_length (const_char_p, argbuf) > 0)
     {
-      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_error ("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);
+           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;
 
-             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_error ("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;
-           }
-         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;
+           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
-           sw->args = 0;
        }
 
+      alloc_switch ();
       switches[n_switches].part1 = 0;
     }
 }
@@ -5060,6 +4463,22 @@ compile_input_file_p (struct infile *infile)
   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
@@ -5080,6 +4499,10 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
   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.  */
@@ -5088,7 +4511,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
       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.
@@ -5099,12 +4523,12 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                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)
@@ -5143,7 +4567,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
        switch (c = *p++)
          {
          case 0:
-           fatal_error ("spec '%s' invalid", spec);
+           fatal_error ("spec %qs invalid", spec);
 
          case 'b':
            if (save_temps_length)
@@ -5292,7 +4716,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    p += 2;
                    /* We don't support extra suffix characters after %O.  */
                    if (*p == '.' || ISALNUM ((unsigned char) *p))
-                     fatal_error ("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
@@ -5333,7 +4757,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    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.,
@@ -5351,7 +4775,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    tmp[basename_length + suffix_length] = '\0';
                    temp_filename = tmp;
 
-                   if (strcmp (temp_filename, input_filename) != 0)
+                   if (filename_cmp (temp_filename, gcc_input_filename) != 0)
                      {
 #ifndef HOST_LACKS_INODE_NUMBERS
                        struct stat st_temp;
@@ -5359,12 +4783,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                        /* 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.  */
@@ -5374,9 +4799,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                            || 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);
+                       bool files_differ = filename_cmp (input_realname, temp_realname);
                        free (input_realname);
                        free (temp_realname);
                        if (files_differ)
@@ -5426,8 +4851,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    t->filename_length = temp_filename_length;
                  }
 
-               if (saved_suffix)
-                 free (saved_suffix);
+               free (saved_suffix);
 
                obstack_grow (&obstack, t->filename, t->filename_length);
                delete_this_arg = 1;
@@ -5476,7 +4900,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              }
            else
              {
-               obstack_grow (&obstack, input_filename, input_filename_length);
+               obstack_grow (&obstack, gcc_input_filename,
+                             input_filename_length);
                arg_going = 1;
              }
            break;
@@ -5494,6 +4919,15 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                  do_spec_1 (" ", 0, NULL);
                }
 
+             if (multiarch_dir)
+               {
+                 do_spec_1 ("-imultiarch", 1, NULL);
+                 /* Make this a separate argument.  */
+                 do_spec_1 (" ", 0, NULL);
+                 do_spec_1 (multiarch_dir, 1, NULL);
+                 do_spec_1 (" ", 0, NULL);
+               }
+
              if (gcc_exec_prefix)
                {
                  do_spec_1 ("-iprefix", 1, NULL);
@@ -5598,18 +5032,18 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
          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_error ("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;
            }
 
@@ -5618,17 +5052,19 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            {
              const char *p1 = p;
              char *string;
+             char *opt;
+             unsigned ix;
 
              /* Skip past the option value and make a copy.  */
              if (*p != '{')
-               fatal_error ("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;
@@ -5641,32 +5077,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
          /* 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
@@ -5783,10 +5204,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
           /* 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++;
@@ -5798,7 +5226,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                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;
                  }
 
@@ -5809,23 +5237,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
          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.
               This feature allows individual machine descriptions
-              to add and use their own specs.
-              %[...] modifies -D options the way %P does;
-              %(...) uses the spec unmodified.  */
-         case '[':
-           warning (0, "use of obsolete %%[ operator in specs");
+              to add and use their own specs.  */
          case '(':
            {
              const char *name = p;
@@ -5834,7 +5259,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
              /* The string after the S/P is the name of a spec that is to be
                 processed.  */
-             while (*p && *p != ')' && *p != ']')
+             while (*p && *p != ')')
                p++;
 
              /* See if it's in the list.  */
@@ -5843,70 +5268,27 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                  {
                    name = *(sl->ptr_spec);
 #ifdef DEBUG_SPECS
-                   fnotice (stderr, "Processing spec %c%s%c, which is '%s'\n",
-                           c, sl->name, (c == '(') ? ')' : ']', name);
+                   fnotice (stderr, "Processing spec (%s), which is '%s'\n",
+                            sl->name, name);
 #endif
                    break;
                  }
 
              if (sl)
                {
-                 if (c == '(')
-                   {
-                     value = do_spec_1 (name, 0, NULL);
-                     if (value != 0)
-                       return value;
-                   }
-                 else
-                   {
-                     char *x = (char *) alloca (strlen (name) * 2 + 1);
-                     char *buf = x;
-                     const char *y = name;
-                     int flag = 0;
-
-                     /* Copy all of NAME into BUF, but put __ after
-                        every -D and at the end of each arg.  */
-                     while (1)
-                       {
-                         if (! strncmp (y, "-D", 2))
-                           {
-                             *x++ = '-';
-                             *x++ = 'D';
-                             *x++ = '_';
-                             *x++ = '_';
-                             y += 2;
-                             flag = 1;
-                             continue;
-                           }
-                         else if (flag
-                                  && (*y == ' ' || *y == '\t' || *y == '='
-                                      || *y == '}' || *y == 0))
-                           {
-                             *x++ = '_';
-                             *x++ = '_';
-                             flag = 0;
-                           }
-                         if (*y == 0)
-                           break;
-                         else
-                           *x++ = *y++;
-                       }
-                     *x = 0;
-
-                     value = do_spec_1 (buf, 0, NULL);
-                     if (value != 0)
-                       return value;
-                   }
+                 value = do_spec_1 (name, 0, NULL);
+                 if (value != 0)
+                   return value;
                }
 
-             /* Discard the closing paren or bracket.  */
+             /* Discard the closing paren.  */
              if (*p)
                p++;
            }
            break;
 
          default:
-           error ("spec failure: unrecognized spec option '%c'", c);
+           error ("spec failure: unrecognized spec option %qc", c);
            break;
          }
        break;
@@ -5953,9 +5335,7 @@ eval_spec_function (const char *func, const char *args)
   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;
@@ -5968,11 +5348,9 @@ eval_spec_function (const char *func, const char *args)
 
   sf = lookup_spec_function (func);
   if (sf == NULL)
-    fatal_error ("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;
@@ -5988,17 +5366,16 @@ eval_spec_function (const char *func, const char *args)
 
   alloc_args ();
   if (do_spec_2 (args) < 0)
-    fatal_error ("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;
@@ -6116,6 +5493,21 @@ switch_matches (const char *atom, const char *end_atom, int starred)
        && check_live_switch (i, plen))
       return true;
 
+    /* Check if a switch with separated form matching the atom.
+       We check -D and -U switches. */
+    else if (switches[i].args != 0)
+      {
+       if ((*switches[i].part1 == 'D' || *switches[i].part1 == 'U')
+           && *switches[i].part1 == atom[0])
+         {
+           if (!strncmp (switches[i].args[0], &atom[1], len - 1)
+               && (starred || (switches[i].part1[1] == '\0'
+                               && switches[i].args[0][len - 1] == '\0'))
+               && check_live_switch (i, (starred ? 1 : -1)))
+             return true;
+         }
+      }
+
   return false;
 }
 
@@ -6305,7 +5697,7 @@ handle_braces (const char *p)
   return p;
 
  invalid:
-  fatal_error ("braced spec '%s' is invalid at '%c'", orig, *p);
+  fatal_error ("braced spec %qs is invalid at %qc", orig, *p);
 
 #undef SKIP_WHITE
 }
@@ -6393,7 +5785,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom,
   return p;
 
  invalid:
-  fatal_error ("braced spec body '%s' is invalid", body);
+  fatal_error ("braced spec body %qs is invalid", body);
 }
 \f
 /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
@@ -6564,11 +5956,11 @@ is_directory (const char *path1, bool linker)
   if (linker
       && IS_DIR_SEPARATOR (path[0])
       && ((cp - path == 6
-          && strncmp (path + 1, "lib", 3) == 0)
+          && filename_ncmp (path + 1, "lib", 3) == 0)
          || (cp - path == 10
-             && strncmp (path + 1, "usr", 3) == 0
+             && filename_ncmp (path + 1, "usr", 3) == 0
              && IS_DIR_SEPARATOR (path[4])
-             && strncmp (path + 5, "lib", 3) == 0)))
+             && filename_ncmp (path + 5, "lib", 3) == 0)))
     return 0;
 
   return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
@@ -6582,9 +5974,9 @@ set_input (const char *filename)
 {
   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.  */
@@ -6602,7 +5994,7 @@ set_input (const char *filename)
     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;
 }
@@ -6643,7 +6035,7 @@ compare_files (char *cmpfile[])
        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;
          }
@@ -6653,7 +6045,7 @@ compare_files (char *cmpfile[])
 
     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;
       }
 
@@ -6664,7 +6056,7 @@ compare_files (char *cmpfile[])
          if (fd < 0)
            {
              error ("%s: could not open compare-debug file %s",
-                    input_filename, cmpfile[i]);
+                    gcc_input_filename, cmpfile[i]);
              ret = 1;
              break;
            }
@@ -6683,7 +6075,7 @@ compare_files (char *cmpfile[])
       {
        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;
          }
       }
@@ -6705,7 +6097,7 @@ compare_files (char *cmpfile[])
       if (!temp[i])
        {
          error ("%s: could not open compare-debug file %s",
-                input_filename, cmpfile[i]);
+                gcc_input_filename, cmpfile[i]);
          ret = 1;
          break;
        }
@@ -6721,7 +6113,7 @@ compare_files (char *cmpfile[])
        if (c0 != c1)
          {
            error ("%s: -fcompare-debug failure",
-                  input_filename);
+                  gcc_input_filename);
            ret = 1;
            break;
          }
@@ -6751,9 +6143,12 @@ main (int argc, char **argv)
   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.  */
@@ -6762,9 +6157,9 @@ main (int argc, char **argv)
   p = argv[0] + strlen (argv[0]);
   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
     --p;
-  programname = p;
+  progname = p;
 
-  xmalloc_set_program_name (programname);
+  xmalloc_set_program_name (progname);
 
   expandargv (&argc, &argv);
 
@@ -6772,7 +6167,16 @@ main (int argc, char **argv)
   if (argv != old_argv)
     at_file_supplied = true;
 
-  prune_options (&argc, &argv);
+  /* Register the language-independent parameters.  */
+  global_init_params ();
+  finish_params ();
+
+  init_options_struct (&global_options, &global_options_set);
+
+  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.  */
@@ -6784,6 +6188,10 @@ main (int argc, char **argv)
 
   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_signal);
 #ifdef SIGHUP
@@ -6802,6 +6210,10 @@ main (int argc, char **argv)
   signal (SIGCHLD, SIG_DFL);
 #endif
 
+  /* Parsing and gimplification sometimes need quite large stack.
+     Increase stack size limits if possible.  */
+  stack_limit_increase (64 * 1024 * 1024);
+
   /* Allocate the argument vector.  */
   alloc_args ();
 
@@ -6858,7 +6270,7 @@ main (int argc, char **argv)
      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.  */
@@ -6903,43 +6315,6 @@ main (int argc, char **argv)
   for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++)
     do_self_spec (driver_self_specs[i]);
 
-  if (compare_debug)
-    {
-      enum save_temps save;
-
-      if (!compare_debug_second)
-       {
-         n_switches_debug_check[1] = n_switches;
-         switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
-                                            n_switches + 1);
-
-         do_self_spec ("%:compare-debug-self-opt()");
-         n_switches_debug_check[0] = n_switches;
-         switches_debug_check[0] = switches;
-
-         n_switches = n_switches_debug_check[1];
-         switches = switches_debug_check[1];
-       }
-
-      /* Avoid crash when computing %j in this early.  */
-      save = save_temps_flag;
-      save_temps_flag = SAVE_TEMPS_NONE;
-
-      compare_debug = -compare_debug;
-      do_self_spec ("%:compare-debug-self-opt()");
-
-      save_temps_flag = save;
-
-      if (!compare_debug_second)
-       {
-         n_switches_debug_check[1] = n_switches;
-         switches_debug_check[1] = switches;
-         compare_debug = -compare_debug;
-         n_switches = n_switches_debug_check[0];
-         switches = switches_debug_check[0];
-       }
-    }
-
   /* If not cross-compiling, look for executables in the standard
      places.  */
   if (*cross_compile == '0')
@@ -6955,10 +6330,10 @@ main (int argc, char **argv)
   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
@@ -6978,10 +6353,10 @@ main (int argc, char **argv)
   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.  */
@@ -6989,9 +6364,10 @@ main (int argc, char **argv)
       && 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
@@ -7048,6 +6424,58 @@ main (int argc, char **argv)
       read_specs (filename ? filename : uptr->filename, FALSE);
     }
 
+  /* Process any user self specs.  */
+  {
+    struct spec_list *sl;
+    for (sl = specs; sl; sl = sl->next)
+      if (sl->name_len == sizeof "self_spec" - 1
+         && !strcmp (sl->name, "self_spec"))
+       do_self_spec (*sl->ptr_spec);
+  }
+
+  if (compare_debug)
+    {
+      enum save_temps save;
+
+      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_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];
+       }
+
+      /* Avoid crash when computing %j in this early.  */
+      save = save_temps_flag;
+      save_temps_flag = SAVE_TEMPS_NONE;
+
+      compare_debug = -compare_debug;
+      do_self_spec ("%:compare-debug-self-opt()");
+
+      save_temps_flag = save;
+
+      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];
+       }
+    }
+
+
   /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
   if (gcc_exec_prefix)
     gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
@@ -7063,7 +6491,7 @@ main (int argc, char **argv)
   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);
@@ -7072,9 +6500,15 @@ main (int argc, char **argv)
 
   /* 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)
+  if (have_c)
+    lto_wrapper_file = NULL;
+  else
+    lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper",
+                                   X_OK, false);
+  if (lto_wrapper_file)
     {
+      lto_wrapper_file = convert_white_space (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);
@@ -7087,7 +6521,7 @@ main (int argc, char **argv)
 
   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.  */
 
@@ -7131,6 +6565,15 @@ main (int argc, char **argv)
       return (0);
     }
 
+  if (print_multiarch)
+    {
+      if (multiarch_dir == NULL)
+       printf ("\n");
+      else
+       printf ("%s\n", multiarch_dir);
+      return (0);
+    }
+
   if (print_sysroot)
     {
       if (target_system_root)
@@ -7189,9 +6632,9 @@ main (int argc, char **argv)
 
   if (print_version)
     {
-      printf (_("%s %s%s\n"), programname, pkgversion_string,
+      printf (_("%s %s%s\n"), progname, pkgversion_string,
              version_string);
-      printf ("Copyright %s 2010 Free Software Foundation, Inc.\n",
+      printf ("Copyright %s 2012 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"),
@@ -7249,6 +6692,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
   if (n_infiles == added_libraries)
     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.  */
 
@@ -7260,10 +6706,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
   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++)
     {
@@ -7296,63 +6739,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
     }
 
   if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
-   fatal_error ("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_error ("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++)
     {
@@ -7368,16 +6755,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
       /* 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)
        {
@@ -7386,19 +6770,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
          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
            {
              if (compare_debug)
                {
-                 if (debug_check_temp_file[0])
-                   free (debug_check_temp_file[0]);
+                 free (debug_check_temp_file[0]);
                  debug_check_temp_file[0] = NULL;
 
-                 if (debug_check_temp_file[1])
-                   free (debug_check_temp_file[1]);
+                 free (debug_check_temp_file[1]);
                  debug_check_temp_file[1] = NULL;
                }
 
@@ -7413,12 +6795,14 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
                  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)
@@ -7428,8 +6812,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                    }
 
                  gcc_assert (debug_check_temp_file[1]
-                             && strcmp (debug_check_temp_file[0],
-                                        debug_check_temp_file[1]));
+                             && filename_cmp (debug_check_temp_file[0],
+                                              debug_check_temp_file[1]));
 
                  if (verbose_flag)
                    inform (0, "comparing final insns dumps");
@@ -7440,12 +6824,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
              if (compare_debug)
                {
-                 if (debug_check_temp_file[0])
-                   free (debug_check_temp_file[0]);
+                 free (debug_check_temp_file[0]);
                  debug_check_temp_file[0] = NULL;
 
-                 if (debug_check_temp_file[1])
-                   free (debug_check_temp_file[1]);
+                 free (debug_check_temp_file[1]);
                  debug_check_temp_file[1] = NULL;
                }
            }
@@ -7463,7 +6845,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
       if (this_file_error)
        {
          delete_failure_queue ();
-         error_count++;
+         errorcount++;
        }
       /* If this compilation succeeded, don't delete those files later.  */
       clear_failure_queue ();
@@ -7478,20 +6860,21 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
       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.  */
@@ -7502,34 +6885,50 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
   /* 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;
-      const char *fuse_linker_plugin = "fuse-linker-plugin";
 
-      /* We'll use ld if we can't find collect2.  */
-      if (! strcmp (linker_name_spec, "collect2"))
+      if (! have_c)
        {
-         char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
-         if (s == NULL)
-           linker_name_spec = "ld";
-       }
+#if HAVE_LTO_PLUGIN > 0
+#if HAVE_LTO_PLUGIN == 2
+         const char *fno_use_linker_plugin = "fno-use-linker-plugin";
+#else
+         const char *fuse_linker_plugin = "fuse-linker-plugin";
+#endif
+#endif
 
-      if (switch_matches (fuse_linker_plugin,
-                         fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
-       {
-         linker_plugin_file_spec = find_a_file (&exec_prefixes,
-                                                "liblto_plugin.so", R_OK,
-                                                false);
-         if (!linker_plugin_file_spec)
-           fatal_error ("-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_error ("could not find libgcc.a");
+         /* We'll use ld if we can't find collect2.  */
+         if (! strcmp (linker_name_spec, "collect2"))
+           {
+             char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
+             if (s == NULL)
+               linker_name_spec = "ld";
+           }
+
+#if HAVE_LTO_PLUGIN > 0
+#if HAVE_LTO_PLUGIN == 2
+         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
+           {
+             char *temp_spec = find_a_file (&exec_prefixes,
+                                            LTOPLUGINSONAME, R_OK,
+                                            false);
+             if (!temp_spec)
+               fatal_error ("-fuse-linker-plugin, but %s not found",
+                            LTOPLUGINSONAME);
+             linker_plugin_file_spec = convert_white_space (temp_spec);
+           }
+#endif
+         lto_gcc_spec = argv[0];
        }
-      lto_gcc_spec = argv[0];
 
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
         for collect.  */
@@ -7545,14 +6944,14 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
        }
       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] == '*'))
@@ -7561,7 +6960,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
   /* Delete some or all of the temporary files we made.  */
 
-  if (error_count)
+  if (seen_error ())
     delete_failure_queue ();
   delete_temp_files ();
 
@@ -7571,8 +6970,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
       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);
 }
 
@@ -7667,103 +7067,7 @@ pfatal_with_name (const char *name)
 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)
-{
-  internal_error ("internal gcc abort in %s, at %s:%d", func, file, line);
-}
-\f
-/* Output an error message and exit.  */
-
-void
-internal_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");
-  delete_temp_files ();
-  exit (pass_exit_codes ? ICE_EXIT_CODE : 1);
-}
-
-void
-fatal_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");
-  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);
-  error_count++;
-  fprintf (stderr, "%s: %s", programname, _("error: "));
-  vfprintf (stderr, _(gmsgid), ap);
-  va_end (ap);
-
-  fprintf (stderr, "\n");
-}
-
-void
-warning (int dummy ATTRIBUTE_UNUSED, const char *gmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, gmsgid);
-  fprintf (stderr, "%s: %s", programname, _("warning: "));
-  vfprintf (stderr, _(gmsgid), ap);
-  va_end (ap);
-
-  fprintf (stderr, "\n");
-}
-
-static void
-inform (int dummy ATTRIBUTE_UNUSED, const char *gmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, gmsgid);
-  fprintf (stderr, "%s: %s", programname, _("note: "));
-  vfprintf (stderr, _(gmsgid), ap);
-  va_end (ap);
-
-  fprintf (stderr, "\n");
-}
-
-static void
-fnotice (FILE *fp, const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  vfprintf (fp, _(cmsgid), ap);
-  va_end (ap);
+  error ("%s: %m", name);
 }
 \f
 static inline void
@@ -7918,7 +7222,7 @@ used_arg (const char *p, int len)
              if (*q == '\0')
                {
                invalid_matches:
-                 fatal_error ("multilib spec '%s' is invalid",
+                 fatal_error ("multilib spec %qs is invalid",
                               multilib_matches);
                }
              q++;
@@ -8041,7 +7345,9 @@ default_arg (const char *p, int len)
    options are present, then we will ignore this completely. Passing
    that, gcc will consider each multilib_select in turn using the same
    rules for matching the options. If a match is found, that subdirectory
-   will be used.  */
+   will be used.
+   A subdirectory name is optionally followed by a colon and the corresponding
+   multiarch name.  */
 
 static void
 set_multilib_dir (void)
@@ -8110,7 +7416,7 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_exclusions:
-             fatal_error ("multilib exclusions '%s' is invalid",
+             fatal_error ("multilib exclusions %qs is invalid",
                           multilib_exclusions);
            }
 
@@ -8168,7 +7474,7 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal_error ("multilib select '%s' is invalid",
+             fatal_error ("multilib select %qs is invalid",
                           multilib_select);
            }
          ++p;
@@ -8253,10 +7559,25 @@ set_multilib_dir (void)
            q++;
          if (q < end)
            {
-             char *new_multilib_os_dir = XNEWVEC (char, end - q);
-             memcpy (new_multilib_os_dir, q + 1, end - q - 1);
-             new_multilib_os_dir[end - q - 1] = '\0';
-             multilib_os_dir = new_multilib_os_dir;
+             const char *q2 = q + 1, *ml_end = end;
+             char *new_multilib_os_dir;
+
+             while (q2 < end && *q2 != ':')
+               q2++;
+             if (*q2 == ':')
+               ml_end = q2;
+             new_multilib_os_dir = XNEWVEC (char, ml_end - q);
+             memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
+             new_multilib_os_dir[ml_end - q - 1] = '\0';
+             multilib_os_dir = *new_multilib_os_dir ? new_multilib_os_dir : ".";
+
+             if (q2 < end && *q2 == ':')
+               {
+                 char *new_multiarch_dir = XNEWVEC (char, end - q2);
+                 memcpy (new_multiarch_dir, q2 + 1, end - q2 - 1);
+                 new_multiarch_dir[end - q2 - 1] = '\0';
+                 multiarch_dir = new_multiarch_dir;
+               }
              break;
            }
        }
@@ -8309,16 +7630,17 @@ print_multilib_info (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal_error ("multilib select '%s' is invalid", multilib_select);
+             fatal_error ("multilib select %qs is invalid", multilib_select);
            }
 
          ++p;
        }
 
       /* When --disable-multilib was used but target defines
-        MULTILIB_OSDIRNAMES, entries starting with .: are there just
-        to find multilib_os_dir, so skip them from output.  */
-      if (this_path[0] == '.' && this_path[1] == ':')
+        MULTILIB_OSDIRNAMES, entries starting with .: (and not starting
+         with .:: for multiarch configurations) are there just to find
+         multilib_os_dir, so skip them from output.  */
+      if (this_path[0] == '.' && this_path[1] == ':' && this_path[2] != ':')
        skip = 1;
 
       /* Check for matches with the multilib_exclusions. We don't bother
@@ -8347,7 +7669,7 @@ print_multilib_info (void)
                if (*e == '\0')
                  {
                  invalid_exclusion:
-                   fatal_error ("multilib exclusion '%s' is invalid",
+                   fatal_error ("multilib exclusion %qs is invalid",
                                 multilib_exclusions);
                  }
 
@@ -8419,7 +7741,7 @@ print_multilib_info (void)
          /* If this is a duplicate, skip it.  */
          skip = (last_path != 0
                  && (unsigned int) (p - this_path) == last_path_len
-                 && ! strncmp (last_path, this_path, last_path_len));
+                 && ! filename_ncmp (last_path, this_path, last_path_len));
 
          last_path = this_path;
          last_path_len = p - this_path;
@@ -8553,7 +7875,7 @@ getenv_spec_function (int argc, const char **argv)
 
   value = getenv (argv[0]);
   if (!value)
-    fatal_error ("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
@@ -8623,12 +7945,33 @@ replace_outfile_spec_function (int argc, const char **argv)
 
   for (i = 0; i < n_infiles; i++)
     {
-      if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+      if (outfiles[i] && !filename_cmp (outfiles[i], argv[0]))
        outfiles[i] = xstrdup (argv[1]);
     }
   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] && !filename_cmp (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))*
@@ -8644,12 +7987,12 @@ compare_version_strings (const char *v1, const char *v2)
     abort ();
   rresult = regexec (&r, v1, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal_error ("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_error ("invalid version number `%s'", v2);
+    fatal_error ("invalid version number %qs", v2);
   else if (rresult != 0)
     abort ();
 
@@ -8739,7 +8082,7 @@ version_compare_spec_function (int argc, const char **argv)
       break;
 
     default:
-      fatal_error ("unknown operator '%s' in %%:version-compare", argv[0]);
+      fatal_error ("unknown operator %qs in %%:version-compare", argv[0]);
     }
   if (! result)
     return NULL;
@@ -8766,11 +8109,11 @@ include_spec_function (int argc, const char **argv)
   return NULL;
 }
 
-/* %:find-file spec function.  This function replace its argument by
+/* %: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)
+find_file_spec_function (int argc, const char **argv)
 {
   const char *file;
 
@@ -8782,6 +8125,22 @@ find_file_spec_function (int argc, const char**argv)
 }
 
 
+/* %: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.  */
 
@@ -8795,12 +8154,22 @@ print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
   return NULL;
 }
 
-/* Compute a timestamp to initialize flag_random_seed.  */
+/* Get a random number for -frandom-seed */
 
-static unsigned
-get_local_tick (void)
+static unsigned HOST_WIDE_INT
+get_random_number (void)
 {
-  unsigned ret = 0;
+  unsigned HOST_WIDE_INT ret = 0;
+  int fd; 
+
+  fd = open ("/dev/urandom", O_RDONLY); 
+  if (fd >= 0)
+    {
+      read (fd, &ret, sizeof (HOST_WIDE_INT));
+      close (fd);
+      if (ret)
+        return ret;
+    }
 
   /* Get some more or less random data.  */
 #ifdef HAVE_GETTIMEOFDAY
@@ -8819,7 +8188,7 @@ get_local_tick (void)
   }
 #endif
 
-  return ret;
+  return ret ^ getpid();
 }
 
 /* %:compare-debug-dump-opt spec function.  Save the last argument,
@@ -8841,19 +8210,20 @@ compare_debug_dump_opt_spec_function (int arg,
   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";
@@ -8865,9 +8235,9 @@ compare_debug_dump_opt_spec_function (int arg,
 
       do_spec_1 (" ", 0, NULL);
 
-      gcc_assert (argbuf_index > 0);
+      gcc_assert (VEC_length (const_char_p, argbuf) > 0);
 
-      name = concat (argbuf[argbuf_index - 1], ext, NULL);
+      name = concat (VEC_last (const_char_p, argbuf), ext, NULL);
 
       ret = concat ("-fdump-final-insns=", name, NULL);
     }
@@ -8877,7 +8247,7 @@ compare_debug_dump_opt_spec_function (int arg,
 
   if (!which)
     {
-      unsigned HOST_WIDE_INT value = get_local_tick () ^ getpid ();
+      unsigned HOST_WIDE_INT value = get_random_number ();
 
       sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value);
     }
@@ -8911,9 +8281,9 @@ compare_debug_self_opt_spec_function (int arg,
   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;
@@ -8966,3 +8336,94 @@ compare_debug_auxbase_opt_spec_function (int arg,
 
   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;
+}
+
+/* Insert backslash before spaces in ORIG (usually a file path), to 
+   avoid being broken by spec parser.
+
+   This function is needed as do_spec_1 treats white space (' ' and '\t')
+   as the end of an argument. But in case of -plugin /usr/gcc install/xxx.so,
+   the file name should be treated as a single argument rather than being
+   broken into multiple. Solution is to insert '\\' before the space in a 
+   file name.
+   
+   This function converts and only converts all occurrence of ' ' 
+   to '\\' + ' ' and '\t' to '\\' + '\t'.  For example:
+   "a b"  -> "a\\ b"
+   "a  b" -> "a\\ \\ b"
+   "a\tb" -> "a\\\tb"
+   "a\\ b" -> "a\\\\ b"
+
+   orig: input null-terminating string that was allocated by xalloc. The
+   memory it points to might be freed in this function. Behavior undefined
+   if ORIG wasn't xalloced or was freed already at entry.
+
+   Return: ORIG if no conversion needed. Otherwise a newly allocated string
+   that was converted from ORIG.  */
+
+static char *
+convert_white_space (char *orig)
+{
+  int len, number_of_space = 0;
+
+  for (len = 0; orig[len]; len++)
+    if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+
+  if (number_of_space)
+    {
+      char *new_spec = (char *) xmalloc (len + number_of_space + 1);
+      int j, k;
+      for (j = 0, k = 0; j <= len; j++, k++)
+       {
+         if (orig[j] == ' ' || orig[j] == '\t')
+           new_spec[k++] = '\\';
+         new_spec[k] = orig[j];
+       }
+      free (orig);
+      return new_spec;
+  }
+  else
+    return orig;
+}