OSDN Git Service

IA64 uses // instead of # for comments in its assembly file.
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 5f857fa..6a0dae5 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,6 +1,7 @@
 /* Compiler driver program that can handle many languages.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -81,6 +82,7 @@ compilation is specified by a string called a "spec".  */
 #include "intl.h"
 #include "prefix.h"
 #include "gcc.h"
+#include "diagnostic.h"
 #include "flags.h"
 #include "opts.h"
 
@@ -261,11 +263,11 @@ static int use_pipes;
 
 static const char *compiler_version;
 
-/* The target version specified with -V */
+/* The target version */
 
 static const char *const spec_version = DEFAULT_TARGET_VERSION;
 
-/* The target machine specified with -b.  */
+/* The target machine.  */
 
 static const char *spec_machine = DEFAULT_TARGET_MACHINE;
 
@@ -278,27 +280,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;
@@ -377,8 +358,6 @@ static int default_arg (const char *, int);
 static void set_multilib_dir (void);
 static void print_multilib_info (void);
 static void perror_with_name (const char *);
-static void fatal_ice (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
-static void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
 static void display_help (void);
 static void add_preprocessor_option (const char *, int);
 static void add_assembler_option (const char *, int);
@@ -387,7 +366,7 @@ static void process_command (int, const char **);
 static int execute (void);
 static void alloc_args (void);
 static void clear_args (void);
-static void fatal_error (int);
+static void fatal_signal (int);
 #if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
 static void init_gcc_specs (struct obstack *, const char *, const char *,
                            const char *);
@@ -402,6 +381,8 @@ static const char *if_exists_else_spec_function (int, const char **);
 static const char *replace_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 **);
@@ -427,7 +408,7 @@ or with constant text in a single argument.
  %b     substitute the basename of the input file being processed.
        This is the substring up to (and not including) the last period
        and not including the directory unless -save-temps was specified
-       to put temporaries in a different location.     
+       to put temporaries in a different location.
  %B    same as %b, but include the file suffix (text after the last period).
  %gSUFFIX
        substitute a file name that has suffix SUFFIX and is chosen
@@ -564,7 +545,7 @@ or with constant text in a single argument.
  %{!.S:X} substitutes X, if NOT processing a file with suffix S.
  %{,S:X}  substitutes X, if processing a file which will use spec S.
  %{!,S:X} substitutes X, if NOT processing a file which will use spec S.
-         
+
  %{S|T:X} substitutes X if either -S or -T was given to GCC.  This may be
          combined with '!', '.', ',', and '*' as above binding stronger
          than the OR.
@@ -683,12 +664,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.  */
-#ifndef SWITCHES_NEED_SPACES
-#define SWITCHES_NEED_SPACES ""
-#endif
-
 /* config.h can define ENDFILE_SPEC to override the default crtn files.  */
 #ifndef ENDFILE_SPEC
 #define ENDFILE_SPEC ""
@@ -764,10 +739,21 @@ 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
+   to understand them.  In practice, this means it had better be collect2.  */
 #ifndef LINK_COMMAND_SPEC
 #define LINK_COMMAND_SPEC "\
 %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
-    %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
+    %(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}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
     %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
@@ -813,8 +799,11 @@ 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;
@@ -838,13 +827,13 @@ static const char *trad_capable_cpp =
    therefore no dependency entry, confuses make into thinking a .o
    file that happens to exist is up-to-date.  */
 static const char *cpp_unique_options =
-"%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}}\
- %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
+"%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
  %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\
  %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
  %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
  %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
  %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\
@@ -867,7 +856,8 @@ 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}}\
- %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
+ %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{a*}\
  %{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}\
@@ -891,11 +881,15 @@ static const char *asm_options =
 
 static const char *invoke_as =
 #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
-"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
- %{!S:-o %|.s |\n as %(asm_options) %|.s %A }";
+"%{!fwpa:\
+   %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
+   %{!S:-o %|.s |\n as %(asm_options) %|.s %A }\
+  }";
 #else
-"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
- %{!S:-o %|.s |\n as %(asm_options) %m.s %A }";
+"%{!fwpa:\
+   %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
+   %{!S:-o %|.s |\n as %(asm_options) %m.s %A }\
+  }";
 #endif
 
 /* Some compilers have limits on line lengths, and the multilib_select
@@ -926,7 +920,8 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 #endif
 
 static const char *const driver_self_specs[] = {
-  DRIVER_SELF_SPECS, GOMP_SELF_SPECS
+  "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
+  DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS
 };
 
 #ifndef OPTION_DEFAULT_SPECS
@@ -961,7 +956,7 @@ static struct user_specs *user_specs_head, *user_specs_tail;
 #ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
 /* This defines which switches stop a full compilation.  */
 #define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
-  ((CHAR) == 'c' || (CHAR) == 'S')
+  ((CHAR) == 'c' || (CHAR) == 'S' || (CHAR) == 'E')
 
 #ifndef SWITCH_CURTAILS_COMPILATION
 #define SWITCH_CURTAILS_COMPILATION(CHAR) \
@@ -1066,12 +1061,12 @@ 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},
+                    %{!fdump-ada-spec*:-o %g.s %{!o*:--output-pch=%i.gch}\
+                    %W{o*:--output-pch=%*}}%V}}}}}}", 0, 0, 0},
   {".i", "@cpp-output", 0, 1, 0},
   {"@cpp-output",
    "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0},
@@ -1159,6 +1154,7 @@ static const struct option_map option_map[] =
    {"--dependencies", "-M", 0},
    {"--dump", "-d", "a"},
    {"--dumpbase", "-dumpbase", "a"},
+   {"--dumpdir", "-dumpdir", "a"},
    {"--encoding", "-fencoding=", "aj"},
    {"--entry", "-e", 0},
    {"--extra-warnings", "-W", 0},
@@ -1367,7 +1363,7 @@ translate_options (int *argcp, const char *const **argvp)
 
                  else if (strchr (arginfo, '*') != 0)
                    {
-                     error ("incomplete '%s' option", option_map[j].name);
+                     error ("incomplete %qs option", option_map[j].name);
                      break;
                    }
 
@@ -1378,7 +1374,7 @@ translate_options (int *argcp, const char *const **argvp)
                        {
                          if (i + 1 == argc)
                            {
-                             error ("missing argument to '%s' option",
+                             error ("missing argument to %qs option",
                                     option_map[j].name);
                              break;
                            }
@@ -1391,7 +1387,7 @@ translate_options (int *argcp, const char *const **argvp)
                  else if (strchr (arginfo, 'o') == 0)
                    {
                      if (arg != 0)
-                       error ("extraneous argument to '%s' option",
+                       error ("extraneous argument to %qs option",
                               option_map[j].name);
                      arg = 0;
                    }
@@ -1449,7 +1445,7 @@ translate_options (int *argcp, const char *const **argvp)
            }
        }
       else
-       /* Ordinary operands, or +e options.  */
+       /* Ordinary operands.  */
        newv[newindex++] = argv[i++];
     }
 
@@ -1642,7 +1638,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),
@@ -1652,6 +1647,10 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("multilib_exclusions",     &multilib_exclusions),
   INIT_STATIC_SPEC ("multilib_options",                &multilib_options),
   INIT_STATIC_SPEC ("linker",                  &linker_name_spec),
+  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),
@@ -1689,6 +1688,8 @@ static const struct spec_function static_spec_functions[] =
   { "replace-outfile",         replace_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 },
@@ -1759,7 +1760,7 @@ init_spec (void)
     return;                    /* Already initialized.  */
 
   if (verbose_flag)
-    notice ("Using built-in specs.\n");
+    fnotice (stderr, "Using built-in specs.\n");
 
 #ifdef EXTRA_SPECS
   extra_specs = XCNEWVEC (struct spec_list, ARRAY_SIZE (extra_specs_1));
@@ -1944,7 +1945,7 @@ set_spec (const char *name, const char *spec)
 
 #ifdef DEBUG_SPECS
   if (verbose_flag)
-    notice ("Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
+    fnotice (stderr, "Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
 #endif
 
   /* Free the old spec.  */
@@ -1973,7 +1974,7 @@ static int argbuf_index;
 
 static int have_o_argbuf_index = 0;
 
-/* Were the options -c or -S passed.  */
+/* Were the options -c, -S or -E passed.  */
 static int have_c = 0;
 
 /* Was the option -o passed.  */
@@ -1999,10 +2000,6 @@ 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.  */
 
@@ -2040,7 +2037,15 @@ store_arg (const char *arg, int delete_always, int delete_failure)
   if (strcmp (arg, "-o") == 0)
     have_o_argbuf_index = argbuf_index;
   if (delete_always || delete_failure)
-    record_temp_file (arg, delete_always, delete_failure);
+    {
+      const char *p;
+      /* If the temporary file we should delete is specified as
+        part of a joined argument extract the filename.  */
+      if (arg[0] == '-'
+         && (p = strrchr (arg, '=')))
+       arg = p + 1;
+      record_temp_file (arg, delete_always, delete_failure);
+    }
 }
 \f
 /* Load specs from a file name named FILENAME, replacing occurrences of
@@ -2059,7 +2064,7 @@ load_specs (const char *filename)
   char *specs_p;
 
   if (verbose_flag)
-    notice ("Reading specs from %s\n", filename);
+    fnotice (stderr, "Reading specs from %s\n", filename);
 
   /* Open and stat the file.  */
   desc = open (filename, O_RDONLY, 0);
@@ -2155,8 +2160,9 @@ read_specs (const char *filename, int main_p)
                p1++;
 
              if (*p1++ != '<' || p[-2] != '>')
-               fatal ("specs %%include syntax malformed after %ld characters",
-                      (long) (p1 - buffer + 1));
+               fatal_error ("specs %%include syntax malformed after "
+                            "%ld characters",
+                            (long) (p1 - buffer + 1));
 
              p[-2] = '\0';
              new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
@@ -2174,15 +2180,16 @@ read_specs (const char *filename, int main_p)
                p1++;
 
              if (*p1++ != '<' || p[-2] != '>')
-               fatal ("specs %%include syntax malformed after %ld characters",
-                      (long) (p1 - buffer + 1));
+               fatal_error ("specs %%include syntax malformed after "
+                            "%ld characters",
+                            (long) (p1 - buffer + 1));
 
              p[-2] = '\0';
              new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
              if (new_filename)
                read_specs (new_filename, FALSE);
              else if (verbose_flag)
-               notice ("could not find specs file %s\n", p1);
+               fnotice (stderr, "could not find specs file %s\n", p1);
              continue;
            }
          else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
@@ -2199,16 +2206,18 @@ read_specs (const char *filename, int main_p)
                p1++;
 
              if (! ISALPHA ((unsigned char) *p1))
-               fatal ("specs %%rename syntax malformed after %ld characters",
-                      (long) (p1 - buffer));
+               fatal_error ("specs %%rename syntax malformed after "
+                            "%ld characters",
+                            (long) (p1 - buffer));
 
              p2 = p1;
              while (*p2 && !ISSPACE ((unsigned char) *p2))
                p2++;
 
              if (*p2 != ' ' && *p2 != '\t')
-               fatal ("specs %%rename syntax malformed after %ld characters",
-                      (long) (p2 - buffer));
+               fatal_error ("specs %%rename syntax malformed after "
+                            "%ld characters",
+                            (long) (p2 - buffer));
 
              name_len = p2 - p1;
              *p2++ = '\0';
@@ -2216,8 +2225,9 @@ read_specs (const char *filename, int main_p)
                p2++;
 
              if (! ISALPHA ((unsigned char) *p2))
-               fatal ("specs %%rename syntax malformed after %ld characters",
-                      (long) (p2 - buffer));
+               fatal_error ("specs %%rename syntax malformed after "
+                            "%ld characters",
+                            (long) (p2 - buffer));
 
              /* Get new spec name.  */
              p3 = p2;
@@ -2225,8 +2235,9 @@ read_specs (const char *filename, int main_p)
                p3++;
 
              if (p3 != p - 1)
-               fatal ("specs %%rename syntax malformed after %ld characters",
-                      (long) (p3 - buffer));
+               fatal_error ("specs %%rename syntax malformed after "
+                            "%ld characters",
+                            (long) (p3 - buffer));
              *p3 = '\0';
 
              for (sl = specs; sl; sl = sl->next)
@@ -2234,21 +2245,22 @@ read_specs (const char *filename, int main_p)
                  break;
 
              if (!sl)
-               fatal ("specs %s spec was not found to be renamed", p1);
+               fatal_error ("specs %s spec was not found to be renamed", p1);
 
              if (strcmp (p1, p2) == 0)
                continue;
 
              for (newsl = specs; newsl; newsl = newsl->next)
                if (strcmp (newsl->name, p2) == 0)
-                 fatal ("%s: attempt to rename spec '%s' to already defined spec '%s'",
+                 fatal_error ("%s: attempt to rename spec %qs to "
+                              "already defined spec %qs",
                    filename, p1, p2);
 
              if (verbose_flag)
                {
-                 notice ("rename spec %s to %s\n", p1, p2);
+                 fnotice (stderr, "rename spec %s to %s\n", p1, p2);
 #ifdef DEBUG_SPECS
-                 notice ("spec is '%s'\n\n", *(sl->ptr_spec));
+                 fnotice (stderr, "spec is '%s'\n\n", *(sl->ptr_spec));
 #endif
                }
 
@@ -2261,8 +2273,8 @@ read_specs (const char *filename, int main_p)
              continue;
            }
          else
-           fatal ("specs unknown %% command after %ld characters",
-                  (long) (p1 - buffer));
+           fatal_error ("specs unknown %% command after %ld characters",
+                        (long) (p1 - buffer));
        }
 
       /* Find the colon that should end the suffix.  */
@@ -2272,8 +2284,8 @@ read_specs (const char *filename, int main_p)
 
       /* The colon shouldn't be missing.  */
       if (*p1 != ':')
-       fatal ("specs file malformed after %ld characters",
-              (long) (p1 - buffer));
+       fatal_error ("specs file malformed after %ld characters",
+                    (long) (p1 - buffer));
 
       /* Skip back over trailing whitespace.  */
       p2 = p1;
@@ -2285,8 +2297,8 @@ read_specs (const char *filename, int main_p)
       /* Find the next line.  */
       p = skip_whitespace (p1 + 1);
       if (p[1] == 0)
-       fatal ("specs file malformed after %ld characters",
-              (long) (p - buffer));
+       fatal_error ("specs file malformed after %ld characters",
+                    (long) (p - buffer));
 
       p1 = p;
       /* Find next blank line or end of string.  */
@@ -2337,7 +2349,7 @@ read_specs (const char *filename, int main_p)
     }
 
   if (link_command_spec == 0)
-    fatal ("spec file has no spec for linking");
+    fatal_error ("spec file has no spec for linking");
 }
 \f
 /* Record the names of temporary files we tell compilers to write,
@@ -2665,7 +2677,7 @@ static void
 xputenv (const char *string)
 {
   if (verbose_flag)
-    notice ("%s\n", string);
+    fnotice (stderr, "%s\n", string);
   putenv (CONST_CAST (char *, string));
 }
 
@@ -2866,7 +2878,7 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
                      int require_machine_suffix, int os_multilib)
 {
   if (!IS_ABSOLUTE_PATH (prefix))
-    fatal ("system path '%s' is not absolute", prefix);
+    fatal_error ("system path %qs is not absolute", prefix);
 
   if (target_system_root)
     {
@@ -2927,7 +2939,7 @@ execute (void)
 
   commands[0].prog = argbuf[0]; /* first command.  */
   commands[0].argv = &argbuf[0];
+
   if (!wrapper_string)
     {
       string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
@@ -2938,7 +2950,7 @@ execute (void)
     if (strcmp (argbuf[i], "|") == 0)
       {                                /* each command.  */
 #if defined (__MSDOS__) || defined (OS2) || defined (VMS)
-       fatal ("-pipe not supported");
+       fatal_error ("-pipe not supported");
 #endif
        argbuf[i] = 0;  /* termination of command args.  */
        commands[n_commands].prog = argbuf[i + 1];
@@ -2970,14 +2982,23 @@ execute (void)
              for (j = commands[i].argv; *j; j++)
                {
                  const char *p;
-                 fprintf (stderr, " \"");
                  for (p = *j; *p; ++p)
+                   if (!ISALNUM ((unsigned char) *p)
+                       && *p != '_' && *p != '/' && *p != '-' && *p != '.')
+                     break;
+                 if (*p || !*j)
                    {
-                     if (*p == '"' || *p == '\\' || *p == '$')
-                       fputc ('\\', stderr);
-                     fputc (*p, stderr);
+                     fprintf (stderr, " \"");
+                     for (p = *j; *p; ++p)
+                       {
+                         if (*p == '"' || *p == '\\' || *p == '$')
+                           fputc ('\\', stderr);
+                         fputc (*p, stderr);
+                       }
+                     fputc ('"', stderr);
                    }
-                 fputc ('"', stderr);
+                 else
+                   fprintf (stderr, " %s", *j);
                }
            }
          else
@@ -3000,7 +3021,7 @@ execute (void)
          return 0;
         }
 #ifdef DEBUG
-      notice ("\nGo ahead? (y or n) ");
+      fnotice (stderr, "\nGo ahead? (y or n) ");
       fflush (stderr);
       i = getchar ();
       if (i != '\n')
@@ -3043,9 +3064,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++)
     {
@@ -3061,7 +3082,7 @@ execute (void)
       if (errmsg != NULL)
        {
          if (err == 0)
-           fatal (errmsg);
+           fatal_error (errmsg);
          else
            {
              errno = err;
@@ -3084,13 +3105,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);
@@ -3116,12 +3137,8 @@ execute (void)
              }
            else
 #endif
-             fatal_ice ("\
-Internal error: %s (program %s)\n\
-Please submit a full bug report.\n\
-See %s for instructions.",
-                       strsignal (WTERMSIG (status)), commands[i].prog,
-                       bug_report_url);
+             internal_error ("%s (program %s)",
+                             strsignal (WTERMSIG (status)), commands[i].prog);
          }
        else if (WIFEXITED (status)
                 && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
@@ -3144,7 +3161,8 @@ See %s for instructions.",
            if (ut + st != 0)
              {
                if (report_times)
-                 notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st);
+                 fnotice (stderr, "# %s %.2f %.2f\n",
+                          commands[i].prog, ut, st);
 
                if (report_times_to_file)
                  {
@@ -3196,12 +3214,15 @@ See %s for instructions.",
    SWITCH_LIVE to indicate this switch is true in a conditional spec.
    SWITCH_FALSE to indicate this switch is overridden by a later switch.
    SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
+   SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored
+   in all do_spec calls afterwards.  Used for %<S from self specs.
    The `validated' field is nonzero if any spec has looked at this switch;
    if it remains zero at the end of the run, it must be meaningless.  */
 
-#define SWITCH_LIVE    0x1
-#define SWITCH_FALSE   0x2
-#define SWITCH_IGNORE  0x4
+#define SWITCH_LIVE                            0x1
+#define SWITCH_FALSE                           0x2
+#define SWITCH_IGNORE                  0x4
+#define SWITCH_IGNORE_PERMANENTLY      0x8
 
 struct switchstr
 {
@@ -3216,6 +3237,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
@@ -3261,6 +3284,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.  */
 
@@ -3335,7 +3360,7 @@ 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);
@@ -3380,8 +3405,6 @@ display_help (void)
   --sysroot=<directory>    Use <directory> as the root directory for headers\n\
                            and libraries\n"), stdout);
   fputs (_("  -B <directory>           Add <directory> to the compiler's search paths\n"), stdout);
-  fputs (_("  -b <machine>             Run gcc for target <machine>, if installed\n"), stdout);
-  fputs (_("  -V <version>             Run gcc version number <version>, if installed\n"), stdout);
   fputs (_("  -v                       Display the programs invoked by the compiler\n"), stdout);
   fputs (_("  -###                     Like -v but options quoted and commands not executed\n"), stdout);
   fputs (_("  -E                       Preprocess only; do not compile, assemble or link\n"), stdout);
@@ -3399,7 +3422,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.  */
@@ -3442,11 +3465,56 @@ add_linker_option (const char *option, int len)
   if (! linker_options)
     linker_options = XNEWVEC (char *, n_linker_options);
   else
-    linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);  
+    linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
 
   linker_options [n_linker_options - 1] = save_string (option, len);
 }
 \f
+/* Allocate space for an input file in infiles.  */
+
+static void
+alloc_infile (void)
+{
+  if (n_infiles_alloc == 0)
+    {
+      n_infiles_alloc = 16;
+      infiles = XNEWVEC (struct infile, n_infiles_alloc);
+    }
+  else if (n_infiles_alloc == n_infiles)
+    {
+      n_infiles_alloc *= 2;
+      infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc);
+    }
+}
+
+/* Store an input file with the given NAME and LANGUAGE in
+   infiles.  */
+
+static void
+add_infile (const char *name, const char *language)
+{
+  alloc_infile ();
+  infiles[n_infiles].name = name;
+  infiles[n_infiles++].language = language;
+}
+
+/* Allocate space for a switch in switches.  */
+
+static void
+alloc_switch (void)
+{
+  if (n_switches_alloc == 0)
+    {
+      n_switches_alloc = 16;
+      switches = XNEWVEC (struct switchstr, n_switches_alloc);
+    }
+  else if (n_switches_alloc == n_switches)
+    {
+      n_switches_alloc *= 2;
+      switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc);
+    }
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -3458,11 +3526,6 @@ process_command (int argc, const char **argv)
   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;
@@ -3486,92 +3549,11 @@ process_command (int argc, const char **argv)
        }
     }
 
-  /* If there is a -V or -b option (or both), process it now, before
-     trying to interpret the rest of the command line.
-     Use heuristic that all configuration names must have at least
-     one dash '-'. This allows us to pass options starting with -b.  */
-  if (argc > 1 && argv[1][0] == '-'
-      && (argv[1][1] == 'V'
-         || (argv[1][1] == 'b'
-             && (argv[1][2] == '\0'
-                 || NULL != strchr (argv[1] + 2, '-')))))
-    {
-      const char *new_version = DEFAULT_TARGET_VERSION;
-      const char *new_machine = DEFAULT_TARGET_MACHINE;
-      const char *progname = argv[0];
-      char **new_argv;
-      char *new_argv0;
-      int baselen;
-      int status = 0;
-      int err = 0;
-      const char *errmsg;
-
-      while (argc > 1 && argv[1][0] == '-'
-            && (argv[1][1] == 'V'
-                || (argv[1][1] == 'b'
-                    && (argv[1][2] == '\0'
-                        || NULL != strchr (argv[1] + 2, '-')))))
-       {
-         char opt = argv[1][1];
-         const char *arg;
-         if (argv[1][2] != '\0')
-           {
-             arg = argv[1] + 2;
-             argc -= 1;
-             argv += 1;
-           }
-         else if (argc > 2)
-           {
-             arg = argv[2];
-             argc -= 2;
-             argv += 2;
-           }
-         else
-           fatal ("'-%c' option must have argument", opt);
-         if (opt == 'V')
-           new_version = arg;
-         else
-           new_machine = arg;
-       }
-
-      for (baselen = strlen (progname); baselen > 0; baselen--)
-       if (IS_DIR_SEPARATOR (progname[baselen-1]))
-         break;
-      new_argv0 = XDUPVAR (char, progname, baselen,
-                          baselen + concat_length (new_version, new_machine,
-                                                   "-gcc-", NULL) + 1);
-      strcpy (new_argv0 + baselen, new_machine);
-      strcat (new_argv0, "-gcc-");
-      strcat (new_argv0, new_version);
-
-      new_argv = XDUPVEC (char *, argv, argc + 1);
-      new_argv[0] = new_argv0;
-
-      errmsg = pex_one (PEX_SEARCH, new_argv0, new_argv, progname, NULL,
-                       NULL, &status, &err);
-
-      if (errmsg)
-       {
-         if (err == 0)
-           fatal ("couldn't run '%s': %s", new_argv0, errmsg);
-         else
-           fatal ("couldn't run '%s': %s: %s", new_argv0, errmsg,
-                   xstrerror (err));
-        }
-      exit (status);
-    }
-
   /* Convert new-style -- options to old-style.  */
   translate_options (&argc,
                     CONST_CAST2 (const char *const **, const char ***,
                                  &argv));
 
-  /* Do language-specific adjustment/addition of flags.  */
-  lang_specific_driver (&argc,
-                       CONST_CAST2 (const char *const **, const char ***,
-                                    &argv),
-                       &added_libraries);
-
   /* Handle any -no-canonical-prefixes flag early, to assign the function
      that builds relative prefixes.  This function creates default search
      paths that are needed later in normal option handling.  */
@@ -3627,6 +3609,12 @@ process_command (int argc, const char **argv)
      is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX
      or an automatically created GCC_EXEC_PREFIX from argv[0].  */
 
+  /* Do language-specific adjustment/addition of flags.  */
+  lang_specific_driver (&argc,
+                       CONST_CAST2 (const char *const **, const char ***,
+                                    &argv),
+                       &added_libraries);
+
   if (gcc_exec_prefix)
     {
       int len = strlen (gcc_exec_prefix);
@@ -3751,12 +3739,22 @@ 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).  */
+  /* Process the options and store input files and switches in their
+     vectors.  */
+
+  last_language_n_infiles = -1;
 
   for (i = 1; i < argc; i++)
     {
+      const char *p = NULL;
+      int c = 0;
+
+      if (argv[i][0] == '-' && argv[i][1] != 0)
+       {
+         p = &argv[i][1];
+         c = *p;
+       }
+
       if (! strcmp (argv[i], "-dumpspecs"))
        {
          struct spec_list *sl;
@@ -3782,59 +3780,50 @@ process_command (int argc, const char **argv)
          /* translate_options () has turned --version into -fversion.  */
          print_version = 1;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* CPP driver cannot obtain switch from cc1_options.  */
          if (is_cpp_driver)
            add_preprocessor_option ("--version", strlen ("--version"));
          add_assembler_option ("--version", strlen ("--version"));
          add_linker_option ("--version", strlen ("--version"));
+
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-fhelp") == 0)
        {
          /* translate_options () has turned --help into -fhelp.  */
          print_help_list = 1;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* CPP driver cannot obtain switch from cc1_options.  */
          if (is_cpp_driver)
            add_preprocessor_option ("--help", 6);
          add_assembler_option ("--help", 6);
          add_linker_option ("--help", 6);
+
+         goto normal_switch;
        }
       else if (strncmp (argv[i], "-fhelp=", 7) == 0)
        {
          /* translate_options () has turned --help into -fhelp.  */
          print_subprocess_help = 2;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-ftarget-help") == 0)
        {
          /* translate_options() has turned --target-help into -ftarget-help.  */
          print_subprocess_help = 1;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* CPP driver cannot obtain switch from cc1_options.  */
          if (is_cpp_driver)
            add_preprocessor_option ("--target-help", 13);
          add_assembler_option ("--target-help", 13);
          add_linker_option ("--target-help", 13);
+
+         goto normal_switch;
        }
       else if (! strcmp (argv[i], "-pass-exit-codes"))
        {
          pass_exit_codes = 1;
-         n_switches++;
        }
       else if (! strcmp (argv[i], "-print-search-dirs"))
        print_search_dirs = 1;
@@ -3857,16 +3846,18 @@ process_command (int argc, const char **argv)
       else if (! strcmp (argv[i], "-fcompare-debug-second"))
        {
          compare_debug_second = 1;
-         n_switches++;
+         goto normal_switch;
        }
       else if (! strcmp (argv[i], "-fno-compare-debug"))
        {
          argv[i] = "-fcompare-debug=";
+         p = &argv[i][1];
          goto compare_debug_with_arg;
        }
       else if (! strcmp (argv[i], "-fcompare-debug"))
        {
          argv[i] = "-fcompare-debug=-gtoggle";
+         p = &argv[i][1];
          goto compare_debug_with_arg;
        }
 #define OPT "-fcompare-debug="
@@ -3884,7 +3875,7 @@ process_command (int argc, const char **argv)
            compare_debug_opt = NULL;
          else
            compare_debug_opt = opt;
-         n_switches++;
+         goto normal_switch;
        }
       else if (! strncmp (argv[i], "-Wa,", 4))
        {
@@ -3920,63 +3911,73 @@ process_command (int argc, const char **argv)
          /* 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;
+         int prev, j;
          /* Split the argument at commas.  */
-         for (j = 3; argv[i][j]; j++)
-           n_infiles += (argv[i][j] == ',');
+         prev = 4;
+         for (j = 4; argv[i][j]; j++)
+           if (argv[i][j] == ',')
+             {
+               add_infile (save_string (argv[i] + prev, j - prev), "*");
+               prev = j + 1;
+             }
+         /* Record the part after the last comma.  */
+         add_infile (argv[i] + prev, "*");
        }
       else if (strcmp (argv[i], "-Xlinker") == 0)
        {
          if (i + 1 == argc)
-           fatal ("argument to '-Xlinker' is missing");
+           fatal_error ("argument to %<-Xlinker%> is missing");
 
-         n_infiles++;
+         add_infile (argv[i+1], "*");
          i++;
        }
       else if (strcmp (argv[i], "-Xpreprocessor") == 0)
        {
          if (i + 1 == argc)
-           fatal ("argument to '-Xpreprocessor' is missing");
+           fatal_error ("argument to %<-Xpreprocessor%> is missing");
 
          add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
+         i++;
        }
       else if (strcmp (argv[i], "-Xassembler") == 0)
        {
          if (i + 1 == argc)
-           fatal ("argument to '-Xassembler' is missing");
+           fatal_error ("argument to %<-Xassembler%> is missing");
 
          add_assembler_option (argv[i+1], strlen (argv[i+1]));
+         i++;
        }
       else if (strcmp (argv[i], "-l") == 0)
        {
          if (i + 1 == argc)
-           fatal ("argument to '-l' is missing");
+           fatal_error ("argument to %<-l%> is missing");
 
-         n_infiles++;
+         /* POSIX allows separation of -l and the lib arg;
+            canonicalize by concatenating -l with its arg */
+         add_infile (concat ("-l", argv[i + 1], NULL), "*");
          i++;
        }
       else if (strncmp (argv[i], "-l", 2) == 0)
-       n_infiles++;
+       {
+         add_infile (argv[i], "*");
+       }
       else if (strcmp (argv[i], "-save-temps") == 0)
        {
          save_temps_flag = SAVE_TEMPS_CWD;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strncmp (argv[i], "-save-temps=", 12) == 0)
        {
-         n_switches++;
          if (strcmp (argv[i]+12, "cwd") == 0)
            save_temps_flag = SAVE_TEMPS_CWD;
          else if (strcmp (argv[i]+12, "obj") == 0
                   || strcmp (argv[i]+12, "object") == 0)
            save_temps_flag = SAVE_TEMPS_OBJ;
          else
-           fatal ("'%s' is an unknown -save-temps option", argv[i]);
+           fatal_error ("%qs is an unknown -save-temps option", argv[i]);
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-no-canonical-prefixes") == 0)
        /* Already handled as a special case, so ignored here.  */
@@ -3984,13 +3985,13 @@ process_command (int argc, const char **argv)
       else if (strcmp (argv[i], "-combine") == 0)
        {
          combine_flag = 1;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-specs") == 0)
        {
          struct user_specs *user = XNEW (struct user_specs);
          if (++i >= argc)
-           fatal ("argument to '-specs' is missing");
+           fatal_error ("argument to %<-specs%> is missing");
 
          user->next = (struct user_specs *) 0;
          user->filename = argv[i];
@@ -4004,7 +4005,7 @@ process_command (int argc, const char **argv)
        {
          struct user_specs *user = XNEW (struct user_specs);
          if (strlen (argv[i]) == 7)
-           fatal ("argument to '-specs=' is missing");
+           fatal_error ("argument to %<-specs=%> is missing");
 
          user->next = (struct user_specs *) 0;
          user->filename = argv[i] + 7;
@@ -4014,6 +4015,11 @@ process_command (int argc, const char **argv)
            user_specs_head = user;
          user_specs_tail = user;
        }
+      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
+       {
+         target_system_root = argv[i] + strlen ("--sysroot=");
+         target_system_root_changed = 1;
+       }
       else if (strcmp (argv[i], "-time") == 0)
        report_times = 1;
       else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
@@ -4027,16 +4033,14 @@ process_command (int argc, const char **argv)
          /* -pipe has to go into the switches array as well as
             setting a flag.  */
          use_pipes = 1;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-wrapper") == 0)
         {
          if (++i >= argc)
-           fatal ("argument to '-wrapper' is missing");
+           fatal_error ("argument to %<-wrapper%> is missing");
 
           wrapper_string = argv[i];
-         n_switches++;
-         n_switches++;
         }
       else if (strcmp (argv[i], "-###") == 0)
        {
@@ -4049,29 +4053,17 @@ process_command (int argc, const char **argv)
        }
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
-         const char *p = &argv[i][1];
-         int c = *p;
-
          switch (c)
            {
-           case 'b':
-             if (p[1] && NULL == strchr (argv[i] + 2, '-'))
-               goto normal_switch;
-
-             /* Fall through.  */
-           case 'V':
-             fatal ("'-%c' must come at the start of the command line", c);
-             break;
-
            case 'B':
              {
                const char *value;
                int len;
 
                if (p[1] == 0 && i + 1 == argc)
-                 fatal ("argument to '-B' is missing");
+                 fatal_error ("argument to %<-B%> is missing");
                if (p[1] == 0)
-                 value = argv[++i];
+                 value = argv[i + 1];
                else
                  value = p + 1;
 
@@ -4100,27 +4092,38 @@ process_command (int argc, const char **argv)
                            PREFIX_PRIORITY_B_OPT, 0, 0);
                add_prefix (&include_prefixes, value, NULL,
                            PREFIX_PRIORITY_B_OPT, 0, 0);
-               n_switches++;
              }
-             break;
+             goto normal_switch;
 
            case 'v':   /* Print our subcommands and print versions.  */
-             n_switches++;
              /* If they do anything other than exactly `-v', don't set
                 verbose_flag; rather, continue on to give the error.  */
              if (p[1] != 0)
                break;
              verbose_flag++;
+             goto normal_switch;
+
+           case 'x':
+             if (p[1] == 0 && i + 1 == argc)
+               fatal_error ("argument to %<-x%> is missing");
+             if (p[1] == 0)
+               spec_lang = argv[++i];
+             else
+               spec_lang = p + 1;
+             if (! strcmp (spec_lang, "none"))
+               /* Suppress the warning if -xnone comes after the last input
+                  file, because alternate command interfaces like g++ might
+                  find it useful to place -xnone after each input file.  */
+               spec_lang = 0;
+             else
+               last_language_n_infiles = n_infiles;
              break;
 
            case 'S':
            case 'c':
+           case 'E':
              if (p[1] == 0)
-               {
-                 have_c = 1;
-                 n_switches++;
-                 break;
-               }
+               have_c = 1;
              goto normal_switch;
 
            case 'o':
@@ -4130,7 +4133,7 @@ process_command (int argc, const char **argv)
                {
                  int skip;
 
-                 /* Forward scan, just in case -S or -c is specified
+                 /* Forward scan, just in case -S, -E or -c is specified
                     after -o.  */
                  int j = i + 1;
                  if (p[1] == 0)
@@ -4158,64 +4161,120 @@ process_command (int argc, const char **argv)
              if (p[1] == 0)
                argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
              else
-               argv[i] = convert_filename (argv[i], ! have_c, 0);
+               {
+                 argv[i] = convert_filename (argv[i], ! have_c, 0);
+                 p = &argv[i][1];
+               }
 #endif
              /* Save the output name in case -save-temps=obj was used.  */
-             save_temps_prefix = xstrdup ((p[1] == 0) ? argv[i + 1] : argv[i] + 1);
+             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
+             alloc_switch ();
+             switches[n_switches].part1 = p;
+             /* Deal with option arguments in separate argv elements.  */
+             if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
+                 || WORD_SWITCH_TAKES_ARG (p))
+               {
+                 int j = 0;
+                 int n_args = WORD_SWITCH_TAKES_ARG (p);
 
+                 if (n_args == 0)
+                   {
+                     /* Count only the option arguments in separate
+                        argv elements.  */
+                     n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
+                   }
+                 if (i + n_args >= argc)
+                   fatal_error ("argument to %<-%s%> is missing", p);
+                 switches[n_switches].args
+                   = XNEWVEC (const char *, n_args + 1);
+                 while (j < n_args)
+                   switches[n_switches].args[j++] = argv[++i];
+                 /* Null-terminate the vector.  */
+                 switches[n_switches].args[j] = 0;
+               }
+             else if (c == 'o')
+               {
+                 /* On some systems, ld cannot handle "-o" without
+                    a space.  So split the option from its argument.  */
+                 char *part1 = XNEWVEC (char, 2);
+                 part1[0] = c;
+                 part1[1] = '\0';
+
+                 switches[n_switches].part1 = part1;
+                 switches[n_switches].args = XNEWVEC (const char *, 2);
+                 switches[n_switches].args[0] = xstrdup (p+1);
+                 switches[n_switches].args[1] = 0;
+               }
+             else
+               switches[n_switches].args = 0;
+
+             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++;
-
-             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
        {
-         n_infiles++;
-         lang_n_infiles++;
+          const char *p = strrchr (argv[i], '@');
+          char *fname;
+         long offset;
+         int consumed;
+#ifdef HAVE_TARGET_OBJECT_SUFFIX
+         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
+#endif
+         /* For LTO static archive support we handle input file
+            specifications that are composed of a filename and
+            an offset like FNAME@OFFSET.  */
+         if (p
+             && p != argv[i]
+             && sscanf (p, "@%li%n", &offset, &consumed) >= 1
+             && strlen (p) == (unsigned int)consumed)
+           {
+              fname = (char *)xmalloc (p - argv[i] + 1);
+              memcpy (fname, argv[i], p - argv[i]);
+              fname[p - argv[i]] = '\0';
+             /* Only accept non-stdin and existing FNAME parts, otherwise
+                try with the full name.  */
+             if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
+               {
+                 free (fname);
+                 fname = xstrdup (argv[i]);
+               }
+           }
+         else
+           fname = xstrdup (argv[i]);
+          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
+           perror_with_name (fname);
+          else
+           add_infile (argv[i], spec_lang);
+
+          free (fname);
        }
     }
 
@@ -4242,7 +4301,7 @@ process_command (int argc, const char **argv)
     {
       /* -save-temps overrides -pipe, so that temp files are produced */
       if (save_temps_flag)
-       error ("warning: -pipe ignored because -save-temps specified");
+       warning (0, "-pipe ignored because -save-temps specified");
       use_pipes = 0;
     }
 
@@ -4254,13 +4313,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)
@@ -4272,7 +4329,7 @@ process_command (int argc, const char **argv)
   /* Set up the search paths.  We add directories that we expect to
      contain GNU Toolchain components before directories specified by
      the machine description so that we will find GNU components (like
-     the GNU assembler) before those of the host system.  */ 
+     the GNU assembler) before those of the host system.  */
 
   /* If we don't know where the toolchain has been installed, use the
      configured-in locations.  */
@@ -4313,7 +4370,7 @@ 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],
                                              standard_bindir_prefix,
@@ -4329,230 +4386,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 ("argument to '-x' is missing");
-             if (p[1] == 0)
-               spec_lang = argv[++i];
-             else
-               spec_lang = p + 1;
-             if (! strcmp (spec_lang, "none"))
-               /* Suppress the warning if -xnone comes after the last input
-                  file, because alternate command interfaces like g++ might
-                  find it useful to place -xnone after each input file.  */
-               spec_lang = 0;
-             else
-               last_language_n_infiles = n_infiles;
-             continue;
-           }
-         switches[n_switches].part1 = p;
-         /* Deal with option arguments in separate argv elements.  */
-         if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
-             || WORD_SWITCH_TAKES_ARG (p))
-           {
-             int j = 0;
-             int n_args = WORD_SWITCH_TAKES_ARG (p);
-
-             if (n_args == 0)
-               {
-                 /* Count only the option arguments in separate argv elements.  */
-                 n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
-               }
-             if (i + n_args >= argc)
-               fatal ("argument to '-%s' is missing", p);
-             switches[n_switches].args
-               = XNEWVEC (const char *, n_args + 1);
-             while (j < n_args)
-               switches[n_switches].args[j++] = argv[++i];
-             /* Null-terminate the vector.  */
-             switches[n_switches].args[j] = 0;
-           }
-         else if (strchr (switches_need_spaces, c))
-           {
-             /* On some systems, ld cannot handle some options without
-                a space.  So split the option from its argument.  */
-             char *part1 = XNEWVEC (char, 2);
-             part1[0] = c;
-             part1[1] = '\0';
-
-             switches[n_switches].part1 = part1;
-             switches[n_switches].args = XNEWVEC (const char *, 2);
-             switches[n_switches].args[0] = xstrdup (p+1);
-             switches[n_switches].args[1] = 0;
-           }
-         else
-           switches[n_switches].args = 0;
-
-         switches[n_switches].live_cond = 0;
-         switches[n_switches].validated = 0;
-         switches[n_switches].ordering = 0;
-         /* These are always valid, since gcc.c itself understands the
-            first four and gfortranspec.c understands -static-libgfortran.  */
-         if (!strcmp (p, "save-temps")
-             || !strcmp (p, "static-libgcc")
-             || !strcmp (p, "shared-libgcc")
-             || !strcmp (p, "pipe")
-             || !strcmp (p, "static-libgfortran"))
-           switches[n_switches].validated = 1;
-         else
-           {
-             char ch = switches[n_switches].part1[0];
-             if (ch == 'B')
-               switches[n_switches].validated = 1;
-           }
-         n_switches++;
-       }
-      else
-       {
-#ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
-#endif
-
-         if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
-           {
-             perror_with_name (argv[i]);
-             error_count++;
-           }
-         else
-           {
-             infiles[n_infiles].language = spec_lang;
-             infiles[n_infiles++].name = argv[i];
-           }
-       }
-    }
-
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
-    error ("warning: '-x %s' after last input file has no effect", spec_lang);
+    warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
 
   if (compare_debug == 2 || compare_debug == 3)
     {
+      alloc_switch ();
       switches[n_switches].part1 = concat ("fcompare-debug=",
                                           compare_debug_opt,
                                           NULL);
@@ -4567,15 +4406,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;
 }
 
@@ -4607,11 +4447,6 @@ set_collect_gcc_options (void)
       if ((switches[i].live_cond & SWITCH_IGNORE) != 0)
        continue;
 
-      /* Don't use -fwhole-program when compiling the init and fini routines,
-        since we'd wrongly assume that the routines aren't needed.  */
-      if (strcmp (switches[i].part1, "fwhole-program") == 0)
-       continue;
-
       obstack_grow (&collect_obstack, "'-", 2);
       q = switches[i].part1;
       while ((p = strchr (q, '\'')))
@@ -4650,7 +4485,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;
@@ -4684,6 +4519,13 @@ static int this_is_output_file;
    search dirs for it.  */
 static int this_is_library_file;
 
+/* Nonzero means %T has been seen; the next arg to be terminated
+   is the name of a linker script and we should try all of the
+   standard search dirs for it.  If it is found insert a --script
+   command line switch and then substitute the full path in place,
+   otherwise generate an error message.  */
+static int this_is_linker_script;
+
 /* Nonzero means that the input of this command is coming from a pipe.  */
 static int input_from_pipe;
 
@@ -4704,6 +4546,19 @@ end_going_arg (void)
       string = XOBFINISH (&obstack, const char *);
       if (this_is_library_file)
        string = find_file (string);
+      if (this_is_linker_script)
+       {
+         char * full_script_path = find_a_file (&startfile_prefixes, string, R_OK, true);
+
+         if (full_script_path == NULL)
+           {
+             error ("unable to locate default linker script %qs in the library search paths", string);
+             /* Script was not found on search path.  */
+             return;
+           }
+         store_arg ("--script", false, false);
+         string = full_script_path;
+       }
       store_arg (string, delete_this_arg, this_is_output_file);
       if (this_is_output_file)
        outfiles[input_file_number] = string;
@@ -4793,6 +4648,7 @@ do_spec_2 (const char *spec)
   delete_this_arg = 0;
   this_is_output_file = 0;
   this_is_library_file = 0;
+  this_is_linker_script = 0;
   input_from_pipe = 0;
   suffix_subst = NULL;
 
@@ -4859,13 +4715,20 @@ do_option_spec (const char *name, const char *spec)
 static void
 do_self_spec (const char *spec)
 {
+  int i;
+
   do_spec_2 (spec);
   do_spec_1 (" ", 0, NULL);
 
+  /* Mark %<S switches processed by do_self_spec to be ignored permanently.
+     do_self_specs adds the replacements to switches array, so it shouldn't
+     be processed afterwards.  */
+  for (i = 0; i < n_switches; i++)
+    if ((switches[i].live_cond & SWITCH_IGNORE))
+      switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
+
   if (argbuf_index > 0)
     {
-      int i;
-
       switches = XRESIZEVEC (struct switchstr, switches,
                             n_switches + argbuf_index + 1);
 
@@ -4877,7 +4740,7 @@ do_self_spec (const char *spec)
 
          /* Each switch should start with '-'.  */
          if (c != '-')
-           fatal ("switch '%s' does not start with '-'", argbuf[i]);
+           fatal_error ("switch %qs does not start with %<-%>", argbuf[i]);
 
          p++;
          c = *p;
@@ -4901,7 +4764,7 @@ do_self_spec (const char *spec)
                  n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
                }
              if (i + n_args >= argbuf_index)
-               fatal ("argument to '-%s' is missing", p);
+               fatal_error ("argument to %<-%s%> is missing", p);
              sw->args
                = XNEWVEC (const char *, n_args + 1);
              while (j < n_args)
@@ -4909,9 +4772,9 @@ do_self_spec (const char *spec)
              /* Null-terminate the vector.  */
              sw->args[j] = 0;
            }
-         else if (strchr (switches_need_spaces, c))
+         else if (c == 'o')
            {
-             /* On some systems, ld cannot handle some options without
+             /* On some systems, ld cannot handle "-o" without
                 a space.  So split the option from its argument.  */
              char *part1 = XNEWVEC (char, 2);
              part1[0] = c;
@@ -4993,20 +4856,20 @@ create_at_file (char **argv)
   int status;
 
   if (f == NULL)
-    fatal ("could not open temporary response file %s",
-          temp_file);
+    fatal_error ("could not open temporary response file %s",
+                temp_file);
 
   status = writeargv (argv, f);
 
   if (status)
-    fatal ("could not write to temporary response file %s",
-          temp_file);
+    fatal_error ("could not write to temporary response file %s",
+                temp_file);
 
   status = fclose (f);
 
   if (EOF == status)
-    fatal ("could not close temporary response file %s",
-          temp_file);
+    fatal_error ("could not close temporary response file %s",
+                temp_file);
 
   store_arg (at_argument, 0, 0);
 
@@ -5080,6 +4943,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
        delete_this_arg = 0;
        this_is_output_file = 0;
        this_is_library_file = 0;
+       this_is_linker_script = 0;
        input_from_pipe = 0;
        break;
 
@@ -5099,13 +4963,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
        delete_this_arg = 0;
        this_is_output_file = 0;
        this_is_library_file = 0;
+       this_is_linker_script = 0;
        break;
 
       case '%':
        switch (c = *p++)
          {
          case 0:
-           fatal ("spec '%s' invalid", spec);
+           fatal_error ("spec %qs invalid", spec);
 
          case 'b':
            if (save_temps_length)
@@ -5167,7 +5032,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              buf = (char *) alloca (p - q + 1);
              strncpy (buf, q, p - q);
              buf[p - q] = 0;
-             error ("%s", buf);
+             error ("%s", _(buf));
              return -1;
            }
            break;
@@ -5181,7 +5046,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              buf = (char *) alloca (p - q + 1);
              strncpy (buf, q, p - q);
              buf[p - q] = 0;
-             notice ("%s\n", buf);
+             inform (0, "%s", _(buf));
              if (*p)
                p++;
            }
@@ -5254,7 +5119,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 ("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
@@ -5295,7 +5160,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.,
@@ -5313,7 +5178,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 (strcmp (temp_filename, gcc_input_filename) != 0)
                      {
 #ifndef HOST_LACKS_INODE_NUMBERS
                        struct stat st_temp;
@@ -5321,12 +5186,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.  */
@@ -5336,7 +5202,7 @@ 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);
                        free (input_realname);
@@ -5438,7 +5304,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;
@@ -5546,6 +5413,10 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            this_is_library_file = 1;
            break;
 
+         case 'T':
+           this_is_linker_script = 1;
+           break;
+
          case 'V':
            outfiles[input_file_number] = NULL;
            break;
@@ -5559,7 +5430,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              int cur_index = argbuf_index;
              /* Handle the {...} following the %W.  */
              if (*p != '{')
-               fatal ("spec '%s' has invalid '%%W%c", spec, *p);
+               fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p);
              p = handle_braces (p + 1);
              if (p == 0)
                return -1;
@@ -5579,7 +5450,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
              /* Skip past the option value and make a copy.  */
              if (*p != '{')
-               fatal ("spec '%s' has invalid '%%x%c'", spec, *p);
+               fatal_error ("spec %qs has invalid %<%%x%c%>", spec, *p);
              while (*p++ != '}')
                ;
              string = save_string (p1 + 1, p - p1 - 2);
@@ -5774,7 +5645,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              /* 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.
@@ -5783,7 +5654,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
               %[...] modifies -D options the way %P does;
               %(...) uses the spec unmodified.  */
          case '[':
-           error ("warning: use of obsolete %%[ operator in specs");
+           warning (0, "use of obsolete %%[ operator in specs");
          case '(':
            {
              const char *name = p;
@@ -5801,7 +5672,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                  {
                    name = *(sl->ptr_spec);
 #ifdef DEBUG_SPECS
-                   notice ("Processing spec %c%s%c, which is '%s'\n",
+                   fnotice (stderr, "Processing spec %c%s%c, which is '%s'\n",
                            c, sl->name, (c == '(') ? ')' : ']', name);
 #endif
                    break;
@@ -5864,7 +5735,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            break;
 
          default:
-           error ("spec failure: unrecognized spec option '%c'", c);
+           error ("spec failure: unrecognized spec option %qc", c);
            break;
          }
        break;
@@ -5920,12 +5791,13 @@ eval_spec_function (const char *func, const char *args)
   int save_this_is_output_file;
   int save_this_is_library_file;
   int save_input_from_pipe;
+  int save_this_is_linker_script;
   const char *save_suffix_subst;
 
 
   sf = lookup_spec_function (func);
   if (sf == NULL)
-    fatal ("unknown spec function '%s'", func);
+    fatal_error ("unknown spec function %qs", func);
 
   /* Push the spec processing context.  */
   save_argbuf_index = argbuf_index;
@@ -5936,6 +5808,7 @@ eval_spec_function (const char *func, const char *args)
   save_delete_this_arg = delete_this_arg;
   save_this_is_output_file = this_is_output_file;
   save_this_is_library_file = this_is_library_file;
+  save_this_is_linker_script = this_is_linker_script;
   save_input_from_pipe = input_from_pipe;
   save_suffix_subst = suffix_subst;
 
@@ -5944,7 +5817,7 @@ eval_spec_function (const char *func, const char *args)
 
   alloc_args ();
   if (do_spec_2 (args) < 0)
-    fatal ("error in args to spec function '%s'", func);
+    fatal_error ("error in args to spec function %qs", func);
 
   /* argbuf_index is an index for the next argument to be inserted, and
      so contains the count of the args already inserted.  */
@@ -5961,6 +5834,7 @@ eval_spec_function (const char *func, const char *args)
   delete_this_arg = save_delete_this_arg;
   this_is_output_file = save_this_is_output_file;
   this_is_library_file = save_this_is_library_file;
+  this_is_linker_script = save_this_is_linker_script;
   input_from_pipe = save_input_from_pipe;
   suffix_subst = save_suffix_subst;
 
@@ -5992,10 +5866,10 @@ handle_spec_function (const char *p)
         break;
       /* Only allow [A-Za-z0-9], -, and _ in function names.  */
       if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_'))
-       fatal ("malformed spec function name");
+       fatal_error ("malformed spec function name");
     }
   if (*endp != '(')            /* ) */
-    fatal ("no arguments for spec function");
+    fatal_error ("no arguments for spec function");
   func = save_string (p, endp - p);
   p = ++endp;
 
@@ -6014,7 +5888,7 @@ handle_spec_function (const char *p)
     }
   /* ( */
   if (*endp != ')')
-    fatal ("malformed spec function arguments");
+    fatal_error ("malformed spec function arguments");
   args = save_string (p, endp - p);
   p = ++endp;
 
@@ -6191,7 +6065,7 @@ handle_braces (const char *p)
          if (atom == end_atom)
            {
              if (!n_way_choice || disj_matched || *p == '|'
-                 || a_is_negated || a_is_suffix || a_is_spectype 
+                 || a_is_negated || a_is_suffix || a_is_spectype
                  || a_is_starred)
                goto invalid;
 
@@ -6205,7 +6079,7 @@ handle_braces (const char *p)
            {
              if ((a_is_suffix || a_is_spectype) && a_is_starred)
                goto invalid;
-             
+
              if (!a_is_starred)
                disj_starred = false;
 
@@ -6219,7 +6093,7 @@ handle_braces (const char *p)
                    a_matched = input_spec_matches (atom, end_atom);
                  else
                    a_matched = switch_matches (atom, end_atom, a_is_starred);
-                 
+
                  if (a_matched != a_is_negated)
                    {
                      disj_matched = true;
@@ -6260,7 +6134,7 @@ handle_braces (const char *p)
   return p;
 
  invalid:
-  fatal ("braced spec '%s' is invalid at '%c'", orig, *p);
+  fatal_error ("braced spec %qs is invalid at %qc", orig, *p);
 
 #undef SKIP_WHITE
 }
@@ -6348,7 +6222,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom,
   return p;
 
  invalid:
-  fatal ("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
@@ -6370,7 +6244,8 @@ check_live_switch (int switchnum, int prefix_length)
   if (switches[switchnum].live_cond != 0)
     return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
            && (switches[switchnum].live_cond & SWITCH_FALSE) == 0
-           && (switches[switchnum].live_cond & SWITCH_IGNORE) == 0);
+           && (switches[switchnum].live_cond & SWITCH_IGNORE_PERMANENTLY)
+              == 0);
 
   /* In the common case of {<at-most-one-letter>*}, a negating
      switch would always match, so ignore that case.  We will just
@@ -6536,9 +6411,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.  */
@@ -6556,7 +6431,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;
 }
@@ -6564,7 +6439,7 @@ set_input (const char *filename)
 /* On fatal signals, delete all the temporary files.  */
 
 static void
-fatal_error (int signum)
+fatal_signal (int signum)
 {
   signal (signum, SIG_DFL);
   delete_failure_queue ();
@@ -6597,7 +6472,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;
          }
@@ -6607,7 +6482,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;
       }
 
@@ -6618,7 +6493,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;
            }
@@ -6637,7 +6512,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;
          }
       }
@@ -6659,7 +6534,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;
        }
@@ -6675,7 +6550,7 @@ compare_files (char *cmpfile[])
        if (c0 != c1)
          {
            error ("%s: -fcompare-debug failure",
-                  input_filename);
+                  gcc_input_filename);
            ret = 1;
            break;
          }
@@ -6716,9 +6591,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);
 
@@ -6738,17 +6613,21 @@ 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_error);
+    signal (SIGINT, fatal_signal);
 #ifdef SIGHUP
   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
-    signal (SIGHUP, fatal_error);
+    signal (SIGHUP, fatal_signal);
 #endif
   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
-    signal (SIGTERM, fatal_error);
+    signal (SIGTERM, fatal_signal);
 #ifdef SIGPIPE
   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
-    signal (SIGPIPE, fatal_error);
+    signal (SIGPIPE, fatal_signal);
 #endif
 #ifdef SIGCHLD
   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
@@ -6803,14 +6682,6 @@ main (int argc, char **argv)
     multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
   }
 
-  /* Set up to remember the pathname of gcc and any options
-     needed for collect.  We use argv[0] instead of programname because
-     we need the complete pathname.  */
-  obstack_init (&collect_obstack);
-  obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
-  obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
-  xputenv (XOBFINISH (&collect_obstack, char *));
-
 #ifdef INIT_ENVIRONMENT
   /* Set up any other necessary machine specific environment variables.  */
   xputenv (INIT_ENVIRONMENT);
@@ -6982,9 +6853,9 @@ main (int argc, char **argv)
       else if (*cross_compile == '0')
        {
          add_prefix (&startfile_prefixes,
-                     concat (gcc_exec_prefix 
-                             ? gcc_exec_prefix : standard_exec_prefix, 
-                             machine_suffix, 
+                     concat (gcc_exec_prefix
+                             ? gcc_exec_prefix : standard_exec_prefix,
+                             machine_suffix,
                              standard_startfile_prefix, NULL),
                      NULL, PREFIX_PRIORITY_LAST, 0, 1);
        }
@@ -7024,11 +6895,32 @@ main (int argc, char **argv)
      the subdirectory based on the options.  */
   set_multilib_dir ();
 
+  /* Set up to remember the pathname of gcc and any options
+     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);
+  obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
+  xputenv (XOBFINISH (&collect_obstack, char *));
+
+  /* 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)
+    {
+      obstack_init (&collect_obstack);
+      obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
+                   sizeof ("COLLECT_LTO_WRAPPER=") - 1);
+      obstack_grow (&collect_obstack, lto_wrapper_spec,
+                   strlen (lto_wrapper_spec) + 1);
+      xputenv (XOBFINISH (&collect_obstack, char *));
+    }
+
   /* Warn about any switches that no pass was interested in.  */
 
   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.  */
 
@@ -7105,7 +6997,7 @@ main (int argc, char **argv)
       else
        /* The error status indicates that only one set of fixed
           headers should be built.  */
-       fatal ("not configured with sysroot headers suffix");
+       fatal_error ("not configured with sysroot headers suffix");
     }
 
   if (print_help_list)
@@ -7130,9 +7022,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 2009 Free Software Foundation, Inc.\n",
+      printf ("Copyright %s 2010 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"),
@@ -7151,8 +7043,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
       int n;
       const char *thrmod;
 
-      notice ("Target: %s\n", spec_machine);
-      notice ("Configured with: %s\n", configuration_arguments);
+      fnotice (stderr, "Target: %s\n", spec_machine);
+      fnotice (stderr, "Configured with: %s\n", configuration_arguments);
 
 #ifdef THREAD_MODEL_SPEC
       /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
@@ -7166,7 +7058,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
       thrmod = thread_model;
 #endif
 
-      notice ("Thread model: %s\n", thrmod);
+      fnotice (stderr, "Thread model: %s\n", thrmod);
 
       /* compiler_version is truncated at the first space when initialized
         from version string, so truncate version_string at the first space
@@ -7177,17 +7069,18 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
       if (! strncmp (version_string, compiler_version, n)
          && compiler_version[n] == 0)
-       notice ("gcc version %s %s\n", version_string, pkgversion_string);
+       fnotice (stderr, "gcc version %s %s\n", version_string,
+                pkgversion_string);
       else
-       notice ("gcc driver version %s %sexecuting gcc version %s\n",
-               version_string, pkgversion_string, compiler_version);
+       fnotice (stderr, "gcc driver version %s %sexecuting gcc version %s\n",
+                version_string, pkgversion_string, compiler_version);
 
       if (n_infiles == 0)
        return (0);
     }
 
   if (n_infiles == added_libraries)
-    fatal ("no input files");
+    fatal_error ("no input files");
 
   /* Make a place to record the compiler output file names
      that correspond to the input files.  */
@@ -7236,7 +7129,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 ("cannot specify -o with -c or -S with multiple files");
+   fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
 
   if (combine_flag && save_temps_flag)
     {
@@ -7262,7 +7155,7 @@ 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
@@ -7270,7 +7163,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                  value = do_spec (input_file_compiler->spec);
                  infiles[i].preprocessed = true;
                  if (!have_o_argbuf_index)
-                   fatal ("spec '%s' is invalid", input_file_compiler->spec);
+                   fatal_error ("spec %qs is invalid",
+                                input_file_compiler->spec);
                  infiles[i].name = argbuf[have_o_argbuf_index];
                  infiles[i].incompiler
                    = lookup_compiler (infiles[i].name,
@@ -7285,7 +7179,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
          if (this_file_error)
            {
              delete_failure_queue ();
-             error_count++;
+             errorcount++;
              break;
            }
          clear_failure_queue ();
@@ -7307,7 +7201,7 @@ 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.  */
 
@@ -7325,7 +7219,7 @@ 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
@@ -7348,7 +7242,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
              else if (compare_debug && debug_check_temp_file[0])
                {
                  if (verbose_flag)
-                   error ("Recompiling with -fcompare-debug");
+                   inform (0, "recompiling with -fcompare-debug");
 
                  compare_debug = -compare_debug;
                  n_switches = n_switches_debug_check[1];
@@ -7371,7 +7265,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                                         debug_check_temp_file[1]));
 
                  if (verbose_flag)
-                   error ("Comparing final insns dumps");
+                   inform (0, "comparing final insns dumps");
 
                  if (compare_files (debug_check_temp_file))
                    this_file_error = 1;
@@ -7402,7 +7296,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 ();
@@ -7424,13 +7318,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
          }
     }
 
-  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.  */
@@ -7441,9 +7335,10 @@ 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"))
@@ -7452,6 +7347,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
          if (s == NULL)
            linker_name_spec = "ld";
        }
+
+      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");
+       }
+      lto_gcc_spec = argv[0];
+
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
         for collect.  */
       putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);
@@ -7466,23 +7378,23 @@ 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] == '*'))
-       error ("%s: linker input file unused because linking not done",
-              outfiles[i]);
+       warning (0, "%s: linker input file unused because linking not done",
+                outfiles[i]);
 
   /* Delete some or all of the temporary files we made.  */
 
-  if (error_count)
+  if (seen_error ())
     delete_failure_queue ();
   delete_temp_files ();
 
@@ -7493,7 +7405,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
     }
 
   return (signal_count != 0 ? 2
-         : error_count > 0 ? (pass_exit_codes ? greatest_status : 1)
+         : seen_error () ? (pass_exit_codes ? greatest_status : 1)
          : 0);
 }
 
@@ -7588,76 +7500,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)
-{
-  fatal_ice ("internal gcc abort in %s, at %s:%d", func, file, line);
-}
-\f
-/* Output an error message and exit.  */
-
-void
-fatal_ice (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
-  fprintf (stderr, "\n");
-  delete_temp_files ();
-  exit (pass_exit_codes ? ICE_EXIT_CODE : 1);
-}
-
-void
-fatal (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
-  fprintf (stderr, "\n");
-  delete_temp_files ();
-  exit (1);
-}
-
-/* The argument is actually c-format, not gcc-internal-format,
-   but because functions with identical names are used through
-   the rest of the compiler with gcc-internal-format, we just
-   need to hope all users of these functions use the common
-   subset between c-format and gcc-internal-format.  */
-
-void
-error (const char *gmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, gmsgid);
-  fprintf (stderr, "%s: ", programname);
-  vfprintf (stderr, _(gmsgid), ap);
-  va_end (ap);
-
-  fprintf (stderr, "\n");
-}
-
-static void
-notice (const char *cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
+  error ("%s: %m", name);
 }
 \f
 static inline void
@@ -7812,7 +7655,8 @@ used_arg (const char *p, int len)
              if (*q == '\0')
                {
                invalid_matches:
-                 fatal ("multilib spec '%s' is invalid", multilib_matches);
+                 fatal_error ("multilib spec %qs is invalid",
+                              multilib_matches);
                }
              q++;
            }
@@ -8003,8 +7847,8 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_exclusions:
-             fatal ("multilib exclusions '%s' is invalid",
-                    multilib_exclusions);
+             fatal_error ("multilib exclusions %qs is invalid",
+                          multilib_exclusions);
            }
 
          if (! ok)
@@ -8061,8 +7905,8 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal ("multilib select '%s' is invalid",
-                    multilib_select);
+             fatal_error ("multilib select %qs is invalid",
+                          multilib_select);
            }
          ++p;
        }
@@ -8202,7 +8046,7 @@ print_multilib_info (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal ("multilib select '%s' is invalid", multilib_select);
+             fatal_error ("multilib select %qs is invalid", multilib_select);
            }
 
          ++p;
@@ -8240,8 +8084,8 @@ print_multilib_info (void)
                if (*e == '\0')
                  {
                  invalid_exclusion:
-                   fatal ("multilib exclusion '%s' is invalid",
-                          multilib_exclusions);
+                   fatal_error ("multilib exclusion %qs is invalid",
+                                multilib_exclusions);
                  }
 
                if (! m)
@@ -8446,7 +8290,7 @@ getenv_spec_function (int argc, const char **argv)
 
   value = getenv (argv[0]);
   if (!value)
-    fatal ("environment variable \"%s\" not defined", argv[0]);
+    fatal_error ("environment variable %qs not defined", argv[0]);
 
   /* We have to escape every character of the environment variable so
      they are not interpreted as active spec characters.  A
@@ -8459,9 +8303,9 @@ getenv_spec_function (int argc, const char **argv)
       ptr[0] = '\\';
       ptr[1] = *value++;
     }
-  
+
   strcpy (ptr, argv[1]);
-  
+
   return result;
 }
 
@@ -8537,12 +8381,12 @@ compare_version_strings (const char *v1, const char *v2)
     abort ();
   rresult = regexec (&r, v1, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal ("invalid version number `%s'", v1);
+    fatal_error ("invalid version number %qs", v1);
   else if (rresult != 0)
     abort ();
   rresult = regexec (&r, v2, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal ("invalid version number `%s'", v2);
+    fatal_error ("invalid version number %qs", v2);
   else if (rresult != 0)
     abort ();
 
@@ -8585,13 +8429,13 @@ version_compare_spec_function (int argc, const char **argv)
   bool result;
 
   if (argc < 3)
-    fatal ("too few arguments to %%:version-compare");
+    fatal_error ("too few arguments to %%:version-compare");
   if (argv[0][0] == '\0')
     abort ();
   if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!')
     nargs = 2;
   if (argc != nargs + 3)
-    fatal ("too many arguments to %%:version-compare");
+    fatal_error ("too many arguments to %%:version-compare");
 
   switch_len = strlen (argv[nargs + 1]);
   for (i = 0; i < n_switches; i++)
@@ -8632,7 +8476,7 @@ version_compare_spec_function (int argc, const char **argv)
       break;
 
     default:
-      fatal ("unknown operator '%s' in %%:version-compare", argv[0]);
+      fatal_error ("unknown operator %qs in %%:version-compare", argv[0]);
     }
   if (! result)
     return NULL;
@@ -8659,6 +8503,38 @@ include_spec_function (int argc, const char **argv)
   return NULL;
 }
 
+/* %:find-file spec function.  This function replaces its argument by
+    the file found thru find_file, that is the -print-file-name gcc
+    program option. */
+static const char *
+find_file_spec_function (int argc, const char **argv)
+{
+  const char *file;
+
+  if (argc != 1)
+    abort ();
+
+  file = find_file (argv[0]);
+  return file;
+}
+
+
+/* %:find-plugindir spec function.  This function replaces its argument
+    by the -iplugindir=<dir> option.  `dir' is found thru find_file, that
+    is the -print-file-name gcc program option. */
+static const char *
+find_plugindir_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
+{
+  const char *option;
+
+  if (argc != 0)
+    abort ();
+
+  option = concat ("-iplugindir=", find_file ("plugin"), NULL);
+  return option;
+}
+
+
 /* %:print-asm-header spec function.  Print a banner to say that the
    following output is from the assembler.  */
 
@@ -8672,6 +8548,33 @@ print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
   return NULL;
 }
 
+/* Compute a timestamp to initialize flag_random_seed.  */
+
+static unsigned
+get_local_tick (void)
+{
+  unsigned ret = 0;
+
+  /* Get some more or less random data.  */
+#ifdef HAVE_GETTIMEOFDAY
+  {
+    struct timeval tv;
+
+    gettimeofday (&tv, NULL);
+    ret = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  }
+#else
+  {
+    time_t now = time (NULL);
+
+    if (now != (time_t)-1)
+      ret = (unsigned) now;
+  }
+#endif
+
+  return ret;
+}
+
 /* %:compare-debug-dump-opt spec function.  Save the last argument,
    expected to be the last -fdump-final-insns option, or generate a
    temporary.  */
@@ -8683,41 +8586,61 @@ compare_debug_dump_opt_spec_function (int arg,
   const char *ret;
   char *name;
   int which;
+  static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3];
 
   if (arg != 0)
-    fatal ("too many arguments to %%:compare-debug-dump-opt");
-
-  if (!compare_debug)
-    return NULL;
+    fatal_error ("too many arguments to %%:compare-debug-dump-opt");
 
   do_spec_2 ("%{fdump-final-insns=*:%*}");
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0)
+  if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], "."))
     {
+      if (!compare_debug)
+       return NULL;
+
       name = xstrdup (argv[argbuf_index - 1]);
       ret = NULL;
     }
   else
     {
-#define OPT "-fdump-final-insns="
-      ret = "-fdump-final-insns=%g.gkd";
+      const char *ext = NULL;
+
+      if (argbuf_index > 0)
+       {
+         do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
+         ext = ".gkd";
+       }
+      else if (!compare_debug)
+       return NULL;
+      else
+       do_spec_2 ("%g.gkd");
 
-      do_spec_2 (ret + sizeof (OPT) - 1);
       do_spec_1 (" ", 0, NULL);
-#undef OPT
 
       gcc_assert (argbuf_index > 0);
 
-      name = xstrdup (argbuf[argbuf_index - 1]);
+      name = concat (argbuf[argbuf_index - 1], ext, NULL);
+
+      ret = concat ("-fdump-final-insns=", name, NULL);
     }
 
   which = compare_debug < 0;
   debug_check_temp_file[which] = name;
 
-#if 0
-  error ("compare-debug: [%i]=\"%s\", ret %s", which, name, ret);
-#endif
+  if (!which)
+    {
+      unsigned HOST_WIDE_INT value = get_local_tick () ^ getpid ();
+
+      sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value);
+    }
+
+  if (*random_seed)
+    ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ",
+                 ret, NULL);
+
+  if (which)
+    *random_seed = 0;
 
   return ret;
 }
@@ -8733,7 +8656,7 @@ compare_debug_self_opt_spec_function (int arg,
                                      const char **argv ATTRIBUTE_UNUSED)
 {
   if (arg != 0)
-    fatal ("too many arguments to %%:compare-debug-self-opt");
+    fatal_error ("too many arguments to %%:compare-debug-self-opt");
 
   if (compare_debug >= 0)
     return NULL;
@@ -8768,17 +8691,18 @@ compare_debug_auxbase_opt_spec_function (int arg,
   int len;
 
   if (arg == 0)
-    fatal ("too few arguments to %%:compare-debug-auxbase-opt");
+    fatal_error ("too few arguments to %%:compare-debug-auxbase-opt");
 
   if (arg != 1)
-    fatal ("too many arguments to %%:compare-debug-auxbase-opt");
+    fatal_error ("too many arguments to %%:compare-debug-auxbase-opt");
 
   if (compare_debug >= 0)
     return NULL;
 
   len = strlen (argv[0]);
   if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
-    fatal ("argument to %%:compare-debug-auxbase-opt does not end in .gk");
+    fatal_error ("argument to %%:compare-debug-auxbase-opt "
+                "does not end in .gk");
 
   if (debug_auxbase_opt)
     return debug_auxbase_opt;
@@ -8791,5 +8715,7 @@ compare_debug_auxbase_opt_spec_function (int arg,
   memcpy (name + sizeof (OPT) - 1, argv[0], len);
   name[sizeof (OPT) - 1 + len] = '\0';
 
+#undef OPT
+
   return name;
 }